aiwcli 0.15.5 → 0.15.7
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.
- package/README.md +6 -3
- package/dist/capabilities/branch/adapters.d.ts +2 -0
- package/dist/capabilities/branch/adapters.js +21 -0
- package/dist/capabilities/branch/contracts.d.ts +57 -0
- package/dist/capabilities/branch/contracts.js +1 -0
- package/dist/capabilities/branch/control-plane.d.ts +2 -0
- package/dist/capabilities/branch/control-plane.js +343 -0
- package/dist/capabilities/branch/runtime-core.d.ts +5 -0
- package/dist/capabilities/branch/runtime-core.js +36 -0
- package/dist/capabilities/installation/control-plane/clean-command.d.ts +41 -0
- package/dist/capabilities/installation/control-plane/clean-command.js +196 -0
- package/dist/capabilities/installation/control-plane/clear-command.d.ts +160 -0
- package/dist/capabilities/installation/control-plane/clear-command.js +1220 -0
- package/dist/capabilities/installation/control-plane/init-command.d.ts +81 -0
- package/dist/capabilities/installation/control-plane/init-command.js +449 -0
- package/dist/capabilities/launch/contracts.d.ts +51 -0
- package/dist/capabilities/launch/contracts.js +1 -0
- package/dist/capabilities/launch/control-plane/execute-launch.d.ts +2 -0
- package/dist/capabilities/launch/control-plane/execute-launch.js +222 -0
- package/dist/capabilities/launch/runtime-core/launch-options.d.ts +14 -0
- package/dist/capabilities/launch/runtime-core/launch-options.js +69 -0
- package/dist/cli/base-command.d.ts +18 -0
- package/dist/cli/base-command.js +55 -0
- package/dist/commands/branch.d.ts +0 -20
- package/dist/commands/branch.js +24 -416
- package/dist/commands/clean.d.ts +1 -41
- package/dist/commands/clean.js +1 -196
- package/dist/commands/clear.d.ts +1 -161
- package/dist/commands/clear.js +1 -1121
- package/dist/commands/init/index.d.ts +1 -98
- package/dist/commands/init/index.js +4 -478
- package/dist/commands/launch.d.ts +36 -11
- package/dist/commands/launch.js +135 -159
- package/dist/lib/base-command.d.ts +1 -114
- package/dist/lib/base-command.js +1 -153
- package/dist/lib/claude-settings-types.d.ts +31 -19
- package/dist/lib/context/context-formatter.d.ts +74 -0
- package/dist/lib/context/context-formatter.js +493 -0
- package/dist/lib/context/context-selector.d.ts +42 -0
- package/dist/lib/context/context-selector.js +451 -0
- package/dist/lib/context/context-store.d.ts +100 -0
- package/dist/lib/context/context-store.js +618 -0
- package/dist/lib/context/plan-manager.d.ts +54 -0
- package/dist/lib/context/plan-manager.js +282 -0
- package/dist/lib/context/task-tracker.d.ts +44 -0
- package/dist/lib/context/task-tracker.js +146 -0
- package/dist/lib/core-ide-base.d.ts +4 -0
- package/dist/lib/core-ide-base.js +77 -0
- package/dist/lib/core-installer.d.ts +5 -0
- package/dist/lib/core-installer.js +54 -0
- package/dist/lib/git-exclude-manager.d.ts +2 -2
- package/dist/lib/git-exclude-manager.js +3 -3
- package/dist/lib/hooks/hook-utils.d.ts +143 -0
- package/dist/lib/hooks/hook-utils.js +609 -0
- package/dist/lib/hooks/session-end-logic.d.ts +5 -0
- package/dist/lib/hooks/session-end-logic.js +63 -0
- package/dist/lib/hooks-merger.js +25 -19
- package/dist/lib/ide-path-resolver.d.ts +19 -7
- package/dist/lib/ide-path-resolver.js +25 -9
- package/dist/lib/install-state.d.ts +34 -0
- package/dist/lib/install-state.js +161 -0
- package/dist/lib/launch-options.d.ts +1 -0
- package/dist/lib/launch-options.js +1 -0
- package/dist/lib/lsp-patch.d.ts +12 -0
- package/dist/lib/lsp-patch.js +156 -0
- package/dist/lib/multiplexer.d.ts +57 -0
- package/dist/lib/multiplexer.js +19 -0
- package/dist/lib/multiplexers/psmux.d.ts +75 -0
- package/dist/lib/multiplexers/psmux.js +384 -0
- package/dist/lib/multiplexers/tmux.d.ts +44 -0
- package/dist/lib/multiplexers/tmux.js +262 -0
- package/dist/lib/mux-utils.d.ts +5 -0
- package/dist/lib/mux-utils.js +42 -0
- package/dist/lib/paths.d.ts +2 -2
- package/dist/lib/paths.js +2 -2
- package/dist/lib/platform-commands.d.ts +27 -0
- package/dist/lib/platform-commands.js +49 -0
- package/dist/lib/runtime/aiw-cli.d.ts +37 -0
- package/dist/lib/runtime/aiw-cli.js +74 -0
- package/dist/lib/runtime/atomic-write.d.ts +19 -0
- package/dist/lib/runtime/atomic-write.js +121 -0
- package/dist/lib/runtime/cli-args.d.ts +55 -0
- package/dist/lib/runtime/cli-args.js +185 -0
- package/dist/lib/runtime/constants.d.ts +56 -0
- package/dist/lib/runtime/constants.js +230 -0
- package/dist/lib/runtime/executable-policy.d.ts +16 -0
- package/dist/lib/runtime/executable-policy.js +57 -0
- package/dist/lib/runtime/git-state.d.ts +9 -0
- package/dist/lib/runtime/git-state.js +59 -0
- package/dist/lib/runtime/inference.d.ts +37 -0
- package/dist/lib/runtime/inference.js +262 -0
- package/dist/lib/runtime/lint-dispatch.d.ts +40 -0
- package/dist/lib/runtime/lint-dispatch.js +285 -0
- package/dist/lib/runtime/logger.d.ts +66 -0
- package/dist/lib/runtime/logger.js +201 -0
- package/dist/lib/runtime/models.d.ts +14 -0
- package/dist/lib/runtime/models.js +14 -0
- package/dist/lib/runtime/platform-adapter.d.ts +7 -0
- package/dist/lib/runtime/platform-adapter.js +21 -0
- package/dist/lib/runtime/preflight.d.ts +24 -0
- package/dist/lib/runtime/preflight.js +65 -0
- package/dist/lib/runtime/sentinel-ipc.d.ts +14 -0
- package/dist/lib/runtime/sentinel-ipc.js +67 -0
- package/dist/lib/runtime/state-io.d.ts +30 -0
- package/dist/lib/runtime/state-io.js +174 -0
- package/dist/lib/runtime/stop-words.d.ts +20 -0
- package/dist/lib/runtime/stop-words.js +150 -0
- package/dist/lib/runtime/subprocess-utils.d.ts +29 -0
- package/dist/lib/runtime/subprocess-utils.js +96 -0
- package/dist/lib/runtime/tmux-preflight.d.ts +13 -0
- package/dist/lib/runtime/tmux-preflight.js +78 -0
- package/dist/lib/runtime/utils.d.ts +54 -0
- package/dist/lib/runtime/utils.js +162 -0
- package/dist/lib/sentinel-wrapper.d.ts +9 -0
- package/dist/lib/sentinel-wrapper.js +20 -0
- package/dist/lib/shell-quoting.d.ts +5 -0
- package/dist/lib/shell-quoting.js +17 -0
- package/dist/lib/spawn-errors.d.ts +6 -0
- package/dist/lib/spawn-errors.js +15 -0
- package/dist/lib/spawn.js +5 -11
- package/dist/lib/template-installer.d.ts +4 -5
- package/dist/lib/template-installer.js +36 -34
- package/dist/lib/template-resolver.d.ts +6 -7
- package/dist/lib/template-resolver.js +26 -21
- package/dist/lib/template-settings-reconstructor.d.ts +7 -2
- package/dist/lib/template-settings-reconstructor.js +76 -45
- package/dist/lib/terminal-strategy.d.ts +11 -0
- package/dist/lib/terminal-strategy.js +49 -0
- package/dist/lib/terminal.d.ts +28 -0
- package/dist/lib/terminal.js +162 -112
- package/dist/lib/tmux-pane-placement.d.ts +17 -0
- package/dist/lib/tmux-pane-placement.js +58 -0
- package/dist/lib/tmux-primitives.d.ts +5 -0
- package/dist/lib/tmux-primitives.js +15 -0
- package/dist/lib/tmux-session.d.ts +32 -0
- package/dist/lib/tmux-session.js +86 -0
- package/dist/lib/tty-detection.js +1 -1
- package/dist/lib/types.d.ts +168 -0
- package/dist/lib/types.js +6 -0
- package/dist/lib/version.d.ts +1 -1
- package/dist/lib/version.js +1 -1
- package/dist/platform/launch.d.ts +10 -0
- package/dist/platform/launch.js +10 -0
- package/dist/templates/CLAUDE.md +31 -40
- package/dist/templates/cc-native/.claude/settings.json +27 -27
- package/dist/templates/cc-native/CC-NATIVE-README.md +1 -1
- package/dist/templates/cc-native/TEMPLATE-SCHEMA.md +10 -9
- package/dist/templates/cc-native/_cc-native/CLAUDE.md +18 -18
- package/dist/templates/cc-native/_cc-native/artifacts/CLAUDE.md +3 -3
- package/dist/templates/cc-native/_cc-native/artifacts/lib/format.ts +14 -14
- package/dist/templates/cc-native/_cc-native/artifacts/lib/tracker.ts +1 -1
- package/dist/templates/cc-native/_cc-native/artifacts/lib/write.ts +3 -3
- package/dist/templates/cc-native/_cc-native/cc-native.config.json +3 -3
- package/dist/templates/cc-native/_cc-native/hooks/CLAUDE.md +16 -15
- package/dist/templates/cc-native/_cc-native/hooks/cc-native-plan-review.ts +3 -3
- package/dist/templates/cc-native/_cc-native/hooks/enhance_plan_post_subagent.ts +2 -2
- package/dist/templates/cc-native/_cc-native/hooks/enhance_plan_post_write.ts +2 -2
- package/dist/templates/cc-native/_cc-native/hooks/mark_questions_asked.ts +3 -3
- package/dist/templates/cc-native/_cc-native/hooks/plan_questions_early.ts +2 -2
- package/dist/templates/cc-native/_cc-native/hooks/validate_task_prompt.ts +3 -3
- package/dist/templates/cc-native/_cc-native/lib-ts/CLAUDE.md +8 -8
- package/dist/templates/cc-native/_cc-native/lib-ts/aggregate-agents.ts +1 -1
- package/dist/templates/cc-native/_cc-native/lib-ts/cc-native-state.ts +4 -4
- package/dist/templates/cc-native/_cc-native/lib-ts/cli-output-parser.ts +1 -1
- package/dist/templates/cc-native/_cc-native/lib-ts/config.ts +1 -1
- package/dist/templates/cc-native/_cc-native/lib-ts/debug.ts +1 -1
- package/dist/templates/cc-native/_cc-native/lib-ts/json-parser.ts +1 -1
- package/dist/templates/cc-native/_cc-native/lib-ts/plan-discovery.ts +2 -2
- package/dist/templates/cc-native/_cc-native/lib-ts/rlm/logger.ts +1 -1
- package/dist/templates/cc-native/_cc-native/lib-ts/rlm/retrieval-pipeline.ts +2 -2
- package/dist/templates/cc-native/_cc-native/lib-ts/rlm/types.ts +1 -1
- package/dist/templates/cc-native/_cc-native/lib-ts/settings.ts +8 -8
- package/dist/templates/cc-native/_cc-native/lib-ts/state.ts +3 -3
- package/dist/templates/cc-native/_cc-native/lib-ts/tsconfig.json +2 -2
- package/dist/templates/cc-native/_cc-native/lib-ts/types.ts +3 -3
- package/dist/templates/cc-native/_cc-native/plan-review/CLAUDE.md +3 -1
- package/dist/templates/cc-native/_cc-native/plan-review/lib/__tests__/agent-selection.test.ts +345 -0
- package/dist/templates/cc-native/_cc-native/plan-review/lib/__tests__/preflight.test.ts +344 -0
- package/dist/templates/cc-native/_cc-native/plan-review/lib/agent-selection.ts +37 -15
- package/dist/templates/cc-native/_cc-native/plan-review/lib/corroboration.ts +16 -69
- package/dist/templates/cc-native/_cc-native/plan-review/lib/orchestrator.ts +1 -1
- package/dist/templates/cc-native/_cc-native/plan-review/lib/output-builder.ts +1 -1
- package/dist/templates/cc-native/_cc-native/plan-review/lib/plan-questions.ts +2 -2
- package/dist/templates/cc-native/_cc-native/plan-review/lib/preflight.ts +56 -26
- package/dist/templates/cc-native/_cc-native/plan-review/lib/review-pipeline.ts +7 -7
- package/dist/templates/cc-native/_cc-native/plan-review/lib/reviewers/agent.ts +4 -4
- package/dist/templates/cc-native/_cc-native/plan-review/lib/reviewers/base/base-agent.ts +3 -3
- package/dist/templates/cc-native/_cc-native/plan-review/lib/reviewers/index.ts +1 -1
- package/dist/templates/cc-native/_cc-native/plan-review/lib/reviewers/providers/claude-agent.ts +2 -2
- package/dist/templates/cc-native/_cc-native/plan-review/lib/reviewers/providers/codex-agent.ts +4 -4
- package/dist/templates/cc-native/_cc-native/plan-review/lib/reviewers/providers/gemini-agent.ts +1 -1
- package/dist/templates/cc-native/_cc-native/plan-review/lib/reviewers/providers/orchestrator-claude-agent.ts +5 -6
- package/dist/templates/core/.codex/workflows/codex.md +17 -0
- package/dist/templates/core/.codex/workflows/handoff.md +5 -0
- package/dist/templates/core/.codex/workflows/meta-plan.md +7 -0
- package/dist/templates/core/.cognition/AGENTS.md +5 -0
- package/dist/templates/core/.cognition/config.json +12 -0
- package/dist/templates/{_shared → core}/.windsurf/workflows/handoff.md +1 -1
- package/dist/templates/{_shared → core}/.windsurf/workflows/meta-plan.md +1 -1
- package/dist/templates/core/hooks-ts/_utils/git-state.ts +2 -0
- package/dist/templates/{_shared → core}/hooks-ts/archive_plan.ts +14 -23
- package/dist/templates/core/hooks-ts/codex_explorer.ts +160 -0
- package/dist/templates/{_shared → core}/hooks-ts/context_monitor.ts +23 -55
- package/dist/templates/{_shared → core}/hooks-ts/file-suggestion.ts +4 -3
- package/dist/templates/{_shared → core}/hooks-ts/lint_after_edit.ts +7 -9
- package/dist/templates/{_shared → core}/hooks-ts/pre_compact.ts +5 -5
- package/dist/templates/{_shared → core}/hooks-ts/session_end.ts +38 -78
- package/dist/templates/{_shared → core}/hooks-ts/session_start.ts +5 -5
- package/dist/templates/core/hooks-ts/task_create_capture.ts +32 -0
- package/dist/templates/{_shared → core}/hooks-ts/task_update_capture.ts +9 -24
- package/dist/templates/core/hooks-ts/user_prompt_submit.ts +46 -0
- package/dist/templates/{_shared → core}/lib-ts/CLAUDE.md +27 -16
- package/dist/templates/{_shared → core}/lib-ts/agent-exec/backends/headless.ts +3 -2
- package/dist/templates/{_shared → core}/lib-ts/agent-exec/backends/tmux.ts +44 -15
- package/dist/templates/{_shared → core}/lib-ts/agent-exec/base-agent.ts +6 -4
- package/dist/templates/{_shared → core}/lib-ts/agent-exec/execution-backend.ts +1 -1
- package/dist/templates/{_shared → core}/lib-ts/agent-exec/index.ts +2 -2
- package/dist/templates/{_shared → core}/lib-ts/agent-exec/structured-output.ts +4 -5
- package/dist/templates/{_shared → core}/lib-ts/context/CLAUDE.md +9 -6
- package/dist/templates/{_shared → core}/lib-ts/context/context-formatter.ts +16 -21
- package/dist/templates/{_shared → core}/lib-ts/context/context-selector.ts +8 -6
- package/dist/templates/{_shared → core}/lib-ts/context/context-store.ts +32 -20
- package/dist/templates/{_shared → core}/lib-ts/context/plan-manager.ts +19 -15
- package/dist/templates/{_shared → core}/lib-ts/context/task-tracker.ts +3 -3
- package/dist/templates/core/lib-ts/hooks/context-monitor-logic.ts +32 -0
- package/dist/templates/{_shared/lib-ts/base → core/lib-ts/hooks}/hook-utils.ts +168 -41
- package/dist/templates/core/lib-ts/hooks/prompt-binding-logic.ts +80 -0
- package/dist/templates/core/lib-ts/hooks/session-end-logic.ts +93 -0
- package/dist/templates/core/lib-ts/package.json +19 -0
- package/dist/templates/core/lib-ts/runtime/agent-launcher.ts +295 -0
- package/dist/templates/core/lib-ts/runtime/aiw-cli.ts +106 -0
- package/dist/templates/{_shared/lib-ts/base → core/lib-ts/runtime}/atomic-write.ts +12 -7
- package/dist/templates/{_shared/lib-ts/base → core/lib-ts/runtime}/cli-args.ts +8 -6
- package/dist/templates/{_shared/lib-ts/base → core/lib-ts/runtime}/constants.ts +326 -324
- package/dist/templates/core/lib-ts/runtime/executable-policy.ts +89 -0
- package/dist/templates/{_shared/lib-ts/base → core/lib-ts/runtime}/git-state.ts +6 -4
- package/dist/templates/{_shared/lib-ts/base → core/lib-ts/runtime}/inference.ts +59 -10
- package/dist/templates/{_shared/lib-ts/base → core/lib-ts/runtime}/lint-dispatch.ts +25 -23
- package/dist/templates/{_shared/lib-ts/base → core/lib-ts/runtime}/logger.ts +32 -29
- package/dist/templates/{_shared/lib-ts/base → core/lib-ts/runtime}/models.ts +2 -2
- package/dist/templates/core/lib-ts/runtime/platform-adapter.ts +33 -0
- package/dist/templates/{_shared/lib-ts/base → core/lib-ts/runtime}/preflight.ts +4 -3
- package/dist/templates/core/lib-ts/runtime/sentinel-ipc.ts +91 -0
- package/dist/templates/{_shared/lib-ts/base → core/lib-ts/runtime}/state-io.ts +11 -7
- package/dist/templates/core/lib-ts/runtime/stop-words.ts +185 -0
- package/dist/templates/core/lib-ts/runtime/subprocess-utils.ts +147 -0
- package/dist/templates/core/lib-ts/runtime/tmux-preflight.ts +93 -0
- package/dist/templates/{_shared/lib-ts/base → core/lib-ts/runtime}/utils.ts +4 -3
- package/dist/templates/{_shared → core}/lib-ts/templates/formatters.ts +7 -5
- package/dist/templates/{_shared → core}/lib-ts/templates/plan-context.ts +2 -1
- package/dist/templates/{_shared → core}/lib-ts/tsconfig.json +3 -1
- package/dist/templates/{_shared → core}/lib-ts/types.ts +78 -77
- package/dist/templates/core/scripts/resolve-run.ts +61 -0
- package/dist/templates/{_shared → core}/scripts/resolve_context.ts +3 -3
- package/dist/templates/{_shared → core}/scripts/status_line.ts +25 -20
- package/dist/templates/core/skills/codex/CLAUDE.md +78 -0
- package/dist/templates/{_shared → core}/skills/codex/SKILL.md +21 -18
- package/dist/templates/{_shared → core}/skills/codex/lib/codex-watcher.ts +76 -103
- package/dist/templates/{_shared → core}/skills/codex/scripts/launch-codex.ts +119 -133
- package/dist/templates/{_shared → core}/skills/codex/scripts/watch-codex.ts +6 -4
- package/dist/templates/core/skills/devin/CLAUDE.md +65 -0
- package/dist/templates/core/skills/devin/SKILL.md +73 -0
- package/dist/templates/core/skills/devin/lib/devin-watcher.ts +280 -0
- package/dist/templates/core/skills/devin/scripts/launch-devin.ts +257 -0
- package/dist/templates/{_shared → core}/skills/handoff-system/CLAUDE.md +436 -433
- package/dist/templates/{_shared → core}/skills/handoff-system/lib/document-generator.ts +9 -7
- package/dist/templates/{_shared → core}/skills/handoff-system/lib/handoff-reader.ts +6 -4
- package/dist/templates/{_shared → core}/skills/handoff-system/scripts/resume_handoff.ts +10 -8
- package/dist/templates/{_shared → core}/skills/handoff-system/scripts/save_handoff.ts +12 -10
- package/dist/templates/{_shared → core}/skills/handoff-system/workflows/handoff-resume.md +2 -2
- package/dist/templates/{_shared → core}/skills/handoff-system/workflows/handoff.md +6 -5
- package/dist/templates/{_shared → core}/skills/meta-plan/CLAUDE.md +2 -1
- package/dist/templates/{_shared → core}/skills/meta-plan/workflows/meta-plan.md +8 -7
- package/oclif.manifest.json +89 -13
- package/package.json +13 -12
- package/dist/templates/_shared/.claude/settings.json +0 -120
- package/dist/templates/_shared/.claude/skills/codex/SKILL.md +0 -35
- package/dist/templates/_shared/.claude/skills/handoff/SKILL.md +0 -13
- package/dist/templates/_shared/.claude/skills/handoff-resume/SKILL.md +0 -13
- package/dist/templates/_shared/.claude/skills/meta-plan/SKILL.md +0 -43
- package/dist/templates/_shared/.codex/workflows/codex.md +0 -11
- package/dist/templates/_shared/.codex/workflows/handoff.md +0 -226
- package/dist/templates/_shared/.codex/workflows/meta-plan.md +0 -347
- package/dist/templates/_shared/hooks-ts/_utils/git-state.ts +0 -2
- package/dist/templates/_shared/hooks-ts/task_create_capture.ts +0 -48
- package/dist/templates/_shared/hooks-ts/user_prompt_submit.ts +0 -93
- package/dist/templates/_shared/lib-ts/base/launchers/tmux-launcher.ts +0 -173
- package/dist/templates/_shared/lib-ts/base/launchers/window-launcher.ts +0 -93
- package/dist/templates/_shared/lib-ts/base/launchers/wt-launcher.ts +0 -64
- package/dist/templates/_shared/lib-ts/base/pane-launcher.ts +0 -55
- package/dist/templates/_shared/lib-ts/base/sentinel-ipc.ts +0 -87
- package/dist/templates/_shared/lib-ts/base/stop-words.ts +0 -184
- package/dist/templates/_shared/lib-ts/base/subprocess-utils.ts +0 -249
- package/dist/templates/_shared/lib-ts/base/tmux-driver.ts +0 -341
- package/dist/templates/_shared/lib-ts/base/tmux-pane-placement.ts +0 -78
- package/dist/templates/_shared/lib-ts/package.json +0 -20
- package/dist/templates/_shared/scripts/resolve-run.ts +0 -62
- package/dist/templates/_shared/skills/codex/CLAUDE.md +0 -70
- /package/dist/templates/{_shared → core}/lib-ts/agent-exec/backends/index.ts +0 -0
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
# Shared TypeScript Library
|
|
2
2
|
|
|
3
|
-
**Location:** `
|
|
3
|
+
**Location:** `core/lib-ts/` — cross-method infrastructure used by ALL templates.
|
|
4
4
|
|
|
5
5
|
**One import gets you started:**
|
|
6
6
|
```typescript
|
|
7
|
-
import { loadHookInput, runHook, logInfo, emitContext } from "../lib-ts/
|
|
7
|
+
import { loadHookInput, runHook, logInfo, emitContext } from "../lib-ts/hooks/hook-utils.js";
|
|
8
8
|
```
|
|
9
9
|
|
|
10
10
|
`hook-utils.ts` re-exports the most-used functions from `logger.ts`, `constants.ts`, and `context-store.ts`. Start here. Only import from deeper modules when you need specific capabilities.
|
|
11
11
|
|
|
12
|
-
**Import direction:** Hooks --> method lib --> `
|
|
12
|
+
**Import direction:** Hooks --> method lib --> `core/lib-ts/`. Never the reverse.
|
|
13
13
|
|
|
14
14
|
---
|
|
15
15
|
|
|
@@ -21,7 +21,7 @@ These cause silent failures or UI noise when violated:
|
|
|
21
21
|
- **stdout is sacred:** Only hook JSON output goes to stdout. Use logger functions for diagnostics, never `console.log()` or `print()`
|
|
22
22
|
- **stderr is opt-in:** `logDebug/logInfo/logWarn/logError` write to file only. Use `logBlocking()` when you NEED stderr visibility
|
|
23
23
|
- **Catch non-critical errors locally:** Uncaught errors bubble to `runHook` which writes to stderr, showing "hook error" in the UI even on exit 0
|
|
24
|
-
- **No reverse imports:** Never import from method
|
|
24
|
+
- **No reverse imports:** Never import from method-specific libraries into shared lib
|
|
25
25
|
|
|
26
26
|
---
|
|
27
27
|
|
|
@@ -31,7 +31,7 @@ Copy this for new hooks:
|
|
|
31
31
|
|
|
32
32
|
```typescript
|
|
33
33
|
#!/usr/bin/env bun
|
|
34
|
-
import { loadHookInput, runHook, logDebug, logInfo, emitContext } from "../lib-ts/
|
|
34
|
+
import { loadHookInput, runHook, logDebug, logInfo, emitContext } from "../lib-ts/hooks/hook-utils.js";
|
|
35
35
|
|
|
36
36
|
function main(): void {
|
|
37
37
|
const payload = loadHookInput();
|
|
@@ -51,7 +51,7 @@ runHook(main, "my_hook_name");
|
|
|
51
51
|
For async hooks (AI inference, network calls):
|
|
52
52
|
|
|
53
53
|
```typescript
|
|
54
|
-
import { runHookAsync } from "../lib-ts/
|
|
54
|
+
import { runHookAsync } from "../lib-ts/hooks/hook-utils.js";
|
|
55
55
|
|
|
56
56
|
async function asyncMain(): Promise<void> {
|
|
57
57
|
// await something...
|
|
@@ -74,7 +74,7 @@ All logging goes to `_output/hook-log.jsonl`. stderr visibility is opt-in.
|
|
|
74
74
|
| Terminal | `eprint()` | Yes (raw stderr) | Usage help, progress indicators — not logged to JSONL |
|
|
75
75
|
|
|
76
76
|
```typescript
|
|
77
|
-
import { logDebug, logInfo, logWarn, logBlocking } from "../lib-ts/
|
|
77
|
+
import { logDebug, logInfo, logWarn, logBlocking } from "../lib-ts/hooks/hook-utils.js";
|
|
78
78
|
|
|
79
79
|
logInfo("my_hook", "Session started"); // file only
|
|
80
80
|
logWarn("my_hook", `Fallback used: ${reason}`); // file only
|
|
@@ -89,7 +89,7 @@ Hooks have multiple channels back to the session. Pick the right one:
|
|
|
89
89
|
|
|
90
90
|
| Want to... | Function | Who sees it |
|
|
91
91
|
|------------|----------|-------------|
|
|
92
|
-
| **Block (
|
|
92
|
+
| **Block (event-aware)** | `emitBlock(reason, context?)` | Claude + user — auto-dispatches to correct mechanism |
|
|
93
93
|
| Block tool (PreToolUse only) | `emitContextAndBlock(context, reason)` | Claude + user (denial reason prominent) |
|
|
94
94
|
| Return message, don't block | `emitContext(context)` | Claude + user (in transcript) |
|
|
95
95
|
| Log only (diagnostics) | `logInfo()` / `logWarn()` / etc. | Nobody in session — file only |
|
|
@@ -157,7 +157,7 @@ emitPermissionDecision("deny", { message: "Why denied" });
|
|
|
157
157
|
emitPermissionDecision("allow", { updatedInput: { /* modified input */ } });
|
|
158
158
|
```
|
|
159
159
|
|
|
160
|
-
### Channel 6: Non-blocking Context (
|
|
160
|
+
### Channel 6: Non-blocking Context (supported hook events)
|
|
161
161
|
|
|
162
162
|
```typescript
|
|
163
163
|
emitContext("Information added to Claude's context");
|
|
@@ -238,7 +238,7 @@ Claude Code validates `hookSpecificOutput` using a Zod discriminated union keyed
|
|
|
238
238
|
| **0** + deny JSON | Yes | Yes (PreToolUse only) | `additionalContext` + denial reason | Yes |
|
|
239
239
|
| **0** + context JSON | Yes | No | `additionalContext` in transcript | Yes |
|
|
240
240
|
| **1** | No | No | stderr in verbose mode only | Yes |
|
|
241
|
-
| **2** | No | Yes (
|
|
241
|
+
| **2** | No | Yes (event-dependent) | stderr fed as system-reminder | Yes |
|
|
242
242
|
|
|
243
243
|
**Key insight:** Exit 0 + `permissionDecision: "deny"` is the correct way to block a tool. Exit 2 is a blunt instrument — it ignores your JSON and feeds raw stderr to Claude. Use exit 0 + deny for clean blocking with structured feedback.
|
|
244
244
|
|
|
@@ -255,7 +255,7 @@ Early testing suggested ExitPlanMode was "immune" to PreToolUse deny. **This was
|
|
|
255
255
|
- Exit 2 also appeared to "not work" for PreToolUse (JSON was ignored as expected, but the blocking was via stderr, not deny)
|
|
256
256
|
- PostToolUse with exit 2 appeared to work because it used stderr (not JSON), bypassing the Zod issue
|
|
257
257
|
|
|
258
|
-
**Lesson:** When a hook output seems to be "silently ignored," check the JSON schema first. The Zod validator rejects malformed output without
|
|
258
|
+
**Lesson:** When a hook output seems to be "silently ignored," check the JSON schema first. The Zod validator rejects malformed output without an explicit error message.
|
|
259
259
|
|
|
260
260
|
### Debugging Checklist
|
|
261
261
|
|
|
@@ -297,11 +297,19 @@ Transitions: `idle`/`has_staged_work` --> `active` (via `maybeActivate`). `activ
|
|
|
297
297
|
|
|
298
298
|
Use this table to find the right file. Read the source for full API details.
|
|
299
299
|
|
|
300
|
-
### `
|
|
300
|
+
### `hooks/` — Hook Lifecycle
|
|
301
301
|
|
|
302
302
|
| File | Purpose | Key Exports |
|
|
303
303
|
|------|---------|-------------|
|
|
304
304
|
| `hook-utils.ts` | Hook lifecycle, stdin parsing, output emit, re-exports | `runHook`, `runHookAsync`, `loadHookInput`, `emitContext`, `emitContextAndBlock`, `emitBlock`, `emitBlockPrompt`, `emitBlockViaExit`, `emitBlockTopLevel`, `emitPermissionDecision`, `logDebug`...`logBlocking` |
|
|
305
|
+
| `context-monitor-logic.ts` | Context monitor extracted logic | Context window tracking helpers |
|
|
306
|
+
| `prompt-binding-logic.ts` | Prompt binding extracted logic | Prompt-to-context binding helpers |
|
|
307
|
+
| `session-end-logic.ts` | Session end extracted logic | Session end state management helpers |
|
|
308
|
+
|
|
309
|
+
### `runtime/` — Core Infrastructure
|
|
310
|
+
|
|
311
|
+
| File | Purpose | Key Exports |
|
|
312
|
+
|------|---------|-------------|
|
|
305
313
|
| `logger.ts` | JSONL logging engine | `hookLog`, `logDebug`, `logInfo`, `logWarn`, `logError`, `logBlocking`, `logHookError`, `logDiagnostic` |
|
|
306
314
|
| `constants.ts` | Path resolution, limits | `getProjectRoot()`, `getContextDir()`, `MAX_FILE_SIZE` |
|
|
307
315
|
| `atomic-write.ts` | Crash-safe file writes | `atomicWriteFileSync()` |
|
|
@@ -311,7 +319,7 @@ Use this table to find the right file. Read the source for full API details.
|
|
|
311
319
|
| `git-state.ts` | Git snapshot | `captureGitState()` |
|
|
312
320
|
| `subprocess-utils.ts` | Recursive call guard | `isInternalCall()` |
|
|
313
321
|
| `stop-words.ts` | Word list for ID generation | Used by `utils.ts` internally |
|
|
314
|
-
| `lint-dispatch.ts` | Post-edit lint dispatching | `
|
|
322
|
+
| `lint-dispatch.ts` | Post-edit lint dispatching | `getLinterForFile()`, `runLinter()`, `formatLintErrors()` |
|
|
315
323
|
|
|
316
324
|
### `context/` — Context State Management
|
|
317
325
|
|
|
@@ -338,7 +346,7 @@ Use this table to find the right file. Read the source for full API details.
|
|
|
338
346
|
|
|
339
347
|
---
|
|
340
348
|
|
|
341
|
-
## Shared Hooks (`
|
|
349
|
+
## Shared Hooks (`core/hooks-ts/`)
|
|
342
350
|
|
|
343
351
|
These run for ALL templates. Method-specific hooks live in `_{method}/hooks/`.
|
|
344
352
|
|
|
@@ -353,6 +361,8 @@ These run for ALL templates. Method-specific hooks live in `_{method}/hooks/`.
|
|
|
353
361
|
| `task_create_capture.ts` | PostToolUse:TaskCreate | Persists task creation to context state |
|
|
354
362
|
| `task_update_capture.ts` | PostToolUse:TaskUpdate | Persists task updates to context state |
|
|
355
363
|
| `file-suggestion.ts` | PostToolUse:Write | Suggests file organization improvements |
|
|
364
|
+
| `codex_explorer.ts` | UserPromptSubmit | Codex Spark codebase exploration (plan mode, once per session) |
|
|
365
|
+
| `lint_after_edit.ts` | PostToolUse:Write | Post-edit lint dispatching |
|
|
356
366
|
|
|
357
367
|
---
|
|
358
368
|
|
|
@@ -380,7 +390,7 @@ the code, and it belongs at this scope (project-wide rule → root CLAUDE.md; WH
|
|
|
380
390
|
how an agent acts here, remove it. If a convention here conflicts with the codebase,
|
|
381
391
|
the codebase wins — update this file, do not work around it. Prune aggressively.
|
|
382
392
|
|
|
383
|
-
**Staleness anchor:** This file assumes `
|
|
393
|
+
**Staleness anchor:** This file assumes `hooks/hook-utils.ts` exists. If it doesn't, this file
|
|
384
394
|
is stale — update or regenerate before relying on it.
|
|
385
395
|
|
|
386
396
|
**Trigger Audit or Generate:**
|
|
@@ -389,4 +399,5 @@ is stale — update or regenerate before relying on it.
|
|
|
389
399
|
- 30+ days without touching this file → Audit
|
|
390
400
|
- Agent mistake caused by this file → fix immediately, then Audit
|
|
391
401
|
|
|
392
|
-
<!-- context-layer: generated=2026-02-14 | last-audited=2026-
|
|
402
|
+
<!-- context-layer: generated=2026-02-14 | last-audited=2026-03-05 | version=3 | dir-commits-at-audit=29 -->
|
|
403
|
+
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
import * as fs from "node:fs";
|
|
8
8
|
|
|
9
|
-
import { execFileAsync } from "../../
|
|
9
|
+
import { execFileAsync } from "../../runtime/subprocess-utils.js";
|
|
10
10
|
import type { ExecutionBackend, ExecutionRequest, ExecutionResult } from "../execution-backend.js";
|
|
11
11
|
|
|
12
12
|
export class HeadlessBackend implements ExecutionBackend {
|
|
@@ -21,7 +21,7 @@ export class HeadlessBackend implements ExecutionBackend {
|
|
|
21
21
|
|
|
22
22
|
// If outputFilePath specified and exists, read from file instead of stdout
|
|
23
23
|
if (request.outputFilePath && fs.existsSync(request.outputFilePath)) {
|
|
24
|
-
const fileContent = fs.readFileSync(request.outputFilePath, "
|
|
24
|
+
const fileContent = fs.readFileSync(request.outputFilePath, "utf8");
|
|
25
25
|
return {
|
|
26
26
|
...result,
|
|
27
27
|
stdout: fileContent,
|
|
@@ -31,3 +31,4 @@ export class HeadlessBackend implements ExecutionBackend {
|
|
|
31
31
|
return result;
|
|
32
32
|
}
|
|
33
33
|
}
|
|
34
|
+
|
|
@@ -2,15 +2,13 @@
|
|
|
2
2
|
* Tmux execution backend — runs CLI agents in visible tmux panes
|
|
3
3
|
* with sentinel-file-based output capture.
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* not the backend's.
|
|
5
|
+
* Self-contained tmux interaction — does not depend on tmux-driver.ts
|
|
6
|
+
* or the pane launcher stack (those are consolidated into the `aiw` CLI).
|
|
8
7
|
*/
|
|
9
8
|
|
|
10
9
|
import * as fs from "node:fs";
|
|
11
|
-
import
|
|
10
|
+
import path from "node:path";
|
|
12
11
|
|
|
13
|
-
import { execFileAsync } from "../../base/subprocess-utils.js";
|
|
14
12
|
import {
|
|
15
13
|
buildShellCaptureScript,
|
|
16
14
|
cleanupSentinelIpc,
|
|
@@ -18,8 +16,9 @@ import {
|
|
|
18
16
|
readSentinelExitCode,
|
|
19
17
|
readTextIfExists,
|
|
20
18
|
waitForSentinelFile,
|
|
21
|
-
} from "../../
|
|
22
|
-
import {
|
|
19
|
+
} from "../../runtime/sentinel-ipc.js";
|
|
20
|
+
import { execFileAsync, findExecutable } from "../../runtime/subprocess-utils.js";
|
|
21
|
+
import { findPsmux } from "../../runtime/tmux-preflight.js";
|
|
23
22
|
import type { ExecutionBackend, ExecutionRequest, ExecutionResult } from "../execution-backend.js";
|
|
24
23
|
|
|
25
24
|
export interface TmuxBackendOptions {
|
|
@@ -27,6 +26,14 @@ export interface TmuxBackendOptions {
|
|
|
27
26
|
splitTarget?: string;
|
|
28
27
|
}
|
|
29
28
|
|
|
29
|
+
function quoteForSh(input: string): string {
|
|
30
|
+
return `'${input.replaceAll("'", "'\"'\"'")}'`;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function normalizeSplitFlag(value: string | undefined): "-h" | "-v" {
|
|
34
|
+
return value?.trim() === "-v" ? "-v" : "-h";
|
|
35
|
+
}
|
|
36
|
+
|
|
30
37
|
export class TmuxBackend implements ExecutionBackend {
|
|
31
38
|
private options: TmuxBackendOptions;
|
|
32
39
|
|
|
@@ -35,11 +42,25 @@ export class TmuxBackend implements ExecutionBackend {
|
|
|
35
42
|
}
|
|
36
43
|
|
|
37
44
|
async execute(request: ExecutionRequest): Promise<ExecutionResult> {
|
|
38
|
-
|
|
39
|
-
|
|
45
|
+
// On Windows, use psmux (native ConPTY multiplexer) instead of tmux
|
|
46
|
+
const isWindows = process.platform === "win32";
|
|
47
|
+
const muxBinary = isWindows ? "psmux" : "tmux";
|
|
48
|
+
|
|
49
|
+
if (!isWindows && !process.env.TMUX) {
|
|
50
|
+
return {
|
|
51
|
+
stdout: "",
|
|
52
|
+
stderr: "tmux pane launch failed: TMUX is not set",
|
|
53
|
+
exitCode: 1,
|
|
54
|
+
killed: false,
|
|
55
|
+
signal: null,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const tmuxPath = isWindows ? findPsmux() : findExecutable("tmux");
|
|
60
|
+
if (!tmuxPath) {
|
|
40
61
|
return {
|
|
41
62
|
stdout: "",
|
|
42
|
-
stderr:
|
|
63
|
+
stderr: `${muxBinary} pane launch failed: ${muxBinary} not found on PATH`,
|
|
43
64
|
exitCode: 1,
|
|
44
65
|
killed: false,
|
|
45
66
|
signal: null,
|
|
@@ -50,7 +71,7 @@ export class TmuxBackend implements ExecutionBackend {
|
|
|
50
71
|
const ipc = createSentinelIpcPaths(`aiwcli-agent-${agentName}`);
|
|
51
72
|
|
|
52
73
|
try {
|
|
53
|
-
fs.writeFileSync(ipc.inputPath, request.input, "
|
|
74
|
+
fs.writeFileSync(ipc.inputPath, request.input, "utf8");
|
|
54
75
|
|
|
55
76
|
const envEntries = Object.entries(request.env).filter(
|
|
56
77
|
([, value]) => value !== undefined,
|
|
@@ -68,9 +89,15 @@ export class TmuxBackend implements ExecutionBackend {
|
|
|
68
89
|
if (this.options.splitTarget) {
|
|
69
90
|
tmuxArgs.push("-t", this.options.splitTarget);
|
|
70
91
|
}
|
|
71
|
-
|
|
92
|
+
// On Windows (psmux), run directly — no bash wrapper needed.
|
|
93
|
+
// On Unix (tmux), wrap in bash login shell.
|
|
94
|
+
if (isWindows) {
|
|
95
|
+
tmuxArgs.push(script);
|
|
96
|
+
} else {
|
|
97
|
+
tmuxArgs.push(`bash -lc ${quoteForSh(script)}`);
|
|
98
|
+
}
|
|
72
99
|
|
|
73
|
-
const split = await execFileAsync(
|
|
100
|
+
const split = await execFileAsync(tmuxPath, tmuxArgs, { timeout: 5000 });
|
|
74
101
|
if (split.exitCode !== 0) {
|
|
75
102
|
return {
|
|
76
103
|
stdout: "",
|
|
@@ -86,7 +113,7 @@ export class TmuxBackend implements ExecutionBackend {
|
|
|
86
113
|
|
|
87
114
|
if (!finished) {
|
|
88
115
|
if (paneId) {
|
|
89
|
-
await execFileAsync(
|
|
116
|
+
await execFileAsync(tmuxPath, ["kill-pane", "-t", paneId], { timeout: 3000 });
|
|
90
117
|
}
|
|
91
118
|
return {
|
|
92
119
|
stdout: "",
|
|
@@ -103,7 +130,7 @@ export class TmuxBackend implements ExecutionBackend {
|
|
|
103
130
|
|
|
104
131
|
if (request.outputFilePath && fs.existsSync(request.outputFilePath)) {
|
|
105
132
|
return {
|
|
106
|
-
stdout: fs.readFileSync(request.outputFilePath, "
|
|
133
|
+
stdout: fs.readFileSync(request.outputFilePath, "utf8"),
|
|
107
134
|
stderr,
|
|
108
135
|
exitCode,
|
|
109
136
|
killed: false,
|
|
@@ -117,3 +144,5 @@ export class TmuxBackend implements ExecutionBackend {
|
|
|
117
144
|
}
|
|
118
145
|
}
|
|
119
146
|
}
|
|
147
|
+
|
|
148
|
+
|
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Abstract base class for CLI-based agent subprocess invocations.
|
|
3
|
-
* Lives in
|
|
3
|
+
* Lives in core so all templates can use it. Provider-specific
|
|
4
4
|
* implementations (Claude, Codex, Gemini) extend this class.
|
|
5
5
|
*
|
|
6
6
|
* Execution strategy is injected via ExecutionBackend (default: HeadlessBackend).
|
|
7
7
|
* Debug logging is injectable via AgentDebugLogger (default: no-op).
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
-
import { logDebug, logInfo, logWarn, logError } from "../
|
|
11
|
-
import { getInternalSubprocessEnv, findExecutable, normalizePathForCli } from "../
|
|
10
|
+
import { logDebug, logInfo, logWarn, logError } from "../runtime/logger.js";
|
|
11
|
+
import { getInternalSubprocessEnv, findExecutable, normalizePathForCli } from "../runtime/subprocess-utils.js";
|
|
12
12
|
import { HeadlessBackend } from "./backends/headless.js";
|
|
13
13
|
import type { ExecutionBackend, ExecutionResult, AgentDebugLogger } from "./execution-backend.js";
|
|
14
14
|
import type { AgentConfig } from "../types.js";
|
|
15
15
|
|
|
16
16
|
// Re-export for consumers
|
|
17
|
-
|
|
17
|
+
|
|
18
18
|
|
|
19
19
|
/** Configuration object for BaseCliAgent construction. */
|
|
20
20
|
export interface AgentExecutionConfig {
|
|
@@ -227,3 +227,5 @@ export abstract class BaseCliAgent<T> {
|
|
|
227
227
|
return coerced;
|
|
228
228
|
}
|
|
229
229
|
}
|
|
230
|
+
|
|
231
|
+
export {type AgentDebugLogger, type ExecutionResult} from "./execution-backend.js";
|
|
@@ -43,7 +43,7 @@ export interface ExecutionBackend {
|
|
|
43
43
|
// Debug Logger
|
|
44
44
|
// ---------------------------------------------------------------------------
|
|
45
45
|
|
|
46
|
-
/** Injectable debug logger for agents running in
|
|
46
|
+
/** Injectable debug logger for agents running in core context. */
|
|
47
47
|
export interface AgentDebugLogger {
|
|
48
48
|
log(contextPath: string, sessionName: string, component: string, message: string, data?: unknown): void;
|
|
49
49
|
raw(contextPath: string, sessionName: string, component: string, label: string, raw: string): void;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
export { BaseCliAgent, type AgentExecutionConfig } from "./base-agent.js";
|
|
2
|
-
export type { ExecutionBackend, ExecutionRequest, ExecutionResult, AgentDebugLogger } from "./execution-backend.js";
|
|
3
1
|
export { HeadlessBackend } from "./backends/headless.js";
|
|
4
2
|
export { TmuxBackend } from "./backends/tmux.js";
|
|
3
|
+
export { type AgentExecutionConfig, BaseCliAgent } from "./base-agent.js";
|
|
4
|
+
export type { AgentDebugLogger, ExecutionBackend, ExecutionRequest, ExecutionResult } from "./execution-backend.js";
|
|
5
5
|
export { parseJsonObjectMaybe, parseStructuredOutput } from "./structured-output.js";
|
|
6
6
|
export type { StructuredOutputParseOptions } from "./structured-output.js";
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* Supports Claude/Codex-style envelopes and heuristic JSON extraction.
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import { logDebug, logError, logWarn } from "../
|
|
6
|
+
import { logDebug, logError, logWarn } from "../runtime/logger.js";
|
|
7
7
|
|
|
8
8
|
export interface StructuredOutputParseOptions {
|
|
9
9
|
requireFields?: string[];
|
|
@@ -84,10 +84,10 @@ function parseAssistantEnvelope(
|
|
|
84
84
|
options?: StructuredOutputParseOptions,
|
|
85
85
|
): Record<string, unknown> | null {
|
|
86
86
|
const tag = getTag(options);
|
|
87
|
-
const message = envelope
|
|
87
|
+
const {message} = envelope;
|
|
88
88
|
if (!message || typeof message !== "object") return null;
|
|
89
89
|
|
|
90
|
-
const content = (message as Record<string, unknown>)
|
|
90
|
+
const {content} = (message as Record<string, unknown>);
|
|
91
91
|
if (!Array.isArray(content)) return null;
|
|
92
92
|
|
|
93
93
|
for (const item of content) {
|
|
@@ -142,8 +142,7 @@ export function parseStructuredOutput(
|
|
|
142
142
|
return null;
|
|
143
143
|
}
|
|
144
144
|
} else if (Array.isArray(parsed)) {
|
|
145
|
-
for (
|
|
146
|
-
const event = parsed[i];
|
|
145
|
+
for (const [i, event] of parsed.entries()) {
|
|
147
146
|
if (!event || typeof event !== "object") continue;
|
|
148
147
|
const eventObj = event as Record<string, unknown>;
|
|
149
148
|
const assistantResult = parseAssistantEnvelope(eventObj, options);
|
|
@@ -82,13 +82,14 @@ Formats context state for injection into Claude's context window.
|
|
|
82
82
|
|
|
83
83
|
### `context-selector.ts`
|
|
84
84
|
|
|
85
|
-
|
|
85
|
+
Routes prompts to contexts. Single entry point: `determineContext()`.
|
|
86
86
|
|
|
87
|
-
| Function | Purpose |
|
|
87
|
+
| Function / Class | Purpose |
|
|
88
88
|
|----------|---------|
|
|
89
|
-
| `
|
|
90
|
-
| `
|
|
91
|
-
| `
|
|
89
|
+
| `determineContext(prompt, sessionId, projectRoot)` | Main entry — session match, caret commands, plan/handoff fallback, or create new |
|
|
90
|
+
| `resolveContextByPrefix(prefix, root?)` | Resolve context by ID prefix |
|
|
91
|
+
| `parseChainedCaret(prompt)` | Parse `^` caret commands from prompt |
|
|
92
|
+
| `BlockRequest` (class) | Thrown when request should be blocked with a message |
|
|
92
93
|
|
|
93
94
|
### `plan-manager.ts`
|
|
94
95
|
|
|
@@ -123,7 +124,6 @@ Tracks task progress (ISC criteria) within a context.
|
|
|
123
124
|
| `session_end.ts` | `getContextBySessionId()`, `updateMode()`, `saveState()` |
|
|
124
125
|
| `user_prompt_submit.ts` | `getAllContexts()`, `maybeActivate()`, `determineArtifactType()` |
|
|
125
126
|
| `archive_plan.ts` | `getContextBySessionId()`, `archivePlan()` |
|
|
126
|
-
| `save_handoff.ts` | `getContextBySessionId()`, `updateContext()` |
|
|
127
127
|
| `cc-native-plan-review.ts` | `getContextBySessionId()`, `getAllContexts()` |
|
|
128
128
|
|
|
129
129
|
## Design Decisions
|
|
@@ -132,3 +132,6 @@ Tracks task progress (ISC criteria) within a context.
|
|
|
132
132
|
- **No moves out of lib-ts:** Context is pure library code imported by ~8 shared hooks. Moving it would require updating all those import paths for no structural gain. The subfolder is already co-located; it just needed documentation.
|
|
133
133
|
- **`maybeActivate()` is idempotent:** Can be called from any hook without checking current mode — safe to call repeatedly.
|
|
134
134
|
- **`determineArtifactType()` drives session restore:** Returns `"plan"` or `"handoff"` to dispatch the correct restoration path in `session_start.ts`.
|
|
135
|
+
|
|
136
|
+
<!-- context-layer: last-audited=2026-03-05 | version=2 -->
|
|
137
|
+
|
|
@@ -8,10 +8,10 @@
|
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
import * as fs from "node:fs";
|
|
11
|
-
import
|
|
11
|
+
import path from "node:path";
|
|
12
12
|
|
|
13
|
-
import { getContextDir } from "../
|
|
14
|
-
import { displayPath, parseIsoTimestamp } from "../
|
|
13
|
+
import { getContextDir } from "../runtime/constants.js";
|
|
14
|
+
import { displayPath, parseIsoTimestamp } from "../runtime/utils.js";
|
|
15
15
|
import type { ContextState, Task } from "../types.js";
|
|
16
16
|
|
|
17
17
|
const MAX_PLAN_INLINE_CHARS = 30_000;
|
|
@@ -79,9 +79,10 @@ export function formatRelativeTime(isoTimestamp: string | null): string {
|
|
|
79
79
|
// Internal helpers
|
|
80
80
|
// ---------------------------------------------------------------------------
|
|
81
81
|
|
|
82
|
-
function taskAttr(task: Task | Record<string,
|
|
82
|
+
function taskAttr(task: Task | Record<string, unknown>, key: string, defaultVal = ""): string {
|
|
83
83
|
if (typeof task === "object" && task !== null) {
|
|
84
|
-
|
|
84
|
+
const value = (task as Record<string, unknown>)[key];
|
|
85
|
+
return typeof value === "string" ? value : defaultVal;
|
|
85
86
|
}
|
|
86
87
|
return defaultVal;
|
|
87
88
|
}
|
|
@@ -89,7 +90,7 @@ function taskAttr(task: Task | Record<string, any>, key: string, defaultVal = ""
|
|
|
89
90
|
function readPlanContent(planPath: string): [string | null, boolean, number] {
|
|
90
91
|
try {
|
|
91
92
|
if (!fs.existsSync(planPath)) return [null, false, 0];
|
|
92
|
-
const content = fs.readFileSync(planPath, "
|
|
93
|
+
const content = fs.readFileSync(planPath, "utf8");
|
|
93
94
|
const total = content.length;
|
|
94
95
|
if (total > MAX_PLAN_INLINE_CHARS) {
|
|
95
96
|
return [content.slice(0, MAX_PLAN_INLINE_CHARS), true, total];
|
|
@@ -220,11 +221,11 @@ export function formatHandoffContinuation(ctx: ContextState, projectRoot?: strin
|
|
|
220
221
|
|
|
221
222
|
try {
|
|
222
223
|
if (handoffPath && fs.existsSync(handoffPath)) {
|
|
223
|
-
lines.push("### Previous Session Handoff", "", fs.readFileSync(handoffPath, "
|
|
224
|
+
lines.push("### Previous Session Handoff", "", fs.readFileSync(handoffPath, "utf8"), "");
|
|
224
225
|
} else {
|
|
225
226
|
lines.push(`*Handoff document not found at \`${displayPath(handoffPath)}\`*`, "");
|
|
226
227
|
}
|
|
227
|
-
} catch (error:
|
|
228
|
+
} catch (error: unknown) {
|
|
228
229
|
lines.push(`*Handoff document at \`${displayPath(handoffPath)}\` could not be read: ${error}*`, "");
|
|
229
230
|
}
|
|
230
231
|
|
|
@@ -492,19 +493,10 @@ function collectStatePointers(contextId: string, contextDir: string, state: Cont
|
|
|
492
493
|
return "**Key artifacts:**\n" + pointers.join("\n");
|
|
493
494
|
}
|
|
494
495
|
|
|
495
|
-
function
|
|
496
|
-
let count = 0;
|
|
496
|
+
function countFiles(dirPath: string): number {
|
|
497
497
|
try {
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
if (entry.isFile()) {
|
|
501
|
-
count++;
|
|
502
|
-
} else if (entry.isDirectory()) {
|
|
503
|
-
count += countFilesRecursive(path.join(dirPath, entry.name));
|
|
504
|
-
}
|
|
505
|
-
}
|
|
506
|
-
} catch { /* permission errors, etc. */ }
|
|
507
|
-
return count;
|
|
498
|
+
return fs.readdirSync(dirPath).length;
|
|
499
|
+
} catch { return 0; }
|
|
508
500
|
}
|
|
509
501
|
|
|
510
502
|
function collectFolderInventory(contextId: string, contextDir: string, _state: ContextState): string | null {
|
|
@@ -521,7 +513,7 @@ function collectFolderInventory(contextId: string, contextDir: string, _state: C
|
|
|
521
513
|
for (const dir of dirs) {
|
|
522
514
|
const dirPath = path.join(contextDir, dir.name);
|
|
523
515
|
const desc = KNOWN_FOLDERS[dir.name] ?? "Project-specific artifacts";
|
|
524
|
-
const fileCount =
|
|
516
|
+
const fileCount = countFiles(dirPath);
|
|
525
517
|
lines.push(`- \`${dir.name}/\` — ${desc} (${fileCount} file${fileCount !== 1 ? "s" : ""})`);
|
|
526
518
|
}
|
|
527
519
|
return lines.join("\n");
|
|
@@ -586,3 +578,6 @@ export function buildContextInventory(
|
|
|
586
578
|
if (sections.length === 0) return null;
|
|
587
579
|
return "### Context Resources\n\n" + sections.join("\n\n");
|
|
588
580
|
}
|
|
581
|
+
|
|
582
|
+
|
|
583
|
+
|
|
@@ -35,8 +35,8 @@ import {
|
|
|
35
35
|
determineArtifactType,
|
|
36
36
|
} from "./context-store.js";
|
|
37
37
|
import { normalizePlanContent } from "./plan-manager.js";
|
|
38
|
-
import { logDebug, logInfo, logError } from "../
|
|
39
|
-
import { isInternalCall } from "../
|
|
38
|
+
import { logDebug, logInfo, logError } from "../runtime/logger.js";
|
|
39
|
+
import { isInternalCall } from "../runtime/subprocess-utils.js";
|
|
40
40
|
import type { ContextState, CaretCommand } from "../types.js";
|
|
41
41
|
|
|
42
42
|
/** Minimum characters required for new context description. */
|
|
@@ -256,7 +256,7 @@ function matchPlanContent(prompt: string, hasPlanContexts: ContextState[]): Cont
|
|
|
256
256
|
|
|
257
257
|
// Tier 2: Normalized hash match
|
|
258
258
|
const normalized = normalizePlanContent(prompt);
|
|
259
|
-
const normHash = crypto.createHash("sha256").update(normalized, "
|
|
259
|
+
const normHash = crypto.createHash("sha256").update(normalized, "utf8").digest("hex").slice(0, 12);
|
|
260
260
|
for (const ctx of hasPlanContexts) {
|
|
261
261
|
if (ctx.plan_hash && ctx.plan_hash === normHash) {
|
|
262
262
|
logDebug("context_selector", `Tier 2 normalized hash match: ${ctx.id} (hash: ${normHash})`);
|
|
@@ -302,7 +302,7 @@ function createNewContext(
|
|
|
302
302
|
newCtx.mode = "active";
|
|
303
303
|
logInfo("context_selector", `Auto-created context: ${newCtx.id}`);
|
|
304
304
|
return [newCtx.id, "auto_created", formatContextCreated(newCtx)];
|
|
305
|
-
} catch (error:
|
|
305
|
+
} catch (error: unknown) {
|
|
306
306
|
logError("context_selector", `Primary context creation failed: ${error}`);
|
|
307
307
|
try {
|
|
308
308
|
const now = new Date();
|
|
@@ -323,7 +323,7 @@ function createNewContext(
|
|
|
323
323
|
newCtx.mode = "active";
|
|
324
324
|
logInfo("context_selector", `Fallback context created: ${newCtx.id}`);
|
|
325
325
|
return [newCtx.id, "auto_created_fallback", formatContextCreated(newCtx)];
|
|
326
|
-
} catch (error:
|
|
326
|
+
} catch (error: unknown) {
|
|
327
327
|
logError("context_selector", `ALL context creation failed: ${error}`);
|
|
328
328
|
return [null, "creation_failed", null];
|
|
329
329
|
}
|
|
@@ -492,7 +492,7 @@ export function determineContext(
|
|
|
492
492
|
if (sessionId) bindSession(matched.id, sessionId, projectRoot);
|
|
493
493
|
updateMode(matched.id, "active", projectRoot, {
|
|
494
494
|
work_consumed: true, // CHANGED: unified flag
|
|
495
|
-
plan_hash_consumed: matched.plan_hash,
|
|
495
|
+
...(matched.plan_hash ? {plan_hash_consumed: matched.plan_hash} : {}),
|
|
496
496
|
});
|
|
497
497
|
matched.mode = "active";
|
|
498
498
|
logInfo("context_selector", `Plan match (fallback): ${matched.id}`);
|
|
@@ -522,3 +522,5 @@ export function determineContext(
|
|
|
522
522
|
// --- Case 4: default ---
|
|
523
523
|
return createNewContext(prompt, projectRoot);
|
|
524
524
|
}
|
|
525
|
+
|
|
526
|
+
|