aiwcli 0.15.7 → 0.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +106 -1125
- package/bin/run.js +0 -4
- package/dist/capabilities/installation/control-plane/clear-command.d.ts +2 -0
- package/dist/capabilities/installation/control-plane/clear-command.js +32 -3
- package/dist/capabilities/installation/control-plane/init-command.js +2 -2
- package/dist/capabilities/launch/contracts.d.ts +39 -4
- package/dist/capabilities/launch/control-plane/execute-launch.js +158 -119
- package/dist/capabilities/launch/runtime-core/launch-decisions.d.ts +82 -0
- package/dist/capabilities/launch/runtime-core/launch-decisions.js +202 -0
- package/dist/commands/branch.d.ts +1 -1
- package/dist/commands/branch.js +1 -1
- package/dist/commands/launch.d.ts +0 -5
- package/dist/commands/launch.js +2 -37
- package/dist/lib/config.js +1 -2
- package/dist/lib/context/context-store.js +28 -2
- package/dist/lib/core-installer.d.ts +1 -1
- package/dist/lib/core-installer.js +6 -27
- package/dist/lib/debug.d.ts +0 -10
- package/dist/lib/debug.js +0 -10
- package/dist/lib/env-sanitizer.d.ts +25 -0
- package/dist/lib/env-sanitizer.js +46 -0
- package/dist/lib/errors.d.ts +0 -13
- package/dist/lib/errors.js +0 -15
- package/dist/lib/git-exclude-manager.js +1 -1
- package/dist/lib/hooks/context-monitor-logic.d.ts +6 -0
- package/dist/lib/hooks/context-monitor-logic.js +25 -0
- package/dist/lib/hooks/hook-utils.js +11 -0
- package/dist/lib/hooks/prompt-binding-logic.d.ts +7 -0
- package/dist/lib/hooks/prompt-binding-logic.js +50 -0
- package/dist/lib/hooks/session-end-logic.js +2 -14
- package/dist/lib/install-state.js +6 -13
- package/dist/lib/json-io.d.ts +12 -0
- package/dist/lib/json-io.js +30 -0
- package/dist/lib/multiplexer.d.ts +43 -35
- package/dist/lib/multiplexer.js +21 -2
- package/dist/lib/multiplexers/psmux.d.ts +14 -34
- package/dist/lib/multiplexers/psmux.js +70 -130
- package/dist/lib/multiplexers/tmux.d.ts +11 -19
- package/dist/lib/multiplexers/tmux.js +79 -120
- package/dist/lib/multiplexers/wezterm.d.ts +38 -0
- package/dist/lib/multiplexers/wezterm.js +225 -0
- package/dist/lib/mux-utils.d.ts +4 -3
- package/dist/lib/mux-utils.js +7 -13
- package/dist/lib/prompt-file-manager.d.ts +23 -0
- package/dist/lib/prompt-file-manager.js +41 -0
- package/dist/lib/runtime/agent-launcher.d.ts +67 -0
- package/dist/lib/runtime/agent-launcher.js +262 -0
- package/dist/lib/runtime/aiw-cli.d.ts +2 -0
- package/dist/lib/runtime/aiw-cli.js +3 -1
- package/dist/lib/runtime/cli-args.d.ts +5 -2
- package/dist/lib/runtime/cli-args.js +18 -3
- package/dist/lib/runtime/inference.js +3 -14
- package/dist/lib/runtime/models.d.ts +6 -0
- package/dist/lib/runtime/models.js +6 -0
- package/dist/lib/runtime/state-io.d.ts +2 -1
- package/dist/lib/runtime/state-io.js +9 -4
- package/dist/lib/runtime/utils.d.ts +8 -0
- package/dist/lib/runtime/utils.js +31 -1
- package/dist/lib/schemas.d.ts +250 -0
- package/dist/lib/schemas.js +216 -0
- package/dist/lib/sentinel-manager.d.ts +32 -0
- package/dist/lib/sentinel-manager.js +62 -0
- package/dist/lib/sentinel-wrapper.d.ts +1 -0
- package/dist/lib/sentinel-wrapper.js +12 -3
- package/dist/lib/settings-hierarchy.js +3 -20
- package/dist/lib/shell-adapters/bash-adapter.d.ts +18 -0
- package/dist/lib/shell-adapters/bash-adapter.js +69 -0
- package/dist/lib/shell-adapters/index.d.ts +5 -0
- package/dist/lib/shell-adapters/index.js +7 -0
- package/dist/lib/shell-adapters/powershell-adapter.d.ts +18 -0
- package/dist/lib/shell-adapters/powershell-adapter.js +62 -0
- package/dist/lib/shell-adapters/shell-adapter.d.ts +45 -0
- package/dist/lib/shell-adapters/shell-adapter.js +5 -0
- package/dist/lib/spawn-errors.d.ts +3 -0
- package/dist/lib/spawn-errors.js +15 -1
- package/dist/lib/spinner.d.ts +0 -5
- package/dist/lib/spinner.js +0 -16
- package/dist/lib/template-installer.d.ts +10 -0
- package/dist/lib/template-installer.js +4 -4
- package/dist/lib/terminal-strategy.d.ts +1 -0
- package/dist/lib/terminal-strategy.js +12 -6
- package/dist/lib/terminal.d.ts +7 -5
- package/dist/lib/terminal.js +42 -19
- package/dist/lib/tmux-primitives.d.ts +0 -2
- package/dist/lib/tmux-primitives.js +0 -4
- package/dist/lib/tmux-session.js +2 -1
- package/dist/lib/windsurf-hooks-hierarchy.js +6 -23
- package/dist/platform/launch.d.ts +2 -1
- package/dist/platform/launch.js +1 -0
- package/dist/templates/CLAUDE.md +0 -1
- package/dist/templates/cc-native/.claude/settings.json +0 -10
- package/dist/templates/cc-native/TEMPLATE-SCHEMA.md +11 -4
- package/dist/templates/cc-native/_cc-native/cc-native.config.json +3 -7
- package/dist/templates/cc-native/_cc-native/hooks/CLAUDE.md +26 -47
- package/dist/templates/cc-native/_cc-native/hooks/cc-native-plan-review.ts +7 -9
- package/dist/templates/cc-native/_cc-native/hooks/enhance_plan_post_write.ts +2 -3
- package/dist/templates/cc-native/_cc-native/hooks/mark_questions_asked.ts +2 -2
- package/dist/templates/cc-native/_cc-native/hooks/plan_questions_early.ts +0 -25
- package/dist/templates/cc-native/_cc-native/hooks/validate_task_prompt.ts +4 -4
- package/dist/templates/cc-native/_cc-native/lib-ts/.mocharc.json +9 -0
- package/dist/templates/cc-native/_cc-native/lib-ts/__tests__/aggregate-agents.test.ts +118 -0
- package/dist/templates/cc-native/_cc-native/lib-ts/__tests__/artifacts.test.ts +234 -0
- package/dist/templates/cc-native/_cc-native/lib-ts/__tests__/cc-native-state.test.ts +170 -0
- package/dist/templates/cc-native/_cc-native/lib-ts/__tests__/cli-output-parser.test.ts +73 -0
- package/dist/templates/cc-native/_cc-native/lib-ts/__tests__/config.test.ts +64 -0
- package/dist/templates/cc-native/_cc-native/lib-ts/__tests__/constants.test.ts +40 -0
- package/dist/templates/cc-native/_cc-native/lib-ts/__tests__/debug.test.ts +42 -0
- package/dist/templates/cc-native/_cc-native/lib-ts/__tests__/exports.test.ts +58 -0
- package/dist/templates/cc-native/_cc-native/lib-ts/__tests__/helpers.ts +107 -0
- package/dist/templates/cc-native/_cc-native/lib-ts/__tests__/hooks/add-plan-context.hook.test.ts +97 -0
- package/dist/templates/cc-native/_cc-native/lib-ts/__tests__/hooks/plan-questions.hook.test.ts +81 -0
- package/dist/templates/cc-native/_cc-native/lib-ts/__tests__/hooks/plan-review.hook.test.ts +71 -0
- package/dist/templates/cc-native/_cc-native/lib-ts/__tests__/json-parser.test.ts +99 -0
- package/dist/templates/cc-native/_cc-native/lib-ts/__tests__/orchestrator-agent.test.ts +288 -0
- package/dist/templates/cc-native/_cc-native/lib-ts/__tests__/orchestrator.test.ts +48 -0
- package/dist/templates/cc-native/_cc-native/lib-ts/__tests__/reviewers.test.ts +32 -0
- package/dist/templates/cc-native/_cc-native/lib-ts/__tests__/state.test.ts +124 -0
- package/dist/templates/cc-native/_cc-native/lib-ts/__tests__/verdict.test.ts +93 -0
- package/dist/templates/cc-native/_cc-native/lib-ts/agent-selection.ts +163 -0
- package/dist/templates/cc-native/_cc-native/lib-ts/aggregate-agents.ts +6 -14
- package/dist/templates/cc-native/_cc-native/{artifacts/lib → lib-ts/artifacts}/format.ts +597 -599
- package/dist/templates/cc-native/_cc-native/{artifacts/lib → lib-ts/artifacts}/index.ts +26 -26
- package/dist/templates/cc-native/_cc-native/{artifacts/lib → lib-ts/artifacts}/tracker.ts +106 -107
- package/dist/templates/cc-native/_cc-native/{artifacts/lib → lib-ts/artifacts}/write.ts +118 -119
- package/dist/templates/cc-native/_cc-native/lib-ts/artifacts.ts +21 -0
- package/dist/templates/cc-native/_cc-native/lib-ts/cc-native-state.ts +16 -15
- package/dist/templates/cc-native/_cc-native/lib-ts/cli-output-parser.ts +132 -10
- package/dist/templates/cc-native/_cc-native/lib-ts/constants.ts +6 -6
- package/dist/templates/cc-native/_cc-native/{plan-review/lib → lib-ts}/corroboration.ts +119 -119
- package/dist/templates/cc-native/_cc-native/lib-ts/debug.ts +1 -2
- package/dist/templates/cc-native/_cc-native/{plan-review/lib → lib-ts}/graduation.ts +132 -132
- package/dist/templates/cc-native/_cc-native/lib-ts/index.ts +88 -86
- package/dist/templates/cc-native/_cc-native/lib-ts/json-parser.ts +5 -6
- package/dist/templates/cc-native/_cc-native/{plan-review/lib → lib-ts}/orchestrator.ts +70 -70
- package/dist/templates/cc-native/_cc-native/{plan-review/lib → lib-ts}/output-builder.ts +130 -121
- package/dist/templates/cc-native/_cc-native/lib-ts/package-lock.json +1679 -0
- package/dist/templates/cc-native/_cc-native/lib-ts/package.json +24 -0
- package/dist/templates/cc-native/_cc-native/lib-ts/plan-discovery.ts +4 -4
- package/dist/templates/cc-native/_cc-native/lib-ts/plan-enhancement.ts +1 -6
- package/dist/templates/cc-native/_cc-native/{plan-review/lib → lib-ts}/plan-questions.ts +101 -101
- package/dist/templates/cc-native/_cc-native/{plan-review/lib → lib-ts}/review-pipeline.ts +511 -543
- package/dist/templates/cc-native/_cc-native/lib-ts/reviewers/__tests__/agent-providers.test.ts +262 -0
- package/dist/templates/cc-native/_cc-native/{plan-review/lib → lib-ts}/reviewers/agent.ts +71 -85
- package/dist/templates/{core/lib-ts/agent-exec → cc-native/_cc-native/lib-ts/reviewers/base}/base-agent.ts +138 -152
- package/dist/templates/cc-native/_cc-native/{plan-review/lib → lib-ts}/reviewers/index.ts +12 -12
- package/dist/templates/cc-native/_cc-native/{plan-review/lib → lib-ts}/reviewers/providers/claude-agent.ts +66 -57
- package/dist/templates/cc-native/_cc-native/{plan-review/lib → lib-ts}/reviewers/providers/codex-agent.ts +185 -200
- package/dist/templates/cc-native/_cc-native/{plan-review/lib → lib-ts}/reviewers/providers/gemini-agent.ts +39 -40
- package/dist/templates/cc-native/_cc-native/{plan-review/lib → lib-ts}/reviewers/providers/orchestrator-claude-agent.ts +196 -224
- package/dist/templates/cc-native/_cc-native/{plan-review/lib → lib-ts}/reviewers/schemas.ts +201 -201
- package/dist/templates/cc-native/_cc-native/{plan-review/lib → lib-ts}/reviewers/types.ts +21 -23
- package/dist/templates/cc-native/_cc-native/lib-ts/rlm/__tests__/hyde.test.ts +365 -0
- package/dist/templates/cc-native/_cc-native/lib-ts/rlm/__tests__/ollama-client.test.ts +223 -0
- package/dist/templates/cc-native/_cc-native/lib-ts/rlm/embedding-indexer.ts +12 -16
- package/dist/templates/cc-native/_cc-native/lib-ts/rlm/hyde.ts +3 -2
- package/dist/templates/cc-native/_cc-native/lib-ts/rlm/index.ts +31 -31
- package/dist/templates/cc-native/_cc-native/lib-ts/rlm/logger.ts +6 -7
- package/dist/templates/cc-native/_cc-native/lib-ts/rlm/ollama-client.ts +7 -9
- package/dist/templates/cc-native/_cc-native/lib-ts/rlm/retrieval-pipeline.ts +14 -17
- package/dist/templates/cc-native/_cc-native/lib-ts/rlm/transcript-indexer.ts +37 -41
- package/dist/templates/cc-native/_cc-native/lib-ts/rlm/transcript-loader.ts +33 -43
- package/dist/templates/cc-native/_cc-native/lib-ts/rlm/transcript-searcher.ts +20 -20
- package/dist/templates/cc-native/_cc-native/lib-ts/rlm/types.ts +8 -9
- package/dist/templates/cc-native/_cc-native/lib-ts/rlm/vector-store.ts +3 -4
- package/dist/templates/cc-native/_cc-native/lib-ts/settings.ts +50 -126
- package/dist/templates/cc-native/_cc-native/lib-ts/state.ts +19 -21
- package/dist/templates/cc-native/_cc-native/lib-ts/types.ts +13 -88
- package/dist/templates/cc-native/_cc-native/{plan-review/lib → lib-ts}/verdict.ts +72 -72
- package/dist/templates/cc-native/_cc-native/plan-review/CLAUDE.md +35 -0
- package/dist/templates/cc-native/_cc-native/plan-review/lib/agent-selection.ts +1 -1
- package/dist/templates/cc-native/_cc-native/scripts/council_debate.ts +242 -0
- package/dist/templates/cc-native/_cc-native/scripts/council_debate_simple.ts +294 -0
- package/dist/templates/cc-native/_cc-native/{plan-review/workflows → workflows}/specdev.md +9 -9
- package/dist/templates/core/.claude/skills/codex/SKILL.md +25 -0
- package/dist/templates/core/.claude/skills/devin/SKILL.md +25 -0
- package/dist/templates/core/.claude/skills/handoff/SKILL.md +11 -0
- package/dist/templates/core/.claude/skills/handoff-resume/SKILL.md +11 -0
- package/dist/templates/core/.claude/skills/meta-plan/SKILL.md +13 -0
- package/dist/templates/core/.codex/skills/codex/SKILL.md +13 -0
- package/dist/templates/core/.codex/skills/devin/SKILL.md +19 -0
- package/dist/templates/core/.codex/skills/handoff/SKILL.md +11 -0
- package/dist/templates/core/.codex/skills/handoff-resume/SKILL.md +11 -0
- package/dist/templates/core/.codex/{workflows/meta-plan.md → skills/meta-plan/SKILL.md} +6 -0
- package/dist/templates/core/{.cognition → .devin}/AGENTS.md +2 -2
- package/dist/templates/core/.devin/skills/codex/SKILL.md +19 -0
- package/dist/templates/core/.devin/skills/devin/SKILL.md +13 -0
- package/dist/templates/core/.devin/skills/handoff/SKILL.md +11 -0
- package/dist/templates/core/.devin/skills/handoff-resume/SKILL.md +11 -0
- package/dist/templates/core/.devin/skills/meta-plan/SKILL.md +13 -0
- package/dist/templates/core/.windsurf/workflows/handoff-resume.md +9 -0
- package/dist/templates/core/hooks-ts/archive_plan.ts +1 -21
- package/dist/templates/core/hooks-ts/file-suggestion.ts +1 -19
- package/dist/templates/core/hooks-ts/pre_compact.ts +5 -18
- package/dist/templates/core/lib-ts/context/context-store.ts +29 -2
- package/dist/templates/core/lib-ts/hooks/hook-utils.ts +11 -0
- package/dist/templates/core/lib-ts/hooks/session-end-logic.ts +2 -13
- package/dist/templates/core/lib-ts/runtime/agent-launcher.ts +74 -0
- package/dist/templates/core/lib-ts/runtime/aiw-cli.ts +4 -2
- package/dist/templates/core/lib-ts/runtime/cli-args.ts +18 -4
- package/dist/templates/core/lib-ts/runtime/inference.ts +3 -15
- package/dist/templates/core/lib-ts/runtime/models.ts +7 -0
- package/dist/templates/core/lib-ts/runtime/state-io.ts +9 -4
- package/dist/templates/core/lib-ts/runtime/utils.ts +30 -1
- package/dist/templates/core/lib-ts/schemas.ts +233 -0
- package/dist/templates/core/scripts/resolve-run.ts +34 -2
- package/dist/templates/core/scripts/status_line.ts +1 -1
- package/dist/templates/core/skills/codex/CLAUDE.md +9 -4
- package/dist/templates/core/skills/codex/SKILL.md +6 -0
- package/dist/templates/core/skills/codex/lib/codex-watcher.ts +3 -10
- package/dist/templates/core/skills/codex/scripts/launch-codex.ts +26 -26
- package/dist/templates/core/skills/devin/CLAUDE.md +63 -6
- package/dist/templates/core/skills/devin/lib/devin-watcher.ts +116 -96
- package/dist/templates/core/skills/devin/scripts/launch-devin.ts +22 -21
- package/dist/templates/core/skills/handoff-system/CLAUDE.md +1 -1
- package/oclif.manifest.json +4 -4
- package/package.json +4 -4
- package/dist/lib/base-command.d.ts +0 -1
- package/dist/lib/base-command.js +0 -1
- package/dist/lib/env-compat.d.ts +0 -18
- package/dist/lib/env-compat.js +0 -23
- package/dist/lib/launch-options.d.ts +0 -1
- package/dist/lib/launch-options.js +0 -1
- package/dist/lib/stdin.d.ts +0 -48
- package/dist/lib/stdin.js +0 -60
- package/dist/templates/cc-native/_cc-native/CLAUDE.md +0 -73
- package/dist/templates/cc-native/_cc-native/artifacts/CLAUDE.md +0 -64
- package/dist/templates/cc-native/_cc-native/lib-ts/CLAUDE.md +0 -70
- package/dist/templates/cc-native/_cc-native/plan-review/CODING-STANDARDS-CHECKLIST.md +0 -75
- package/dist/templates/cc-native/_cc-native/plan-review/agents/CLAUDE.md +0 -143
- package/dist/templates/cc-native/_cc-native/plan-review/agents/PLAN-ORCHESTRATOR.md +0 -213
- package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-questions/PLAN-QUESTIONER.md +0 -70
- package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/ARCH-EVOLUTION.md +0 -62
- package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/ARCH-PATTERNS.md +0 -61
- package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/ARCH-STRUCTURE.md +0 -62
- package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/ASSUMPTION-TRACER.md +0 -56
- package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/CLARITY-AUDITOR.md +0 -53
- package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/COMPLETENESS-FEASIBILITY.md +0 -66
- package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/COMPLETENESS-GAPS.md +0 -70
- package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/COMPLETENESS-ORDERING.md +0 -62
- package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/CONSTRAINT-VALIDATOR.md +0 -72
- package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/DESIGN-ADR-VALIDATOR.md +0 -61
- package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/DESIGN-SCALE-MATCHER.md +0 -64
- package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/DEVILS-ADVOCATE.md +0 -56
- package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/DOCUMENTATION-PHILOSOPHY.md +0 -86
- package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/HANDOFF-READINESS.md +0 -59
- package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/HIDDEN-COMPLEXITY.md +0 -58
- package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/INCREMENTAL-DELIVERY.md +0 -66
- package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/RISK-DEPENDENCY.md +0 -62
- package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/RISK-FMEA.md +0 -66
- package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/RISK-PREMORTEM.md +0 -71
- package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/RISK-REVERSIBILITY.md +0 -74
- package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/SCOPE-BOUNDARY.md +0 -77
- package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/SIMPLICITY-GUARDIAN.md +0 -62
- package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/SKEPTIC.md +0 -68
- package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/TESTDRIVEN-BEHAVIOR-AUDITOR.md +0 -61
- package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/TESTDRIVEN-CHARACTERIZATION.md +0 -71
- package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/TESTDRIVEN-FIRST-VALIDATOR.md +0 -61
- package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/TESTDRIVEN-PYRAMID-ANALYZER.md +0 -61
- package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/TRADEOFF-COSTS.md +0 -67
- package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/TRADEOFF-STAKEHOLDERS.md +0 -65
- package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/VERIFY-COVERAGE.md +0 -74
- package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/VERIFY-STRENGTH.md +0 -69
- package/dist/templates/cc-native/_cc-native/plan-review/lib/reviewers/base/base-agent.ts +0 -7
- package/dist/templates/core/.codex/workflows/codex.md +0 -17
- package/dist/templates/core/.codex/workflows/handoff.md +0 -5
- package/dist/templates/core/lib-ts/agent-exec/backends/headless.ts +0 -34
- package/dist/templates/core/lib-ts/agent-exec/backends/index.ts +0 -6
- package/dist/templates/core/lib-ts/agent-exec/backends/tmux.ts +0 -148
- package/dist/templates/core/lib-ts/agent-exec/execution-backend.ts +0 -50
- package/dist/templates/core/lib-ts/agent-exec/index.ts +0 -6
- package/dist/templates/core/lib-ts/agent-exec/structured-output.ts +0 -165
- /package/dist/templates/core/{.cognition → .devin}/config.json +0 -0
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PromptFileManager — owns prompt file lifecycle (creation, cleanup).
|
|
3
|
+
* Replaces scattered writeFileSync calls for prompt temp files.
|
|
4
|
+
*/
|
|
5
|
+
import { writeFileSync } from 'node:fs';
|
|
6
|
+
import * as fs from 'node:fs';
|
|
7
|
+
import path from 'node:path';
|
|
8
|
+
export class PromptFileManager {
|
|
9
|
+
files = [];
|
|
10
|
+
tempDir;
|
|
11
|
+
now;
|
|
12
|
+
pid;
|
|
13
|
+
constructor(options) {
|
|
14
|
+
this.tempDir = options.tempDir;
|
|
15
|
+
this.now = options.now;
|
|
16
|
+
this.pid = options.pid;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Write prompt text to a temp file and return the path.
|
|
20
|
+
*/
|
|
21
|
+
materialize(promptText) {
|
|
22
|
+
const filePath = path.join(this.tempDir, `aiwcli-prompt-${this.now()}-${this.pid}.txt`);
|
|
23
|
+
writeFileSync(filePath, promptText, { encoding: 'utf8', mode: 0o600 });
|
|
24
|
+
this.files.push(filePath);
|
|
25
|
+
return filePath;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Clean up all created prompt files. Call in finally block.
|
|
29
|
+
*/
|
|
30
|
+
cleanup() {
|
|
31
|
+
for (const filePath of this.files) {
|
|
32
|
+
try {
|
|
33
|
+
fs.unlinkSync(filePath);
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
// Best-effort cleanup.
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
this.files.length = 0;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared agent-launcher utilities used by Codex, Devin, and future agent skills.
|
|
3
|
+
* Extracted from codex skill to avoid duplication across agent launch scripts.
|
|
4
|
+
*/
|
|
5
|
+
import type { ContextState } from "../types.js";
|
|
6
|
+
export declare const POLL_INTERVAL_MS = 2000;
|
|
7
|
+
export declare const POLL_TIMEOUT_MS = 3000;
|
|
8
|
+
export declare const WAIT_TIMEOUT_MS_DEFAULT = 14400000;
|
|
9
|
+
type PaneBackend = "tmux" | "window" | "exec";
|
|
10
|
+
export interface PaneWatchTarget {
|
|
11
|
+
backend?: PaneBackend;
|
|
12
|
+
paneId?: string;
|
|
13
|
+
sentinelPath?: string;
|
|
14
|
+
}
|
|
15
|
+
export declare function sleep(ms: number): Promise<void>;
|
|
16
|
+
/**
|
|
17
|
+
* Print to stderr (shared by agent launch scripts).
|
|
18
|
+
*/
|
|
19
|
+
export declare function eprint(...args: unknown[]): void;
|
|
20
|
+
/**
|
|
21
|
+
* Best-effort cleanup of a sentinel directory.
|
|
22
|
+
*/
|
|
23
|
+
export declare function cleanupSentinel(sentinelPath: string | null | undefined): void;
|
|
24
|
+
/**
|
|
25
|
+
* Case-sensitive (or case-insensitive on Windows) path comparison.
|
|
26
|
+
*/
|
|
27
|
+
export declare function samePath(a: string, b: string): boolean;
|
|
28
|
+
/**
|
|
29
|
+
* Heuristic check for LLM output that isn't a real summary.
|
|
30
|
+
*/
|
|
31
|
+
export declare function looksLikeBadSummary(output: string): boolean;
|
|
32
|
+
/**
|
|
33
|
+
* Return a deterministic summary file path for a given agent prefix + task ID.
|
|
34
|
+
* Callers can advertise this path before the session finishes so consumers
|
|
35
|
+
* know where to look for the summary once it's written.
|
|
36
|
+
*/
|
|
37
|
+
export declare function getWellKnownSummaryPath(prefix: string, taskId: string, projectRoot?: string): string;
|
|
38
|
+
export declare function persistSummary(summary: string, prefix: string, sessionId?: string, taskId?: string, projectRoot?: string): string | null;
|
|
39
|
+
/** Fallback plan discovery: scan all context plan dirs by mtime. */
|
|
40
|
+
export declare function findLatestPlanByMtime(projectRoot: string): string | null;
|
|
41
|
+
export declare function buildFileModeBootstrapPrompt(targetPath: string, sourceLabel: "plan" | "file", extraPrompt?: string, orientation?: string): string;
|
|
42
|
+
export declare function resolveContextForLaunch(contextFlag: string | undefined, projectRoot: string): ContextState | null;
|
|
43
|
+
export interface WritePromptFileOpts {
|
|
44
|
+
ctx?: ContextState | null;
|
|
45
|
+
extraPrompt?: string;
|
|
46
|
+
projectRoot: string;
|
|
47
|
+
tempFilePrefix: string;
|
|
48
|
+
}
|
|
49
|
+
export interface WriteFileRefPromptFileOpts extends WritePromptFileOpts {
|
|
50
|
+
fileReferencePath: string;
|
|
51
|
+
label: "plan" | "file";
|
|
52
|
+
}
|
|
53
|
+
export interface WriteInlinePromptFileOpts extends WritePromptFileOpts {
|
|
54
|
+
text: string;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Build a file-reference bootstrap prompt and write it to a temp file.
|
|
58
|
+
* Returns the temp file path.
|
|
59
|
+
*/
|
|
60
|
+
export declare function writeFileRefPromptFile(opts: WriteFileRefPromptFileOpts): string;
|
|
61
|
+
/**
|
|
62
|
+
* Write inline text to a temp file, prepend context orientation, append extra prompt.
|
|
63
|
+
* Returns the temp file path.
|
|
64
|
+
*/
|
|
65
|
+
export declare function writeInlinePromptFile(opts: WriteInlinePromptFileOpts): string;
|
|
66
|
+
export declare function waitForPaneClose(target: string | PaneWatchTarget, timeoutMs?: number): Promise<void>;
|
|
67
|
+
export {};
|
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared agent-launcher utilities used by Codex, Devin, and future agent skills.
|
|
3
|
+
* Extracted from codex skill to avoid duplication across agent launch scripts.
|
|
4
|
+
*/
|
|
5
|
+
import * as fs from "node:fs";
|
|
6
|
+
import * as os from "node:os";
|
|
7
|
+
import path from "node:path";
|
|
8
|
+
import { logDebug, logWarn } from "./logger.js";
|
|
9
|
+
import { execFileAsync, findExecutable } from "./subprocess-utils.js";
|
|
10
|
+
import { buildExternalAgentContext } from "../context/context-formatter.js";
|
|
11
|
+
import { getContextBySessionId, getContext } from "../context/context-store.js";
|
|
12
|
+
// ---------------------------------------------------------------------------
|
|
13
|
+
// Constants
|
|
14
|
+
// ---------------------------------------------------------------------------
|
|
15
|
+
export const POLL_INTERVAL_MS = 2000;
|
|
16
|
+
export const POLL_TIMEOUT_MS = 3000;
|
|
17
|
+
export const WAIT_TIMEOUT_MS_DEFAULT = 14_400_000;
|
|
18
|
+
// ---------------------------------------------------------------------------
|
|
19
|
+
// Generic Helpers
|
|
20
|
+
// ---------------------------------------------------------------------------
|
|
21
|
+
export function sleep(ms) {
|
|
22
|
+
return new Promise((resolve) => {
|
|
23
|
+
setTimeout(resolve, ms);
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Print to stderr (shared by agent launch scripts).
|
|
28
|
+
*/
|
|
29
|
+
export function eprint(...args) {
|
|
30
|
+
process.stderr.write(args.map(String).join(" ") + "\n");
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Best-effort cleanup of a sentinel directory.
|
|
34
|
+
*/
|
|
35
|
+
export function cleanupSentinel(sentinelPath) {
|
|
36
|
+
if (!sentinelPath)
|
|
37
|
+
return;
|
|
38
|
+
try {
|
|
39
|
+
const dir = path.dirname(sentinelPath);
|
|
40
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
41
|
+
}
|
|
42
|
+
catch { /* best-effort */ }
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Case-sensitive (or case-insensitive on Windows) path comparison.
|
|
46
|
+
*/
|
|
47
|
+
export function samePath(a, b) {
|
|
48
|
+
const left = path.resolve(a);
|
|
49
|
+
const right = path.resolve(b);
|
|
50
|
+
if (process.platform === "win32") {
|
|
51
|
+
return left.toLowerCase() === right.toLowerCase();
|
|
52
|
+
}
|
|
53
|
+
return left === right;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Heuristic check for LLM output that isn't a real summary.
|
|
57
|
+
*/
|
|
58
|
+
export function looksLikeBadSummary(output) {
|
|
59
|
+
const normalized = output.toLowerCase();
|
|
60
|
+
return (normalized.includes("don't see") ||
|
|
61
|
+
normalized.includes("no output") ||
|
|
62
|
+
normalized.includes("could you provide") ||
|
|
63
|
+
normalized.includes("paste"));
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Return a deterministic summary file path for a given agent prefix + task ID.
|
|
67
|
+
* Callers can advertise this path before the session finishes so consumers
|
|
68
|
+
* know where to look for the summary once it's written.
|
|
69
|
+
*/
|
|
70
|
+
export function getWellKnownSummaryPath(prefix, taskId, projectRoot) {
|
|
71
|
+
const sessionKey = projectRoot
|
|
72
|
+
? path.basename(projectRoot)
|
|
73
|
+
: "unknown";
|
|
74
|
+
const dir = path.join(os.tmpdir(), "aiw-agent-output", sessionKey);
|
|
75
|
+
return path.join(dir, `${prefix}-${taskId}.md`).replaceAll("\\", "/");
|
|
76
|
+
}
|
|
77
|
+
export function persistSummary(summary, prefix, sessionId, taskId, projectRoot) {
|
|
78
|
+
try {
|
|
79
|
+
const suffix = sessionId
|
|
80
|
+
? sessionId.replaceAll(/[^a-zA-Z0-9_-]/g, "").slice(0, 8)
|
|
81
|
+
: String(process.pid);
|
|
82
|
+
const filePath = path.join(os.tmpdir(), `${prefix}-summary-${Date.now()}-${suffix}.md`);
|
|
83
|
+
fs.writeFileSync(filePath, summary, "utf8");
|
|
84
|
+
// Also write to the well-known path for deterministic discovery.
|
|
85
|
+
if (taskId) {
|
|
86
|
+
try {
|
|
87
|
+
const wkPath = getWellKnownSummaryPath(prefix, taskId, projectRoot);
|
|
88
|
+
fs.mkdirSync(path.dirname(wkPath), { recursive: true });
|
|
89
|
+
fs.writeFileSync(wkPath, summary, "utf8");
|
|
90
|
+
}
|
|
91
|
+
catch {
|
|
92
|
+
logWarn("agent-launcher", "Failed to write well-known summary path");
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
return filePath.replaceAll("\\", "/");
|
|
96
|
+
}
|
|
97
|
+
catch (error) {
|
|
98
|
+
logWarn("agent-launcher", `Failed to persist summary: ${String(error)}`);
|
|
99
|
+
return null;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
// ---------------------------------------------------------------------------
|
|
103
|
+
// Plan Discovery
|
|
104
|
+
// ---------------------------------------------------------------------------
|
|
105
|
+
/** Fallback plan discovery: scan all context plan dirs by mtime. */
|
|
106
|
+
export function findLatestPlanByMtime(projectRoot) {
|
|
107
|
+
const contextsDir = path.join(projectRoot, "_output", "contexts");
|
|
108
|
+
if (!fs.existsSync(contextsDir))
|
|
109
|
+
return null;
|
|
110
|
+
let best = null;
|
|
111
|
+
for (const ctxEntry of fs.readdirSync(contextsDir)) {
|
|
112
|
+
if (ctxEntry.startsWith("_"))
|
|
113
|
+
continue;
|
|
114
|
+
const plansDir = path.join(contextsDir, ctxEntry, "plans");
|
|
115
|
+
if (!fs.existsSync(plansDir))
|
|
116
|
+
continue;
|
|
117
|
+
for (const file of fs.readdirSync(plansDir)) {
|
|
118
|
+
if (!file.endsWith(".md"))
|
|
119
|
+
continue;
|
|
120
|
+
const fullPath = path.join(plansDir, file);
|
|
121
|
+
try {
|
|
122
|
+
const mtime = fs.statSync(fullPath).mtimeMs;
|
|
123
|
+
if (!best || mtime > best.mtime) {
|
|
124
|
+
best = { path: fullPath, mtime };
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
catch { /* skip unreadable */ }
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
return best?.path ?? null;
|
|
131
|
+
}
|
|
132
|
+
// ---------------------------------------------------------------------------
|
|
133
|
+
// Bootstrap Prompt Construction
|
|
134
|
+
// ---------------------------------------------------------------------------
|
|
135
|
+
export function buildFileModeBootstrapPrompt(targetPath, sourceLabel, extraPrompt, orientation) {
|
|
136
|
+
const absolutePath = path.resolve(targetPath);
|
|
137
|
+
const sourceTitle = sourceLabel === "plan" ? "Plan Source" : "File Source";
|
|
138
|
+
const sections = ["## Startup Brief", ""];
|
|
139
|
+
if (orientation?.trim()) {
|
|
140
|
+
sections.push(orientation.trim(), "", "---", "");
|
|
141
|
+
}
|
|
142
|
+
sections.push(`## ${sourceTitle}`, "", `Primary input path: ${absolutePath}`, "", "Read this file directly from disk before taking action.", "Treat its contents as the source of truth.", "Do not ask for the file contents to be pasted inline.");
|
|
143
|
+
if (extraPrompt?.trim()) {
|
|
144
|
+
sections.push("", "## Additional Instructions", "", extraPrompt.trim());
|
|
145
|
+
}
|
|
146
|
+
return sections.join("\n");
|
|
147
|
+
}
|
|
148
|
+
// ---------------------------------------------------------------------------
|
|
149
|
+
// Context Resolution
|
|
150
|
+
// ---------------------------------------------------------------------------
|
|
151
|
+
export function resolveContextForLaunch(contextFlag, projectRoot) {
|
|
152
|
+
if (contextFlag) {
|
|
153
|
+
return getContext(contextFlag, projectRoot) ?? null;
|
|
154
|
+
}
|
|
155
|
+
const sessionId = process.env.CLAUDE_SESSION_ID;
|
|
156
|
+
if (sessionId) {
|
|
157
|
+
return getContextBySessionId(sessionId, projectRoot) ?? null;
|
|
158
|
+
}
|
|
159
|
+
return null;
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Build a file-reference bootstrap prompt and write it to a temp file.
|
|
163
|
+
* Returns the temp file path.
|
|
164
|
+
*/
|
|
165
|
+
export function writeFileRefPromptFile(opts) {
|
|
166
|
+
let orientation = "";
|
|
167
|
+
if (opts.ctx) {
|
|
168
|
+
try {
|
|
169
|
+
orientation = buildExternalAgentContext(opts.ctx, opts.projectRoot);
|
|
170
|
+
}
|
|
171
|
+
catch {
|
|
172
|
+
logWarn("agent-launcher", `Context orientation build failed for ${opts.ctx.id}`);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
const bootstrap = buildFileModeBootstrapPrompt(opts.fileReferencePath, opts.label, opts.extraPrompt, orientation);
|
|
176
|
+
const tempFile = path.join(os.tmpdir(), `${opts.tempFilePrefix}-file-ref-${Date.now()}.md`);
|
|
177
|
+
fs.writeFileSync(tempFile, bootstrap, "utf8");
|
|
178
|
+
return tempFile;
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Write inline text to a temp file, prepend context orientation, append extra prompt.
|
|
182
|
+
* Returns the temp file path.
|
|
183
|
+
*/
|
|
184
|
+
export function writeInlinePromptFile(opts) {
|
|
185
|
+
let content = opts.text;
|
|
186
|
+
if (opts.ctx) {
|
|
187
|
+
try {
|
|
188
|
+
const orientation = buildExternalAgentContext(opts.ctx, opts.projectRoot);
|
|
189
|
+
content = `${orientation}\n\n---\n\n${content}`;
|
|
190
|
+
}
|
|
191
|
+
catch {
|
|
192
|
+
logWarn("agent-launcher", `Context orientation prepend failed for ${opts.ctx.id}`);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
if (opts.extraPrompt?.trim()) {
|
|
196
|
+
content = `${content}\n\n---\n\n## Additional Instructions\n\n${opts.extraPrompt}`;
|
|
197
|
+
}
|
|
198
|
+
const tempFile = path.join(os.tmpdir(), `${opts.tempFilePrefix}-prompt-${Date.now()}.md`);
|
|
199
|
+
fs.writeFileSync(tempFile, content, "utf8");
|
|
200
|
+
return tempFile;
|
|
201
|
+
}
|
|
202
|
+
// ---------------------------------------------------------------------------
|
|
203
|
+
// Pane Watching
|
|
204
|
+
// ---------------------------------------------------------------------------
|
|
205
|
+
async function waitForSentinelClose(sentinelPath, timeoutMs) {
|
|
206
|
+
const deadline = Date.now() + timeoutMs;
|
|
207
|
+
while (true) {
|
|
208
|
+
if (fs.existsSync(sentinelPath))
|
|
209
|
+
return;
|
|
210
|
+
if (Date.now() >= deadline) {
|
|
211
|
+
logDebug("agent-launcher", `watch timeout reached waiting for sentinel ${sentinelPath}`);
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
const remainingMs = deadline - Date.now();
|
|
215
|
+
await sleep(Math.max(0, Math.min(POLL_INTERVAL_MS, remainingMs)));
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
function normalizeWatchTarget(target) {
|
|
219
|
+
if (typeof target === "string") {
|
|
220
|
+
return { backend: "tmux", paneId: target };
|
|
221
|
+
}
|
|
222
|
+
return target;
|
|
223
|
+
}
|
|
224
|
+
export async function waitForPaneClose(target, timeoutMs = WAIT_TIMEOUT_MS_DEFAULT) {
|
|
225
|
+
const watch = normalizeWatchTarget(target);
|
|
226
|
+
if (watch.sentinelPath) {
|
|
227
|
+
await waitForSentinelClose(watch.sentinelPath, timeoutMs);
|
|
228
|
+
return;
|
|
229
|
+
}
|
|
230
|
+
const backend = watch.backend ?? "tmux";
|
|
231
|
+
const paneId = watch.paneId ?? "";
|
|
232
|
+
if (backend !== "tmux") {
|
|
233
|
+
logDebug("agent-launcher", `No pane watcher for backend=${backend}; continuing without wait`);
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
if (!paneId)
|
|
237
|
+
return;
|
|
238
|
+
const tmuxPath = findExecutable("tmux");
|
|
239
|
+
if (!tmuxPath) {
|
|
240
|
+
logWarn("agent-launcher", `tmux unavailable while watching pane ${paneId}`);
|
|
241
|
+
return;
|
|
242
|
+
}
|
|
243
|
+
const deadline = Date.now() + timeoutMs;
|
|
244
|
+
while (true) {
|
|
245
|
+
if (Date.now() >= deadline) {
|
|
246
|
+
logDebug("agent-launcher", `watch timeout reached for pane ${paneId} after ${timeoutMs}ms`);
|
|
247
|
+
return;
|
|
248
|
+
}
|
|
249
|
+
const result = await execFileAsync(tmuxPath, ["list-panes", "-a", "-F", "#{pane_id}"], {
|
|
250
|
+
timeout: POLL_TIMEOUT_MS,
|
|
251
|
+
});
|
|
252
|
+
if (result.exitCode !== 0) {
|
|
253
|
+
logDebug("agent-launcher", `list-panes failed; assuming pane closed (${result.stderr.trim() || "no stderr"})`);
|
|
254
|
+
return;
|
|
255
|
+
}
|
|
256
|
+
const activePaneIds = result.stdout.split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
|
|
257
|
+
if (!activePaneIds.includes(paneId))
|
|
258
|
+
return;
|
|
259
|
+
const remainingMs = deadline - Date.now();
|
|
260
|
+
await sleep(Math.max(0, Math.min(POLL_INTERVAL_MS, remainingMs)));
|
|
261
|
+
}
|
|
262
|
+
}
|
|
@@ -30,6 +30,8 @@ export async function aiwLaunch(options) {
|
|
|
30
30
|
const args = ["launch"];
|
|
31
31
|
if (options.codex)
|
|
32
32
|
args.push("--codex");
|
|
33
|
+
if (options.devin)
|
|
34
|
+
args.push("--devin");
|
|
33
35
|
if (options.wait)
|
|
34
36
|
args.push("--wait");
|
|
35
37
|
args.push("--json");
|
|
@@ -55,7 +57,7 @@ function parseJsonResult(result) {
|
|
|
55
57
|
return {
|
|
56
58
|
launched: Boolean(parsed.launched),
|
|
57
59
|
backend: String(parsed.backend ?? "exec"),
|
|
58
|
-
paneId: parsed.paneId ?? null,
|
|
60
|
+
paneId: parsed.handle ?? parsed.paneId ?? null,
|
|
59
61
|
sentinelPath: parsed.sentinelPath ?? null,
|
|
60
62
|
exitCode: typeof parsed.exitCode === "number" ? parsed.exitCode : null,
|
|
61
63
|
reason: parsed.reason ?? null,
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import type { PreflightCommandConfig } from "./preflight.js";
|
|
7
7
|
export type InvocationMode = "structured" | "print" | "preflight";
|
|
8
|
-
export type CliProvider = "claude" | "codex";
|
|
8
|
+
export type CliProvider = "claude" | "codex" | "devin";
|
|
9
9
|
export type ModelTier = "fast" | "standard" | "smart";
|
|
10
10
|
declare const VALID_SANDBOXES: readonly ["read-only", "workspace-write", "danger-full-access"];
|
|
11
11
|
export type CodexSandbox = (typeof VALID_SANDBOXES)[number];
|
|
@@ -39,6 +39,7 @@ export interface CliInvocation {
|
|
|
39
39
|
}
|
|
40
40
|
export declare const MODEL_TIERS: Record<ModelTier, string>;
|
|
41
41
|
export declare const CODEX_MODEL_TIERS: Record<ModelTier, string>;
|
|
42
|
+
export declare const DEVIN_MODEL_TIERS: Record<ModelTier, string>;
|
|
42
43
|
export declare const TIER_TIMEOUTS: Record<ModelTier, number>;
|
|
43
44
|
export declare function isModelTier(value: string): value is ModelTier;
|
|
44
45
|
export declare function resolveModel(model: string | ModelTier): string;
|
|
@@ -46,10 +47,12 @@ export declare function resolveModelForProvider(model: string | ModelTier, provi
|
|
|
46
47
|
export declare function getTierTimeout(tier: ModelTier): number;
|
|
47
48
|
/** Resolve a Codex model: tier resolution + pass-through. No aliases (those are skill-specific). */
|
|
48
49
|
export declare function resolveCodexModel(input: string): string;
|
|
50
|
+
/** Resolve a Devin model: tier resolution + pass-through. No aliases (those are skill-specific). */
|
|
51
|
+
export declare function resolveDevinModel(input: string): string;
|
|
49
52
|
export declare function buildCliInvocation(spec: CliArgSpec | CodexReplSpec): CliInvocation;
|
|
50
53
|
export declare function preflightSpec(provider: CliProvider, model: string): CliArgSpec;
|
|
51
54
|
export declare function inferenceSpec(model: string | ModelTier): CliArgSpec;
|
|
52
55
|
export declare function reviewSpec(provider: CliProvider, model: string, schema: Record<string, unknown>, systemPrompt?: string): CliArgSpec;
|
|
53
56
|
export declare function codexReplSpec(model?: string, sandbox?: CodexSandbox, yolo?: boolean): CodexReplSpec;
|
|
54
57
|
export declare function preflightCommandConfig(provider: CliProvider): PreflightCommandConfig;
|
|
55
|
-
export { CLAUDE_MODELS, CODEX_MODELS } from "./models.js";
|
|
58
|
+
export { CLAUDE_MODELS, CODEX_MODELS, DEVIN_MODELS } from "./models.js";
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* Single source of truth for Claude CLI and Codex CLI flag patterns,
|
|
4
4
|
* platform quoting, model tier resolution, and env setup.
|
|
5
5
|
*/
|
|
6
|
-
import { CLAUDE_MODELS, CODEX_MODELS } from "./models.js";
|
|
6
|
+
import { CLAUDE_MODELS, CODEX_MODELS, DEVIN_MODELS } from "./models.js";
|
|
7
7
|
import { getInternalSubprocessEnv, shellQuoteWin } from "./subprocess-utils.js";
|
|
8
8
|
const VALID_SANDBOXES = ["read-only", "workspace-write", "danger-full-access"];
|
|
9
9
|
export function isCodexSandbox(value) {
|
|
@@ -22,6 +22,11 @@ export const CODEX_MODEL_TIERS = {
|
|
|
22
22
|
standard: CODEX_MODELS.codex,
|
|
23
23
|
smart: CODEX_MODELS.codex,
|
|
24
24
|
};
|
|
25
|
+
export const DEVIN_MODEL_TIERS = {
|
|
26
|
+
fast: DEVIN_MODELS.sonnet,
|
|
27
|
+
standard: DEVIN_MODELS.swe,
|
|
28
|
+
smart: DEVIN_MODELS.opus,
|
|
29
|
+
};
|
|
25
30
|
export const TIER_TIMEOUTS = {
|
|
26
31
|
fast: 15,
|
|
27
32
|
standard: 30,
|
|
@@ -38,7 +43,11 @@ export function resolveModel(model) {
|
|
|
38
43
|
export function resolveModelForProvider(model, provider) {
|
|
39
44
|
if (!isModelTier(model))
|
|
40
45
|
return model;
|
|
41
|
-
|
|
46
|
+
if (provider === "codex")
|
|
47
|
+
return CODEX_MODEL_TIERS[model];
|
|
48
|
+
if (provider === "devin")
|
|
49
|
+
return DEVIN_MODEL_TIERS[model];
|
|
50
|
+
return MODEL_TIERS[model];
|
|
42
51
|
}
|
|
43
52
|
export function getTierTimeout(tier) {
|
|
44
53
|
return TIER_TIMEOUTS[tier];
|
|
@@ -49,6 +58,12 @@ export function resolveCodexModel(input) {
|
|
|
49
58
|
return CODEX_MODEL_TIERS[input];
|
|
50
59
|
return input;
|
|
51
60
|
}
|
|
61
|
+
/** Resolve a Devin model: tier resolution + pass-through. No aliases (those are skill-specific). */
|
|
62
|
+
export function resolveDevinModel(input) {
|
|
63
|
+
if (isModelTier(input))
|
|
64
|
+
return DEVIN_MODEL_TIERS[input];
|
|
65
|
+
return input;
|
|
66
|
+
}
|
|
52
67
|
// ---------------------------------------------------------------------------
|
|
53
68
|
// Core Builder
|
|
54
69
|
// ---------------------------------------------------------------------------
|
|
@@ -182,4 +197,4 @@ export function preflightCommandConfig(provider) {
|
|
|
182
197
|
input,
|
|
183
198
|
};
|
|
184
199
|
}
|
|
185
|
-
export { CLAUDE_MODELS, CODEX_MODELS } from "./models.js";
|
|
200
|
+
export { CLAUDE_MODELS, CODEX_MODELS, DEVIN_MODELS } from "./models.js";
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import { execFileSync } from "node:child_process";
|
|
7
7
|
import { logDebug, logWarn } from "./logger.js";
|
|
8
|
-
import {
|
|
8
|
+
import { filterStopWords } from "./stop-words.js";
|
|
9
9
|
import { buildCliInvocation, inferenceSpec, isModelTier, resolveModel, getTierTimeout, TIER_TIMEOUTS, } from "./cli-args.js";
|
|
10
10
|
import { CODEX_MODELS } from "./models.js";
|
|
11
11
|
import { execFileAsync } from "./subprocess-utils.js";
|
|
@@ -101,7 +101,7 @@ export function generateSemanticSummary(prompt, timeout = 15) {
|
|
|
101
101
|
summary = summary.replaceAll(/^["']+|["']+$/g, "");
|
|
102
102
|
summary = summary.replace(/[.!?]+$/, "");
|
|
103
103
|
// Filter stop words
|
|
104
|
-
summary = filterStopWords(summary);
|
|
104
|
+
summary = filterStopWords(summary).toLowerCase();
|
|
105
105
|
const words = summary.split(/\s+/);
|
|
106
106
|
if (words.length < 6 || words.length > 12)
|
|
107
107
|
return null;
|
|
@@ -146,7 +146,7 @@ Respond with ONLY a JSON object: {"slug": "your 8-12 word phrase here"}`;
|
|
|
146
146
|
* Uses Codex Spark first, then falls back to current fast tier for resilience.
|
|
147
147
|
* See SPEC.md §6.3
|
|
148
148
|
*/
|
|
149
|
-
export function generateContextIdSlug(prompt, timeout =
|
|
149
|
+
export function generateContextIdSlug(prompt, timeout = 8) {
|
|
150
150
|
const truncated = prompt.slice(0, 500);
|
|
151
151
|
const sparkResult = inference(CONTEXT_ID_SLUG_PROMPT, truncated, "fast", timeout, { model: CONTEXT_ID_PRIMARY_MODEL });
|
|
152
152
|
if (!sparkResult.success || !sparkResult.output) {
|
|
@@ -249,14 +249,3 @@ export async function codexInferAsync(prompt, model, options) {
|
|
|
249
249
|
latency_ms: latencyMs,
|
|
250
250
|
};
|
|
251
251
|
}
|
|
252
|
-
/**
|
|
253
|
-
* Filter stop words from text.
|
|
254
|
-
* See SPEC.md §6.4
|
|
255
|
-
*/
|
|
256
|
-
function filterStopWords(text) {
|
|
257
|
-
return text
|
|
258
|
-
.toLowerCase()
|
|
259
|
-
.split(/\s+/)
|
|
260
|
-
.filter((w) => !STOP_WORDS.has(w) && w.length > 1)
|
|
261
|
-
.join(" ");
|
|
262
|
-
}
|
|
@@ -6,7 +6,8 @@
|
|
|
6
6
|
import type { ContextState } from "../types.js";
|
|
7
7
|
/**
|
|
8
8
|
* Serialize a ContextState for JSON output.
|
|
9
|
-
* Omits
|
|
9
|
+
* Omits undefined keys but preserves null (semantically meaningful in the schema).
|
|
10
|
+
* Keeps false, 0, empty string, and empty arrays.
|
|
10
11
|
*/
|
|
11
12
|
export declare function toDict(state: ContextState): Record<string, unknown>;
|
|
12
13
|
/**
|
|
@@ -8,6 +8,7 @@ import path from "node:path";
|
|
|
8
8
|
import { atomicWrite } from "./atomic-write.js";
|
|
9
9
|
import { getContextDir } from "./constants.js";
|
|
10
10
|
import { logWarn } from "./logger.js";
|
|
11
|
+
import { ContextStateSchema } from "../schemas.js";
|
|
11
12
|
/** Mode migration from legacy context_manager values. */
|
|
12
13
|
const MODE_MIGRATION = {
|
|
13
14
|
none: "idle",
|
|
@@ -17,12 +18,13 @@ const MODE_MIGRATION = {
|
|
|
17
18
|
};
|
|
18
19
|
/**
|
|
19
20
|
* Serialize a ContextState for JSON output.
|
|
20
|
-
* Omits
|
|
21
|
+
* Omits undefined keys but preserves null (semantically meaningful in the schema).
|
|
22
|
+
* Keeps false, 0, empty string, and empty arrays.
|
|
21
23
|
*/
|
|
22
24
|
export function toDict(state) {
|
|
23
25
|
const result = {};
|
|
24
26
|
for (const [key, value] of Object.entries(state)) {
|
|
25
|
-
if (value !==
|
|
27
|
+
if (value !== undefined) {
|
|
26
28
|
result[key] = value;
|
|
27
29
|
}
|
|
28
30
|
}
|
|
@@ -96,6 +98,11 @@ export function readStateJson(contextId, projectRoot) {
|
|
|
96
98
|
const raw = fs.readFileSync(sp, "utf8");
|
|
97
99
|
const data = JSON.parse(raw);
|
|
98
100
|
migrateConsumedFlags(data); // Migrate before dictToState
|
|
101
|
+
const parsed = ContextStateSchema.safeParse(data);
|
|
102
|
+
if (!parsed.success) {
|
|
103
|
+
logWarn("state_io", `Schema validation failed for '${contextId}': ${parsed.error.message}`);
|
|
104
|
+
// Fail-open: still attempt to reconstruct state from raw data
|
|
105
|
+
}
|
|
99
106
|
return dictToState(data);
|
|
100
107
|
}
|
|
101
108
|
catch (error) {
|
|
@@ -109,8 +116,6 @@ export function readStateJson(contextId, projectRoot) {
|
|
|
109
116
|
*/
|
|
110
117
|
export function writeStateJson(contextId, state, projectRoot) {
|
|
111
118
|
const sp = statePath(contextId, projectRoot);
|
|
112
|
-
const dir = path.dirname(sp);
|
|
113
|
-
fs.mkdirSync(dir, { recursive: true });
|
|
114
119
|
const content = JSON.stringify(toDict(state), null, 2);
|
|
115
120
|
// fsync: false — state.json is reconstructable from context folder contents
|
|
116
121
|
return atomicWrite(sp, content, 2, [500, 1000], false);
|
|
@@ -52,3 +52,11 @@ export declare function generateSlug(text: string, maxLen?: number, fallbackSlug
|
|
|
52
52
|
* See SPEC.md §14.2
|
|
53
53
|
*/
|
|
54
54
|
export declare function generateContextId(summary: string, existingIds?: Set<string>): string;
|
|
55
|
+
/**
|
|
56
|
+
* Get .md files in a directory sorted by mtime (newest first).
|
|
57
|
+
*/
|
|
58
|
+
export declare function getMdFilesByMtime(dir: string): string[];
|
|
59
|
+
/**
|
|
60
|
+
* Get the most recently modified .md file in a directory.
|
|
61
|
+
*/
|
|
62
|
+
export declare function mostRecentMd(dir: string): string | null;
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
* Core utilities for shared context management.
|
|
3
3
|
* See SPEC.md §14.2, §14.3
|
|
4
4
|
*/
|
|
5
|
+
import * as fs from "node:fs";
|
|
6
|
+
import path from "node:path";
|
|
5
7
|
import { sanitizeTitle } from "./constants.js";
|
|
6
8
|
import { logDebug, logError, logWarn } from "./logger.js";
|
|
7
9
|
import { STOP_WORDS } from "./stop-words.js";
|
|
@@ -99,7 +101,7 @@ export function generateSlug(text, maxLen = 150, fallbackSlug = "context") {
|
|
|
99
101
|
// Tier 1: AI inference via generateContextIdSlug (sync — uses execFileSync)
|
|
100
102
|
try {
|
|
101
103
|
// eslint-disable-next-line @typescript-eslint/no-require-imports, no-undef
|
|
102
|
-
const { generateContextIdSlug } = require("./inference
|
|
104
|
+
const { generateContextIdSlug } = require("./inference");
|
|
103
105
|
const aiSlug = generateContextIdSlug(text);
|
|
104
106
|
if (aiSlug) {
|
|
105
107
|
const filteredWords = aiSlug
|
|
@@ -160,3 +162,31 @@ export function generateContextId(summary, existingIds) {
|
|
|
160
162
|
}
|
|
161
163
|
return `${baseId}-${counter}`;
|
|
162
164
|
}
|
|
165
|
+
/**
|
|
166
|
+
* Get .md files in a directory sorted by mtime (newest first).
|
|
167
|
+
*/
|
|
168
|
+
export function getMdFilesByMtime(dir) {
|
|
169
|
+
try {
|
|
170
|
+
if (!fs.existsSync(dir))
|
|
171
|
+
return [];
|
|
172
|
+
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
173
|
+
return entries
|
|
174
|
+
.filter(e => e.isFile() && e.name.endsWith(".md"))
|
|
175
|
+
.map(e => {
|
|
176
|
+
const fullPath = path.join(dir, e.name);
|
|
177
|
+
const stat = fs.statSync(fullPath);
|
|
178
|
+
return { path: fullPath, mtime: stat.mtimeMs };
|
|
179
|
+
})
|
|
180
|
+
.sort((a, b) => b.mtime - a.mtime)
|
|
181
|
+
.map(f => f.path);
|
|
182
|
+
}
|
|
183
|
+
catch {
|
|
184
|
+
return [];
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Get the most recently modified .md file in a directory.
|
|
189
|
+
*/
|
|
190
|
+
export function mostRecentMd(dir) {
|
|
191
|
+
return getMdFilesByMtime(dir)[0] ?? null;
|
|
192
|
+
}
|