aiwcli 0.11.1 → 0.12.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.
Files changed (108) hide show
  1. package/dist/commands/clear.d.ts +8 -0
  2. package/dist/commands/clear.js +86 -0
  3. package/dist/lib/bmad-installer.d.ts +2 -27
  4. package/dist/lib/bmad-installer.js +3 -43
  5. package/dist/lib/claude-settings-types.d.ts +2 -1
  6. package/dist/lib/env-compat.d.ts +0 -8
  7. package/dist/lib/env-compat.js +0 -12
  8. package/dist/lib/git/index.d.ts +0 -1
  9. package/dist/lib/gitignore-manager.d.ts +0 -2
  10. package/dist/lib/gitignore-manager.js +1 -1
  11. package/dist/lib/hooks-merger.d.ts +1 -15
  12. package/dist/lib/hooks-merger.js +1 -1
  13. package/dist/lib/index.d.ts +3 -7
  14. package/dist/lib/index.js +3 -11
  15. package/dist/lib/output.d.ts +2 -1
  16. package/dist/lib/settings-hierarchy.d.ts +1 -13
  17. package/dist/lib/settings-hierarchy.js +1 -1
  18. package/dist/lib/template-installer.d.ts +5 -9
  19. package/dist/lib/template-installer.js +2 -12
  20. package/dist/lib/template-linter.d.ts +3 -10
  21. package/dist/lib/template-linter.js +2 -2
  22. package/dist/lib/template-resolver.d.ts +6 -0
  23. package/dist/lib/template-resolver.js +10 -0
  24. package/dist/lib/template-settings-reconstructor.d.ts +1 -1
  25. package/dist/lib/template-settings-reconstructor.js +17 -24
  26. package/dist/lib/terminal.d.ts +3 -14
  27. package/dist/lib/terminal.js +0 -4
  28. package/dist/lib/version.d.ts +2 -11
  29. package/dist/lib/version.js +2 -2
  30. package/dist/lib/windsurf-hooks-merger.d.ts +1 -15
  31. package/dist/lib/windsurf-hooks-merger.js +1 -1
  32. package/dist/templates/_shared/.codex/workflows/handoff.md +1 -1
  33. package/dist/templates/_shared/.windsurf/workflows/handoff.md +1 -1
  34. package/dist/templates/_shared/hooks-ts/session_start.ts +15 -20
  35. package/dist/templates/_shared/hooks-ts/user_prompt_submit.ts +12 -14
  36. package/dist/templates/_shared/lib-ts/CLAUDE.md +56 -7
  37. package/dist/templates/_shared/lib-ts/base/hook-utils.ts +174 -43
  38. package/dist/templates/_shared/lib-ts/base/state-io.ts +11 -2
  39. package/dist/templates/_shared/lib-ts/base/subprocess-utils.ts +181 -165
  40. package/dist/templates/_shared/lib-ts/package.json +1 -2
  41. package/dist/templates/_shared/lib-ts/templates/plan-context.ts +27 -34
  42. package/dist/templates/_shared/lib-ts/types.ts +17 -2
  43. package/dist/templates/_shared/scripts/status_line.ts +1 -1
  44. package/dist/templates/_shared/workflows/handoff.md +1 -1
  45. package/dist/templates/cc-native/.claude/settings.json +183 -175
  46. package/dist/templates/cc-native/_cc-native/agents/CLAUDE.md +23 -1
  47. package/dist/templates/cc-native/_cc-native/agents/plan-questions/PLAN-QUESTIONER.md +70 -0
  48. package/dist/templates/cc-native/_cc-native/hooks/CLAUDE.md +6 -1
  49. package/dist/templates/cc-native/_cc-native/hooks/cc-native-plan-review.ts +91 -57
  50. package/dist/templates/cc-native/_cc-native/hooks/enhance_plan_post_subagent.ts +38 -0
  51. package/dist/templates/cc-native/_cc-native/hooks/enhance_plan_post_write.ts +51 -0
  52. package/dist/templates/cc-native/_cc-native/hooks/mark_questions_asked.ts +53 -0
  53. package/dist/templates/cc-native/_cc-native/hooks/plan_questions_early.ts +15 -15
  54. package/dist/templates/cc-native/_cc-native/lib-ts/artifacts.ts +95 -65
  55. package/dist/templates/cc-native/_cc-native/lib-ts/cc-native-state.ts +64 -16
  56. package/dist/templates/cc-native/_cc-native/lib-ts/cli-output-parser.ts +1 -1
  57. package/dist/templates/cc-native/_cc-native/lib-ts/corroboration.ts +6 -2
  58. package/dist/templates/cc-native/_cc-native/lib-ts/index.ts +0 -4
  59. package/dist/templates/cc-native/_cc-native/lib-ts/orchestrator.ts +40 -219
  60. package/dist/templates/cc-native/_cc-native/lib-ts/plan-enhancement.ts +41 -0
  61. package/dist/templates/cc-native/_cc-native/lib-ts/plan-questions.ts +101 -0
  62. package/dist/templates/cc-native/_cc-native/lib-ts/reviewers/agent.ts +22 -226
  63. package/dist/templates/cc-native/_cc-native/lib-ts/reviewers/base/base-agent.ts +217 -0
  64. package/dist/templates/cc-native/_cc-native/lib-ts/reviewers/index.ts +5 -3
  65. package/dist/templates/cc-native/_cc-native/lib-ts/reviewers/providers/claude-agent.ts +65 -0
  66. package/dist/templates/cc-native/_cc-native/lib-ts/reviewers/providers/codex-agent.ts +184 -0
  67. package/dist/templates/cc-native/_cc-native/lib-ts/reviewers/providers/gemini-agent.ts +39 -0
  68. package/dist/templates/cc-native/_cc-native/lib-ts/reviewers/providers/orchestrator-claude-agent.ts +195 -0
  69. package/dist/templates/cc-native/_cc-native/lib-ts/reviewers/schemas.ts +201 -0
  70. package/dist/templates/cc-native/_cc-native/lib-ts/reviewers/types.ts +3 -5
  71. package/dist/templates/cc-native/_cc-native/lib-ts/types.ts +4 -107
  72. package/dist/templates/cc-native/_cc-native/plan-review.config.json +2 -14
  73. package/oclif.manifest.json +1 -1
  74. package/package.json +1 -2
  75. package/dist/templates/cc-native/_cc-native/hooks/add_plan_context.ts +0 -119
  76. package/dist/templates/cc-native/_cc-native/lib-ts/reviewers/codex.ts +0 -130
  77. package/dist/templates/cc-native/_cc-native/lib-ts/reviewers/gemini.ts +0 -107
  78. /package/dist/templates/cc-native/_cc-native/agents/{ARCH-EVOLUTION.md → plan-review/ARCH-EVOLUTION.md} +0 -0
  79. /package/dist/templates/cc-native/_cc-native/agents/{ARCH-PATTERNS.md → plan-review/ARCH-PATTERNS.md} +0 -0
  80. /package/dist/templates/cc-native/_cc-native/agents/{ARCH-STRUCTURE.md → plan-review/ARCH-STRUCTURE.md} +0 -0
  81. /package/dist/templates/cc-native/_cc-native/agents/{ASSUMPTION-TRACER.md → plan-review/ASSUMPTION-TRACER.md} +0 -0
  82. /package/dist/templates/cc-native/_cc-native/agents/{CLARITY-AUDITOR.md → plan-review/CLARITY-AUDITOR.md} +0 -0
  83. /package/dist/templates/cc-native/_cc-native/agents/{COMPLETENESS-FEASIBILITY.md → plan-review/COMPLETENESS-FEASIBILITY.md} +0 -0
  84. /package/dist/templates/cc-native/_cc-native/agents/{COMPLETENESS-GAPS.md → plan-review/COMPLETENESS-GAPS.md} +0 -0
  85. /package/dist/templates/cc-native/_cc-native/agents/{COMPLETENESS-ORDERING.md → plan-review/COMPLETENESS-ORDERING.md} +0 -0
  86. /package/dist/templates/cc-native/_cc-native/agents/{CONSTRAINT-VALIDATOR.md → plan-review/CONSTRAINT-VALIDATOR.md} +0 -0
  87. /package/dist/templates/cc-native/_cc-native/agents/{DESIGN-ADR-VALIDATOR.md → plan-review/DESIGN-ADR-VALIDATOR.md} +0 -0
  88. /package/dist/templates/cc-native/_cc-native/agents/{DESIGN-SCALE-MATCHER.md → plan-review/DESIGN-SCALE-MATCHER.md} +0 -0
  89. /package/dist/templates/cc-native/_cc-native/agents/{DEVILS-ADVOCATE.md → plan-review/DEVILS-ADVOCATE.md} +0 -0
  90. /package/dist/templates/cc-native/_cc-native/agents/{DOCUMENTATION-PHILOSOPHY.md → plan-review/DOCUMENTATION-PHILOSOPHY.md} +0 -0
  91. /package/dist/templates/cc-native/_cc-native/agents/{HANDOFF-READINESS.md → plan-review/HANDOFF-READINESS.md} +0 -0
  92. /package/dist/templates/cc-native/_cc-native/agents/{HIDDEN-COMPLEXITY.md → plan-review/HIDDEN-COMPLEXITY.md} +0 -0
  93. /package/dist/templates/cc-native/_cc-native/agents/{INCREMENTAL-DELIVERY.md → plan-review/INCREMENTAL-DELIVERY.md} +0 -0
  94. /package/dist/templates/cc-native/_cc-native/agents/{RISK-DEPENDENCY.md → plan-review/RISK-DEPENDENCY.md} +0 -0
  95. /package/dist/templates/cc-native/_cc-native/agents/{RISK-FMEA.md → plan-review/RISK-FMEA.md} +0 -0
  96. /package/dist/templates/cc-native/_cc-native/agents/{RISK-PREMORTEM.md → plan-review/RISK-PREMORTEM.md} +0 -0
  97. /package/dist/templates/cc-native/_cc-native/agents/{RISK-REVERSIBILITY.md → plan-review/RISK-REVERSIBILITY.md} +0 -0
  98. /package/dist/templates/cc-native/_cc-native/agents/{SCOPE-BOUNDARY.md → plan-review/SCOPE-BOUNDARY.md} +0 -0
  99. /package/dist/templates/cc-native/_cc-native/agents/{SIMPLICITY-GUARDIAN.md → plan-review/SIMPLICITY-GUARDIAN.md} +0 -0
  100. /package/dist/templates/cc-native/_cc-native/agents/{SKEPTIC.md → plan-review/SKEPTIC.md} +0 -0
  101. /package/dist/templates/cc-native/_cc-native/agents/{TESTDRIVEN-BEHAVIOR-AUDITOR.md → plan-review/TESTDRIVEN-BEHAVIOR-AUDITOR.md} +0 -0
  102. /package/dist/templates/cc-native/_cc-native/agents/{TESTDRIVEN-CHARACTERIZATION.md → plan-review/TESTDRIVEN-CHARACTERIZATION.md} +0 -0
  103. /package/dist/templates/cc-native/_cc-native/agents/{TESTDRIVEN-FIRST-VALIDATOR.md → plan-review/TESTDRIVEN-FIRST-VALIDATOR.md} +0 -0
  104. /package/dist/templates/cc-native/_cc-native/agents/{TESTDRIVEN-PYRAMID-ANALYZER.md → plan-review/TESTDRIVEN-PYRAMID-ANALYZER.md} +0 -0
  105. /package/dist/templates/cc-native/_cc-native/agents/{TRADEOFF-COSTS.md → plan-review/TRADEOFF-COSTS.md} +0 -0
  106. /package/dist/templates/cc-native/_cc-native/agents/{TRADEOFF-STAKEHOLDERS.md → plan-review/TRADEOFF-STAKEHOLDERS.md} +0 -0
  107. /package/dist/templates/cc-native/_cc-native/agents/{VERIFY-COVERAGE.md → plan-review/VERIFY-COVERAGE.md} +0 -0
  108. /package/dist/templates/cc-native/_cc-native/agents/{VERIFY-STRENGTH.md → plan-review/VERIFY-STRENGTH.md} +0 -0
@@ -1,165 +1,181 @@
1
- /**
2
- * Subprocess environment utilities.
3
- * See SPEC.md §5.10
4
- */
5
-
6
- import { execSync, execFile } from "node:child_process";
7
-
8
- /**
9
- * Check if this is an internal subprocess call.
10
- * All hooks should check this and return early to prevent recursion.
11
- */
12
- export function isInternalCall(): boolean {
13
- return process.env.AIWCLI_INTERNAL_CALL === "true";
14
- }
15
-
16
- /**
17
- * Get environment for internal subprocess calls.
18
- * Returns a copy of process.env with AIWCLI_INTERNAL_CALL=true.
19
- */
20
- export function getInternalSubprocessEnv(): Record<string, string | undefined> {
21
- return {
22
- ...process.env,
23
- AIWCLI_INTERNAL_CALL: "true",
24
- };
25
- }
26
-
27
- /**
28
- * Find an executable on the system PATH.
29
- * Uses `where` on Windows, `which` on Unix.
30
- * On Windows, prefers .cmd/.exe over extensionless shims since
31
- * execFileSync cannot spawn extensionless shell scripts.
32
- * Returns the first match or null if not found.
33
- */
34
- export function findExecutable(name: string): string | null {
35
- try {
36
- const cmd = process.platform === "win32" ? `where ${name}` : `which ${name}`;
37
- const lines = execSync(cmd, { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"], shell: true })
38
- .trim()
39
- .split(/\r?\n/)
40
- .map((l) => l.trim())
41
- .filter(Boolean);
42
-
43
- if (lines.length === 0) return null;
44
-
45
- // On Windows, `where` may return an extensionless shim first (e.g. npm creates
46
- // both `claude` and `claude.cmd`). execFileSync can't spawn the extensionless
47
- // one, so prefer .cmd or .exe.
48
- if (process.platform === "win32") {
49
- const preferred = lines.find((l) => /\.(cmd|exe)$/i.test(l));
50
- return preferred ?? lines[0] ?? null;
51
- }
52
-
53
- return lines[0] ?? null;
54
- } catch {
55
- return null;
56
- }
57
- }
58
-
59
- /**
60
- * Type guard for Node.js child_process exec errors.
61
- * ExecSync throws objects with these extra properties on non-zero exit or timeout.
62
- */
63
- export interface ExecSyncError {
64
- killed: boolean;
65
- signal: string | null;
66
- stdout: Buffer | string;
67
- stderr: Buffer | string;
68
- status: number | null;
69
- message: string;
70
- }
71
-
72
- /** Check if an unknown error is an ExecSync error with process info. */
73
- export function isExecSyncError(e: unknown): e is ExecSyncError {
74
- return (
75
- typeof e === "object" &&
76
- e !== null &&
77
- "killed" in e &&
78
- "signal" in e
79
- );
80
- }
81
-
82
- // ---------------------------------------------------------------------------
83
- // Async Subprocess Execution
84
- // ---------------------------------------------------------------------------
85
-
86
- /**
87
- * Result from an async subprocess execution.
88
- * Never throws callers inspect fields to determine outcome.
89
- */
90
- export interface ExecResult {
91
- stdout: string;
92
- stderr: string;
93
- exitCode: number;
94
- killed: boolean;
95
- signal: string | null;
96
- }
97
-
98
- /** Options for execFileAsync. */
99
- export interface ExecAsyncOptions {
100
- /** Data piped to the child's stdin. */
101
- input?: string;
102
- /** Timeout in milliseconds (not seconds). */
103
- timeout?: number;
104
- /** Environment variables for the child process. */
105
- env?: Record<string, string | undefined>;
106
- /** Maximum bytes on stdout/stderr. Default: 10 MB. */
107
- maxBuffer?: number;
108
- /** Use shell for execution. Required on Windows for .cmd files. */
109
- shell?: boolean;
110
- }
111
-
112
- /**
113
- * Async subprocess execution that does NOT block the event loop.
114
- * Drop-in replacement for execFileSync in Promise-based parallel patterns.
115
- *
116
- * Returns ExecResult on both success and non-zero exit.
117
- * On timeout: result.killed = true, result.signal = "SIGTERM".
118
- * On spawn failure: result.exitCode = -1, result.stderr contains error.
119
- */
120
- export function execFileAsync(
121
- file: string,
122
- args: string[],
123
- options?: ExecAsyncOptions,
124
- ): Promise<ExecResult> {
125
- return new Promise((resolve) => {
126
- const child = execFile(
127
- file,
128
- args,
129
- {
130
- encoding: "utf-8",
131
- timeout: options?.timeout ?? 0,
132
- env: options?.env as NodeJS.ProcessEnv,
133
- maxBuffer: options?.maxBuffer ?? 10 * 1024 * 1024,
134
- shell: options?.shell,
135
- },
136
- (error, stdout, stderr) => {
137
- if (error) {
138
- // execFile callback error includes process exit info
139
- const errObj = error as unknown as Record<string, unknown>;
140
- resolve({
141
- stdout: String(stdout ?? ""),
142
- stderr: String(stderr ?? ""),
143
- exitCode: typeof errObj.code === "number" ? errObj.code : (error as any).status ?? 1,
144
- killed: Boolean(errObj.killed),
145
- signal: typeof errObj.signal === "string" ? errObj.signal : null,
146
- });
147
- } else {
148
- resolve({
149
- stdout: String(stdout ?? ""),
150
- stderr: String(stderr ?? ""),
151
- exitCode: 0,
152
- killed: false,
153
- signal: null,
154
- });
155
- }
156
- },
157
- );
158
-
159
- // Pipe input to stdin if provided
160
- if (options?.input != null && child.stdin) {
161
- child.stdin.write(options.input);
162
- child.stdin.end();
163
- }
164
- });
165
- }
1
+ /**
2
+ * Subprocess environment utilities.
3
+ * See SPEC.md §5.10
4
+ */
5
+
6
+ import { execSync, execFile } from "node:child_process";
7
+
8
+ /**
9
+ * Check if this is an internal subprocess call.
10
+ * All hooks should check this and return early to prevent recursion.
11
+ */
12
+ export function isInternalCall(): boolean {
13
+ return process.env.AIWCLI_INTERNAL_CALL === "true";
14
+ }
15
+
16
+ /**
17
+ * Get environment for internal subprocess calls.
18
+ * Returns a copy of process.env with AIWCLI_INTERNAL_CALL=true and
19
+ * Claude Code nesting-detection env vars removed so subprocess
20
+ * claude instances can run without being blocked.
21
+ */
22
+ export function getInternalSubprocessEnv(): Record<string, string | undefined> {
23
+ const env = {
24
+ ...process.env,
25
+ AIWCLI_INTERNAL_CALL: "true",
26
+ };
27
+ // Explicitly delete vars that block subprocess calls (set to undefined does not work)
28
+ delete env.CLAUDECODE;
29
+ delete env.CLAUDE_CODE_ENTRYPOINT;
30
+ return env;
31
+ }
32
+ /**
33
+ * Find an executable on the system PATH.
34
+ * Uses `where` on Windows, `which` on Unix.
35
+ * On Windows, prefers .cmd/.exe over extensionless shims since
36
+ * execFileSync cannot spawn extensionless shell scripts.
37
+ * Returns the first match or null if not found.
38
+ */
39
+ export function findExecutable(name: string): string | null {
40
+ try {
41
+ const cmd = process.platform === "win32" ? `where ${name}` : `which ${name}`;
42
+ const lines = execSync(cmd, { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"], shell: true })
43
+ .trim()
44
+ .split(/\r?\n/)
45
+ .map((l) => l.trim())
46
+ .filter(Boolean);
47
+
48
+ if (lines.length === 0) return null;
49
+
50
+ // On Windows, `where` may return an extensionless shim first (e.g. npm creates
51
+ // both `claude` and `claude.cmd`). execFileSync can't spawn the extensionless
52
+ // one, so prefer .cmd or .exe.
53
+ if (process.platform === "win32") {
54
+ const preferred = lines.find((l) => /\.(cmd|exe)$/i.test(l));
55
+ return preferred ?? lines[0] ?? null;
56
+ }
57
+
58
+ return lines[0] ?? null;
59
+ } catch {
60
+ return null;
61
+ }
62
+ }
63
+
64
+ /**
65
+ * Type guard for Node.js child_process exec errors.
66
+ * ExecSync throws objects with these extra properties on non-zero exit or timeout.
67
+ */
68
+ export interface ExecSyncError {
69
+ killed: boolean;
70
+ signal: string | null;
71
+ stdout: Buffer | string;
72
+ stderr: Buffer | string;
73
+ status: number | null;
74
+ message: string;
75
+ }
76
+
77
+ /** Check if an unknown error is an ExecSync error with process info. */
78
+ export function isExecSyncError(e: unknown): e is ExecSyncError {
79
+ return (
80
+ typeof e === "object" &&
81
+ e !== null &&
82
+ "killed" in e &&
83
+ "signal" in e
84
+ );
85
+ }
86
+
87
+ /**
88
+ * Quote a string for use as a cmd.exe argument when shell: true.
89
+ * Wraps in double quotes and escapes inner double quotes as "".
90
+ * On non-Windows platforms, returns the string unchanged (execFile
91
+ * handles quoting automatically without shell).
92
+ */
93
+ export function shellQuoteWin(arg: string): string {
94
+ if (process.platform !== "win32") return arg;
95
+ return '"' + arg.replace(/"/g, '""') + '"';
96
+ }
97
+
98
+ // ---------------------------------------------------------------------------
99
+ // Async Subprocess Execution
100
+ // ---------------------------------------------------------------------------
101
+
102
+ /**
103
+ * Result from an async subprocess execution.
104
+ * Never throws callers inspect fields to determine outcome.
105
+ */
106
+ export interface ExecResult {
107
+ stdout: string;
108
+ stderr: string;
109
+ exitCode: number;
110
+ killed: boolean;
111
+ signal: string | null;
112
+ }
113
+
114
+ /** Options for execFileAsync. */
115
+ export interface ExecAsyncOptions {
116
+ /** Data piped to the child's stdin. */
117
+ input?: string;
118
+ /** Timeout in milliseconds (not seconds). */
119
+ timeout?: number;
120
+ /** Environment variables for the child process. */
121
+ env?: Record<string, string | undefined>;
122
+ /** Maximum bytes on stdout/stderr. Default: 10 MB. */
123
+ maxBuffer?: number;
124
+ /** Use shell for execution. Required on Windows for .cmd files. */
125
+ shell?: boolean;
126
+ }
127
+
128
+ /**
129
+ * Async subprocess execution that does NOT block the event loop.
130
+ * Drop-in replacement for execFileSync in Promise-based parallel patterns.
131
+ *
132
+ * Returns ExecResult on both success and non-zero exit.
133
+ * On timeout: result.killed = true, result.signal = "SIGTERM".
134
+ * On spawn failure: result.exitCode = -1, result.stderr contains error.
135
+ */
136
+ export function execFileAsync(
137
+ file: string,
138
+ args: string[],
139
+ options?: ExecAsyncOptions,
140
+ ): Promise<ExecResult> {
141
+ return new Promise((resolve) => {
142
+ const child = execFile(
143
+ file,
144
+ args,
145
+ {
146
+ encoding: "utf-8",
147
+ timeout: options?.timeout ?? 0,
148
+ env: options?.env as NodeJS.ProcessEnv,
149
+ maxBuffer: options?.maxBuffer ?? 10 * 1024 * 1024,
150
+ shell: options?.shell,
151
+ },
152
+ (error, stdout, stderr) => {
153
+ if (error) {
154
+ // execFile callback error includes process exit info
155
+ const errObj = error as unknown as Record<string, unknown>;
156
+ resolve({
157
+ stdout: String(stdout ?? ""),
158
+ stderr: String(stderr ?? ""),
159
+ exitCode: typeof errObj.code === "number" ? errObj.code : (error as any).status ?? 1,
160
+ killed: Boolean(errObj.killed),
161
+ signal: typeof errObj.signal === "string" ? errObj.signal : null,
162
+ });
163
+ } else {
164
+ resolve({
165
+ stdout: String(stdout ?? ""),
166
+ stderr: String(stderr ?? ""),
167
+ exitCode: 0,
168
+ killed: false,
169
+ signal: null,
170
+ });
171
+ }
172
+ },
173
+ );
174
+
175
+ // Pipe input to stdin if provided
176
+ if (options?.input != null && child.stdin) {
177
+ child.stdin.write(options.input);
178
+ child.stdin.end();
179
+ }
180
+ });
181
+ }
@@ -7,8 +7,7 @@
7
7
  "test:unit": "mocha '__tests__/base/**/*.test.ts' '__tests__/templates/**/*.test.ts'",
8
8
  "test:contract": "mocha '__tests__/context/**/*.test.ts' '__tests__/handoff/**/*.test.ts'",
9
9
  "test:integration": "mocha '__tests__/integration/**/*.test.ts'",
10
- "test:parity": "mocha '__tests__/integration/python-parity.test.ts'",
11
- "fixtures": "python __tests__/fixtures/generate_fixtures.py"
10
+ "test:parity": "mocha '__tests__/integration/python-parity.test.ts'"
12
11
  },
13
12
  "devDependencies": {
14
13
  "mocha": "^10.0.0",
@@ -1,65 +1,58 @@
1
1
  /**
2
- * Plan context templates for add_plan_context hook.
3
- * See SPEC.md §13.6
2
+ * Plan evaluation guidance template.
3
+ * Injected as context to guide the Plan agent during plan creation.
4
4
  */
5
5
 
6
6
  export function getEvaluationContextReminder(): string {
7
- return `## CRITICAL: Write This Plan for a Different Agent
7
+ return `## Write This Plan for a Different Agent
8
8
 
9
- The agent executing this plan has ZERO context from this conversation — no chat history, no memory of files you explored or research you did.
9
+ The agent executing this plan has zero context from this conversation — no chat history, no memory of files explored or decisions made.
10
10
 
11
- **Write as if YOU are that agent. What would you need?**
11
+ Write as if you are that agent. What would you need?
12
12
 
13
- ### Required Structure
13
+ ### Structure
14
14
 
15
15
  \`\`\`
16
- # Plan: <descriptive title>
16
+ # Plan: [descriptive title]
17
17
 
18
18
  ## Background
19
- Why this change is needed (2-3 sentences)
19
+ Why this change is needed (2-3 sentences of motivation)
20
20
 
21
21
  ## Task
22
- What exactly to build/change
22
+ What exactly to build or change
23
23
 
24
24
  ## Files
25
25
  **Modify:**
26
- - \`exact/path/to/file.py\` - What changes (reference line numbers or patterns)
26
+ - \`exact/path/to/file.ext\` What changes and why
27
27
 
28
28
  **Reference:**
29
- - \`exact/path/to/reference.py\` - Why relevant (e.g., "pattern to follow at lines 12-30")
29
+ - \`exact/path/to/reference.ext\` Why relevant (e.g., "pattern to follow at lines 12-30")
30
30
 
31
31
  ## Steps
32
- 1. [Specific steps with function names, patterns, or code snippets]
32
+ Numbered steps with specific details. For each step, consider whether any of the skills available in your system-reminder messages would help the implementation agent — if so, reference the skill inline at the point of use.
33
+
34
+ 1. [Specific action with function names, patterns, or code snippets]
33
35
  2. [Enough detail for someone who never saw this conversation]
34
36
 
35
37
  ## Constraints
36
- - Technical requirements, preferences, or limitations
37
-
38
- ## Documentation
39
- Decisions not written down are lost when this session ends. Update the nearest CLAUDE.md and MEMORY.md so the next session inherits what you learned.
40
-
41
- **CLAUDE.md** (nearest to changed code — cascades to subdirectories):
42
- - \`exact/path/to/CLAUDE.md\` — What to document
43
-
44
- **What to write:**
45
- - Architectural choices and why alternatives were rejected
46
- - Non-obvious constraints (what breaks if this changes)
47
- - Workarounds with context on the underlying issue
48
- - Patterns that prevent future mistakes
38
+ Technical requirements, preferences, or limitations discovered during planning
49
39
 
50
- **Format:** \`## Topic\` / \`**Decision:** ...\` / \`**Rationale:** ...\`
40
+ ## Verification
41
+ Binary-testable checks the implementation agent runs to confirm success. Reference relevant skills inline where they aid verification.
51
42
 
52
- **MEMORY.md** (cross-session learning for the AI agent):
53
- - Insight that would prevent a future mistake (e.g., "hook X silently drops field Y")
43
+ ## Decisions Worth Preserving
44
+ Decisions made during this session that would be lost without documentation. Focus on:
45
+ - What was chosen and why the alternatives were rejected
46
+ - Constraints that aren't obvious from the code itself
47
+ - Patterns discovered that prevent future mistakes
54
48
 
55
- **Include when:** Architectural decisions, non-obvious constraints, workarounds, or patterns discovered during implementation.
56
- **Omit entries for:** Routine changes with no decisions (rename, formatting, dependency bump).
57
- When in doubt, write it — a lean entry is better than a lost decision.
49
+ The implementation agent should document these so the next session inherits what this session learned.
58
50
  \`\`\`
59
51
 
60
52
  ### Self-Check
61
- - [ ] Could I execute this if I forgot our entire conversation?
62
- - [ ] Are file paths exact (not "the auth file")?
53
+ - [ ] Could I execute this plan having never seen this conversation?
54
+ - [ ] Are all file paths exact (not "the auth file")?
63
55
  - [ ] Are implementation details specific (not "use the approach we discussed")?
64
- - [ ] Do documentation entries capture decisions the next session would otherwise lose?`;
56
+ - [ ] Are relevant skills referenced where they add value?
57
+ - [ ] Are key decisions captured so they survive this session?`;
65
58
  }
@@ -108,13 +108,28 @@ export interface HookInput {
108
108
  transcript_path?: string;
109
109
  }
110
110
 
111
- // §1.7
111
+ // §1.7 — Three hook output patterns (see hook-utils.ts for emit functions)
112
112
  export interface HookOutput {
113
+ // Pattern 1: hookSpecificOutput (PreToolUse, PostToolUse, UserPromptSubmit, etc.)
113
114
  hookSpecificOutput?: {
114
115
  additionalContext?: string;
115
116
  hookEventName?: string;
116
- permissionDecision?: "allow" | "deny";
117
+ permissionDecision?: "allow" | "deny" | "ask";
117
118
  permissionDecisionReason?: string;
119
+ updatedInput?: Record<string, unknown>;
120
+ };
121
+ // Pattern 2: Top-level decision (UserPromptSubmit, Stop, SubagentStop)
122
+ decision?: "block";
123
+ reason?: string;
124
+ }
125
+
126
+ // §1.7b — PermissionRequest output (structurally different from HookOutput)
127
+ export interface PermissionRequestOutput {
128
+ decision: {
129
+ behavior: "allow" | "deny";
130
+ message?: string;
131
+ updatedInput?: Record<string, unknown>;
132
+ updatedPermissions?: Record<string, unknown>;
118
133
  };
119
134
  }
120
135
 
@@ -5,7 +5,7 @@
5
5
  * Renders context window usage and git status with ANSI colors.
6
6
  * Optionally persists context_window data to the session's state.json.
7
7
  *
8
- * Ported from status_line.py — context and git sections only.
8
+ * Context and git sections only.
9
9
  *
10
10
  * Usage: echo '{"session_id":"...","model":{"display_name":"Opus"},...}' | bun status_line.ts
11
11
  */
@@ -150,7 +150,7 @@ If a plan document path was provided in `$ARGUMENTS`:
150
150
  Instead of writing the file directly, pipe your handoff content to the save script:
151
151
 
152
152
  ```bash
153
- python .aiwcli/_shared/scripts/save_handoff.py "{context_id}" <<'EOF'
153
+ bun .aiwcli/_shared/scripts/save_handoff.ts "{context_id}" <<'EOF'
154
154
  {Your complete handoff markdown content from Step 3}
155
155
  EOF
156
156
  ```