glm-coding-router 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,134 @@
1
+ import os from "node:os";
2
+ import { loadConfig } from "../core/config.js";
3
+ import { locateClaude } from "../core/claude.js";
4
+ import { createGlmEnv } from "../core/env.js";
5
+ import { Errors } from "../core/errors.js";
6
+ import { gitTopLevel } from "../core/git.js";
7
+ import { logger, redact } from "../core/logging.js";
8
+ import { spawnAgent } from "../core/process.js";
9
+ import { applyProfile } from "../core/profile.js";
10
+ import { readStdin, resolvePrompt } from "../core/prompt.js";
11
+ import { resolveZaiApiKey } from "../core/zai-key.js";
12
+ import { createDelegateWorktree, delegateBranch, delegateWorktreePath, removeDelegateWorktree, rollbackDelegateBranch, validateDelegateName, } from "../core/worktree.js";
13
+ import { buildWorkerArgs } from "../bin/glm-worker.js";
14
+ import { emitJson } from "./context.js";
15
+ /** A profile literally named after the delegate applies unless --profile says otherwise. */
16
+ function resolveProfileName(name, options, config) {
17
+ if (options.profile) {
18
+ return options.profile;
19
+ }
20
+ return config.profiles[name] ? name : undefined;
21
+ }
22
+ function banner(text, quiet) {
23
+ if (!quiet) {
24
+ process.stdout.write(`${text}\n`);
25
+ }
26
+ }
27
+ /**
28
+ * glm-router delegate (spec §54 v0.3, specs/delegate-worktrees.md): run a GLM
29
+ * worker in an isolated git worktree. Worktree + branch are kept after the run
30
+ * (no automatic git commits); --remove drops the worktree after success only.
31
+ */
32
+ export async function delegateCommand(name, promptArgs, options, deps = {}) {
33
+ validateDelegateName(name);
34
+ const cwd = deps.cwd ?? process.cwd();
35
+ const env = deps.env ?? process.env;
36
+ const runGit = deps.runGit;
37
+ const repoRoot = await gitTopLevel(cwd, runGit);
38
+ if (!repoRoot) {
39
+ throw Errors.gitRepoRequired(cwd);
40
+ }
41
+ const home = deps.home ?? os.homedir();
42
+ const baseConfig = loadConfig(home);
43
+ const profileName = resolveProfileName(name, options, baseConfig);
44
+ const config = applyProfile(baseConfig, profileName);
45
+ const resolved = resolveZaiApiKey({ env, readUserEnv: deps.readUserEnv });
46
+ if (!resolved) {
47
+ throw Errors.zaiKeyMissing();
48
+ }
49
+ const claudePath = locateClaude(config, env);
50
+ const prompt = await resolvePrompt(promptArgs, deps.readStdinFn ?? readStdin, "glm-router delegate");
51
+ const branch = delegateBranch(name);
52
+ const worktreePath = delegateWorktreePath(repoRoot, name);
53
+ if (options.dryRun) {
54
+ if (options.json) {
55
+ emitJson({ name, profile: profileName ?? null, worktree: worktreePath, branch, dryRun: true });
56
+ }
57
+ else {
58
+ banner(`would create worktree ${worktreePath}`, options.quiet);
59
+ banner(`would create branch ${branch} (from HEAD)`, options.quiet);
60
+ banner(`would run glm-worker in the worktree with the given prompt`, options.quiet);
61
+ }
62
+ return 0;
63
+ }
64
+ // Collision checks run inside createDelegateWorktree before anything is written.
65
+ const createdPath = await createDelegateWorktree(repoRoot, name, { runGit });
66
+ if (options.json) {
67
+ emitJson({ name, profile: profileName ?? null, worktree: createdPath, branch });
68
+ }
69
+ else {
70
+ banner(`[glm-router] delegate ${name}`, options.quiet);
71
+ banner(`[glm-router] worktree ${createdPath}`, options.quiet);
72
+ banner(`[glm-router] branch ${branch}`, options.quiet);
73
+ if (profileName) {
74
+ banner(`[glm-router] profile ${profileName}`, options.quiet);
75
+ }
76
+ }
77
+ const args = buildWorkerArgs(prompt, config);
78
+ const childEnv = createGlmEnv(config, resolved.key, env);
79
+ logger.debug(redact(`spawning ${claudePath} in ${createdPath}`, [resolved.key]));
80
+ const spawn = deps.spawn ?? ((binPath, spawnOptions) => spawnAgent(binPath, {
81
+ args: [...spawnOptions.args],
82
+ cwd: spawnOptions.cwd,
83
+ env: spawnOptions.env,
84
+ interactive: false,
85
+ }));
86
+ let exitCode;
87
+ try {
88
+ exitCode = await spawn(claudePath, { args, cwd: createdPath, env: childEnv, interactive: false });
89
+ }
90
+ catch (error) {
91
+ // Worker never started: roll back the pristine worktree and its branch so
92
+ // the same delegate name can simply be re-run.
93
+ const worktreeComplaint = await removeDelegateWorktree(repoRoot, createdPath, { runGit });
94
+ if (worktreeComplaint) {
95
+ logger.debug(`worktree kept after spawn failure: ${worktreeComplaint}`);
96
+ }
97
+ const branchComplaint = await rollbackDelegateBranch(repoRoot, branch, { runGit });
98
+ if (branchComplaint) {
99
+ logger.debug(`branch kept after spawn failure: ${branchComplaint}`);
100
+ }
101
+ throw error;
102
+ }
103
+ let removed = false;
104
+ if (options.remove && exitCode === 0) {
105
+ const complaint = await removeDelegateWorktree(repoRoot, createdPath, { runGit });
106
+ if (complaint) {
107
+ removed = false;
108
+ const message = `git refused to remove the worktree (it may contain uncommitted work):\n ${complaint.trim().split("\n").join("\n ")}`;
109
+ if (options.json) {
110
+ emitJson({ name, exitCode, worktree: createdPath, branch, removed: false, note: message });
111
+ }
112
+ else {
113
+ banner(`[glm-router] ${message}`, options.quiet);
114
+ banner(`[glm-router] worktree kept at ${createdPath}`, options.quiet);
115
+ }
116
+ return exitCode;
117
+ }
118
+ removed = true;
119
+ }
120
+ if (options.json) {
121
+ emitJson({ name, exitCode, worktree: createdPath, branch, removed });
122
+ }
123
+ else {
124
+ banner(`[glm-router] worker exited ${exitCode}`, options.quiet);
125
+ if (removed) {
126
+ banner(`[glm-router] worktree removed; branch ${branch} kept`, options.quiet);
127
+ }
128
+ else {
129
+ banner(`[glm-router] worktree kept at ${createdPath}`, options.quiet);
130
+ banner(`[glm-router] next: inspect it, then merge ${branch} (or discard with git worktree remove)`, options.quiet);
131
+ }
132
+ }
133
+ return exitCode;
134
+ }
@@ -96,6 +96,30 @@ export const Errors = {
96
96
  ],
97
97
  exitCode: ExitCode.InvalidArgs,
98
98
  }),
99
+ gitNotFound: () => new GlmRouterError({
100
+ name: "GIT_NOT_FOUND",
101
+ message: "git was not found on PATH.",
102
+ hint: ["delegate needs git for worktree isolation.", "", "Install Git for Windows: https://git-scm.com/download/win"],
103
+ exitCode: ExitCode.ProjectRootNotFound,
104
+ }),
105
+ gitRepoRequired: (cwd) => new GlmRouterError({
106
+ name: "GIT_REPO_REQUIRED",
107
+ message: `Not inside a git repository (cwd: ${cwd}).`,
108
+ hint: ["delegate runs each worker in a git worktree and needs a repo root.", "", "Run it from inside the project's git repository, or create one:", "", " git init"],
109
+ exitCode: ExitCode.ProjectRootNotFound,
110
+ }),
111
+ worktreeFailed: (operation, cause, hint) => new GlmRouterError({
112
+ name: "WORKTREE_FAILED",
113
+ message: `git ${operation} failed: ${cause.trim() || "unknown git error"}`,
114
+ hint: hint ?? ["Fix the state git describes above, then re-run the delegate command."],
115
+ exitCode: ExitCode.ManagedFileWriteFailed,
116
+ }),
117
+ invalidDelegateName: (name) => new GlmRouterError({
118
+ name: "INVALID_DELEGATE_NAME",
119
+ message: `"${name}" is not a valid delegate name.`,
120
+ hint: ["Use letters, digits, dots, dashes, underscores; start with a letter or digit.", "", "Examples: backend, auth-refresh, tests.v2"],
121
+ exitCode: ExitCode.InvalidArgs,
122
+ }),
99
123
  managedBlockCorrupt: (file, cause) => new GlmRouterError({
100
124
  name: "MANAGED_BLOCK_CORRUPT",
101
125
  message: `Managed block in ${file} is malformed: ${cause}`,
@@ -0,0 +1,31 @@
1
+ import { execFile } from "node:child_process";
2
+ import path from "node:path";
3
+ import { Errors } from "./errors.js";
4
+ function isENOENT(error) {
5
+ return error !== null && typeof error === "object" && error.code === "ENOENT";
6
+ }
7
+ /** Real git runner: resolves with the exit code instead of throwing on failure. */
8
+ export const runGit = (args, cwd) => new Promise((resolve, reject) => {
9
+ execFile("git", args, { cwd, windowsHide: true, encoding: "utf8", maxBuffer: 16 * 1024 * 1024 }, (error, stdout, stderr) => {
10
+ if (error && isENOENT(error)) {
11
+ reject(Errors.gitNotFound());
12
+ return;
13
+ }
14
+ const code = error && typeof error.code === "number"
15
+ ? error.code
16
+ : 0;
17
+ resolve({ code, stdout: stdout ?? "", stderr: stderr ?? "" });
18
+ });
19
+ });
20
+ /**
21
+ * Strict repo-root lookup for delegate (specs/delegate-worktrees.md):
22
+ * unlike findProjectRoot, undefined when cwd is not inside a git repo.
23
+ */
24
+ export async function gitTopLevel(cwd, run = runGit) {
25
+ const result = await run(["rev-parse", "--show-toplevel"], cwd);
26
+ if (result.code !== 0) {
27
+ return undefined;
28
+ }
29
+ const root = result.stdout.trim();
30
+ return root.length > 0 ? path.resolve(root) : undefined;
31
+ }
@@ -0,0 +1,118 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import { runGit } from "./git.js";
4
+ import { Errors } from "./errors.js";
5
+ import { logger } from "./logging.js";
6
+ /** Branch prefix for delegate worktrees (specs/delegate-worktrees.md). */
7
+ export const DELEGATE_BRANCH_PREFIX = "glm/delegate/";
8
+ /** Valid delegate slugs: no path separators, spaces, or leading dash (specs/delegate-worktrees.md). */
9
+ export function validateDelegateName(name) {
10
+ if (!/^[A-Za-z0-9][A-Za-z0-9._-]*$/.test(name) || name === "." || name === ".." || name.toLowerCase() === ".git") {
11
+ throw Errors.invalidDelegateName(name);
12
+ }
13
+ }
14
+ export function delegateBranch(name) {
15
+ return `${DELEGATE_BRANCH_PREFIX}${name}`;
16
+ }
17
+ /**
18
+ * Worktrees live outside the repo so the main checkout's status stays clean
19
+ * and no .gitignore edit is ever needed: <parent-of-root>/<repo>.glm-worktrees/<name>
20
+ */
21
+ export function worktreeBaseDir(repoRoot) {
22
+ return path.join(path.dirname(repoRoot), `${path.basename(repoRoot)}.glm-worktrees`);
23
+ }
24
+ export function delegateWorktreePath(repoRoot, name) {
25
+ return path.join(worktreeBaseDir(repoRoot), name);
26
+ }
27
+ function ok(result) {
28
+ return result.code === 0;
29
+ }
30
+ /** True when a local branch already exists (rev-parse --verify --quiet). */
31
+ export async function branchExists(repoRoot, branch, deps = {}) {
32
+ const run = deps.runGit ?? runGit;
33
+ const result = await run(["rev-parse", "--verify", "--quiet", `refs/heads/${branch}`], repoRoot);
34
+ return ok(result);
35
+ }
36
+ /** True when HEAD resolves (the repo has at least one commit). */
37
+ export async function headIsBorn(repoRoot, deps = {}) {
38
+ const run = deps.runGit ?? runGit;
39
+ const result = await run(["rev-parse", "--verify", "--quiet", "HEAD"], repoRoot);
40
+ return ok(result);
41
+ }
42
+ /**
43
+ * Pre-flight collision checks shared by the real run and --dry-run
44
+ * (specs/delegate-worktrees.md): fail before creating anything.
45
+ */
46
+ export async function assertWorktreeAvailable(repoRoot, name, deps = {}) {
47
+ const existsSync = deps.existsSync ?? fs.existsSync;
48
+ const branch = delegateBranch(name);
49
+ const worktreePath = delegateWorktreePath(repoRoot, name);
50
+ if (await branchExists(repoRoot, branch, deps)) {
51
+ throw Errors.worktreeFailed("branch", `branch ${branch} already exists`, [
52
+ "Inspect or merge it first:",
53
+ "",
54
+ ` git log ${branch}`,
55
+ ` git merge ${branch}`,
56
+ "",
57
+ `or delete it if it is unwanted:`,
58
+ "",
59
+ ` git branch -D ${branch}`,
60
+ ]);
61
+ }
62
+ if (existsSync(worktreePath)) {
63
+ throw Errors.worktreeFailed("worktree add", `path already exists: ${worktreePath}`, [
64
+ "A previous worktree directory is in the way:",
65
+ "",
66
+ ` ${worktreePath}`,
67
+ "",
68
+ "Remove it (or run `git worktree prune`) and re-run the delegate command.",
69
+ ]);
70
+ }
71
+ if (!(await headIsBorn(repoRoot, deps))) {
72
+ throw Errors.worktreeFailed("worktree add", "HEAD does not point at a commit (repository has no commits yet)", [
73
+ "delegate creates the worktree from HEAD, so the repository needs at least one commit first:",
74
+ "",
75
+ " git add -A && git commit -m \"initial commit\"",
76
+ ]);
77
+ }
78
+ return worktreePath;
79
+ }
80
+ /** Create the delegate worktree + branch from HEAD. Returns the worktree path. */
81
+ export async function createDelegateWorktree(repoRoot, name, deps = {}) {
82
+ const run = deps.runGit ?? runGit;
83
+ const worktreePath = await assertWorktreeAvailable(repoRoot, name, deps);
84
+ const branch = delegateBranch(name);
85
+ logger.debug(`git worktree add -b ${branch} ${worktreePath}`);
86
+ const result = await run(["worktree", "add", "-b", branch, worktreePath], repoRoot);
87
+ if (!ok(result)) {
88
+ throw Errors.worktreeFailed("worktree add", result.stderr || result.stdout, ["The worktree was not created; the repository was left as it was."]);
89
+ }
90
+ return worktreePath;
91
+ }
92
+ /**
93
+ * Remove a delegate worktree with plain `git worktree remove` — git refuses
94
+ * on dirty/untracked trees, which is exactly the safety we want
95
+ * (specs/delegate-worktrees.md, `--remove`). Never touches the branch.
96
+ * Returns undefined when removal succeeded, or git's complaint when not.
97
+ */
98
+ export async function removeDelegateWorktree(repoRoot, worktreePath, deps = {}) {
99
+ const run = deps.runGit ?? runGit;
100
+ const result = await run(["worktree", "remove", worktreePath], repoRoot);
101
+ if (ok(result)) {
102
+ return undefined;
103
+ }
104
+ return result.stderr || result.stdout || "git worktree remove failed";
105
+ }
106
+ /**
107
+ * Delete a branch this invocation created and never advanced (worker never
108
+ * started). Only ever called on the spawn-failure rollback path, where the
109
+ * branch provably sits at HEAD — never on branches a worker may have moved.
110
+ */
111
+ export async function rollbackDelegateBranch(repoRoot, branch, deps = {}) {
112
+ const run = deps.runGit ?? runGit;
113
+ const result = await run(["branch", "-D", branch], repoRoot);
114
+ if (ok(result)) {
115
+ return undefined;
116
+ }
117
+ return result.stderr || result.stdout || "git branch -D failed";
118
+ }
@@ -1,46 +1,46 @@
1
1
  /** Managed block content for AGENTS.md (spec §24). Keep in sync with the spec. */
2
- export const AGENTS_MANAGED_BLOCK = `<!-- glm-coding-router:start -->
3
-
4
- ## GLM Worker Delegation
5
-
6
- Available commands:
7
-
8
- - \`glm-worker "<task>"\`
9
- - \`glm-review "<task>"\`
10
-
11
- Codex is the primary orchestrator.
12
-
13
- Delegate:
14
- - CRUD
15
- - boilerplate
16
- - tests
17
- - documentation
18
- - mechanical refactoring
19
- - repository exploration
20
- - straightforward implementation
21
-
22
- Keep in Codex:
23
- - requirements
24
- - planning
25
- - architecture
26
- - ambiguous business logic
27
- - complex debugging
28
- - security decisions
29
- - integration
30
- - final review
31
-
32
- Before delegation create a task packet:
33
-
34
- TASK
35
- SCOPE
36
- FILES ALLOWED TO MODIFY
37
- FILES NOT TO MODIFY
38
- REQUIREMENTS
39
- CONSTRAINTS
40
- ACCEPTANCE CRITERIA
41
- VALIDATION
42
- EXPECTED OUTPUT
43
-
44
- Never trust a worker's success report without inspecting the resulting changes.
45
-
2
+ export const AGENTS_MANAGED_BLOCK = `<!-- glm-coding-router:start -->
3
+
4
+ ## GLM Worker Delegation
5
+
6
+ Available commands:
7
+
8
+ - \`glm-worker "<task>"\`
9
+ - \`glm-review "<task>"\`
10
+
11
+ Codex is the primary orchestrator.
12
+
13
+ Delegate:
14
+ - CRUD
15
+ - boilerplate
16
+ - tests
17
+ - documentation
18
+ - mechanical refactoring
19
+ - repository exploration
20
+ - straightforward implementation
21
+
22
+ Keep in Codex:
23
+ - requirements
24
+ - planning
25
+ - architecture
26
+ - ambiguous business logic
27
+ - complex debugging
28
+ - security decisions
29
+ - integration
30
+ - final review
31
+
32
+ Before delegation create a task packet:
33
+
34
+ TASK
35
+ SCOPE
36
+ FILES ALLOWED TO MODIFY
37
+ FILES NOT TO MODIFY
38
+ REQUIREMENTS
39
+ CONSTRAINTS
40
+ ACCEPTANCE CRITERIA
41
+ VALIDATION
42
+ EXPECTED OUTPUT
43
+
44
+ Never trust a worker's success report without inspecting the resulting changes.
45
+
46
46
  <!-- glm-coding-router:end -->`;
@@ -1,49 +1,49 @@
1
1
  /** Managed block content for CLAUDE.md (spec §20). Keep in sync with the spec. */
2
- export const CLAUDE_MANAGED_BLOCK = `<!-- glm-coding-router:start -->
3
-
4
- ## GLM Worker Delegation
5
-
6
- GLM workers available:
7
-
8
- - \`glm-worker "<task>"\`
9
- - \`glm-review "<task>"\`
10
-
11
- Delegate well-scoped, implementation-heavy work to GLM.
12
-
13
- Use GLM for:
14
- - repository exploration
15
- - CRUD
16
- - boilerplate
17
- - tests
18
- - documentation
19
- - mechanical refactoring
20
- - straightforward implementation
21
-
22
- Claude remains responsible for:
23
- - requirements
24
- - architecture
25
- - ambiguous business rules
26
- - security-sensitive decisions
27
- - complex debugging
28
- - integration
29
- - final review
30
-
31
- Before delegation, define:
32
- - task
33
- - scope
34
- - allowed files
35
- - forbidden files
36
- - requirements
37
- - constraints
38
- - acceptance criteria
39
- - validation command
40
- - expected output
41
-
42
- After worker completion:
43
- 1. inspect the actual diff
44
- 2. validate against requirements
45
- 3. run relevant tests
46
- 4. resolve integration problems
47
- 5. accept only after verification
48
-
2
+ export const CLAUDE_MANAGED_BLOCK = `<!-- glm-coding-router:start -->
3
+
4
+ ## GLM Worker Delegation
5
+
6
+ GLM workers available:
7
+
8
+ - \`glm-worker "<task>"\`
9
+ - \`glm-review "<task>"\`
10
+
11
+ Delegate well-scoped, implementation-heavy work to GLM.
12
+
13
+ Use GLM for:
14
+ - repository exploration
15
+ - CRUD
16
+ - boilerplate
17
+ - tests
18
+ - documentation
19
+ - mechanical refactoring
20
+ - straightforward implementation
21
+
22
+ Claude remains responsible for:
23
+ - requirements
24
+ - architecture
25
+ - ambiguous business rules
26
+ - security-sensitive decisions
27
+ - complex debugging
28
+ - integration
29
+ - final review
30
+
31
+ Before delegation, define:
32
+ - task
33
+ - scope
34
+ - allowed files
35
+ - forbidden files
36
+ - requirements
37
+ - constraints
38
+ - acceptance criteria
39
+ - validation command
40
+ - expected output
41
+
42
+ After worker completion:
43
+ 1. inspect the actual diff
44
+ 2. validate against requirements
45
+ 3. run relevant tests
46
+ 4. resolve integration problems
47
+ 5. accept only after verification
48
+
49
49
  <!-- glm-coding-router:end -->`;
@@ -1,68 +1,68 @@
1
1
  /** Codex skill definition (spec §26). Keep in sync with the spec. */
2
2
  export const GLM_DELEGATION_SKILL_NAME = "glm-delegation";
3
- export const GLM_DELEGATION_SKILL_MD = `---
4
- name: glm-delegation
5
- description: >
6
- Delegate well-scoped implementation, testing,
7
- repository exploration, boilerplate, CRUD,
8
- documentation, and mechanical refactoring to
9
- GLM Coding Plan workers.
10
- ---
11
-
12
- # GLM Delegation
13
-
14
- Available commands:
15
-
16
- glm-worker "<task>"
17
- glm-review "<task>"
18
-
19
- ## Use glm-review for
20
-
21
- - repository exploration
22
- - dependency analysis
23
- - locating implementations
24
- - call-chain discovery
25
- - code review
26
-
27
- ## Use glm-worker for
28
-
29
- - CRUD
30
- - unit tests
31
- - implementation
32
- - documentation
33
- - repetitive changes
34
- - mechanical refactoring
35
-
36
- ## Keep in primary Codex agent
37
-
38
- - requirements
39
- - architecture
40
- - ambiguous rules
41
- - security-sensitive design
42
- - difficult debugging
43
- - integration
44
- - final acceptance
45
-
46
- ## Delegation packet
47
-
48
- Always provide:
49
-
50
- TASK
51
- SCOPE
52
- ALLOWED FILES
53
- FORBIDDEN FILES
54
- REQUIREMENTS
55
- CONSTRAINTS
56
- ACCEPTANCE CRITERIA
57
- VALIDATION
58
- EXPECTED OUTPUT
59
-
60
- ## Verification
61
-
62
- After GLM finishes:
63
-
64
- - inspect the actual diff
65
- - independently run relevant validation
66
- - compare implementation with requirements
67
- - reject or correct worker output when needed
3
+ export const GLM_DELEGATION_SKILL_MD = `---
4
+ name: glm-delegation
5
+ description: >
6
+ Delegate well-scoped implementation, testing,
7
+ repository exploration, boilerplate, CRUD,
8
+ documentation, and mechanical refactoring to
9
+ GLM Coding Plan workers.
10
+ ---
11
+
12
+ # GLM Delegation
13
+
14
+ Available commands:
15
+
16
+ glm-worker "<task>"
17
+ glm-review "<task>"
18
+
19
+ ## Use glm-review for
20
+
21
+ - repository exploration
22
+ - dependency analysis
23
+ - locating implementations
24
+ - call-chain discovery
25
+ - code review
26
+
27
+ ## Use glm-worker for
28
+
29
+ - CRUD
30
+ - unit tests
31
+ - implementation
32
+ - documentation
33
+ - repetitive changes
34
+ - mechanical refactoring
35
+
36
+ ## Keep in primary Codex agent
37
+
38
+ - requirements
39
+ - architecture
40
+ - ambiguous rules
41
+ - security-sensitive design
42
+ - difficult debugging
43
+ - integration
44
+ - final acceptance
45
+
46
+ ## Delegation packet
47
+
48
+ Always provide:
49
+
50
+ TASK
51
+ SCOPE
52
+ ALLOWED FILES
53
+ FORBIDDEN FILES
54
+ REQUIREMENTS
55
+ CONSTRAINTS
56
+ ACCEPTANCE CRITERIA
57
+ VALIDATION
58
+ EXPECTED OUTPUT
59
+
60
+ ## Verification
61
+
62
+ After GLM finishes:
63
+
64
+ - inspect the actual diff
65
+ - independently run relevant validation
66
+ - compare implementation with requirements
67
+ - reject or correct worker output when needed
68
68
  `;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "glm-coding-router",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "GLM Coding Plan workers for Claude Code and Codex",
5
5
  "type": "module",
6
6
  "license": "MIT",