aiwcli 0.15.4 → 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
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stop words for context ID generation.
|
|
3
|
+
*
|
|
4
|
+
* Generated from analysis of 1,424 prompts, context summaries, and plan files.
|
|
5
|
+
* Words that appear frequently but don't help identify the specific task.
|
|
6
|
+
*
|
|
7
|
+
* ACTION VERBS ARE INTENTIONALLY EXCLUDED:
|
|
8
|
+
* add, fix, update, create, implement, refactor, migrate, debug, remove, change,
|
|
9
|
+
* move, rename, delete, build, test, deploy, verify, analyze, modify, write, run,
|
|
10
|
+
* check, replace, save, sync, load, extract, install, clean, merge, etc.
|
|
11
|
+
*
|
|
12
|
+
* See SPEC.md §14.1
|
|
13
|
+
*/
|
|
14
|
+
export const STOP_WORDS = new Set([
|
|
15
|
+
// ARTICLES
|
|
16
|
+
"a", "about", "above",
|
|
17
|
+
"absolutely", "accordingly", "across", "active", "actually", "after", "afterwards", "against", "ago", "ah",
|
|
18
|
+
"aiw", "all", "allow", "almost", "along", "already", "alright", "also",
|
|
19
|
+
"alternatively", "although", "always", // AUXILIARY/MODAL VERBS
|
|
20
|
+
"am", "among", "an", // CONJUNCTIONS
|
|
21
|
+
"and", "another",
|
|
22
|
+
"anybody", "anyone", "anything", "anyway", "anyways", "apparently", "appear", "are",
|
|
23
|
+
"aren", "arent", "args", "around", "as", "ask", "assert",
|
|
24
|
+
"async", "at", "b", // SINGLE LETTERS
|
|
25
|
+
"based",
|
|
26
|
+
"basic", "basically", "bat", "be", "because", "become", "been",
|
|
27
|
+
"before", "begin", "behind", "being", "below",
|
|
28
|
+
"below", "beside", "besides", "between", "beyond", "block", "both",
|
|
29
|
+
"but", "by", "c", "can", "cant", "case", "cases",
|
|
30
|
+
"cause", "cc", "certainly", "chunk", "clarification",
|
|
31
|
+
"class", "clearly", "come", "complete",
|
|
32
|
+
"completely", "consequently", "consider", "const",
|
|
33
|
+
"contain", "contains", "continue", "conversely", "correct", "correctly",
|
|
34
|
+
"could", "couldn", "couldnt", "critical", "current", "currently",
|
|
35
|
+
"d", "def",
|
|
36
|
+
"definitely", "dict", "did", "didn", "didnt", "different", "directory", "do",
|
|
37
|
+
"does", "doesn", "doesn", "doesnt",
|
|
38
|
+
"doing", "don", "done", "dont", "down",
|
|
39
|
+
"during", "e", "each", "eh", "eight", "either", "elif", "else", "empty",
|
|
40
|
+
"end", "enough", "entirely", "eprint", "er", "essentially", // SHORT NOISE
|
|
41
|
+
"etc",
|
|
42
|
+
"eventually", "every", "everybody", "everyone", "everything", "exactly",
|
|
43
|
+
"example", "examples", "except", "exe", "existing",
|
|
44
|
+
"expect", "expected", "f", "false", "feature",
|
|
45
|
+
"features", "feel", "few", "finally", "find", "first", "five",
|
|
46
|
+
"folder", "follow", "following", "footer", "for", "format", "four",
|
|
47
|
+
"from", "full", "furthermore", "g", "general",
|
|
48
|
+
"get", "getting", "give", // COMMON NON-ACTION VERBS
|
|
49
|
+
"go",
|
|
50
|
+
"going", "gonna", "gotta", "group",
|
|
51
|
+
"h", "had", "hadn", "hadnt", "has", "hasn", "hasnt",
|
|
52
|
+
"have", "haven", "havent", "having", "he", "header", "hello",
|
|
53
|
+
"help", "hence", "her", "her", "here", // ADVERBS OF PLACE/TIME
|
|
54
|
+
"heres", "hers", "herself", "hes",
|
|
55
|
+
"hey", "hi", "high", // GENERIC ADJECTIVES
|
|
56
|
+
"him", "himself", "his", "hm", "hmm",
|
|
57
|
+
"how", // LINKING/TRANSITION WORDS
|
|
58
|
+
"however",
|
|
59
|
+
"huh", "i", // PRONOUNS - Personal
|
|
60
|
+
"id", "if", "ill", "im", // CONTRACTED FORMS
|
|
61
|
+
"immediately",
|
|
62
|
+
"import", "important", "in", "include", "index", "information", // GENERIC TECHNICAL NOUNS
|
|
63
|
+
"inside",
|
|
64
|
+
"instead", "into", "is", "isn", "isnt",
|
|
65
|
+
"issue", "it", "item", "items", "its", "itself",
|
|
66
|
+
"ive", "j", "js", "json", // FILLER/HEDGE WORDS
|
|
67
|
+
"just",
|
|
68
|
+
"k", "keep", "kind", "kinda", "know", "l", "lambda", "last", "later",
|
|
69
|
+
"least", "len", "less", "let", "lets", "level", "like", "likewise",
|
|
70
|
+
"line", "lines", "list", "literally", "ll",
|
|
71
|
+
"look", "looking", "low", "m", "main", "make",
|
|
72
|
+
"making", "manual", "many", "may", "maybe", "md", "me",
|
|
73
|
+
"mean", "meanwhile", "method", "might", "mine", "mode", "more",
|
|
74
|
+
"moreover", "most", "much", "multiple", "must", // PRONOUNS - Possessive
|
|
75
|
+
"my",
|
|
76
|
+
"myself", "n", "nah", "near", "nearly", "need", "needed", "neither",
|
|
77
|
+
"never", "nevertheless", "new", "next", "nine", "no", // NEGATION
|
|
78
|
+
"nobody", "none",
|
|
79
|
+
"none", "nonetheless", "no one", "nope", "nor", "not",
|
|
80
|
+
"nothing", "now", "o", "obviously", "of", "off",
|
|
81
|
+
"often", "oh",
|
|
82
|
+
"ok", "okay", "on", "one", "ones", "only",
|
|
83
|
+
"onto", "option", "optional", "options", "or",
|
|
84
|
+
"other", "otherwise", "our", "ours", "ourselves",
|
|
85
|
+
"out", "outside", "over", "overall", "p", "part", "parts", "pass", "per",
|
|
86
|
+
"perhaps", "phase", "pl",
|
|
87
|
+
"please", "point",
|
|
88
|
+
"points", "possibly", "pretty", "previously", "primary", "probably", "process",
|
|
89
|
+
"proper", "provide", "provided", "purpose", "put", // FILE EXTENSIONS
|
|
90
|
+
"py",
|
|
91
|
+
"q", "question", "questions", // QUERY LANGUAGE
|
|
92
|
+
"quite",
|
|
93
|
+
"r", "rather", // FRAGMENT WORDS
|
|
94
|
+
"re",
|
|
95
|
+
"real", "really", "recently", "region",
|
|
96
|
+
"remain", "require", "required",
|
|
97
|
+
"result", "return", "right", "s", "same", "say", "secondary", // DOCUMENT/CODE STRUCTURE
|
|
98
|
+
"section",
|
|
99
|
+
"see", "seem", // PROGRAMMING KEYWORDS
|
|
100
|
+
"self",
|
|
101
|
+
"set", "seven", "several", "shall",
|
|
102
|
+
"she", "shes", "should", "shouldn",
|
|
103
|
+
"shouldnt", "show", "similarly", "simple", "simply",
|
|
104
|
+
"since", "single", "six", "so", "some", // QUANTIFIERS
|
|
105
|
+
"somebody", "someone", // PRONOUNS - Indefinite
|
|
106
|
+
"something",
|
|
107
|
+
"sometimes", "somewhat", "soon", "sorta", "source", "specific", "stable", "start",
|
|
108
|
+
"state", "status", "stay", "step", // STRUCTURAL WORDS
|
|
109
|
+
"steps", "still",
|
|
110
|
+
"str", "stuff", "such", "sys", "t", "take",
|
|
111
|
+
"tell", "ten", "that", "thats", "the", "their",
|
|
112
|
+
"theirs", "them", "themselves", "then", "there", "therefore",
|
|
113
|
+
"theres", "these", "they", "theyre", "theyve", // OVERLY GENERIC TERMS
|
|
114
|
+
"thing",
|
|
115
|
+
"things", "think", "this", // PRONOUNS - Demonstrative
|
|
116
|
+
"those", "though", "three", "through",
|
|
117
|
+
"thus", "time", "times", // PREPOSITIONS
|
|
118
|
+
"to",
|
|
119
|
+
"today", "toml", "tomorrow", "too", // SHORT FILLER
|
|
120
|
+
"totally", "toward",
|
|
121
|
+
"towards", "true", "try", "trying", "ts", // NUMBER WORDS
|
|
122
|
+
"two",
|
|
123
|
+
"type", "types", "u", "uh", "um", // SPEECH-TO-TEXT FILLERS (STT artifacts from voice input)
|
|
124
|
+
"under", "unknown", "unless",
|
|
125
|
+
"until", "up", "upon", "us", "used", "uses", // COMMON CODING TERMS
|
|
126
|
+
"using",
|
|
127
|
+
"v", "value", "ve", "version", "very", "via", "w",
|
|
128
|
+
"wanna", // COMMON REQUEST PHRASES
|
|
129
|
+
"want", "was", "wasn", "wasnt", "way", "ways",
|
|
130
|
+
"we", "well", "were", "weren", "werent", "weve", // QUESTION WORDS
|
|
131
|
+
"what",
|
|
132
|
+
"whats", "when", "whenever", "where", "whereas",
|
|
133
|
+
"wherever", "whether", "which", "while",
|
|
134
|
+
// PRONOUNS - Relative
|
|
135
|
+
"who", "whom", "whos", "whose", "why", "will", "with", "within", "without",
|
|
136
|
+
"won", "wont", "work", "working", "works", "would", "wouldn", "wouldnt", "x", "y", "yaml", "yeah", "yep", "yes",
|
|
137
|
+
"yesterday", "yet", "yield", "you", "youll", "your", "youre", "yours",
|
|
138
|
+
"yourself", "youve", "yup", "z",
|
|
139
|
+
]);
|
|
140
|
+
/**
|
|
141
|
+
* Filter stop words from text.
|
|
142
|
+
* Splits on whitespace, removes words in STOP_WORDS set and single-char words.
|
|
143
|
+
* See SPEC.md §6.4
|
|
144
|
+
*/
|
|
145
|
+
export function filterStopWords(text) {
|
|
146
|
+
return text
|
|
147
|
+
.split(/\s+/)
|
|
148
|
+
.filter((word) => word.length > 1 && !STOP_WORDS.has(word.toLowerCase()))
|
|
149
|
+
.join(" ");
|
|
150
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export declare function isInternalCall(): boolean;
|
|
2
|
+
export declare function getInternalSubprocessEnv(): Record<string, string | undefined>;
|
|
3
|
+
export declare function findExecutable(name: string): string | null;
|
|
4
|
+
export interface ExecSyncError {
|
|
5
|
+
killed: boolean;
|
|
6
|
+
signal: string | null;
|
|
7
|
+
stdout: Buffer | string;
|
|
8
|
+
stderr: Buffer | string;
|
|
9
|
+
status: number | null;
|
|
10
|
+
message: string;
|
|
11
|
+
}
|
|
12
|
+
export declare function isExecSyncError(error: unknown): error is ExecSyncError;
|
|
13
|
+
export declare function normalizePathForCli(pathValue: string): string;
|
|
14
|
+
export declare function shellQuoteWin(arg: string): string;
|
|
15
|
+
export interface ExecResult {
|
|
16
|
+
stdout: string;
|
|
17
|
+
stderr: string;
|
|
18
|
+
exitCode: number;
|
|
19
|
+
killed: boolean;
|
|
20
|
+
signal: string | null;
|
|
21
|
+
}
|
|
22
|
+
export interface ExecAsyncOptions {
|
|
23
|
+
input?: string | undefined;
|
|
24
|
+
timeout?: number | undefined;
|
|
25
|
+
env?: Record<string, string | undefined> | undefined;
|
|
26
|
+
maxBuffer?: number | undefined;
|
|
27
|
+
shell?: boolean | undefined;
|
|
28
|
+
}
|
|
29
|
+
export declare function execFileAsync(file: string, args: string[], options?: ExecAsyncOptions): Promise<ExecResult>;
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { execFile } from 'node:child_process';
|
|
2
|
+
import { resolveExecutable } from './executable-policy.js';
|
|
3
|
+
const childProcesses = new Set();
|
|
4
|
+
function cleanupChildren() {
|
|
5
|
+
for (const child of childProcesses) {
|
|
6
|
+
try {
|
|
7
|
+
child.kill('SIGKILL');
|
|
8
|
+
}
|
|
9
|
+
catch {
|
|
10
|
+
// Child may have already exited.
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
childProcesses.clear();
|
|
14
|
+
}
|
|
15
|
+
process.on('exit', () => {
|
|
16
|
+
cleanupChildren();
|
|
17
|
+
});
|
|
18
|
+
process.on('SIGINT', () => {
|
|
19
|
+
cleanupChildren();
|
|
20
|
+
process.exit(130);
|
|
21
|
+
});
|
|
22
|
+
process.on('SIGTERM', () => {
|
|
23
|
+
cleanupChildren();
|
|
24
|
+
process.exit(143);
|
|
25
|
+
});
|
|
26
|
+
export function isInternalCall() {
|
|
27
|
+
return process.env.AIWCLI_INTERNAL_CALL === 'true';
|
|
28
|
+
}
|
|
29
|
+
export function getInternalSubprocessEnv() {
|
|
30
|
+
const env = {
|
|
31
|
+
...process.env,
|
|
32
|
+
AIWCLI_INTERNAL_CALL: 'true',
|
|
33
|
+
};
|
|
34
|
+
delete env.CLAUDECODE;
|
|
35
|
+
delete env.CLAUDE_CODE_ENTRYPOINT;
|
|
36
|
+
return env;
|
|
37
|
+
}
|
|
38
|
+
export function findExecutable(name) {
|
|
39
|
+
return resolveExecutable(name, { windowsProfile: 'cmdOrExeFirst' });
|
|
40
|
+
}
|
|
41
|
+
export function isExecSyncError(error) {
|
|
42
|
+
return typeof error === 'object' && error !== null && 'killed' in error && 'signal' in error;
|
|
43
|
+
}
|
|
44
|
+
export function normalizePathForCli(pathValue) {
|
|
45
|
+
if (process.platform !== 'win32')
|
|
46
|
+
return pathValue;
|
|
47
|
+
return pathValue.replaceAll('\\', '/');
|
|
48
|
+
}
|
|
49
|
+
export function shellQuoteWin(arg) {
|
|
50
|
+
if (process.platform !== 'win32')
|
|
51
|
+
return arg;
|
|
52
|
+
return '"' + arg.replaceAll('"', '""') + '"';
|
|
53
|
+
}
|
|
54
|
+
export function execFileAsync(file, args, options) {
|
|
55
|
+
return new Promise((resolve) => {
|
|
56
|
+
const child = execFile(file, args, {
|
|
57
|
+
encoding: 'utf8',
|
|
58
|
+
timeout: options?.timeout ?? 0,
|
|
59
|
+
env: options?.env,
|
|
60
|
+
maxBuffer: options?.maxBuffer ?? 10 * 1024 * 1024,
|
|
61
|
+
shell: options?.shell,
|
|
62
|
+
}, (error, stdout, stderr) => {
|
|
63
|
+
if (error) {
|
|
64
|
+
const errObj = error;
|
|
65
|
+
resolve({
|
|
66
|
+
stdout: String(stdout ?? ''),
|
|
67
|
+
stderr: String(stderr ?? ''),
|
|
68
|
+
exitCode: typeof errObj.code === 'number'
|
|
69
|
+
? errObj.code
|
|
70
|
+
: typeof errObj.status === 'number'
|
|
71
|
+
? errObj.status
|
|
72
|
+
: 1,
|
|
73
|
+
killed: Boolean(errObj.killed),
|
|
74
|
+
signal: typeof errObj.signal === 'string' ? errObj.signal : null,
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
else {
|
|
78
|
+
resolve({
|
|
79
|
+
stdout: String(stdout ?? ''),
|
|
80
|
+
stderr: String(stderr ?? ''),
|
|
81
|
+
exitCode: 0,
|
|
82
|
+
killed: false,
|
|
83
|
+
signal: null,
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
childProcesses.add(child);
|
|
88
|
+
child.on('exit', () => {
|
|
89
|
+
childProcesses.delete(child);
|
|
90
|
+
});
|
|
91
|
+
if (options?.input !== null && options?.input !== undefined && child.stdin) {
|
|
92
|
+
child.stdin.write(options.input);
|
|
93
|
+
child.stdin.end();
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export declare function selectMsysBashFromLookupPaths(paths: string[]): null | string;
|
|
2
|
+
export declare function deriveMsysBashFromGitPath(gitPath: string): null | string;
|
|
3
|
+
export declare function findMsysBash(): null | string;
|
|
4
|
+
export declare function isTmuxReachableViaBash(bashPath: string): boolean;
|
|
5
|
+
export declare function isNativeTmuxAvailable(platform?: NodeJS.Platform): boolean;
|
|
6
|
+
/** Find psmux (native Windows terminal multiplexer) on PATH. */
|
|
7
|
+
export declare function findPsmux(): null | string;
|
|
8
|
+
export interface WindowsTmuxPreflight {
|
|
9
|
+
available: boolean;
|
|
10
|
+
bashPath?: string;
|
|
11
|
+
reason?: string;
|
|
12
|
+
}
|
|
13
|
+
export declare function preflightWindowsTmux(): WindowsTmuxPreflight;
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { execFileSync } from 'node:child_process';
|
|
2
|
+
import { existsSync } from 'node:fs';
|
|
3
|
+
import { isCommandAvailable, lookupExecutables } from './executable-policy.js';
|
|
4
|
+
import { isWindowsPlatform } from './platform-adapter.js';
|
|
5
|
+
export function selectMsysBashFromLookupPaths(paths) {
|
|
6
|
+
for (const candidate of paths) {
|
|
7
|
+
const trimmed = candidate.trim();
|
|
8
|
+
if (trimmed && /git|msys|mingw/iu.test(trimmed))
|
|
9
|
+
return trimmed;
|
|
10
|
+
}
|
|
11
|
+
return null;
|
|
12
|
+
}
|
|
13
|
+
export function deriveMsysBashFromGitPath(gitPath) {
|
|
14
|
+
const trimmed = gitPath.trim();
|
|
15
|
+
if (!trimmed)
|
|
16
|
+
return null;
|
|
17
|
+
const gitMatch = trimmed.match(/^(.+[/\\]Git)[/\\]cmd[/\\]git\.exe$/iu);
|
|
18
|
+
if (!gitMatch?.[1])
|
|
19
|
+
return null;
|
|
20
|
+
return `${gitMatch[1]}\\usr\\bin\\bash.exe`;
|
|
21
|
+
}
|
|
22
|
+
export function findMsysBash() {
|
|
23
|
+
const directBash = selectMsysBashFromLookupPaths(lookupExecutables('bash', { platform: 'win32' }));
|
|
24
|
+
if (directBash)
|
|
25
|
+
return directBash;
|
|
26
|
+
const gitCandidates = lookupExecutables('git', { platform: 'win32' });
|
|
27
|
+
for (const candidate of gitCandidates) {
|
|
28
|
+
const derived = deriveMsysBashFromGitPath(candidate);
|
|
29
|
+
if (derived && existsSync(derived))
|
|
30
|
+
return derived;
|
|
31
|
+
}
|
|
32
|
+
const knownPaths = [
|
|
33
|
+
String.raw `C:\Program Files\Git\usr\bin\bash.exe`,
|
|
34
|
+
String.raw `C:\Program Files (x86)\Git\usr\bin\bash.exe`,
|
|
35
|
+
];
|
|
36
|
+
for (const knownPath of knownPaths) {
|
|
37
|
+
if (existsSync(knownPath))
|
|
38
|
+
return knownPath;
|
|
39
|
+
}
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
export function isTmuxReachableViaBash(bashPath) {
|
|
43
|
+
try {
|
|
44
|
+
execFileSync(bashPath, ['-lc', 'tmux -V'], {
|
|
45
|
+
timeout: 3000,
|
|
46
|
+
stdio: 'ignore',
|
|
47
|
+
env: { ...process.env, MSYS_NO_PATHCONV: '1' },
|
|
48
|
+
windowsHide: true,
|
|
49
|
+
});
|
|
50
|
+
return true;
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
return false;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
export function isNativeTmuxAvailable(platform = process.platform) {
|
|
57
|
+
return isCommandAvailable('tmux', platform);
|
|
58
|
+
}
|
|
59
|
+
/** Find psmux (native Windows terminal multiplexer) on PATH. */
|
|
60
|
+
export function findPsmux() {
|
|
61
|
+
if (!isWindowsPlatform())
|
|
62
|
+
return null;
|
|
63
|
+
const candidates = lookupExecutables('psmux', { platform: 'win32' });
|
|
64
|
+
return candidates[0]?.trim() || null;
|
|
65
|
+
}
|
|
66
|
+
export function preflightWindowsTmux() {
|
|
67
|
+
if (!isWindowsPlatform()) {
|
|
68
|
+
return { available: false, reason: 'not running on Windows' };
|
|
69
|
+
}
|
|
70
|
+
const bashPath = findMsysBash();
|
|
71
|
+
if (!bashPath) {
|
|
72
|
+
return { available: false, reason: 'Git Bash not found' };
|
|
73
|
+
}
|
|
74
|
+
if (!isTmuxReachableViaBash(bashPath)) {
|
|
75
|
+
return { available: false, bashPath, reason: 'tmux not available in Git Bash' };
|
|
76
|
+
}
|
|
77
|
+
return { available: true, bashPath };
|
|
78
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Core utilities for shared context management.
|
|
3
|
+
* See SPEC.md §14.2, §14.3
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Print to stderr. For terminal-only UX messages, not diagnostics.
|
|
7
|
+
*/
|
|
8
|
+
export declare function eprint(...args: unknown[]): void;
|
|
9
|
+
/**
|
|
10
|
+
* Get current local datetime as Date.
|
|
11
|
+
*/
|
|
12
|
+
export declare function nowLocal(): Date;
|
|
13
|
+
/**
|
|
14
|
+
* Get current time as ISO 8601 string (local time, no timezone suffix).
|
|
15
|
+
* Matches Python datetime.now().isoformat() behavior.
|
|
16
|
+
*/
|
|
17
|
+
export declare function nowIso(): string;
|
|
18
|
+
/**
|
|
19
|
+
* Format datetime for display.
|
|
20
|
+
* Returns "YYYY-MM-DD HH:MM:SS"
|
|
21
|
+
* See SPEC.md §14.3
|
|
22
|
+
*/
|
|
23
|
+
export declare function formatTimestamp(dt?: Date): string;
|
|
24
|
+
/**
|
|
25
|
+
* Parse ISO 8601 timestamp string.
|
|
26
|
+
* Returns null if parsing fails.
|
|
27
|
+
* See SPEC.md §14.3
|
|
28
|
+
*/
|
|
29
|
+
export declare function parseIsoTimestamp(isoStr: string): Date | null;
|
|
30
|
+
/**
|
|
31
|
+
* Normalize a filesystem path for display — always uses forward slashes.
|
|
32
|
+
* No-op on Unix; converts backslashes on Windows.
|
|
33
|
+
*/
|
|
34
|
+
export declare function displayPath(p: string): string;
|
|
35
|
+
/**
|
|
36
|
+
* Clean text for stop-word matching in slug generation.
|
|
37
|
+
* Strips apostrophes (i'm -> im), removes punctuation, normalizes whitespace.
|
|
38
|
+
* See SPEC.md §14.2
|
|
39
|
+
*/
|
|
40
|
+
export declare function cleanTextForSlug(text: string): string;
|
|
41
|
+
/**
|
|
42
|
+
* Generate a slug from text using AI inference with stop-word fallbacks.
|
|
43
|
+
* Pipeline: AI inference → stop-word post-filter → stop-word fallback → word-length fallback.
|
|
44
|
+
* Reusable by both context ID generation and plan archival.
|
|
45
|
+
* See SPEC.md §14.2
|
|
46
|
+
*/
|
|
47
|
+
export declare function generateSlug(text: string, maxLen?: number, fallbackSlug?: string): string;
|
|
48
|
+
/**
|
|
49
|
+
* Generate a context ID from a summary string.
|
|
50
|
+
* Format: YYMMDD-HHMM-slug
|
|
51
|
+
* Delegates slug generation to generateSlug().
|
|
52
|
+
* See SPEC.md §14.2
|
|
53
|
+
*/
|
|
54
|
+
export declare function generateContextId(summary: string, existingIds?: Set<string>): string;
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Core utilities for shared context management.
|
|
3
|
+
* See SPEC.md §14.2, §14.3
|
|
4
|
+
*/
|
|
5
|
+
import { sanitizeTitle } from "./constants.js";
|
|
6
|
+
import { logDebug, logError, logWarn } from "./logger.js";
|
|
7
|
+
import { STOP_WORDS } from "./stop-words.js";
|
|
8
|
+
/**
|
|
9
|
+
* Print to stderr. For terminal-only UX messages, not diagnostics.
|
|
10
|
+
*/
|
|
11
|
+
export function eprint(...args) {
|
|
12
|
+
process.stderr.write(args.map(String).join(" ") + "\n");
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Get current local datetime as Date.
|
|
16
|
+
*/
|
|
17
|
+
export function nowLocal() {
|
|
18
|
+
return new Date();
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Get current time as ISO 8601 string (local time, no timezone suffix).
|
|
22
|
+
* Matches Python datetime.now().isoformat() behavior.
|
|
23
|
+
*/
|
|
24
|
+
export function nowIso() {
|
|
25
|
+
const d = new Date();
|
|
26
|
+
const year = d.getFullYear();
|
|
27
|
+
const month = String(d.getMonth() + 1).padStart(2, "0");
|
|
28
|
+
const day = String(d.getDate()).padStart(2, "0");
|
|
29
|
+
const hours = String(d.getHours()).padStart(2, "0");
|
|
30
|
+
const minutes = String(d.getMinutes()).padStart(2, "0");
|
|
31
|
+
const seconds = String(d.getSeconds()).padStart(2, "0");
|
|
32
|
+
const ms = String(d.getMilliseconds()).padStart(3, "0");
|
|
33
|
+
return `${year}-${month}-${day}T${hours}:${minutes}:${seconds}.${ms}`;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Format datetime for display.
|
|
37
|
+
* Returns "YYYY-MM-DD HH:MM:SS"
|
|
38
|
+
* See SPEC.md §14.3
|
|
39
|
+
*/
|
|
40
|
+
export function formatTimestamp(dt) {
|
|
41
|
+
const d = dt ?? nowLocal();
|
|
42
|
+
const year = d.getFullYear();
|
|
43
|
+
const month = String(d.getMonth() + 1).padStart(2, "0");
|
|
44
|
+
const day = String(d.getDate()).padStart(2, "0");
|
|
45
|
+
const hours = String(d.getHours()).padStart(2, "0");
|
|
46
|
+
const minutes = String(d.getMinutes()).padStart(2, "0");
|
|
47
|
+
const seconds = String(d.getSeconds()).padStart(2, "0");
|
|
48
|
+
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Parse ISO 8601 timestamp string.
|
|
52
|
+
* Returns null if parsing fails.
|
|
53
|
+
* See SPEC.md §14.3
|
|
54
|
+
*/
|
|
55
|
+
export function parseIsoTimestamp(isoStr) {
|
|
56
|
+
try {
|
|
57
|
+
const normalized = isoStr.replace("Z", "+00:00");
|
|
58
|
+
const d = new Date(normalized);
|
|
59
|
+
if (isNaN(d.getTime()))
|
|
60
|
+
return null;
|
|
61
|
+
return d;
|
|
62
|
+
}
|
|
63
|
+
catch {
|
|
64
|
+
return null;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Normalize a filesystem path for display — always uses forward slashes.
|
|
69
|
+
* No-op on Unix; converts backslashes on Windows.
|
|
70
|
+
*/
|
|
71
|
+
export function displayPath(p) {
|
|
72
|
+
return p.replaceAll("\\", "/");
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Clean text for stop-word matching in slug generation.
|
|
76
|
+
* Strips apostrophes (i'm -> im), removes punctuation, normalizes whitespace.
|
|
77
|
+
* See SPEC.md §14.2
|
|
78
|
+
*/
|
|
79
|
+
export function cleanTextForSlug(text) {
|
|
80
|
+
if (!text)
|
|
81
|
+
return "";
|
|
82
|
+
let result = text.toLowerCase();
|
|
83
|
+
result = result.replaceAll('\'', ""); // i'm -> im, you're -> youre
|
|
84
|
+
result = result.replaceAll(/[^a-z0-9\s]/g, " "); // punctuation -> spaces
|
|
85
|
+
result = result.replaceAll(/\s+/g, " ").trim();
|
|
86
|
+
return result;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Generate a slug from text using AI inference with stop-word fallbacks.
|
|
90
|
+
* Pipeline: AI inference → stop-word post-filter → stop-word fallback → word-length fallback.
|
|
91
|
+
* Reusable by both context ID generation and plan archival.
|
|
92
|
+
* See SPEC.md §14.2
|
|
93
|
+
*/
|
|
94
|
+
export function generateSlug(text, maxLen = 150, fallbackSlug = "context") {
|
|
95
|
+
if (!text || !text.trim())
|
|
96
|
+
return fallbackSlug;
|
|
97
|
+
let slug = null;
|
|
98
|
+
const cleanedText = cleanTextForSlug(text);
|
|
99
|
+
// Tier 1: AI inference via generateContextIdSlug (sync — uses execFileSync)
|
|
100
|
+
try {
|
|
101
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports, no-undef
|
|
102
|
+
const { generateContextIdSlug } = require("./inference.js");
|
|
103
|
+
const aiSlug = generateContextIdSlug(text);
|
|
104
|
+
if (aiSlug) {
|
|
105
|
+
const filteredWords = aiSlug
|
|
106
|
+
.split(/\s+/)
|
|
107
|
+
.filter((w) => !STOP_WORDS.has(w.toLowerCase()) && w.length > 1);
|
|
108
|
+
if (filteredWords.length >= 5) {
|
|
109
|
+
slug = sanitizeTitle(filteredWords.join(" "), maxLen);
|
|
110
|
+
}
|
|
111
|
+
else {
|
|
112
|
+
logDebug("utils", `AI slug too generic after stop-word filter (${filteredWords.length} words remain), using fallback`);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
catch (error) {
|
|
117
|
+
logWarn("utils", `AI slug generation failed, using fallback: ${error}`);
|
|
118
|
+
}
|
|
119
|
+
// Tier 2: Stop-word filtering on cleaned text
|
|
120
|
+
if (!slug) {
|
|
121
|
+
const words = cleanedText
|
|
122
|
+
.split(/\s+/)
|
|
123
|
+
.filter((w) => !STOP_WORDS.has(w) && w.length > 1)
|
|
124
|
+
.slice(0, 12);
|
|
125
|
+
slug = words.length >= 3
|
|
126
|
+
? sanitizeTitle(words.join(" "), maxLen)
|
|
127
|
+
: sanitizeTitle(cleanedText.split(/\s+/).filter((w) => w.length > 2).slice(0, 6).join(" "), maxLen) || fallbackSlug;
|
|
128
|
+
}
|
|
129
|
+
return slug;
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Generate a context ID from a summary string.
|
|
133
|
+
* Format: YYMMDD-HHMM-slug
|
|
134
|
+
* Delegates slug generation to generateSlug().
|
|
135
|
+
* See SPEC.md §14.2
|
|
136
|
+
*/
|
|
137
|
+
export function generateContextId(summary, existingIds) {
|
|
138
|
+
const now = new Date();
|
|
139
|
+
const yy = String(now.getFullYear()).slice(2);
|
|
140
|
+
const mm = String(now.getMonth() + 1).padStart(2, "0");
|
|
141
|
+
const dd = String(now.getDate()).padStart(2, "0");
|
|
142
|
+
const hh = String(now.getHours()).padStart(2, "0");
|
|
143
|
+
const min = String(now.getMinutes()).padStart(2, "0");
|
|
144
|
+
const timestamp = `${yy}${mm}${dd}-${hh}${min}`;
|
|
145
|
+
let baseId;
|
|
146
|
+
try {
|
|
147
|
+
const slug = generateSlug(summary);
|
|
148
|
+
baseId = `${timestamp}-${slug}`;
|
|
149
|
+
}
|
|
150
|
+
catch (error) {
|
|
151
|
+
logError("utils", `Context ID generation failed entirely, using timestamp: ${error}`);
|
|
152
|
+
baseId = `${timestamp}-context`;
|
|
153
|
+
}
|
|
154
|
+
if (!existingIds || !existingIds.has(baseId)) {
|
|
155
|
+
return baseId;
|
|
156
|
+
}
|
|
157
|
+
let counter = 2;
|
|
158
|
+
while (existingIds.has(`${baseId}-${counter}`)) {
|
|
159
|
+
counter++;
|
|
160
|
+
}
|
|
161
|
+
return `${baseId}-${counter}`;
|
|
162
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export interface SentinelWrapParams {
|
|
2
|
+
autoClose: boolean;
|
|
3
|
+
command: string;
|
|
4
|
+
holdMessage: string;
|
|
5
|
+
holdPane: boolean;
|
|
6
|
+
sentinelPath: string;
|
|
7
|
+
}
|
|
8
|
+
export declare function wrapSentinelSh(params: SentinelWrapParams): string;
|
|
9
|
+
export declare function wrapSentinelPowerShell(params: SentinelWrapParams): string;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { quoteForPowerShell, quoteForSh } from './shell-quoting.js';
|
|
2
|
+
export function wrapSentinelSh(params) {
|
|
3
|
+
const { command, sentinelPath, autoClose, holdPane, holdMessage } = params;
|
|
4
|
+
const base = `${command}; code=$?; printf '%s' "$code" > ${quoteForSh(sentinelPath)}`;
|
|
5
|
+
if (autoClose) {
|
|
6
|
+
return `${base}; tmux kill-pane -t "$TMUX_PANE" >/dev/null 2>&1 || true; exit $code`;
|
|
7
|
+
}
|
|
8
|
+
if (holdPane) {
|
|
9
|
+
return `${base}; echo; echo ${quoteForSh(holdMessage)}; exec bash`;
|
|
10
|
+
}
|
|
11
|
+
return `${base}; exit $code`;
|
|
12
|
+
}
|
|
13
|
+
export function wrapSentinelPowerShell(params) {
|
|
14
|
+
const { command, sentinelPath, autoClose, holdPane, holdMessage } = params;
|
|
15
|
+
const base = `${command}; $code = $LASTEXITCODE; Set-Content -Path ${quoteForPowerShell(sentinelPath)} -Value $code -NoNewline`;
|
|
16
|
+
if (holdPane && !autoClose) {
|
|
17
|
+
return `${base}; Write-Host ''; Write-Host ${quoteForPowerShell(holdMessage)}; Read-Host -Prompt 'Press Enter to close' | Out-Null`;
|
|
18
|
+
}
|
|
19
|
+
return `${base}; exit $code`;
|
|
20
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export declare function quoteForSh(input: string): string;
|
|
2
|
+
export declare function quoteForPowerShell(input: string): string;
|
|
3
|
+
/** Wrap a PowerShell command using -EncodedCommand to avoid all quoting issues. */
|
|
4
|
+
export declare function toEncodedPowerShell(command: string): string;
|
|
5
|
+
export declare function escapeSingleQuotedPath(path: string, dialect: 'bash' | 'powershell'): string;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export function quoteForSh(input) {
|
|
2
|
+
return `'${input.replaceAll("'", "'\"'\"'")}'`;
|
|
3
|
+
}
|
|
4
|
+
export function quoteForPowerShell(input) {
|
|
5
|
+
return `'${input.replaceAll("'", "''")}'`;
|
|
6
|
+
}
|
|
7
|
+
/** Wrap a PowerShell command using -EncodedCommand to avoid all quoting issues. */
|
|
8
|
+
export function toEncodedPowerShell(command) {
|
|
9
|
+
const encoded = Buffer.from(command, 'utf16le').toString('base64');
|
|
10
|
+
return `powershell.exe -NoProfile -EncodedCommand ${encoded}`;
|
|
11
|
+
}
|
|
12
|
+
export function escapeSingleQuotedPath(path, dialect) {
|
|
13
|
+
if (dialect === 'powershell') {
|
|
14
|
+
return path.replaceAll("'", "''");
|
|
15
|
+
}
|
|
16
|
+
return path.replaceAll("'", String.raw `'\''`);
|
|
17
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { ProcessSpawnError } from './errors.js';
|
|
2
|
+
export declare function classifySpawnError(command: string, error: NodeJS.ErrnoException): ProcessSpawnError;
|
|
3
|
+
export declare function resolveWindowsSpawnArgs(command: string, args: string[], cmdExists: (commandName: string) => boolean): null | {
|
|
4
|
+
args: string[];
|
|
5
|
+
command: string;
|
|
6
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { ProcessSpawnError } from './errors.js';
|
|
2
|
+
export function classifySpawnError(command, error) {
|
|
3
|
+
if (error.code === 'ENOENT') {
|
|
4
|
+
return new ProcessSpawnError(`Command not found: ${command}. Install Claude Code from https://claude.ai/download.`, 'ENOENT');
|
|
5
|
+
}
|
|
6
|
+
if (error.code === 'EACCES') {
|
|
7
|
+
return new ProcessSpawnError(`Permission denied: ${command}. Check file permissions.`, 'EACCES');
|
|
8
|
+
}
|
|
9
|
+
return new ProcessSpawnError(`Failed to spawn ${command}: ${error.message}. Check that the command exists and is executable.`, error.code);
|
|
10
|
+
}
|
|
11
|
+
export function resolveWindowsSpawnArgs(command, args, cmdExists) {
|
|
12
|
+
if (!cmdExists(`${command}.cmd`))
|
|
13
|
+
return null;
|
|
14
|
+
return { command: 'cmd.exe', args: ['/c', command, ...args] };
|
|
15
|
+
}
|