Compare commits
No commits in common. "f6e29a5cae57b24cdf28f2db454e0d8b610467ae" and "85fac3158d84809a66ce013477bf90e54d851436" have entirely different histories.
f6e29a5cae
...
85fac3158d
@ -1,109 +0,0 @@
|
|||||||
import type { Role, RoleResult, StartStep } from "@uncaged/nerve-core";
|
|
||||||
import { hermesAdapter } from "@uncaged/nerve-adapter-hermes";
|
|
||||||
import type { LlmExtractorConfig } from "@uncaged/nerve-workflow-utils";
|
|
||||||
import { createRole, isDryRun } from "@uncaged/nerve-workflow-utils";
|
|
||||||
import { z } from "zod";
|
|
||||||
|
|
||||||
export const committerMetaSchema = z.object({
|
|
||||||
committed: z
|
|
||||||
.boolean()
|
|
||||||
.describe("true if branch created, changes committed, and pushed successfully"),
|
|
||||||
});
|
|
||||||
export type CommitterMeta = z.infer<typeof committerMetaSchema>;
|
|
||||||
|
|
||||||
export type BuildWorkspaceCommitterDeps = {
|
|
||||||
extract: LlmExtractorConfig;
|
|
||||||
nerveRoot: string;
|
|
||||||
workflowName: string;
|
|
||||||
conventionalCommitScopeHint: string;
|
|
||||||
branchCheckoutExample: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
function workspaceCommitterPrompt({
|
|
||||||
threadId,
|
|
||||||
nerveRoot,
|
|
||||||
workflowName,
|
|
||||||
conventionalCommitScopeHint,
|
|
||||||
branchCheckoutExample,
|
|
||||||
}: {
|
|
||||||
threadId: string;
|
|
||||||
nerveRoot: string;
|
|
||||||
workflowName: string;
|
|
||||||
conventionalCommitScopeHint: string;
|
|
||||||
branchCheckoutExample: string;
|
|
||||||
}): string {
|
|
||||||
return `You are the **committer** agent (Hermes) for the **${workflowName}** workflow. The coder finished with a passing build; you branch, commit, and push workspace changes.
|
|
||||||
|
|
||||||
## Context
|
|
||||||
|
|
||||||
1. Read the workflow thread: \`nerve thread show ${threadId}\`
|
|
||||||
2. Your git repository root is: \`${nerveRoot}\` — \`cd\` there for all git commands.
|
|
||||||
|
|
||||||
## Steps (in order)
|
|
||||||
|
|
||||||
1. Run \`git status\`. There should be uncommitted changes from the coder. If there is nothing to commit, set **committed** to false and explain.
|
|
||||||
2. Create a short-lived branch (do not commit directly on the default branch if it would mix unrelated work):
|
|
||||||
- Prefer \`fix/<short-slug>\` or \`feat/<short-slug>\` with a lowercase hyphenated slug from the thread (planner/coder context).
|
|
||||||
- Example: \`${branchCheckoutExample}\`
|
|
||||||
3. \`git add -A\`
|
|
||||||
4. Write a **conventional commit** message summarizing what changed and why (scope may be \`${conventionalCommitScopeHint}\` or similar).
|
|
||||||
5. \`git commit -m "<message>"\` (use multiple \`-m\` if you need a body).
|
|
||||||
6. \`git push -u origin <branch-name>\`
|
|
||||||
|
|
||||||
**committed=true** only if branch was created, commit succeeded, and **push** succeeded.
|
|
||||||
|
|
||||||
End your reply with a JSON line:
|
|
||||||
\`\`\`json
|
|
||||||
{ "committed": true }
|
|
||||||
\`\`\`
|
|
||||||
or
|
|
||||||
\`\`\`json
|
|
||||||
{ "committed": false }
|
|
||||||
\`\`\``;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function buildWorkspaceCommitterRole({
|
|
||||||
extract,
|
|
||||||
nerveRoot,
|
|
||||||
workflowName,
|
|
||||||
conventionalCommitScopeHint,
|
|
||||||
branchCheckoutExample,
|
|
||||||
}: BuildWorkspaceCommitterDeps): Role<CommitterMeta> {
|
|
||||||
const innerRole = createRole(
|
|
||||||
hermesAdapter,
|
|
||||||
async (start: StartStep) =>
|
|
||||||
workspaceCommitterPrompt({
|
|
||||||
threadId: start.meta.threadId,
|
|
||||||
nerveRoot,
|
|
||||||
workflowName,
|
|
||||||
conventionalCommitScopeHint,
|
|
||||||
branchCheckoutExample,
|
|
||||||
}),
|
|
||||||
committerMetaSchema,
|
|
||||||
extract,
|
|
||||||
);
|
|
||||||
|
|
||||||
return async (start, _messages): Promise<RoleResult<CommitterMeta>> => {
|
|
||||||
if (isDryRun(start)) {
|
|
||||||
return {
|
|
||||||
content: "[dry-run] committer skipped (no git branch/commit/push)",
|
|
||||||
meta: { committed: true },
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
const innerStart = {
|
|
||||||
...start,
|
|
||||||
meta: { ...start.meta, workdir: nerveRoot },
|
|
||||||
} as StartStep;
|
|
||||||
|
|
||||||
try {
|
|
||||||
return await innerRole(innerStart, _messages);
|
|
||||||
} catch (e) {
|
|
||||||
const msg = e instanceof Error ? e.message : String(e);
|
|
||||||
return {
|
|
||||||
content: `committer failed: ${msg}`,
|
|
||||||
meta: { committed: false },
|
|
||||||
};
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@ -63,8 +63,6 @@ export function buildDevelopSenseWorkflow({
|
|||||||
extract,
|
extract,
|
||||||
nerveRoot: cwd,
|
nerveRoot: cwd,
|
||||||
workflowName: "develop-sense",
|
workflowName: "develop-sense",
|
||||||
conventionalCommitScopeHint: "sense",
|
|
||||||
branchCheckoutExample: "git checkout -b fix/sense-export-path",
|
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,62 @@
|
|||||||
export {
|
import type { Role, RoleResult, StartStep } from "@uncaged/nerve-core";
|
||||||
buildWorkspaceCommitterRole,
|
import { hermesAdapter } from "@uncaged/nerve-adapter-hermes";
|
||||||
|
import type { LlmExtractorConfig } from "@uncaged/nerve-workflow-utils";
|
||||||
|
import { createRole, isDryRun } from "@uncaged/nerve-workflow-utils";
|
||||||
|
import { z } from "zod";
|
||||||
|
|
||||||
|
import { workspaceCommitterPrompt } from "./prompt.js";
|
||||||
|
|
||||||
|
export const committerMetaSchema = z.object({
|
||||||
|
committed: z
|
||||||
|
.boolean()
|
||||||
|
.describe("true if branch created, changes committed, and pushed successfully"),
|
||||||
|
});
|
||||||
|
export type CommitterMeta = z.infer<typeof committerMetaSchema>;
|
||||||
|
|
||||||
|
export type BuildWorkspaceCommitterDeps = {
|
||||||
|
extract: LlmExtractorConfig;
|
||||||
|
nerveRoot: string;
|
||||||
|
workflowName: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function buildWorkspaceCommitterRole({
|
||||||
|
extract,
|
||||||
|
nerveRoot,
|
||||||
|
workflowName,
|
||||||
|
}: BuildWorkspaceCommitterDeps): Role<CommitterMeta> {
|
||||||
|
const innerRole = createRole(
|
||||||
|
hermesAdapter,
|
||||||
|
async (start: StartStep) =>
|
||||||
|
workspaceCommitterPrompt({
|
||||||
|
threadId: start.meta.threadId,
|
||||||
|
nerveRoot,
|
||||||
|
workflowName,
|
||||||
|
}),
|
||||||
committerMetaSchema,
|
committerMetaSchema,
|
||||||
type BuildWorkspaceCommitterDeps,
|
extract,
|
||||||
type CommitterMeta,
|
);
|
||||||
} from "../../../_shared/workspace-committer.js";
|
|
||||||
|
return async (start, _messages): Promise<RoleResult<CommitterMeta>> => {
|
||||||
|
if (isDryRun(start)) {
|
||||||
|
return {
|
||||||
|
content: "[dry-run] committer skipped (no git branch/commit/push)",
|
||||||
|
meta: { committed: true },
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const innerStart = {
|
||||||
|
...start,
|
||||||
|
meta: { ...start.meta, workdir: nerveRoot },
|
||||||
|
} as StartStep;
|
||||||
|
|
||||||
|
try {
|
||||||
|
return await innerRole(innerStart, _messages);
|
||||||
|
} catch (e) {
|
||||||
|
const msg = e instanceof Error ? e.message : String(e);
|
||||||
|
return {
|
||||||
|
content: `committer failed: ${msg}`,
|
||||||
|
meta: { committed: false },
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|||||||
38
workflows/develop-sense/roles/committer/prompt.ts
Normal file
38
workflows/develop-sense/roles/committer/prompt.ts
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
export function workspaceCommitterPrompt({
|
||||||
|
threadId,
|
||||||
|
nerveRoot,
|
||||||
|
workflowName,
|
||||||
|
}: {
|
||||||
|
threadId: string;
|
||||||
|
nerveRoot: string;
|
||||||
|
workflowName: string;
|
||||||
|
}): string {
|
||||||
|
return `You are the **committer** agent (Hermes) for the **${workflowName}** workflow. The coder finished with a passing build; you branch, commit, and push workspace changes.
|
||||||
|
|
||||||
|
## Context
|
||||||
|
|
||||||
|
1. Read the workflow thread: \`nerve thread show ${threadId}\`
|
||||||
|
2. Your git repository root is: \`${nerveRoot}\` — \`cd\` there for all git commands.
|
||||||
|
|
||||||
|
## Steps (in order)
|
||||||
|
|
||||||
|
1. Run \`git status\`. There should be uncommitted changes from the coder. If there is nothing to commit, set **committed** to false and explain.
|
||||||
|
2. Create a short-lived branch (do not commit directly on the default branch if it would mix unrelated work):
|
||||||
|
- Prefer \`fix/<short-slug>\` or \`feat/<short-slug>\` with a lowercase hyphenated slug from the thread (planner/coder context).
|
||||||
|
- Example: \`git checkout -b fix/sense-export-path\`
|
||||||
|
3. \`git add -A\`
|
||||||
|
4. Write a **conventional commit** message summarizing what changed and why (scope may be \`sense\` or similar).
|
||||||
|
5. \`git commit -m "<message>"\` (use multiple \`-m\` if you need a body).
|
||||||
|
6. \`git push -u origin <branch-name>\`
|
||||||
|
|
||||||
|
**committed=true** only if branch was created, commit succeeded, and **push** succeeded.
|
||||||
|
|
||||||
|
End your reply with a JSON line:
|
||||||
|
\`\`\`json
|
||||||
|
{ "committed": true }
|
||||||
|
\`\`\`
|
||||||
|
or
|
||||||
|
\`\`\`json
|
||||||
|
{ "committed": false }
|
||||||
|
\`\`\``;
|
||||||
|
}
|
||||||
@ -10,5 +10,5 @@
|
|||||||
"declaration": false,
|
"declaration": false,
|
||||||
"types": ["node"]
|
"types": ["node"]
|
||||||
},
|
},
|
||||||
"include": ["./**/*.ts", "../_shared/**/*.ts"]
|
"include": ["./**/*.ts"]
|
||||||
}
|
}
|
||||||
|
|||||||
@ -63,8 +63,6 @@ export function buildDevelopWorkflow({
|
|||||||
extract,
|
extract,
|
||||||
nerveRoot,
|
nerveRoot,
|
||||||
workflowName: "develop-workflow",
|
workflowName: "develop-workflow",
|
||||||
conventionalCommitScopeHint: "workflow",
|
|
||||||
branchCheckoutExample: "git checkout -b feat/workflow-new-step",
|
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,62 @@
|
|||||||
export {
|
import type { Role, RoleResult, StartStep } from "@uncaged/nerve-core";
|
||||||
buildWorkspaceCommitterRole,
|
import { hermesAdapter } from "@uncaged/nerve-adapter-hermes";
|
||||||
|
import type { LlmExtractorConfig } from "@uncaged/nerve-workflow-utils";
|
||||||
|
import { createRole, isDryRun } from "@uncaged/nerve-workflow-utils";
|
||||||
|
import { z } from "zod";
|
||||||
|
|
||||||
|
import { workspaceCommitterPrompt } from "./prompt.js";
|
||||||
|
|
||||||
|
export const committerMetaSchema = z.object({
|
||||||
|
committed: z
|
||||||
|
.boolean()
|
||||||
|
.describe("true if branch created, changes committed, and pushed successfully"),
|
||||||
|
});
|
||||||
|
export type CommitterMeta = z.infer<typeof committerMetaSchema>;
|
||||||
|
|
||||||
|
export type BuildWorkspaceCommitterDeps = {
|
||||||
|
extract: LlmExtractorConfig;
|
||||||
|
nerveRoot: string;
|
||||||
|
workflowName: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function buildWorkspaceCommitterRole({
|
||||||
|
extract,
|
||||||
|
nerveRoot,
|
||||||
|
workflowName,
|
||||||
|
}: BuildWorkspaceCommitterDeps): Role<CommitterMeta> {
|
||||||
|
const innerRole = createRole(
|
||||||
|
hermesAdapter,
|
||||||
|
async (start: StartStep) =>
|
||||||
|
workspaceCommitterPrompt({
|
||||||
|
threadId: start.meta.threadId,
|
||||||
|
nerveRoot,
|
||||||
|
workflowName,
|
||||||
|
}),
|
||||||
committerMetaSchema,
|
committerMetaSchema,
|
||||||
type BuildWorkspaceCommitterDeps,
|
extract,
|
||||||
type CommitterMeta,
|
);
|
||||||
} from "../../../_shared/workspace-committer.js";
|
|
||||||
|
return async (start, _messages): Promise<RoleResult<CommitterMeta>> => {
|
||||||
|
if (isDryRun(start)) {
|
||||||
|
return {
|
||||||
|
content: "[dry-run] committer skipped (no git branch/commit/push)",
|
||||||
|
meta: { committed: true },
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const innerStart = {
|
||||||
|
...start,
|
||||||
|
meta: { ...start.meta, workdir: nerveRoot },
|
||||||
|
} as StartStep;
|
||||||
|
|
||||||
|
try {
|
||||||
|
return await innerRole(innerStart, _messages);
|
||||||
|
} catch (e) {
|
||||||
|
const msg = e instanceof Error ? e.message : String(e);
|
||||||
|
return {
|
||||||
|
content: `committer failed: ${msg}`,
|
||||||
|
meta: { committed: false },
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|||||||
38
workflows/develop-workflow/roles/committer/prompt.ts
Normal file
38
workflows/develop-workflow/roles/committer/prompt.ts
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
export function workspaceCommitterPrompt({
|
||||||
|
threadId,
|
||||||
|
nerveRoot,
|
||||||
|
workflowName,
|
||||||
|
}: {
|
||||||
|
threadId: string;
|
||||||
|
nerveRoot: string;
|
||||||
|
workflowName: string;
|
||||||
|
}): string {
|
||||||
|
return `You are the **committer** agent (Hermes) for the **${workflowName}** workflow. The coder finished with a passing build; you branch, commit, and push workspace changes.
|
||||||
|
|
||||||
|
## Context
|
||||||
|
|
||||||
|
1. Read the workflow thread: \`nerve thread show ${threadId}\`
|
||||||
|
2. Your git repository root is: \`${nerveRoot}\` — \`cd\` there for all git commands.
|
||||||
|
|
||||||
|
## Steps (in order)
|
||||||
|
|
||||||
|
1. Run \`git status\`. There should be uncommitted changes from the coder. If there is nothing to commit, set **committed** to false and explain.
|
||||||
|
2. Create a short-lived branch (do not commit directly on the default branch if it would mix unrelated work):
|
||||||
|
- Prefer \`fix/<short-slug>\` or \`feat/<short-slug>\` with a lowercase hyphenated slug from the thread (planner/coder context).
|
||||||
|
- Example: \`git checkout -b feat/workflow-new-step\`
|
||||||
|
3. \`git add -A\`
|
||||||
|
4. Write a **conventional commit** message summarizing what changed and why (scope may be \`workflow\` or similar).
|
||||||
|
5. \`git commit -m "<message>"\` (use multiple \`-m\` if you need a body).
|
||||||
|
6. \`git push -u origin <branch-name>\`
|
||||||
|
|
||||||
|
**committed=true** only if branch was created, commit succeeded, and **push** succeeded.
|
||||||
|
|
||||||
|
End your reply with a JSON line:
|
||||||
|
\`\`\`json
|
||||||
|
{ "committed": true }
|
||||||
|
\`\`\`
|
||||||
|
or
|
||||||
|
\`\`\`json
|
||||||
|
{ "committed": false }
|
||||||
|
\`\`\``;
|
||||||
|
}
|
||||||
@ -9,5 +9,5 @@
|
|||||||
"noEmit": true,
|
"noEmit": true,
|
||||||
"types": ["node"]
|
"types": ["node"]
|
||||||
},
|
},
|
||||||
"include": ["./**/*.ts", "../_shared/**/*.ts"]
|
"include": ["./**/*.ts"]
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user