aiwcli 0.11.1 → 0.12.1

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 (117) 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 +3 -13
  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 +3 -3
  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_end.ts +75 -4
  35. package/dist/templates/_shared/hooks-ts/session_start.ts +11 -13
  36. package/dist/templates/_shared/hooks-ts/user_prompt_submit.ts +6 -8
  37. package/dist/templates/_shared/lib-ts/CLAUDE.md +56 -7
  38. package/dist/templates/_shared/lib-ts/base/hook-utils.ts +176 -29
  39. package/dist/templates/_shared/lib-ts/base/logger.ts +1 -1
  40. package/dist/templates/_shared/lib-ts/base/state-io.ts +11 -2
  41. package/dist/templates/_shared/lib-ts/base/subprocess-utils.ts +181 -165
  42. package/dist/templates/_shared/lib-ts/context/plan-manager.ts +14 -13
  43. package/dist/templates/_shared/lib-ts/handoff/handoff-reader.ts +3 -2
  44. package/dist/templates/_shared/lib-ts/package.json +1 -2
  45. package/dist/templates/_shared/lib-ts/templates/plan-context.ts +27 -34
  46. package/dist/templates/_shared/lib-ts/types.ts +17 -2
  47. package/dist/templates/_shared/scripts/resume_handoff.ts +4 -4
  48. package/dist/templates/_shared/scripts/save_handoff.ts +7 -7
  49. package/dist/templates/_shared/scripts/status_line.ts +104 -71
  50. package/dist/templates/_shared/workflows/handoff.md +1 -1
  51. package/dist/templates/cc-native/.claude/settings.json +182 -175
  52. package/dist/templates/cc-native/_cc-native/agents/CLAUDE.md +23 -1
  53. package/dist/templates/cc-native/_cc-native/agents/plan-questions/PLAN-QUESTIONER.md +70 -0
  54. package/dist/templates/cc-native/_cc-native/hooks/CLAUDE.md +6 -1
  55. package/dist/templates/cc-native/_cc-native/hooks/cc-native-plan-review.ts +142 -111
  56. package/dist/templates/cc-native/_cc-native/hooks/enhance_plan_post_subagent.ts +54 -0
  57. package/dist/templates/cc-native/_cc-native/hooks/enhance_plan_post_write.ts +52 -0
  58. package/dist/templates/cc-native/_cc-native/hooks/mark_questions_asked.ts +53 -0
  59. package/dist/templates/cc-native/_cc-native/hooks/plan_questions_early.ts +19 -19
  60. package/dist/templates/cc-native/_cc-native/lib-ts/aggregate-agents.ts +6 -5
  61. package/dist/templates/cc-native/_cc-native/lib-ts/artifacts.ts +114 -83
  62. package/dist/templates/cc-native/_cc-native/lib-ts/cc-native-state.ts +107 -10
  63. package/dist/templates/cc-native/_cc-native/lib-ts/cli-output-parser.ts +1 -1
  64. package/dist/templates/cc-native/_cc-native/lib-ts/corroboration.ts +6 -2
  65. package/dist/templates/cc-native/_cc-native/lib-ts/index.ts +0 -4
  66. package/dist/templates/cc-native/_cc-native/lib-ts/orchestrator.ts +40 -219
  67. package/dist/templates/cc-native/_cc-native/lib-ts/plan-enhancement.ts +41 -0
  68. package/dist/templates/cc-native/_cc-native/lib-ts/plan-questions.ts +102 -0
  69. package/dist/templates/cc-native/_cc-native/lib-ts/reviewers/agent.ts +26 -227
  70. package/dist/templates/cc-native/_cc-native/lib-ts/reviewers/base/base-agent.ts +217 -0
  71. package/dist/templates/cc-native/_cc-native/lib-ts/reviewers/index.ts +4 -2
  72. package/dist/templates/cc-native/_cc-native/lib-ts/reviewers/providers/claude-agent.ts +65 -0
  73. package/dist/templates/cc-native/_cc-native/lib-ts/reviewers/providers/codex-agent.ts +185 -0
  74. package/dist/templates/cc-native/_cc-native/lib-ts/reviewers/providers/gemini-agent.ts +39 -0
  75. package/dist/templates/cc-native/_cc-native/lib-ts/reviewers/providers/orchestrator-claude-agent.ts +195 -0
  76. package/dist/templates/cc-native/_cc-native/lib-ts/reviewers/schemas.ts +201 -0
  77. package/dist/templates/cc-native/_cc-native/lib-ts/reviewers/types.ts +2 -2
  78. package/dist/templates/cc-native/_cc-native/lib-ts/state.ts +17 -16
  79. package/dist/templates/cc-native/_cc-native/lib-ts/types.ts +13 -108
  80. package/dist/templates/cc-native/_cc-native/lib-ts/verdict.ts +3 -3
  81. package/dist/templates/cc-native/_cc-native/plan-review.config.json +2 -14
  82. package/oclif.manifest.json +1 -1
  83. package/package.json +1 -2
  84. package/dist/templates/cc-native/_cc-native/hooks/add_plan_context.ts +0 -119
  85. package/dist/templates/cc-native/_cc-native/lib-ts/reviewers/codex.ts +0 -130
  86. package/dist/templates/cc-native/_cc-native/lib-ts/reviewers/gemini.ts +0 -107
  87. /package/dist/templates/cc-native/_cc-native/agents/{ARCH-EVOLUTION.md → plan-review/ARCH-EVOLUTION.md} +0 -0
  88. /package/dist/templates/cc-native/_cc-native/agents/{ARCH-PATTERNS.md → plan-review/ARCH-PATTERNS.md} +0 -0
  89. /package/dist/templates/cc-native/_cc-native/agents/{ARCH-STRUCTURE.md → plan-review/ARCH-STRUCTURE.md} +0 -0
  90. /package/dist/templates/cc-native/_cc-native/agents/{ASSUMPTION-TRACER.md → plan-review/ASSUMPTION-TRACER.md} +0 -0
  91. /package/dist/templates/cc-native/_cc-native/agents/{CLARITY-AUDITOR.md → plan-review/CLARITY-AUDITOR.md} +0 -0
  92. /package/dist/templates/cc-native/_cc-native/agents/{COMPLETENESS-FEASIBILITY.md → plan-review/COMPLETENESS-FEASIBILITY.md} +0 -0
  93. /package/dist/templates/cc-native/_cc-native/agents/{COMPLETENESS-GAPS.md → plan-review/COMPLETENESS-GAPS.md} +0 -0
  94. /package/dist/templates/cc-native/_cc-native/agents/{COMPLETENESS-ORDERING.md → plan-review/COMPLETENESS-ORDERING.md} +0 -0
  95. /package/dist/templates/cc-native/_cc-native/agents/{CONSTRAINT-VALIDATOR.md → plan-review/CONSTRAINT-VALIDATOR.md} +0 -0
  96. /package/dist/templates/cc-native/_cc-native/agents/{DESIGN-ADR-VALIDATOR.md → plan-review/DESIGN-ADR-VALIDATOR.md} +0 -0
  97. /package/dist/templates/cc-native/_cc-native/agents/{DESIGN-SCALE-MATCHER.md → plan-review/DESIGN-SCALE-MATCHER.md} +0 -0
  98. /package/dist/templates/cc-native/_cc-native/agents/{DEVILS-ADVOCATE.md → plan-review/DEVILS-ADVOCATE.md} +0 -0
  99. /package/dist/templates/cc-native/_cc-native/agents/{DOCUMENTATION-PHILOSOPHY.md → plan-review/DOCUMENTATION-PHILOSOPHY.md} +0 -0
  100. /package/dist/templates/cc-native/_cc-native/agents/{HANDOFF-READINESS.md → plan-review/HANDOFF-READINESS.md} +0 -0
  101. /package/dist/templates/cc-native/_cc-native/agents/{HIDDEN-COMPLEXITY.md → plan-review/HIDDEN-COMPLEXITY.md} +0 -0
  102. /package/dist/templates/cc-native/_cc-native/agents/{INCREMENTAL-DELIVERY.md → plan-review/INCREMENTAL-DELIVERY.md} +0 -0
  103. /package/dist/templates/cc-native/_cc-native/agents/{RISK-DEPENDENCY.md → plan-review/RISK-DEPENDENCY.md} +0 -0
  104. /package/dist/templates/cc-native/_cc-native/agents/{RISK-FMEA.md → plan-review/RISK-FMEA.md} +0 -0
  105. /package/dist/templates/cc-native/_cc-native/agents/{RISK-PREMORTEM.md → plan-review/RISK-PREMORTEM.md} +0 -0
  106. /package/dist/templates/cc-native/_cc-native/agents/{RISK-REVERSIBILITY.md → plan-review/RISK-REVERSIBILITY.md} +0 -0
  107. /package/dist/templates/cc-native/_cc-native/agents/{SCOPE-BOUNDARY.md → plan-review/SCOPE-BOUNDARY.md} +0 -0
  108. /package/dist/templates/cc-native/_cc-native/agents/{SIMPLICITY-GUARDIAN.md → plan-review/SIMPLICITY-GUARDIAN.md} +0 -0
  109. /package/dist/templates/cc-native/_cc-native/agents/{SKEPTIC.md → plan-review/SKEPTIC.md} +0 -0
  110. /package/dist/templates/cc-native/_cc-native/agents/{TESTDRIVEN-BEHAVIOR-AUDITOR.md → plan-review/TESTDRIVEN-BEHAVIOR-AUDITOR.md} +0 -0
  111. /package/dist/templates/cc-native/_cc-native/agents/{TESTDRIVEN-CHARACTERIZATION.md → plan-review/TESTDRIVEN-CHARACTERIZATION.md} +0 -0
  112. /package/dist/templates/cc-native/_cc-native/agents/{TESTDRIVEN-FIRST-VALIDATOR.md → plan-review/TESTDRIVEN-FIRST-VALIDATOR.md} +0 -0
  113. /package/dist/templates/cc-native/_cc-native/agents/{TESTDRIVEN-PYRAMID-ANALYZER.md → plan-review/TESTDRIVEN-PYRAMID-ANALYZER.md} +0 -0
  114. /package/dist/templates/cc-native/_cc-native/agents/{TRADEOFF-COSTS.md → plan-review/TRADEOFF-COSTS.md} +0 -0
  115. /package/dist/templates/cc-native/_cc-native/agents/{TRADEOFF-STAKEHOLDERS.md → plan-review/TRADEOFF-STAKEHOLDERS.md} +0 -0
  116. /package/dist/templates/cc-native/_cc-native/agents/{VERIFY-COVERAGE.md → plan-review/VERIFY-COVERAGE.md} +0 -0
  117. /package/dist/templates/cc-native/_cc-native/agents/{VERIFY-STRENGTH.md → plan-review/VERIFY-STRENGTH.md} +0 -0
@@ -5,12 +5,13 @@
5
5
  */
6
6
 
7
7
  import * as fs from "node:fs";
8
- import * as path from "node:path";
8
+ import * as path from "node:path";
9
+
10
+ import { validatePlanPath } from "./constants.js";
11
+ import type { IterationState, IterationEntry } from "./types.js";
9
12
  import { atomicWrite } from "../../_shared/lib-ts/base/atomic-write.js";
10
13
  import { logInfo, logWarn, logError } from "../../_shared/lib-ts/base/logger.js";
11
14
  import { nowIso } from "../../_shared/lib-ts/base/utils.js";
12
- import { validatePlanPath } from "./constants.js";
13
- import type { IterationState, IterationEntry } from "./types.js";
14
15
 
15
16
  // ---------------------------------------------------------------------------
16
17
  // Constants
@@ -72,11 +73,11 @@ export function loadState(planPath: string): Record<string, unknown> | null {
72
73
  }
73
74
 
74
75
  return state;
75
- } catch (e: unknown) {
76
- if (e instanceof Error && e.message.includes("Invalid plan path")) {
77
- logError("state", `SECURITY: Invalid plan path: ${e}`);
76
+ } catch (error: unknown) {
77
+ if (error instanceof Error && error.message.includes("Invalid plan path")) {
78
+ logError("state", `SECURITY: Invalid plan path: ${error}`);
78
79
  } else {
79
- logError("state", `Failed to load state: ${e}`);
80
+ logError("state", `Failed to load state: ${error}`);
80
81
  }
81
82
  return null;
82
83
  }
@@ -109,11 +110,11 @@ export function saveStateToPlan(
109
110
  }
110
111
 
111
112
  return true;
112
- } catch (e: unknown) {
113
- if (e instanceof Error && e.message.includes("Invalid plan path")) {
114
- logError("state", `SECURITY: Invalid plan path: ${e}`);
113
+ } catch (error: unknown) {
114
+ if (error instanceof Error && error.message.includes("Invalid plan path")) {
115
+ logError("state", `SECURITY: Invalid plan path: ${error}`);
115
116
  } else {
116
- logError("state", String(e));
117
+ logError("state", String(error));
117
118
  }
118
119
  return false;
119
120
  }
@@ -131,12 +132,12 @@ export function deleteState(planPath: string): boolean {
131
132
  logInfo("state", `Deleted state file: ${stateFile}`);
132
133
  }
133
134
  return true;
134
- } catch (e: unknown) {
135
- if (e instanceof Error && e.message.includes("Invalid plan path")) {
136
- logError("state", `SECURITY: Invalid plan path in delete: ${e}`);
135
+ } catch (error: unknown) {
136
+ if (error instanceof Error && error.message.includes("Invalid plan path")) {
137
+ logError("state", `SECURITY: Invalid plan path in delete: ${error}`);
137
138
  return false;
138
139
  }
139
- logWarn("state", `Failed to delete state file: ${e}`);
140
+ logWarn("state", `Failed to delete state file: ${error}`);
140
141
  return false;
141
142
  }
142
143
  }
@@ -207,7 +208,7 @@ export function shouldContinueIterating(
207
208
  verdict: string,
208
209
  config?: Record<string, unknown>,
209
210
  ): boolean {
210
- const current = iteration.current;
211
+ const {current} = iteration;
211
212
  const maxIter = iteration.max;
212
213
 
213
214
  // At or past max iterations
@@ -65,7 +65,7 @@ export interface CorroborationResult {
65
65
  blocking: CorroboratedGroup[];
66
66
  solo: SoloFinding[];
67
67
  unclassified: Array<{ agent: string; issue: ReviewIssue }>;
68
- verdict: "pass" | "fail";
68
+ verdict: "pass" | "warn" | "fail";
69
69
  }
70
70
 
71
71
  /** Normalized review data from any reviewer */
@@ -102,7 +102,6 @@ export interface OrchestratorResult {
102
102
  export interface CombinedReviewResult {
103
103
  plan_hash: string;
104
104
  overall_verdict: Verdict;
105
- cli_reviewers: Record<string, ReviewerResult>;
106
105
  orchestration: OrchestratorResult | null;
107
106
  agents: Record<string, ReviewerResult>;
108
107
  timestamp: string;
@@ -194,8 +193,16 @@ export interface PlanReviewState {
194
193
 
195
194
  /** Questions-asked tracking state */
196
195
  export interface QuestionsAskedState {
197
- asked: boolean;
196
+ asked: boolean; // Backward-compatible: true if either phase asked
198
197
  asked_at: string;
198
+ early_questions_asked?: {
199
+ asked: boolean;
200
+ asked_at: string;
201
+ };
202
+ plan_questions_agent_asked?: {
203
+ asked: boolean;
204
+ asked_at: string;
205
+ };
199
206
  }
200
207
 
201
208
  /** Stuck detection state — tracks repeated errors, file edits, and test failures */
@@ -262,112 +269,10 @@ export interface Reviewer {
262
269
  }
263
270
 
264
271
  // ---------------------------------------------------------------------------
265
- // JSON Schemas
266
- // ---------------------------------------------------------------------------
267
-
268
- /** JSON schema for review structured output */
269
- export const REVIEW_SCHEMA: Record<string, unknown> = {
270
- type: "object",
271
- properties: {
272
- verdict: { type: "string", enum: ["pass", "warn", "fail"] },
273
- summary: { type: "string", minLength: 20 },
274
- issues: {
275
- type: "array",
276
- items: {
277
- type: "object",
278
- properties: {
279
- severity: { type: "string", enum: ["high", "medium", "low"] },
280
- category: { type: "string" },
281
- issue: { type: "string" },
282
- suggested_fix: { type: "string" },
283
- dimension: {
284
- type: "string",
285
- enum: [
286
- "completeness", "simplicity", "security", "performance",
287
- "reliability", "maintainability", "testability", "scope",
288
- "feasibility", "clarity",
289
- ],
290
- },
291
- },
292
- required: ["severity", "category", "issue", "suggested_fix"],
293
- additionalProperties: false,
294
- },
295
- },
296
- missing_sections: { type: "array", items: { type: "string" } },
297
- questions: { type: "array", items: { type: "string" } },
298
- },
299
- required: ["verdict", "summary", "issues", "missing_sections", "questions"],
300
- additionalProperties: false,
301
- };
302
-
303
- /** JSON schema for orchestrator structured output */
304
- export const ORCHESTRATOR_SCHEMA: Record<string, unknown> = {
305
- type: "object",
306
- properties: {
307
- complexity: { type: "string", enum: ["simple", "medium", "high"] },
308
- category: {
309
- type: "string",
310
- enum: [
311
- "code",
312
- "infrastructure",
313
- "documentation",
314
- "life",
315
- "business",
316
- "design",
317
- "research",
318
- ],
319
- },
320
- selectedAgents: { type: "array", items: { type: "string" } },
321
- reasoning: { type: "string" },
322
- skipReason: { type: "string" },
323
- },
324
- required: ["complexity", "category", "selectedAgents", "reasoning"],
325
- additionalProperties: false,
326
- };
327
-
328
- // ---------------------------------------------------------------------------
329
- // Prompt Constants
272
+ // JSON Schemas (moved to reviewers/schemas.ts)
330
273
  // ---------------------------------------------------------------------------
331
-
332
- export const REVIEW_PROMPT_PREFIX = `You are a senior staff software engineer acting as a strict plan reviewer.
333
-
334
- Review the PLAN below. Focus on:
335
- - missing steps, unclear assumptions, edge cases
336
- - security/privacy concerns
337
- - testing/rollout/rollback completeness
338
- - operational concerns (observability, failure modes)
339
- `;
340
-
341
- export const AGENT_REVIEW_PROMPT_PREFIX = `# SINGLE-TURN PLAN REVIEW
342
-
343
- ## CRITICAL: ONE TURN ONLY
344
- You have exactly ONE response to complete this review. Do NOT attempt multi-step workflows, context queries, or phased analysis. Analyze the plan and output your review immediately.
345
-
346
- ## YOUR TASK
347
- Review the plan below from your area of expertise. Then call StructuredOutput with your assessment.
348
-
349
- ## REQUIRED OUTPUT (all fields must have content)
350
- Call StructuredOutput with:
351
- - **verdict**: "pass" (no concerns), "warn" (some concerns), or "fail" (critical issues)
352
- - **summary**: 2-3 sentences with your overall assessment and key findings (REQUIRED)
353
- - **issues**: Array of concerns found. Format each as:
354
- {"severity": "high/medium/low", "category": "...", "issue": "...", "suggested_fix": "...", "dimension": "..."}
355
- - **dimension**: Classify each issue into exactly one dimension:
356
- completeness, simplicity, security, performance, reliability,
357
- maintainability, testability, scope, feasibility, or clarity.
358
- Examples: "missing error handling" → reliability, "excessive abstraction" → simplicity,
359
- "no test strategy" → testability, "missing deployment steps" → completeness,
360
- "unclear interaction between components" → clarity.
361
- - **missing_sections**: Topics the plan should address but doesn't
362
- - **questions**: Things that need clarification before implementation
363
-
364
- ## IMPORTANT RULES
365
- 1. A "warn" verdict MUST include at least one issue explaining why
366
- 2. Summary MUST explain your reasoning, not just "looks good" or empty
367
- 3. Focus on your expertise area (architecture, security, performance, etc.)
368
- 4. Output StructuredOutput NOW - no other tools, no questions, no delays
369
- 5. Return ONLY your top 3 most critical issues. Prioritize high-severity over medium/low. Quality over quantity.
370
- `;
274
+ // Re-export for backwards compatibility
275
+ export { AGENT_REVIEW_PROMPT_PREFIX, ORCHESTRATOR_SCHEMA, REVIEW_PROMPT_PREFIX, REVIEW_SCHEMA } from "./reviewers/schemas.js";
371
276
 
372
277
  // ---------------------------------------------------------------------------
373
278
  // Display Defaults
@@ -52,13 +52,13 @@ export function computeReviewDecision(
52
52
  );
53
53
 
54
54
  if (signalVerdicts.length === 0) {
55
- return { should_deny: false, reason: "no_signal", score: 0.0 };
55
+ return { should_deny: false, reason: "no_signal", score: 0 };
56
56
  }
57
57
 
58
58
  // Fail blocks unconditionally
59
59
  const failCount = signalVerdicts.filter((v) => v === "fail").length;
60
60
  if (failCount > 0) {
61
- return { should_deny: true, reason: "fail_veto", score: 1.0 };
61
+ return { should_deny: true, reason: "fail_veto", score: 1 };
62
62
  }
63
63
 
64
64
  // Warn also blocks — reviewers flagged concerns worth addressing
@@ -68,5 +68,5 @@ export function computeReviewDecision(
68
68
  return { should_deny: true, reason: "warn_block", score: warnRatio };
69
69
  }
70
70
 
71
- return { should_deny: false, reason: "acceptable", score: 0.0 };
71
+ return { should_deny: false, reason: "acceptable", score: 0 };
72
72
  }
@@ -13,18 +13,6 @@
13
13
  },
14
14
  "planReview": {
15
15
  "enabled": true,
16
- "reviewers": {
17
- "codex": {
18
- "enabled": true,
19
- "model": "gpt-5.1-codex-mini",
20
- "timeout": 120
21
- },
22
- "gemini": {
23
- "enabled": false,
24
- "model": "",
25
- "timeout": 120
26
- }
27
- },
28
16
  "display": {
29
17
  "maxIssues": 12,
30
18
  "maxMissingSections": 12,
@@ -53,8 +41,8 @@
53
41
  },
54
42
  "reviewIterations": {
55
43
  "simple": 1,
56
- "medium": 1,
57
- "high": 2
44
+ "medium": 3,
45
+ "high": 5
58
46
  },
59
47
  "highIssueThreshold": 2,
60
48
  "earlyExitOnAllPass": true,
@@ -416,5 +416,5 @@
416
416
  ]
417
417
  }
418
418
  },
419
- "version": "0.11.1"
419
+ "version": "0.12.1"
420
420
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "aiwcli",
3
3
  "description": "AI Workflow CLI - Command-line interface for AI-powered workflows",
4
- "version": "0.11.1",
4
+ "version": "0.12.1",
5
5
  "author": "jofu-tofu",
6
6
  "bin": {
7
7
  "aiw": "bin/run.js"
@@ -21,7 +21,6 @@
21
21
  },
22
22
  "devDependencies": {
23
23
  "@eslint/compat": "^1",
24
- "@oclif/prettier-config": "^0.2.1",
25
24
  "@oclif/test": "^4",
26
25
  "@types/chai": "^4",
27
26
  "@types/mocha": "^10",
@@ -1,119 +0,0 @@
1
- #!/usr/bin/env bun
2
- /**
3
- * Plan context hook — handles question marking and advisory question nudges.
4
- *
5
- * Registered for two events:
6
- * - PostToolUse: AskUserQuestion — marks that questions were asked this session.
7
- * - PreToolUse: Task — nudges Plan subagent to ask questions first (advisory, never blocks).
8
- *
9
- * All enforcement is advisory: injects additionalContext to guide Claude toward asking
10
- * non-obvious questions, but never blocks the tool call. Claude can proceed regardless.
11
- *
12
- * Fail-safe: Any error allows the action silently.
13
- */
14
-
15
- import { getProjectRoot } from "../../_shared/lib-ts/base/constants.js";
16
- import {
17
- emitContext,
18
- loadHookInput,
19
- logDebug,
20
- logDiagnostic,
21
- logInfo,
22
- runHook,
23
- } from "../../_shared/lib-ts/base/hook-utils.js";
24
- import { isInternalCall } from "../../_shared/lib-ts/base/subprocess-utils.js";
25
- import { getEvaluationContextReminder } from "../../_shared/lib-ts/templates/plan-context.js";
26
- import { markQuestionsAsked, wasQuestionsAsked } from "../lib-ts/cc-native-state.js";
27
-
28
- const CONTEXT_REMINDER = getEvaluationContextReminder();
29
-
30
- const TASK_ENFORCEMENT_CONTEXT =
31
- "Before spawning a Plan agent, consider asking the user non-obvious questions " +
32
- "via AskUserQuestion. Code exploration reveals WHAT exists — questions reveal WHAT MATTERS.\n\n" +
33
- "Generate 5+ candidate questions across these categories, then keep only 3-4 where " +
34
- "different answers would lead to meaningfully different plans:\n\n" +
35
- "1. INTENT & SUCCESS CRITERIA — What does 'done well' look like? Are there multiple " +
36
- "interpretations of this request? What's a 10 vs a 6?\n\n" +
37
- "2. CONSTRAINTS & HISTORY — Has this been attempted before? Are there off-limits areas, " +
38
- "performance requirements, or security considerations not visible in the code?\n\n" +
39
- "3. TRADE-OFF PREFERENCES — Speed vs thoroughness? Minimal change vs clean architecture? " +
40
- "Backward compatibility vs clean break?\n\n" +
41
- "Frame each question with 2-3 concrete options so the user can choose rather than compose. " +
42
- "Use AskUserQuestion with structured options — never ask questions as inline text.";
43
-
44
- function isPlanTask(payload: Record<string, unknown>): boolean {
45
- const toolInput = payload.tool_input;
46
- if (!toolInput || typeof toolInput !== "object") return false;
47
- return String((toolInput as Record<string, unknown>).subagent_type ?? "") === "Plan";
48
- }
49
-
50
- function main(): void {
51
- // Guard: skip for internal subprocess calls (prevents recursive hook execution)
52
- if (isInternalCall()) return;
53
-
54
- const payload = loadHookInput();
55
- if (!payload) return;
56
-
57
- const toolName = payload.tool_name;
58
- const hookEvent = payload.hook_event_name ?? "unknown";
59
- logDiagnostic(
60
- "add_plan_context",
61
- "receive",
62
- `tool=${toolName}, event=${hookEvent}`,
63
- { inputs: { tool_name: toolName, hook_event: hookEvent } },
64
- );
65
-
66
- const projectRoot = getProjectRoot(payload.cwd);
67
-
68
- // PostToolUse: AskUserQuestion — mark that questions were asked
69
- if (toolName === "AskUserQuestion") {
70
- const sessionId = String(payload.session_id ?? "");
71
- if (sessionId) {
72
- markQuestionsAsked(sessionId, projectRoot);
73
- logInfo("add_plan_context", `Marked questions asked for session ${sessionId.slice(0, 8)}...`);
74
- }
75
-
76
- return;
77
- }
78
-
79
- // PreToolUse: Task — nudge Plan subagent to ask questions first (advisory)
80
- if (toolName === "Task") {
81
- if (!isPlanTask(payload)) return; // Only gate Plan subagent spawns
82
-
83
- const permissionMode = payload.permission_mode ?? "";
84
- if (permissionMode !== "plan") return; // Only enforce during plan mode
85
-
86
- const sessionId = payload.session_id;
87
- if (!sessionId) {
88
- logDebug("add_plan_context", "No session_id for Task gate, skipping enforcement");
89
- return;
90
- }
91
-
92
- const sessionIdStr = String(sessionId);
93
-
94
- if (wasQuestionsAsked(sessionIdStr, projectRoot)) {
95
- logInfo("add_plan_context", "Questions asked, allowing Plan Task with eval context");
96
- logDiagnostic(
97
- "add_plan_context",
98
- "decide",
99
- "Questions asked, allowing Plan Task",
100
- { decision: "allow_with_context", reasoning: "was_questions_asked=True" },
101
- );
102
- emitContext(CONTEXT_REMINDER);
103
- return;
104
- }
105
-
106
- // Questions NOT asked: nudge toward asking questions (advisory only)
107
- logInfo("add_plan_context", "Questions not asked - nudging Plan Task to ask first");
108
- logDiagnostic(
109
- "add_plan_context",
110
- "decide",
111
- "Questions not asked, nudging Plan Task",
112
- { decision: "nudge", reasoning: "was_questions_asked=False, advisory context" },
113
- );
114
- emitContext(TASK_ENFORCEMENT_CONTEXT);
115
-
116
- }
117
- }
118
-
119
- runHook(main, "add_plan_context");
@@ -1,130 +0,0 @@
1
- /**
2
- * Codex CLI plan reviewer.
3
- * Runs Codex in non-interactive mode with read-only sandbox.
4
- * See cc-native-plan-review-spec.md §4.11
5
- */
6
-
7
- import * as fs from "node:fs";
8
- import * as os from "node:os";
9
- import * as path from "node:path";
10
- import { logDebug, logInfo, logWarn, logError } from "../../../_shared/lib-ts/base/logger.js";
11
- import { findExecutable, execFileAsync } from "../../../_shared/lib-ts/base/subprocess-utils.js";
12
- import { parseJsonMaybe, coerceToReview } from "../json-parser.js";
13
- import { REVIEW_PROMPT_PREFIX } from "../types.js";
14
- import type { ReviewerResult, ReviewOptions } from "../types.js";
15
- import { makeResult } from "./types.js";
16
- import type { Reviewer } from "./types.js";
17
-
18
- /**
19
- * Codex reviewer — runs codex exec --sandbox read-only.
20
- */
21
- export class CodexReviewer implements Reviewer {
22
- private settings: Record<string, unknown>;
23
-
24
- constructor(settings: Record<string, unknown>) {
25
- this.settings = settings;
26
- }
27
-
28
- async review(
29
- plan: string,
30
- schema: Record<string, unknown>,
31
- options: ReviewOptions,
32
- ): Promise<ReviewerResult> {
33
- return runCodexReview(plan, schema, this.settings);
34
- }
35
- }
36
-
37
- /**
38
- * Run Codex CLI to review the plan.
39
- * Never throws — returns error ReviewerResult on failure.
40
- */
41
- export async function runCodexReview(
42
- plan: string,
43
- schema: Record<string, unknown>,
44
- settings: Record<string, unknown>,
45
- ): Promise<ReviewerResult> {
46
- const codexSettings =
47
- ((settings.reviewers as Record<string, unknown> | undefined)?.codex as
48
- | Record<string, unknown>
49
- | undefined) ?? {};
50
- const timeout = (codexSettings.timeout as number) ?? 120;
51
- const model = (codexSettings.model as string) ?? "";
52
-
53
- const codexPath = findExecutable("codex");
54
- if (!codexPath) {
55
- logWarn("codex", "CLI not found on PATH");
56
- return makeResult("codex", false, "skip", {}, "", "codex CLI not found on PATH");
57
- }
58
-
59
- logDebug("codex", `Found CLI at: ${codexPath}`);
60
-
61
- const prompt = `${REVIEW_PROMPT_PREFIX}
62
- Return ONLY a JSON object that matches this JSON Schema:
63
- ${JSON.stringify(schema)}
64
-
65
- PLAN:
66
- <<<
67
- ${plan}
68
- >>>
69
- `;
70
-
71
- const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "codex-review-"));
72
-
73
- try {
74
- const schemaPath = path.join(tmpDir, "schema.json");
75
- const outPath = path.join(tmpDir, "codex_review.json");
76
-
77
- fs.writeFileSync(schemaPath, JSON.stringify(schema, null, 2), "utf-8");
78
-
79
- const cmdArgs = ["exec", "--sandbox", "read-only"];
80
-
81
- if (model) {
82
- cmdArgs.push("--model", model);
83
- }
84
-
85
- cmdArgs.push("--output-schema", schemaPath, "-o", outPath, "-");
86
-
87
- logDebug("codex", `Running command: codex ${cmdArgs.join(" ")}`);
88
-
89
- const result = await execFileAsync(codexPath, cmdArgs, {
90
- input: prompt,
91
- timeout: timeout * 1000,
92
- maxBuffer: 10 * 1024 * 1024,
93
- shell: process.platform === "win32",
94
- });
95
-
96
- if (result.killed || result.signal === "SIGTERM") {
97
- logWarn("codex", `TIMEOUT after ${timeout}s`);
98
- return makeResult("codex", false, "error", {}, "", `codex timed out after ${timeout}s`);
99
- }
100
-
101
- if (!result.stdout && !result.stderr && !fs.existsSync(outPath) && result.exitCode !== 0) {
102
- logError("codex", `Process exited with code ${result.exitCode} and no output`);
103
- return makeResult("codex", false, "error", {}, "", `codex failed to run (exit ${result.exitCode})`);
104
- }
105
-
106
- logDebug("codex", `Exit code: ${result.exitCode}`);
107
-
108
- let raw = "";
109
- if (fs.existsSync(outPath)) {
110
- raw = fs.readFileSync(outPath, "utf-8");
111
- }
112
-
113
- const obj = parseJsonMaybe(raw) ?? parseJsonMaybe(result.stdout);
114
- const [ok, verdict, norm] = coerceToReview(
115
- obj,
116
- "Retry or check CLI auth/config.",
117
- );
118
-
119
- const err = result.stderr.trim();
120
- return makeResult("codex", ok, verdict, norm, raw || result.stdout, err);
121
- } finally {
122
- // Clean up temp directory
123
- try {
124
- fs.rmSync(tmpDir, { recursive: true, force: true });
125
- } catch {
126
- // Best effort cleanup
127
- }
128
- }
129
- }
130
-
@@ -1,107 +0,0 @@
1
- /**
2
- * Gemini CLI plan reviewer.
3
- * Runs Gemini CLI in YOLO mode (auto-approve).
4
- * See cc-native-plan-review-spec.md §4.12
5
- */
6
-
7
- import { logDebug, logInfo, logWarn, logError } from "../../../_shared/lib-ts/base/logger.js";
8
- import { findExecutable, execFileAsync } from "../../../_shared/lib-ts/base/subprocess-utils.js";
9
- import { parseJsonMaybe, coerceToReview } from "../json-parser.js";
10
- import type { ReviewerResult, ReviewOptions } from "../types.js";
11
- import { makeResult } from "./types.js";
12
- import type { Reviewer } from "./types.js";
13
-
14
- /**
15
- * Gemini reviewer — runs gemini -y -p <instruction>.
16
- */
17
- export class GeminiReviewer implements Reviewer {
18
- private settings: Record<string, unknown>;
19
-
20
- constructor(settings: Record<string, unknown>) {
21
- this.settings = settings;
22
- }
23
-
24
- async review(
25
- plan: string,
26
- schema: Record<string, unknown>,
27
- options: ReviewOptions,
28
- ): Promise<ReviewerResult> {
29
- return runGeminiReview(plan, schema, this.settings);
30
- }
31
- }
32
-
33
- /**
34
- * Run Gemini CLI to review the plan.
35
- * Never throws — returns error ReviewerResult on failure.
36
- */
37
- export async function runGeminiReview(
38
- plan: string,
39
- schema: Record<string, unknown>,
40
- settings: Record<string, unknown>,
41
- ): Promise<ReviewerResult> {
42
- const geminiSettings =
43
- ((settings.reviewers as Record<string, unknown> | undefined)?.gemini as
44
- | Record<string, unknown>
45
- | undefined) ?? {};
46
- const timeout = (geminiSettings.timeout as number) ?? 120;
47
- const model = (geminiSettings.model as string) ?? "";
48
-
49
- const geminiPath = findExecutable("gemini");
50
- if (!geminiPath) {
51
- logWarn("gemini", "CLI not found on PATH");
52
- return makeResult("gemini", false, "skip", {}, "", "gemini CLI not found on PATH");
53
- }
54
-
55
- logDebug("gemini", `Found CLI at: ${geminiPath}`);
56
-
57
- const instruction = `
58
-
59
- Review the PLAN above as a senior staff software engineer. Focus on:
60
- - missing steps, unclear assumptions, edge cases
61
- - security/privacy concerns
62
- - testing/rollout/rollback completeness
63
- - operational concerns (observability, failure modes)
64
-
65
- Return ONLY a JSON object that matches this JSON Schema (no markdown, no code fences):
66
- ${JSON.stringify(schema)}
67
- `;
68
-
69
- const cmdArgs = ["-y", "-p", instruction];
70
-
71
- if (model) {
72
- cmdArgs.push("--model", model);
73
- }
74
-
75
- logDebug("gemini", "Running command: gemini -y -p <instruction>");
76
-
77
- const result = await execFileAsync(geminiPath, cmdArgs, {
78
- input: plan,
79
- timeout: timeout * 1000,
80
- maxBuffer: 10 * 1024 * 1024,
81
- shell: process.platform === "win32",
82
- });
83
-
84
- if (result.killed || result.signal === "SIGTERM") {
85
- logWarn("gemini", `TIMEOUT after ${timeout}s`);
86
- return makeResult("gemini", false, "error", {}, "", `gemini timed out after ${timeout}s`);
87
- }
88
-
89
- if (!result.stdout && !result.stderr && result.exitCode !== 0) {
90
- logError("gemini", `Process exited with code ${result.exitCode}`);
91
- return makeResult("gemini", false, "error", {}, "", `gemini failed to run (exit ${result.exitCode})`);
92
- }
93
-
94
- logDebug("gemini", `Exit code: ${result.exitCode}`);
95
-
96
- const raw = result.stdout.trim();
97
- const err = result.stderr.trim();
98
-
99
- const obj = parseJsonMaybe(raw);
100
- const [ok, verdict, norm] = coerceToReview(
101
- obj,
102
- "Retry or check CLI auth/config.",
103
- );
104
-
105
- return makeResult("gemini", ok, verdict, norm, raw, err);
106
- }
107
-