aiwcli 0.12.0 → 0.12.2

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 (81) hide show
  1. package/dist/lib/template-installer.js +3 -3
  2. package/dist/lib/version.js +2 -2
  3. package/dist/templates/_shared/hooks-ts/session_end.ts +75 -4
  4. package/dist/templates/_shared/hooks-ts/session_start.ts +10 -1
  5. package/dist/templates/_shared/hooks-ts/user_prompt_submit.ts +12 -0
  6. package/dist/templates/_shared/lib-ts/base/hook-utils.ts +45 -29
  7. package/dist/templates/_shared/lib-ts/base/logger.ts +1 -1
  8. package/dist/templates/_shared/lib-ts/base/subprocess-utils.ts +1 -1
  9. package/dist/templates/_shared/lib-ts/context/context-formatter.ts +151 -29
  10. package/dist/templates/_shared/lib-ts/context/plan-manager.ts +14 -13
  11. package/dist/templates/_shared/lib-ts/handoff/handoff-reader.ts +3 -2
  12. package/dist/templates/_shared/scripts/resume_handoff.ts +29 -4
  13. package/dist/templates/_shared/scripts/save_handoff.ts +7 -7
  14. package/dist/templates/_shared/scripts/status_line.ts +103 -70
  15. package/dist/templates/cc-native/.claude/settings.json +11 -12
  16. package/dist/templates/cc-native/_cc-native/agents/CLAUDE.md +1 -7
  17. package/dist/templates/cc-native/_cc-native/agents/plan-review/ARCH-EVOLUTION.md +62 -63
  18. package/dist/templates/cc-native/_cc-native/agents/plan-review/ARCH-PATTERNS.md +61 -62
  19. package/dist/templates/cc-native/_cc-native/agents/plan-review/ARCH-STRUCTURE.md +62 -63
  20. package/dist/templates/cc-native/_cc-native/agents/plan-review/ASSUMPTION-TRACER.md +56 -57
  21. package/dist/templates/cc-native/_cc-native/agents/plan-review/CLARITY-AUDITOR.md +53 -54
  22. package/dist/templates/cc-native/_cc-native/agents/plan-review/COMPLETENESS-FEASIBILITY.md +66 -67
  23. package/dist/templates/cc-native/_cc-native/agents/plan-review/COMPLETENESS-GAPS.md +70 -71
  24. package/dist/templates/cc-native/_cc-native/agents/plan-review/COMPLETENESS-ORDERING.md +62 -63
  25. package/dist/templates/cc-native/_cc-native/agents/plan-review/CONSTRAINT-VALIDATOR.md +72 -73
  26. package/dist/templates/cc-native/_cc-native/agents/plan-review/DESIGN-ADR-VALIDATOR.md +61 -62
  27. package/dist/templates/cc-native/_cc-native/agents/plan-review/DESIGN-SCALE-MATCHER.md +64 -65
  28. package/dist/templates/cc-native/_cc-native/agents/plan-review/DEVILS-ADVOCATE.md +56 -57
  29. package/dist/templates/cc-native/_cc-native/agents/plan-review/DOCUMENTATION-PHILOSOPHY.md +86 -87
  30. package/dist/templates/cc-native/_cc-native/agents/plan-review/HANDOFF-READINESS.md +59 -60
  31. package/dist/templates/cc-native/_cc-native/agents/plan-review/HIDDEN-COMPLEXITY.md +58 -59
  32. package/dist/templates/cc-native/_cc-native/agents/plan-review/INCREMENTAL-DELIVERY.md +66 -67
  33. package/dist/templates/cc-native/_cc-native/agents/plan-review/RISK-DEPENDENCY.md +62 -63
  34. package/dist/templates/cc-native/_cc-native/agents/plan-review/RISK-FMEA.md +66 -67
  35. package/dist/templates/cc-native/_cc-native/agents/plan-review/RISK-PREMORTEM.md +71 -72
  36. package/dist/templates/cc-native/_cc-native/agents/plan-review/RISK-REVERSIBILITY.md +74 -75
  37. package/dist/templates/cc-native/_cc-native/agents/plan-review/SCOPE-BOUNDARY.md +77 -78
  38. package/dist/templates/cc-native/_cc-native/agents/plan-review/SIMPLICITY-GUARDIAN.md +62 -63
  39. package/dist/templates/cc-native/_cc-native/agents/plan-review/SKEPTIC.md +68 -69
  40. package/dist/templates/cc-native/_cc-native/agents/plan-review/TESTDRIVEN-BEHAVIOR-AUDITOR.md +61 -62
  41. package/dist/templates/cc-native/_cc-native/agents/plan-review/TESTDRIVEN-CHARACTERIZATION.md +71 -72
  42. package/dist/templates/cc-native/_cc-native/agents/plan-review/TESTDRIVEN-FIRST-VALIDATOR.md +61 -62
  43. package/dist/templates/cc-native/_cc-native/agents/plan-review/TESTDRIVEN-PYRAMID-ANALYZER.md +61 -62
  44. package/dist/templates/cc-native/_cc-native/agents/plan-review/TRADEOFF-COSTS.md +67 -68
  45. package/dist/templates/cc-native/_cc-native/agents/plan-review/TRADEOFF-STAKEHOLDERS.md +65 -66
  46. package/dist/templates/cc-native/_cc-native/agents/plan-review/VERIFY-COVERAGE.md +74 -75
  47. package/dist/templates/cc-native/_cc-native/agents/plan-review/VERIFY-STRENGTH.md +69 -70
  48. package/dist/templates/cc-native/_cc-native/hooks/CLAUDE.md +19 -2
  49. package/dist/templates/cc-native/_cc-native/hooks/cc-native-plan-review.ts +28 -1013
  50. package/dist/templates/cc-native/_cc-native/hooks/enhance_plan_post_subagent.ts +24 -8
  51. package/dist/templates/cc-native/_cc-native/hooks/enhance_plan_post_write.ts +3 -2
  52. package/dist/templates/cc-native/_cc-native/hooks/mark_questions_asked.ts +5 -5
  53. package/dist/templates/cc-native/_cc-native/hooks/plan_questions_early.ts +4 -4
  54. package/dist/templates/cc-native/_cc-native/lib-ts/agent-selection.ts +163 -0
  55. package/dist/templates/cc-native/_cc-native/lib-ts/aggregate-agents.ts +5 -5
  56. package/dist/templates/cc-native/_cc-native/lib-ts/artifacts/format.ts +597 -0
  57. package/dist/templates/cc-native/_cc-native/lib-ts/artifacts/index.ts +26 -0
  58. package/dist/templates/cc-native/_cc-native/lib-ts/artifacts/tracker.ts +107 -0
  59. package/dist/templates/cc-native/_cc-native/lib-ts/artifacts/write.ts +119 -0
  60. package/dist/templates/cc-native/_cc-native/lib-ts/artifacts.ts +19 -820
  61. package/dist/templates/cc-native/_cc-native/lib-ts/cc-native-state.ts +77 -5
  62. package/dist/templates/cc-native/_cc-native/lib-ts/graduation.ts +132 -0
  63. package/dist/templates/cc-native/_cc-native/lib-ts/orchestrator.ts +7 -8
  64. package/dist/templates/cc-native/_cc-native/lib-ts/output-builder.ts +130 -0
  65. package/dist/templates/cc-native/_cc-native/lib-ts/plan-discovery.ts +80 -0
  66. package/dist/templates/cc-native/_cc-native/lib-ts/plan-questions.ts +3 -2
  67. package/dist/templates/cc-native/_cc-native/lib-ts/review-pipeline.ts +489 -0
  68. package/dist/templates/cc-native/_cc-native/lib-ts/reviewers/agent.ts +14 -11
  69. package/dist/templates/cc-native/_cc-native/lib-ts/reviewers/base/base-agent.ts +108 -108
  70. package/dist/templates/cc-native/_cc-native/lib-ts/reviewers/index.ts +2 -2
  71. package/dist/templates/cc-native/_cc-native/lib-ts/reviewers/providers/claude-agent.ts +18 -18
  72. package/dist/templates/cc-native/_cc-native/lib-ts/reviewers/providers/codex-agent.ts +75 -74
  73. package/dist/templates/cc-native/_cc-native/lib-ts/reviewers/providers/gemini-agent.ts +8 -8
  74. package/dist/templates/cc-native/_cc-native/lib-ts/reviewers/providers/orchestrator-claude-agent.ts +34 -34
  75. package/dist/templates/cc-native/_cc-native/lib-ts/reviewers/types.ts +4 -2
  76. package/dist/templates/cc-native/_cc-native/lib-ts/settings.ts +184 -0
  77. package/dist/templates/cc-native/_cc-native/lib-ts/state.ts +35 -0
  78. package/dist/templates/cc-native/_cc-native/lib-ts/types.ts +48 -2
  79. package/dist/templates/cc-native/_cc-native/lib-ts/verdict.ts +3 -3
  80. package/oclif.manifest.json +1 -1
  81. package/package.json +1 -1
@@ -75,14 +75,14 @@ export async function checkTemplateStatus(templatePath, targetDir, ides, templat
75
75
  * Patterns to exclude when copying template directories.
76
76
  * These are development/test artifacts that shouldn't be packaged.
77
77
  */
78
- const EXCLUDED_PATTERNS = [
78
+ const EXCLUDED_PATTERNS = new Set([
79
79
  '_output',
80
- ];
80
+ ]);
81
81
  /**
82
82
  * Check if a filename should be excluded from copying
83
83
  */
84
84
  export function shouldExclude(name) {
85
- return EXCLUDED_PATTERNS.includes(name);
85
+ return EXCLUDED_PATTERNS.has(name);
86
86
  }
87
87
  /**
88
88
  * Copy directory recursively with proper error handling.
@@ -37,7 +37,7 @@ const MIN_CLAUDE_CODE_VERSION = '0.1.0';
37
37
  * Known incompatible Claude Code versions.
38
38
  * These versions have confirmed issues with AI Workflow CLI.
39
39
  */
40
- const INCOMPATIBLE_VERSIONS = ['0.0.9'];
40
+ const INCOMPATIBLE_VERSIONS = new Set(['0.0.9']);
41
41
  /**
42
42
  * Detects Claude Code version by executing `claude --version`.
43
43
  *
@@ -109,7 +109,7 @@ export function checkVersionCompatibility(version) {
109
109
  };
110
110
  }
111
111
  // Check known incompatible versions first
112
- if (INCOMPATIBLE_VERSIONS.includes(version)) {
112
+ if (INCOMPATIBLE_VERSIONS.has(version)) {
113
113
  return {
114
114
  compatible: false,
115
115
  version,
@@ -5,18 +5,70 @@
5
5
  */
6
6
  import * as crypto from "node:crypto";
7
7
  import * as fs from "node:fs";
8
+ import * as path from "node:path";
8
9
 
9
- import { getProjectRoot } from "../lib-ts/base/constants.js";
10
+ import { getProjectRoot, getContextDir } from "../lib-ts/base/constants.js";
10
11
  import { getGitState } from "../lib-ts/base/git-state.js";
11
12
  import {
12
- loadHookInput, logDebug, logDiagnostic, logError, logInfo, logWarn as _logWarn, runHook,
13
+ loadHookInput, runHook, logDebug, logInfo, logWarn, logError, logDiagnostic,
13
14
  } from "../lib-ts/base/hook-utils.js";
14
15
  import { nowIso } from "../lib-ts/base/utils.js";
15
16
  import { getContextBySessionId, saveState } from "../lib-ts/context/context-store.js";
16
17
  import {
17
- extractPlanAnchors, findLatestPlan, generatePlanId, normalizePlanContent,
18
+ findLatestPlan, normalizePlanContent, generatePlanId, extractPlanAnchors,
18
19
  } from "../lib-ts/context/plan-manager.js";
19
20
 
21
+ /**
22
+ * Archive session transcript to context's session-transcripts/ folder.
23
+ * Returns archived path on success, null if skipped or failed.
24
+ */
25
+ function archiveTranscript(
26
+ transcriptPath: string,
27
+ contextId: string,
28
+ sessionId: string,
29
+ projectRoot: string,
30
+ ): string | null {
31
+ // 1. Validate inputs
32
+ if (!transcriptPath || !fs.existsSync(transcriptPath)) {
33
+ logDebug("session_end", `Transcript not found: ${transcriptPath}`);
34
+ return null;
35
+ }
36
+
37
+ // 2. Ensure session-transcripts directory exists
38
+ const contextDir = getContextDir(contextId, projectRoot);
39
+ const transcriptsDir = path.join(contextDir, "session-transcripts");
40
+ fs.mkdirSync(transcriptsDir, { recursive: true });
41
+
42
+ // 3. Generate archive filename: YYYY-MM-DD-HHMM-{session_id}.jsonl
43
+ const now = new Date();
44
+ // Format: 2026-02-14-1400 (year-month-day-hourminute)
45
+ // Note: Hours and minutes are concatenated without separator (HHMM)
46
+ const timestamp =
47
+ `${now.getFullYear()}-` +
48
+ `${String(now.getMonth() + 1).padStart(2, "0")}-` +
49
+ `${String(now.getDate()).padStart(2, "0")}-` +
50
+ `${String(now.getHours()).padStart(2, "0")}${String(now.getMinutes()).padStart(2, "0")}`;
51
+
52
+ // 4. Handle collisions (rare, but possible with rapid session churn)
53
+ let archiveName = `${timestamp}-${sessionId}.jsonl`;
54
+ let archivePath = path.join(transcriptsDir, archiveName);
55
+ let counter = 2;
56
+ while (fs.existsSync(archivePath)) {
57
+ archiveName = `${timestamp}-${sessionId}-${counter}.jsonl`;
58
+ archivePath = path.join(transcriptsDir, archiveName);
59
+ counter++;
60
+ }
61
+
62
+ // 5. Copy transcript file
63
+ try {
64
+ fs.copyFileSync(transcriptPath, archivePath);
65
+ return archivePath;
66
+ } catch (error) {
67
+ logError("session_end", `Failed to copy transcript: ${error}`);
68
+ return null;
69
+ }
70
+ }
71
+
20
72
  function main(): void {
21
73
  const payload = loadHookInput();
22
74
  if (!payload) return;
@@ -50,6 +102,25 @@ function main(): void {
50
102
  };
51
103
  state.last_active = nowIso();
52
104
 
105
+ // Archive transcript (NEW)
106
+ // Note: state is a ContextState object (from getContextBySessionId on line 33)
107
+ // state.id is the context ID used to construct paths like _output/contexts/{context_id}/
108
+ if (payload.transcript_path) {
109
+ try {
110
+ const archived = archiveTranscript(
111
+ payload.transcript_path,
112
+ state.id, // Context ID, verified by existing code on line 98: saveState(state.id, ...)
113
+ sessionId,
114
+ projectRoot,
115
+ );
116
+ if (archived) {
117
+ logInfo("session_end", `Archived transcript: ${path.basename(archived)}`);
118
+ }
119
+ } catch (error) {
120
+ logError("session_end", `Transcript archival failed: ${error}`);
121
+ }
122
+ }
123
+
53
124
  // Plan fallback assignment (skip in plan mode — rejected plans shouldn't stage)
54
125
  if (permissionMode !== "plan") {
55
126
  // Step 1: Assign plan fields if missing
@@ -57,7 +128,7 @@ function main(): void {
57
128
  const latestPlanPath = findLatestPlan(state.id, projectRoot);
58
129
  if (latestPlanPath) {
59
130
  try {
60
- const content = fs.readFileSync(latestPlanPath, "utf8");
131
+ const content = fs.readFileSync(latestPlanPath, "utf-8");
61
132
  const normalized = normalizePlanContent(content);
62
133
  const planHash = crypto.createHash("sha256")
63
134
  .update(normalized, "utf-8")
@@ -13,6 +13,7 @@ import {
13
13
  } from "../lib-ts/context/context-store.js";
14
14
  import {
15
15
  buildRestoreSections, formatHandoffContinuation, getModeDisplay,
16
+ buildContextInventory,
16
17
  } from "../lib-ts/context/context-formatter.js";
17
18
  import type { ContextState } from "../lib-ts/types.js";
18
19
 
@@ -39,6 +40,9 @@ function handleCompactRestore(sessionId: string, projectRoot: string): void {
39
40
  const restore = buildRestoreSections(state, projectRoot, true);
40
41
  if (restore) sections.push(restore);
41
42
 
43
+ const inventory = buildContextInventory(state, projectRoot);
44
+ if (inventory) sections.push("", inventory);
45
+
42
46
  sections.push(
43
47
  "",
44
48
  "---",
@@ -79,6 +83,9 @@ async function handleClearRestore(sessionId: string, projectRoot: string): Promi
79
83
  const restore = buildRestoreSections(ctx, projectRoot, false);
80
84
  if (restore) sections.push(restore);
81
85
 
86
+ const inventory = buildContextInventory(ctx, projectRoot);
87
+ if (inventory) sections.push("", inventory);
88
+
82
89
  sections.push(
83
90
  "",
84
91
  "---",
@@ -100,7 +107,9 @@ async function handleClearRestore(sessionId: string, projectRoot: string): Promi
100
107
  logInfo("session_start", `Clear restore: ${ctx.id} has_handoff → active (handoff_consumed=true)`);
101
108
 
102
109
  const handoffContent = formatHandoffContinuation(ctx, projectRoot);
103
- emitContext(handoffContent);
110
+ const handoffInventory = buildContextInventory(ctx, projectRoot);
111
+ const combined = handoffInventory ? handoffContent + "\n\n" + handoffInventory : handoffContent;
112
+ emitContext(combined);
104
113
  return;
105
114
  }
106
115
 
@@ -14,6 +14,7 @@ import {
14
14
  getContextBySessionId, bindSession, maybeActivate, saveState,
15
15
  } from "../lib-ts/context/context-store.js";
16
16
  import { determineContext, BlockRequest } from "../lib-ts/context/context-selector.js";
17
+ import { buildContextInventory } from "../lib-ts/context/context-formatter.js";
17
18
 
18
19
  async function asyncMain(): Promise<void> {
19
20
  const payload = loadHookInput();
@@ -64,6 +65,17 @@ async function asyncMain(): Promise<void> {
64
65
  if (outputText) {
65
66
  outputs.push(outputText);
66
67
  }
68
+
69
+ // Append context folder inventory
70
+ try {
71
+ const boundState = getContextBySessionId(sessionId, projectRoot);
72
+ if (boundState) {
73
+ const inventory = buildContextInventory(boundState, projectRoot);
74
+ if (inventory) outputs.push(inventory);
75
+ }
76
+ } catch (e) {
77
+ logWarn("user_prompt_submit", `Inventory failed (non-critical): ${e}`);
78
+ }
67
79
  } catch (e) {
68
80
  if (e instanceof BlockRequest) {
69
81
  emitBlock((e as Error).message);
@@ -4,14 +4,15 @@
4
4
  * See SPEC.md §5
5
5
  */
6
6
 
7
- import * as fs from "node:fs";
8
- import { logDebug, logInfo, logWarn, logError, logBlocking, logHookError, logDiagnostic, hookLog, setSessionId, setContextPath, getContextPath as _getContextPath } from "./logger.js";
7
+ import * as fs from "node:fs";
8
+
9
9
  import { getProjectRoot } from "./constants.js";
10
+ import { logDebug, logWarn, hookLog, setSessionId, getContextPath as _getContextPath } from "./logger.js";
10
11
  import { getContextBySessionId } from "../context/context-store.js";
11
12
  import type { HookInput, HookOutput, PermissionRequestOutput } from "../types.js";
12
13
 
13
14
  // Re-export logger functions for convenience (matches Python hook_utils re-exports)
14
- export { logDebug, logInfo, logWarn, logError, logBlocking, logHookError, logDiagnostic, hookLog, setSessionId, setContextPath };
15
+ export { setSessionId };
15
16
 
16
17
  // Context window baseline: tokens not visible in hook data §5.9
17
18
  export const CONTEXT_BASELINE_TOKENS = 22_600;
@@ -93,7 +94,7 @@ export function checkSkipPersistence(
93
94
  const toolInput = getToolInput(payload);
94
95
  if (!toolInput) return false;
95
96
 
96
- const metadata = toolInput.metadata;
97
+ const {metadata} = toolInput;
97
98
  if (metadata && typeof metadata === "object" && metadata.skip_persistence) {
98
99
  logDebug(hookName, "Skipping persistence (skip_persistence flag set)");
99
100
  return true;
@@ -105,11 +106,23 @@ export function checkSkipPersistence(
105
106
  * Emit hookSpecificOutput with additionalContext to stdout.
106
107
  * hookEventName is required by Claude Code's Zod validator (discriminated union).
107
108
  * Auto-detected from stdin payload (set by loadHookInput/runHook).
109
+ *
110
+ * SubagentStop and Stop events use top-level systemMessage field instead of hookSpecificOutput.
108
111
  * See SPEC.md §5.5
109
112
  */
110
113
  export function emitContext(additionalContext: string): void {
111
114
  const eventName = _lastHookEvent ?? undefined;
112
115
  const tool = _lastToolName;
116
+
117
+ // SubagentStop and Stop use top-level systemMessage field
118
+ if (eventName === "SubagentStop" || eventName === "Stop") {
119
+ const out = { systemMessage: additionalContext };
120
+ process.stdout.write(JSON.stringify(out) + "\n");
121
+ _logEmit("systemMessage", additionalContext.length, { event: eventName ?? "unknown", systemMessage: additionalContext });
122
+ return;
123
+ }
124
+
125
+ // All other events use hookSpecificOutput
113
126
  const out: HookOutput = {
114
127
  hookSpecificOutput: {
115
128
  ...(eventName ? { hookEventName: eventName } : {}),
@@ -153,8 +166,8 @@ export function emitContextAndBlock(
153
166
  process.stdout.write(json + "\n");
154
167
  }
155
168
 
156
- /** Log hook output (context or block) to hook-log.jsonl for visibility. */
157
- function _logEmit(type: "context" | "block", chars: number, payload: Record<string, any>): void {
169
+ /** Log hook output (context, systemMessage, or block) to hook-log.jsonl for visibility. */
170
+ function _logEmit(type: "context" | "systemMessage" | "block", chars: number, payload: Record<string, any>): void {
158
171
  const hook = _cachedHookName ?? "unknown";
159
172
  const event = payload.event ?? "unknown";
160
173
  const mechanism = payload.mechanism ? ` via ${payload.mechanism}` : "";
@@ -268,27 +281,28 @@ export function emitPermissionDecision(
268
281
  export function emitBlock(reason: string, context?: string): void {
269
282
  const event = _lastHookEvent;
270
283
  switch (event) {
271
- case "PreToolUse":
272
- emitContextAndBlock(context ?? reason, reason);
273
- break;
274
- case "UserPromptSubmit":
275
- emitBlockPrompt(reason, context);
284
+ case "PermissionRequest":
285
+ emitPermissionDecision("deny", { message: reason });
276
286
  break;
277
287
  case "PostToolUse":
278
288
  case "PostToolUseFailure":
279
289
  emitBlockViaExit(reason, context);
280
290
  break;
291
+ case "PreToolUse":
292
+ emitContextAndBlock(context ?? reason, reason);
293
+ break;
281
294
  case "Stop":
282
295
  case "SubagentStop":
283
296
  emitBlockTopLevel(reason);
284
297
  break;
285
- case "PermissionRequest":
286
- emitPermissionDecision("deny", { message: reason });
298
+ case "UserPromptSubmit":
299
+ emitBlockPrompt(reason, context);
287
300
  break;
288
- default:
301
+ default: {
289
302
  logWarn(_cachedHookName ?? "unknown",
290
303
  `emitBlock() called from ${event ?? "unknown"} — no blocking mechanism exists for this event type, ignoring`);
291
- break;
304
+ break;
305
+ }
292
306
  }
293
307
  }
294
308
 
@@ -296,7 +310,7 @@ export function emitBlock(reason: string, context?: string): void {
296
310
  * Auto-detect template origin from the hook script path.
297
311
  */
298
312
  function detectTemplate(scriptPath = ""): string {
299
- const p = (scriptPath || (process.argv[1] ?? "")).replace(/\\/g, "/");
313
+ const p = (scriptPath || (process.argv[1] ?? "")).replaceAll('\\', "/");
300
314
  if (p.includes("/_shared/hooks/") || p.startsWith("_shared/hooks/")) {
301
315
  return "shared";
302
316
  }
@@ -438,16 +452,16 @@ export function runHook(
438
452
  const result = mainFunc();
439
453
  exitCode = typeof result === "number" ? result : 0;
440
454
  status = exitCode !== 0 ? "blocked" : "success";
441
- } catch (e: any) {
442
- if (e instanceof Error && e.message.startsWith("SystemExit:")) {
443
- const code = parseInt(e.message.slice(11), 10);
444
- exitCode = isNaN(code) ? (e.message.slice(11) ? 1 : 0) : code;
455
+ } catch (error: any) {
456
+ if (error instanceof Error && error.message.startsWith("SystemExit:")) {
457
+ const code = parseInt(error.message.slice(11), 10);
458
+ exitCode = isNaN(code) ? (error.message.slice(11) ? 1 : 0) : code;
445
459
  status = exitCode !== 0 ? "blocked" : "success";
446
460
  } else {
447
461
  exitCode = 0; // Non-blocking
448
462
  status = "error";
449
- const stack = e instanceof Error ? e.stack ?? "" : "";
450
- errorInfo = [e instanceof Error ? e : new Error(String(e)), stack];
463
+ const stack = error instanceof Error ? error.stack ?? "" : "";
464
+ errorInfo = [error instanceof Error ? error : new Error(String(error)), stack];
451
465
  }
452
466
  }
453
467
 
@@ -487,19 +501,19 @@ export function runHookAsync(
487
501
  _emitHookEnd(hookName, startTime, exitCode, exitCode !== 0 ? "blocked" : "success", null, startData, event, tool, template);
488
502
  _drainAndExit(exitCode);
489
503
  })
490
- .catch((e: any) => {
504
+ .catch((error: any) => {
491
505
  let exitCode = 0;
492
506
  let status = "error";
493
507
  let errorInfo: [Error, string] | null = null;
494
508
 
495
- if (e instanceof Error && e.message.startsWith("SystemExit:")) {
496
- const code = parseInt(e.message.slice(11), 10);
497
- exitCode = isNaN(code) ? (e.message.slice(11) ? 1 : 0) : code;
509
+ if (error instanceof Error && error.message.startsWith("SystemExit:")) {
510
+ const code = parseInt(error.message.slice(11), 10);
511
+ exitCode = isNaN(code) ? (error.message.slice(11) ? 1 : 0) : code;
498
512
  status = exitCode !== 0 ? "blocked" : "success";
499
513
  } else {
500
514
  exitCode = 0; // Non-blocking (fail open)
501
- const stack = e instanceof Error ? e.stack ?? "" : "";
502
- errorInfo = [e instanceof Error ? e : new Error(String(e)), stack];
515
+ const stack = error instanceof Error ? error.stack ?? "" : "";
516
+ errorInfo = [error instanceof Error ? error : new Error(String(error)), stack];
503
517
  }
504
518
 
505
519
  _emitHookEnd(hookName, startTime, exitCode, status, errorInfo, startData, event, tool, template);
@@ -541,7 +555,7 @@ function _emitHookEnd(
541
555
  if (errorInfo) {
542
556
  const [err, tb] = errorInfo;
543
557
  endData.error_type = err.constructor.name;
544
- hookLog("error", hookName, `[${endEvent}] ${err.constructor.name}: ${String(err).replace(/[\n\r]/g, " ").slice(0, 200)}`, { traceback_str: tb });
558
+ hookLog("error", hookName, `[${endEvent}] ${err.constructor.name}: ${String(err).replaceAll(/[\n\r]/g, " ").slice(0, 200)}`, { traceback_str: tb });
545
559
  hookLog("error", hookName, `HOOK_END: ${err}`, { data: endData, traceback_str: tb });
546
560
  } else if (status === "blocked") {
547
561
  hookLog("warn", hookName, "HOOK_END", { data: endData });
@@ -568,3 +582,5 @@ function _drainAndExit(code: number): void {
568
582
  process.exit(code);
569
583
  });
570
584
  }
585
+
586
+ export {logInfo, logError, logBlocking, logHookError, logDiagnostic, setContextPath, hookLog, logDebug, logWarn} from "./logger.js";
@@ -235,7 +235,7 @@ export function logHookError(
235
235
  tracebackStr = "",
236
236
  ): void {
237
237
  const errStr = typeof error === "string" ? error : String(error);
238
- const msg = errStr.replace(/[\n\r]/g, " ").slice(0, 200);
238
+ const msg = errStr.replaceAll(/[\n\r]/g, " ").slice(0, 200);
239
239
  const errType =
240
240
  typeof error === "object" && error !== null
241
241
  ? error.constructor.name
@@ -92,7 +92,7 @@ export function isExecSyncError(e: unknown): e is ExecSyncError {
92
92
  */
93
93
  export function shellQuoteWin(arg: string): string {
94
94
  if (process.platform !== "win32") return arg;
95
- return '"' + arg.replace(/"/g, '""') + '"';
95
+ return '"' + arg.replaceAll('"', '""') + '"';
96
96
  }
97
97
 
98
98
  // ---------------------------------------------------------------------------