@namzu/cli 26.3.0 → 28.0.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/CHANGELOG.md +271 -0
- package/README.md +67 -46
- package/dist/bin.js +7 -0
- package/dist/bin.js.map +1 -1
- package/dist/checkpoints/store.d.ts +17 -4
- package/dist/checkpoints/store.d.ts.map +1 -1
- package/dist/checkpoints/store.js +20 -5
- package/dist/checkpoints/store.js.map +1 -1
- package/dist/cli.d.ts +2 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +124 -14
- package/dist/cli.js.map +1 -1
- package/dist/commands/acp.d.ts +23 -1
- package/dist/commands/acp.d.ts.map +1 -1
- package/dist/commands/acp.js +41 -2
- package/dist/commands/acp.js.map +1 -1
- package/dist/commands/drain.d.ts +69 -2
- package/dist/commands/drain.d.ts.map +1 -1
- package/dist/commands/drain.js +216 -136
- package/dist/commands/drain.js.map +1 -1
- package/dist/commands/eval.js +1 -1
- package/dist/commands/eval.js.map +1 -1
- package/dist/commands/{run-flags.d.ts → exec-flags.d.ts} +36 -28
- package/dist/commands/exec-flags.d.ts.map +1 -0
- package/dist/commands/{run-flags.js → exec-flags.js} +35 -27
- package/dist/commands/exec-flags.js.map +1 -0
- package/dist/commands/exec-json.d.ts +75 -0
- package/dist/commands/exec-json.d.ts.map +1 -0
- package/dist/commands/exec-json.js +473 -0
- package/dist/commands/exec-json.js.map +1 -0
- package/dist/commands/exec.d.ts +42 -0
- package/dist/commands/exec.d.ts.map +1 -0
- package/dist/commands/exec.js +683 -0
- package/dist/commands/exec.js.map +1 -0
- package/dist/commands/host-queries.d.ts +12 -0
- package/dist/commands/host-queries.d.ts.map +1 -0
- package/dist/commands/host-queries.js +149 -0
- package/dist/commands/host-queries.js.map +1 -0
- package/dist/commands/prior-messages.js +1 -1
- package/dist/commands/prior-messages.js.map +1 -1
- package/dist/commands/provider-wait.d.ts +5 -5
- package/dist/commands/provider-wait.d.ts.map +1 -1
- package/dist/commands/provider-wait.js +2 -2
- package/dist/commands/registry.d.ts.map +1 -1
- package/dist/commands/registry.js +2 -0
- package/dist/commands/registry.js.map +1 -1
- package/dist/commands/resident-flags.d.ts +2 -2
- package/dist/commands/resident-flags.d.ts.map +1 -1
- package/dist/commands/resident-flags.js +4 -2
- package/dist/commands/resident-flags.js.map +1 -1
- package/dist/commands/resident-learning.js +1 -1
- package/dist/commands/resident-learning.js.map +1 -1
- package/dist/commands/resident.d.ts.map +1 -1
- package/dist/commands/resident.js +3 -2
- package/dist/commands/resident.js.map +1 -1
- package/dist/commands/serve.js +2 -2
- package/dist/commands/serve.js.map +1 -1
- package/dist/commands/skills.js +1 -1
- package/dist/commands/skills.js.map +1 -1
- package/dist/commands/state.js +8 -8
- package/dist/commands/state.js.map +1 -1
- package/dist/commands/stdin.d.ts +5 -5
- package/dist/commands/stdin.js +5 -5
- package/dist/commands/types.d.ts +2 -0
- package/dist/commands/types.d.ts.map +1 -1
- package/dist/config/load.d.ts +1 -1
- package/dist/config/load.d.ts.map +1 -1
- package/dist/config/load.js +36 -5
- package/dist/config/load.js.map +1 -1
- package/dist/config/schema.d.ts +59 -20
- package/dist/config/schema.d.ts.map +1 -1
- package/dist/config/schema.js.map +1 -1
- package/dist/config/tool-result-screens.js +1 -1
- package/dist/config/turn-guards.d.ts +23 -0
- package/dist/config/turn-guards.d.ts.map +1 -0
- package/dist/config/turn-guards.js +46 -0
- package/dist/config/turn-guards.js.map +1 -0
- package/dist/context/directories.d.ts +37 -0
- package/dist/context/directories.d.ts.map +1 -0
- package/dist/context/directories.js +69 -0
- package/dist/context/directories.js.map +1 -0
- package/dist/context/environment.d.ts +55 -0
- package/dist/context/environment.d.ts.map +1 -1
- package/dist/context/environment.js +96 -0
- package/dist/context/environment.js.map +1 -1
- package/dist/context/project-tracker.d.ts +3 -3
- package/dist/context/project-tracker.d.ts.map +1 -1
- package/dist/context/project-tracker.js +3 -3
- package/dist/context/project-tracker.js.map +1 -1
- package/dist/context/project.d.ts +2 -2
- package/dist/context/project.js +2 -2
- package/dist/context/sandbox.d.ts +22 -3
- package/dist/context/sandbox.d.ts.map +1 -1
- package/dist/context/sandbox.js +42 -4
- package/dist/context/sandbox.js.map +1 -1
- package/dist/doctor/checks/chain.d.ts +1 -1
- package/dist/doctor/checks/chain.js +7 -7
- package/dist/doctor/checks/chain.js.map +1 -1
- package/dist/doctor/checks/invariants.d.ts +2 -2
- package/dist/doctor/checks/invariants.js +5 -5
- package/dist/doctor/checks/invariants.js.map +1 -1
- package/dist/doctor/checks/logging.js +1 -1
- package/dist/doctor/checks/logging.js.map +1 -1
- package/dist/doctor/checks/sandbox.js +1 -1
- package/dist/doctor/checks/sandbox.js.map +1 -1
- package/dist/doctor/checks/session-export.d.ts +1 -1
- package/dist/doctor/checks/session-export.js +2 -2
- package/dist/doctor/checks/session-export.js.map +1 -1
- package/dist/doctor/checks/telemetry.d.ts +1 -1
- package/dist/doctor/checks/telemetry.js +1 -1
- package/dist/doctor/registry.js +2 -2
- package/dist/doctor/registry.js.map +1 -1
- package/dist/exit-codes.d.ts +2 -2
- package/dist/exit-codes.js +2 -2
- package/dist/integrations/mcp/servers.d.ts +1 -1
- package/dist/integrations/providers/access.d.ts +4 -1
- package/dist/integrations/providers/access.d.ts.map +1 -1
- package/dist/integrations/providers/access.js +6 -3
- package/dist/integrations/providers/access.js.map +1 -1
- package/dist/integrations/providers/chain-capabilities.d.ts +6 -6
- package/dist/integrations/providers/chain-capabilities.js +8 -8
- package/dist/integrations/providers/chain-capabilities.js.map +1 -1
- package/dist/integrations/providers/register.d.ts +1 -1
- package/dist/integrations/providers/register.js +1 -1
- package/dist/integrations/providers/registry.d.ts +1 -1
- package/dist/integrations/providers/zen-catalogue.d.ts +100 -0
- package/dist/integrations/providers/zen-catalogue.d.ts.map +1 -0
- package/dist/integrations/providers/zen-catalogue.js +196 -0
- package/dist/integrations/providers/zen-catalogue.js.map +1 -0
- package/dist/integrations/resident/inspection.d.ts +4 -1
- package/dist/integrations/resident/inspection.d.ts.map +1 -1
- package/dist/integrations/resident/inspection.js +53 -34
- package/dist/integrations/resident/inspection.js.map +1 -1
- package/dist/integrations/resident/learning-storage.d.ts +7 -2
- package/dist/integrations/resident/learning-storage.d.ts.map +1 -1
- package/dist/integrations/resident/learning-storage.js +12 -8
- package/dist/integrations/resident/learning-storage.js.map +1 -1
- package/dist/integrations/resident/runner-launch.d.ts +3 -3
- package/dist/integrations/resident/runner-launch.d.ts.map +1 -1
- package/dist/integrations/resident/runner-store.d.ts +1 -1
- package/dist/integrations/resident/runner-store.d.ts.map +1 -1
- package/dist/integrations/resident/runner-store.js +5 -2
- package/dist/integrations/resident/runner-store.js.map +1 -1
- package/dist/integrations/resident/runner-worker.js +23 -0
- package/dist/integrations/resident/runner-worker.js.map +1 -1
- package/dist/integrations/resident/session-log-reads.d.ts +37 -0
- package/dist/integrations/resident/session-log-reads.d.ts.map +1 -0
- package/dist/integrations/resident/session-log-reads.js +125 -0
- package/dist/integrations/resident/session-log-reads.js.map +1 -0
- package/dist/integrations/resident/session-step.d.ts +4 -2
- package/dist/integrations/resident/session-step.d.ts.map +1 -1
- package/dist/integrations/resident/session-step.js +16 -14
- package/dist/integrations/resident/session-step.js.map +1 -1
- package/dist/integrations/resident/storage.d.ts +23 -1
- package/dist/integrations/resident/storage.d.ts.map +1 -1
- package/dist/integrations/resident/storage.js +60 -17
- package/dist/integrations/resident/storage.js.map +1 -1
- package/dist/integrations/resident/tool-evidence.d.ts +4 -2
- package/dist/integrations/resident/tool-evidence.d.ts.map +1 -1
- package/dist/integrations/resident/tool-evidence.js +36 -30
- package/dist/integrations/resident/tool-evidence.js.map +1 -1
- package/dist/integrations/resident/verification.d.ts +2 -2
- package/dist/integrations/resident/verification.d.ts.map +1 -1
- package/dist/integrations/resident/verification.js +4 -4
- package/dist/integrations/resident/verification.js.map +1 -1
- package/dist/integrations/sessions/checkpoint-view.d.ts +13 -0
- package/dist/integrations/sessions/checkpoint-view.d.ts.map +1 -0
- package/dist/integrations/sessions/checkpoint-view.js +48 -0
- package/dist/integrations/sessions/checkpoint-view.js.map +1 -0
- package/dist/integrations/sessions/context-inventory.js +1 -1
- package/dist/integrations/sessions/context-inventory.js.map +1 -1
- package/dist/integrations/sessions/conversation-search.d.ts +16 -20
- package/dist/integrations/sessions/conversation-search.d.ts.map +1 -1
- package/dist/integrations/sessions/conversation-search.js +305 -731
- package/dist/integrations/sessions/conversation-search.js.map +1 -1
- package/dist/integrations/sessions/evidence-page-validation.d.ts +4 -4
- package/dist/integrations/sessions/evidence-page-validation.d.ts.map +1 -1
- package/dist/integrations/sessions/evidence-page-validation.js +1 -1
- package/dist/integrations/sessions/evidence-page-validation.js.map +1 -1
- package/dist/integrations/sessions/evidence-recall.d.ts +40 -2
- package/dist/integrations/sessions/evidence-recall.d.ts.map +1 -1
- package/dist/integrations/sessions/evidence-recall.js +41 -97
- package/dist/integrations/sessions/evidence-recall.js.map +1 -1
- package/dist/integrations/sessions/store.d.ts +153 -85
- package/dist/integrations/sessions/store.d.ts.map +1 -1
- package/dist/integrations/sessions/store.js +414 -484
- package/dist/integrations/sessions/store.js.map +1 -1
- package/dist/integrations/sessions/task-context.d.ts +15 -2
- package/dist/integrations/sessions/task-context.d.ts.map +1 -1
- package/dist/integrations/sessions/task-context.js +34 -11
- package/dist/integrations/sessions/task-context.js.map +1 -1
- package/dist/integrations/sessions/transcript-export.d.ts +13 -6
- package/dist/integrations/sessions/transcript-export.d.ts.map +1 -1
- package/dist/integrations/sessions/transcript-export.js +148 -263
- package/dist/integrations/sessions/transcript-export.js.map +1 -1
- package/dist/integrations/state/home.d.ts +4 -16
- package/dist/integrations/state/home.d.ts.map +1 -1
- package/dist/integrations/state/home.js +6 -42
- package/dist/integrations/state/home.js.map +1 -1
- package/dist/integrations/state/project.d.ts +6 -7
- package/dist/integrations/state/project.d.ts.map +1 -1
- package/dist/integrations/state/project.js +7 -9
- package/dist/integrations/state/project.js.map +1 -1
- package/dist/integrations/state/report.d.ts +27 -41
- package/dist/integrations/state/report.d.ts.map +1 -1
- package/dist/integrations/state/report.js +172 -464
- package/dist/integrations/state/report.js.map +1 -1
- package/dist/integrations/state/retention.d.ts +18 -0
- package/dist/integrations/state/retention.d.ts.map +1 -0
- package/dist/integrations/state/retention.js +18 -0
- package/dist/integrations/state/retention.js.map +1 -0
- package/dist/integrations/subagents/activity.d.ts +36 -31
- package/dist/integrations/subagents/activity.d.ts.map +1 -1
- package/dist/integrations/subagents/activity.js +27 -23
- package/dist/integrations/subagents/activity.js.map +1 -1
- package/dist/integrations/subagents/batches.d.ts +91 -0
- package/dist/integrations/subagents/batches.d.ts.map +1 -0
- package/dist/integrations/subagents/batches.js +172 -0
- package/dist/integrations/subagents/batches.js.map +1 -0
- package/dist/integrations/subagents/parent.d.ts +26 -11
- package/dist/integrations/subagents/parent.d.ts.map +1 -1
- package/dist/integrations/subagents/parent.js +13 -28
- package/dist/integrations/subagents/parent.js.map +1 -1
- package/dist/integrations/subagents/policy.d.ts +2 -2
- package/dist/integrations/subagents/policy.d.ts.map +1 -1
- package/dist/integrations/subagents/policy.js +2 -2
- package/dist/integrations/subagents/policy.js.map +1 -1
- package/dist/integrations/subagents/replay.d.ts +91 -26
- package/dist/integrations/subagents/replay.d.ts.map +1 -1
- package/dist/integrations/subagents/replay.js +216 -114
- package/dist/integrations/subagents/replay.js.map +1 -1
- package/dist/integrations/subagents/runtime.d.ts +50 -26
- package/dist/integrations/subagents/runtime.d.ts.map +1 -1
- package/dist/integrations/subagents/runtime.js +132 -126
- package/dist/integrations/subagents/runtime.js.map +1 -1
- package/dist/integrations/subagents/saved-agents.d.ts +57 -0
- package/dist/integrations/subagents/saved-agents.d.ts.map +1 -0
- package/dist/integrations/subagents/saved-agents.js +102 -0
- package/dist/integrations/subagents/saved-agents.js.map +1 -0
- package/dist/integrations/subagents/slash.d.ts +55 -0
- package/dist/integrations/subagents/slash.d.ts.map +1 -0
- package/dist/integrations/subagents/slash.js +45 -0
- package/dist/integrations/subagents/slash.js.map +1 -0
- package/dist/integrations/telemetry/session-export.d.ts +6 -6
- package/dist/integrations/telemetry/session-export.d.ts.map +1 -1
- package/dist/integrations/telemetry/session-export.js +2 -2
- package/dist/integrations/web/search.d.ts +1 -1
- package/dist/logging.d.ts +5 -5
- package/dist/logging.js +6 -6
- package/dist/memory/presentation.d.ts +11 -0
- package/dist/memory/presentation.d.ts.map +1 -1
- package/dist/memory/presentation.js +25 -0
- package/dist/memory/presentation.js.map +1 -1
- package/dist/memory/store.d.ts +13 -7
- package/dist/memory/store.d.ts.map +1 -1
- package/dist/memory/store.js +37 -11
- package/dist/memory/store.js.map +1 -1
- package/dist/memory/typed.d.ts +116 -0
- package/dist/memory/typed.d.ts.map +1 -0
- package/dist/memory/typed.js +336 -0
- package/dist/memory/typed.js.map +1 -0
- package/dist/permissions/checks.d.ts +1 -1
- package/dist/permissions/checks.js +1 -1
- package/dist/permissions/headless-trust.d.ts +4 -4
- package/dist/permissions/headless-trust.d.ts.map +1 -1
- package/dist/permissions/headless-trust.js +6 -6
- package/dist/permissions/headless-trust.js.map +1 -1
- package/dist/permissions/mode.d.ts +4 -4
- package/dist/permissions/mode.js +1 -1
- package/dist/permissions/rules.d.ts +1 -1
- package/dist/permissions/rules.js +1 -1
- package/dist/termination.d.ts +75 -0
- package/dist/termination.d.ts.map +1 -0
- package/dist/termination.js +143 -0
- package/dist/termination.js.map +1 -0
- package/dist/tui/AgentExplorer.d.ts +2 -2
- package/dist/tui/AgentExplorer.js +4 -4
- package/dist/tui/AgentExplorer.js.map +1 -1
- package/dist/tui/App.d.ts +9 -1
- package/dist/tui/App.d.ts.map +1 -1
- package/dist/tui/App.js +456 -307
- package/dist/tui/App.js.map +1 -1
- package/dist/tui/LiveActivity.d.ts +1 -1
- package/dist/tui/LiveActivity.d.ts.map +1 -1
- package/dist/tui/PermissionOverlay.d.ts +8 -0
- package/dist/tui/PermissionOverlay.d.ts.map +1 -1
- package/dist/tui/PermissionOverlay.js +25 -2
- package/dist/tui/PermissionOverlay.js.map +1 -1
- package/dist/tui/Picker.js +1 -1
- package/dist/tui/agent.d.ts +211 -135
- package/dist/tui/agent.d.ts.map +1 -1
- package/dist/tui/agent.js +535 -316
- package/dist/tui/agent.js.map +1 -1
- package/dist/tui/conversation-evidence-view.js +3 -3
- package/dist/tui/conversation-evidence-view.js.map +1 -1
- package/dist/tui/conversation-history.d.ts +4 -21
- package/dist/tui/conversation-history.d.ts.map +1 -1
- package/dist/tui/conversation-history.js +4 -28
- package/dist/tui/conversation-history.js.map +1 -1
- package/dist/tui/index.d.ts.map +1 -1
- package/dist/tui/index.js +27 -1
- package/dist/tui/index.js.map +1 -1
- package/dist/tui/log-pane.js +1 -1
- package/dist/tui/markdownParser.d.ts +1 -1
- package/dist/tui/markdownParser.js +1 -1
- package/dist/tui/permission-review.d.ts +16 -0
- package/dist/tui/permission-review.d.ts.map +1 -1
- package/dist/tui/permission-review.js +25 -2
- package/dist/tui/permission-review.js.map +1 -1
- package/dist/tui/slashCommands.d.ts +30 -41
- package/dist/tui/slashCommands.d.ts.map +1 -1
- package/dist/tui/slashCommands.js +75 -66
- package/dist/tui/slashCommands.js.map +1 -1
- package/dist/tui/status-panel-layout.js +1 -1
- package/dist/tui/status-panel-layout.js.map +1 -1
- package/dist/tui/{run-interruption.d.ts → turn-interruption.d.ts} +4 -4
- package/dist/tui/turn-interruption.d.ts.map +1 -0
- package/dist/tui/{run-interruption.js → turn-interruption.js} +20 -20
- package/dist/tui/turn-interruption.js.map +1 -0
- package/dist/tui/turn-limits-settings.d.ts +39 -0
- package/dist/tui/turn-limits-settings.d.ts.map +1 -0
- package/dist/tui/{run-limits-settings.js → turn-limits-settings.js} +18 -18
- package/dist/tui/turn-limits-settings.js.map +1 -0
- package/dist/tui/types.d.ts +3 -3
- package/dist/tui/types.d.ts.map +1 -1
- package/dist/user-commands/store.d.ts +4 -4
- package/dist/user-commands/store.js +5 -5
- package/dist/user-commands/store.js.map +1 -1
- package/package.json +6 -6
- package/dist/commands/run-flags.d.ts.map +0 -1
- package/dist/commands/run-flags.js.map +0 -1
- package/dist/commands/run-stream.d.ts +0 -65
- package/dist/commands/run-stream.d.ts.map +0 -1
- package/dist/commands/run-stream.js +0 -603
- package/dist/commands/run-stream.js.map +0 -1
- package/dist/commands/run.d.ts +0 -39
- package/dist/commands/run.d.ts.map +0 -1
- package/dist/commands/run.js +0 -533
- package/dist/commands/run.js.map +0 -1
- package/dist/config/run-limits.d.ts +0 -11
- package/dist/config/run-limits.d.ts.map +0 -1
- package/dist/config/run-limits.js +0 -64
- package/dist/config/run-limits.js.map +0 -1
- package/dist/integrations/sessions/compaction-evidence.d.ts +0 -5
- package/dist/integrations/sessions/compaction-evidence.d.ts.map +0 -1
- package/dist/integrations/sessions/compaction-evidence.js +0 -59
- package/dist/integrations/sessions/compaction-evidence.js.map +0 -1
- package/dist/integrations/sessions/database.d.ts +0 -5
- package/dist/integrations/sessions/database.d.ts.map +0 -1
- package/dist/integrations/sessions/database.js +0 -34
- package/dist/integrations/sessions/database.js.map +0 -1
- package/dist/integrations/sessions/paths.d.ts +0 -7
- package/dist/integrations/sessions/paths.d.ts.map +0 -1
- package/dist/integrations/sessions/paths.js +0 -14
- package/dist/integrations/sessions/paths.js.map +0 -1
- package/dist/integrations/sessions/run-discovery.d.ts +0 -24
- package/dist/integrations/sessions/run-discovery.d.ts.map +0 -1
- package/dist/integrations/sessions/run-discovery.js +0 -142
- package/dist/integrations/sessions/run-discovery.js.map +0 -1
- package/dist/integrations/sessions/turn-evidence.d.ts +0 -129
- package/dist/integrations/sessions/turn-evidence.d.ts.map +0 -1
- package/dist/integrations/sessions/turn-evidence.js +0 -517
- package/dist/integrations/sessions/turn-evidence.js.map +0 -1
- package/dist/integrations/subagents/history.d.ts +0 -26
- package/dist/integrations/subagents/history.d.ts.map +0 -1
- package/dist/integrations/subagents/history.js +0 -76
- package/dist/integrations/subagents/history.js.map +0 -1
- package/dist/integrations/subagents/runs.d.ts +0 -72
- package/dist/integrations/subagents/runs.d.ts.map +0 -1
- package/dist/integrations/subagents/runs.js +0 -155
- package/dist/integrations/subagents/runs.js.map +0 -1
- package/dist/tui/run-interruption.d.ts.map +0 -1
- package/dist/tui/run-interruption.js.map +0 -1
- package/dist/tui/run-limits-settings.d.ts +0 -39
- package/dist/tui/run-limits-settings.d.ts.map +0 -1
- package/dist/tui/run-limits-settings.js.map +0 -1
|
@@ -0,0 +1,336 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stored memory: the typed, one-file-per-memory store the kernel's memory
|
|
3
|
+
* tools read and write, as the CLI uses it.
|
|
4
|
+
*
|
|
5
|
+
* Four jobs live here. `saveTypedNote` is what `#note` and `/memory add`
|
|
6
|
+
* write through. `composeStoredMemoryPrompt` turns the store's generated index
|
|
7
|
+
* into the prompt section the model sees every turn. `migrateMemoryOnce`
|
|
8
|
+
* moves the JSON store into typed files, once, and offers the project's
|
|
9
|
+
* curated bullets; `importCuratedNotes` copies those when the operator asks,
|
|
10
|
+
* never editing the curated file.
|
|
11
|
+
*
|
|
12
|
+
* The CURATED files (`USER.md`, `MEMORY.md` in the application home and the
|
|
13
|
+
* project) stay what they were: operator-authored text read into every turn.
|
|
14
|
+
* The two are never given the same heading in the prompt.
|
|
15
|
+
*/
|
|
16
|
+
import { createHash } from 'node:crypto';
|
|
17
|
+
import { access, readFile, rename, writeFile } from 'node:fs/promises';
|
|
18
|
+
import { join } from 'node:path';
|
|
19
|
+
import { DiskMemoryStore, MemoryContentRejectedError, MemoryNameConflictError, slugifyMemoryName, } from '@namzu/sdk';
|
|
20
|
+
import { readMemoryFile } from './io.js';
|
|
21
|
+
import { projectMemoryLocation } from './store.js';
|
|
22
|
+
function firstLine(text, limit) {
|
|
23
|
+
const line = (text.split(/\r?\n/).find((part) => part.trim()) ?? '').replace(/\s+/g, ' ').trim();
|
|
24
|
+
if (line.length <= limit)
|
|
25
|
+
return line;
|
|
26
|
+
let head = line.slice(0, limit - 1);
|
|
27
|
+
if (/[\uD800-\uDBFF]$/.test(head))
|
|
28
|
+
head = head.slice(0, -1);
|
|
29
|
+
return `${head.trimEnd()}…`;
|
|
30
|
+
}
|
|
31
|
+
function digest(text) {
|
|
32
|
+
return createHash('sha256').update(text).digest('hex');
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Save an operator note as a typed memory, default type `project`. A note
|
|
36
|
+
* whose exact text an active memory already holds is not saved twice; the
|
|
37
|
+
* result names the one that holds it.
|
|
38
|
+
*/
|
|
39
|
+
export async function saveTypedNote(store, text, type = 'project') {
|
|
40
|
+
const note = text.trim();
|
|
41
|
+
if (!note)
|
|
42
|
+
return { saved: false, type };
|
|
43
|
+
const candidates = await store.list({ query: note, status: 'active', limit: 20 });
|
|
44
|
+
for (const entry of candidates.entries) {
|
|
45
|
+
const record = await store.getRecord(entry.id);
|
|
46
|
+
if (record?.entry.status === 'active' && record.content.content.trim() === note) {
|
|
47
|
+
return {
|
|
48
|
+
saved: false,
|
|
49
|
+
duplicate: true,
|
|
50
|
+
type: record.entry.type ?? type,
|
|
51
|
+
...(record.entry.name
|
|
52
|
+
? { name: record.entry.name, path: join(store.path, `${record.entry.name}.md`) }
|
|
53
|
+
: {}),
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
const { entry } = await store.create({
|
|
58
|
+
title: firstLine(note, 72),
|
|
59
|
+
summary: firstLine(note, 300),
|
|
60
|
+
description: firstLine(note, 150),
|
|
61
|
+
content: note,
|
|
62
|
+
type,
|
|
63
|
+
metadata: { source: 'operator-note', noteDigest: digest(note) },
|
|
64
|
+
});
|
|
65
|
+
return {
|
|
66
|
+
saved: true,
|
|
67
|
+
type,
|
|
68
|
+
...(entry.name ? { name: entry.name, path: join(store.path, `${entry.name}.md`) } : {}),
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* The prompt section for the stored-memory index, or null when the store
|
|
73
|
+
* holds no active memory. Named so it can never be mistaken for the curated
|
|
74
|
+
* sections beside it.
|
|
75
|
+
*/
|
|
76
|
+
export function composeStoredMemoryPrompt(index) {
|
|
77
|
+
if (!index.text)
|
|
78
|
+
return null;
|
|
79
|
+
return [
|
|
80
|
+
'## Stored memories (index)',
|
|
81
|
+
'',
|
|
82
|
+
'Memories saved in earlier sessions, one line each: `- [name](name.md) — description`. Read one with read_memory (by name) when it bears on the task. Correct or archive a wrong one with update_memory rather than saving a second copy. Memories are point-in-time: verify a file, function or flag a memory names against the current code before relying on it. What earlier turns recorded on their own is not listed here; search_memory finds it.',
|
|
83
|
+
'',
|
|
84
|
+
index.text,
|
|
85
|
+
].join('\n');
|
|
86
|
+
}
|
|
87
|
+
/** Records per curated file when it was offered and imported, so a launch offers it once. */
|
|
88
|
+
const MARKER = 'migration.json';
|
|
89
|
+
async function readMarker(directory) {
|
|
90
|
+
try {
|
|
91
|
+
const parsed = JSON.parse(await readFile(join(directory, MARKER), 'utf8'));
|
|
92
|
+
return parsed !== null && typeof parsed === 'object' ? parsed : {};
|
|
93
|
+
}
|
|
94
|
+
catch (error) {
|
|
95
|
+
if (error.code === 'ENOENT')
|
|
96
|
+
return {};
|
|
97
|
+
throw error;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
/** Merge `state` into the marker's record for `path`, re-reading it first. */
|
|
101
|
+
async function markCuratedFile(directory, path, state) {
|
|
102
|
+
const marker = await readMarker(directory).catch(() => ({}));
|
|
103
|
+
const files = { ...(marker.curatedFiles ?? {}) };
|
|
104
|
+
files[path] = { ...(files[path] ?? {}), ...state };
|
|
105
|
+
await writeFile(join(directory, MARKER), `${JSON.stringify({ ...marker, curatedFiles: files }, null, 2)}\n`, { mode: 0o600 });
|
|
106
|
+
}
|
|
107
|
+
async function exists(path) {
|
|
108
|
+
try {
|
|
109
|
+
await access(path);
|
|
110
|
+
return true;
|
|
111
|
+
}
|
|
112
|
+
catch {
|
|
113
|
+
return false;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
/** Move `path` aside to `path.migrated`, or a numbered name when that is taken. */
|
|
117
|
+
async function retire(path) {
|
|
118
|
+
let target = `${path}.migrated`;
|
|
119
|
+
for (let n = 2; await exists(target); n++)
|
|
120
|
+
target = `${path}.migrated-${n}`;
|
|
121
|
+
try {
|
|
122
|
+
await rename(path, target);
|
|
123
|
+
}
|
|
124
|
+
catch (error) {
|
|
125
|
+
// Another process retired it first.
|
|
126
|
+
if (error.code !== 'ENOENT')
|
|
127
|
+
throw error;
|
|
128
|
+
}
|
|
129
|
+
return target;
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* The text of every top-level bullet (`- text`) in a curated file, each once,
|
|
133
|
+
* in order. No bullet is judged to be a note or not: the file is never
|
|
134
|
+
* changed, so copying one the operator wrote costs a memory they can archive,
|
|
135
|
+
* never a line of their file. A nested bullet belongs to its parent and is not
|
|
136
|
+
* taken; only a bullet's first line is.
|
|
137
|
+
*/
|
|
138
|
+
export function curatedBullets(text) {
|
|
139
|
+
const bullets = new Set();
|
|
140
|
+
for (const line of text.split('\n')) {
|
|
141
|
+
const match = /^- (\S.*)$/.exec(line.replace(/\r$/, ''));
|
|
142
|
+
const bullet = match?.[1]?.trim();
|
|
143
|
+
if (bullet)
|
|
144
|
+
bullets.add(bullet);
|
|
145
|
+
}
|
|
146
|
+
return [...bullets];
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Create the memory for one curated bullet, false when it is already stored.
|
|
150
|
+
*
|
|
151
|
+
* Under the name its text slugs to, first: the store refuses a taken name
|
|
152
|
+
* inside its lock, so two turns copying the same bullet at once write it once,
|
|
153
|
+
* the second finding the first's record by its source digest. A name held by
|
|
154
|
+
* a memory with the same text is that bullet already stored; one held by an
|
|
155
|
+
* unrelated memory falls back to a suffixed name.
|
|
156
|
+
*/
|
|
157
|
+
async function copyBullet(store, bullet, sourceDigest, importedFrom) {
|
|
158
|
+
const params = {
|
|
159
|
+
title: firstLine(bullet, 72),
|
|
160
|
+
summary: firstLine(bullet, 300),
|
|
161
|
+
description: firstLine(bullet, 150),
|
|
162
|
+
content: bullet,
|
|
163
|
+
type: 'project',
|
|
164
|
+
metadata: { source: 'curated-bullet', sourceDigest, importedFrom },
|
|
165
|
+
};
|
|
166
|
+
const name = slugifyMemoryName(bullet);
|
|
167
|
+
try {
|
|
168
|
+
await store.create({ ...params, name });
|
|
169
|
+
return true;
|
|
170
|
+
}
|
|
171
|
+
catch (error) {
|
|
172
|
+
if (!(error instanceof MemoryNameConflictError))
|
|
173
|
+
throw error;
|
|
174
|
+
}
|
|
175
|
+
const holder = await store.getByName(name);
|
|
176
|
+
if (holder?.content.metadata?.sourceDigest === sourceDigest ||
|
|
177
|
+
holder?.content.content.trim() === bullet) {
|
|
178
|
+
return false;
|
|
179
|
+
}
|
|
180
|
+
await store.create(params);
|
|
181
|
+
return true;
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* Move what the JSON store held into typed files, once and safely again, and
|
|
185
|
+
* say once per curated file whether it holds notes that could move.
|
|
186
|
+
*
|
|
187
|
+
* 1. A JSON store (`index.json` + `content/`) in `directory` is imported
|
|
188
|
+
* record by record with its ids, timestamps and status, then moved aside
|
|
189
|
+
* to `index.json.migrated` and `content.migrated`. A record the Markdown
|
|
190
|
+
* store refuses to write — over its size limit, or holding a NUL byte —
|
|
191
|
+
* is reported and stays in the retired files; stopping on it would leave
|
|
192
|
+
* `index.json` in place and the store refusing every operation for good.
|
|
193
|
+
* Any other failure leaves the JSON store where it is, to retry next launch.
|
|
194
|
+
* 2. The project's curated `MEMORY.md` is never changed. When it holds
|
|
195
|
+
* top-level bullets — some may be notes `#note` used to append — the
|
|
196
|
+
* report offers them once per file, since the checkout's file and a
|
|
197
|
+
* subdirectory's own `.namzu/MEMORY.md` are different files, and
|
|
198
|
+
* `/memory import-notes` copies them into typed memories when the
|
|
199
|
+
* operator asks. They stay curated, read into every turn as before, until
|
|
200
|
+
* the operator deletes them from the file.
|
|
201
|
+
*/
|
|
202
|
+
export async function migrateMemoryOnce(options) {
|
|
203
|
+
const { store, directory, cwd } = options;
|
|
204
|
+
const problems = [];
|
|
205
|
+
const skippedRecords = [];
|
|
206
|
+
let importedRecords = 0;
|
|
207
|
+
let notesOffer;
|
|
208
|
+
const indexPath = join(directory, 'index.json');
|
|
209
|
+
if (await exists(indexPath)) {
|
|
210
|
+
try {
|
|
211
|
+
const disk = new DiskMemoryStore({ baseDir: directory, directory });
|
|
212
|
+
const { entries } = await disk.list();
|
|
213
|
+
const refused = [];
|
|
214
|
+
for (const entry of entries) {
|
|
215
|
+
const record = await disk.getRecord(entry.id);
|
|
216
|
+
if (!record)
|
|
217
|
+
continue;
|
|
218
|
+
try {
|
|
219
|
+
if ((await store.importRecord(record, { type: 'project' })) === 'imported') {
|
|
220
|
+
importedRecords++;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
catch (error) {
|
|
224
|
+
if (!(error instanceof MemoryContentRejectedError))
|
|
225
|
+
throw error;
|
|
226
|
+
refused.push({
|
|
227
|
+
id: entry.id,
|
|
228
|
+
title: entry.title,
|
|
229
|
+
reason: error.message,
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
await retire(indexPath);
|
|
234
|
+
const content = join(directory, 'content');
|
|
235
|
+
const retiredContent = (await exists(content)) ? await retire(content) : content;
|
|
236
|
+
for (const record of refused) {
|
|
237
|
+
skippedRecords.push(`"${record.title}" (${record.id}) was not moved: ${record.reason} It is kept in ${join(retiredContent, `${record.id}.json`)}.`);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
catch (error) {
|
|
241
|
+
problems.push(`The JSON memory store in ${directory} was not migrated: ${error instanceof Error ? error.message : String(error)}`);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
try {
|
|
245
|
+
const location = projectMemoryLocation(cwd);
|
|
246
|
+
const marker = await readMarker(directory);
|
|
247
|
+
const state = marker.curatedFiles?.[location.path];
|
|
248
|
+
if (!state?.offeredAt && !state?.importedAt) {
|
|
249
|
+
const text = readMemoryFile(location);
|
|
250
|
+
const bullets = text === null ? [] : curatedBullets(text);
|
|
251
|
+
if (bullets.length > 0) {
|
|
252
|
+
notesOffer = { path: location.path, count: bullets.length };
|
|
253
|
+
await markCuratedFile(directory, location.path, {
|
|
254
|
+
offeredAt: new Date().toISOString(),
|
|
255
|
+
});
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
catch (error) {
|
|
260
|
+
problems.push(`Could not check the project's curated memory for notes: ${error instanceof Error ? error.message : String(error)}`);
|
|
261
|
+
}
|
|
262
|
+
return {
|
|
263
|
+
importedRecords,
|
|
264
|
+
skippedRecords,
|
|
265
|
+
...(notesOffer ? { notesOffer } : {}),
|
|
266
|
+
problems,
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
/**
|
|
270
|
+
* Copy the project's curated bullets into typed memory files, because the
|
|
271
|
+
* operator asked (`/memory import-notes`). The curated file is read, never
|
|
272
|
+
* written: deleting a bullet from it is the operator's call. Idempotent: a
|
|
273
|
+
* bullet already stored — by an earlier or concurrent import, as a `#note`
|
|
274
|
+
* with the same text, or under its name with the same text — is not copied
|
|
275
|
+
* again.
|
|
276
|
+
*/
|
|
277
|
+
export async function importCuratedNotes(options) {
|
|
278
|
+
const { store, directory, cwd } = options;
|
|
279
|
+
const location = projectMemoryLocation(cwd);
|
|
280
|
+
const text = readMemoryFile(location);
|
|
281
|
+
const bullets = text === null ? [] : curatedBullets(text);
|
|
282
|
+
if (bullets.length === 0) {
|
|
283
|
+
return { path: location.path, found: 0, copied: 0, alreadyStored: 0 };
|
|
284
|
+
}
|
|
285
|
+
// Digests of what is stored already, archived memories included: a copy
|
|
286
|
+
// the operator archived stays archived rather than coming back.
|
|
287
|
+
const stored = new Set();
|
|
288
|
+
for (const entry of (await store.list({})).entries) {
|
|
289
|
+
const metadata = (await store.get(entry.id))?.metadata;
|
|
290
|
+
stored.add(metadata?.sourceDigest);
|
|
291
|
+
stored.add(metadata?.noteDigest);
|
|
292
|
+
}
|
|
293
|
+
let copied = 0;
|
|
294
|
+
for (const bullet of bullets) {
|
|
295
|
+
const sourceDigest = digest(bullet);
|
|
296
|
+
if (stored.has(sourceDigest))
|
|
297
|
+
continue;
|
|
298
|
+
if (await copyBullet(store, bullet, sourceDigest, location.path))
|
|
299
|
+
copied++;
|
|
300
|
+
stored.add(sourceDigest);
|
|
301
|
+
}
|
|
302
|
+
await markCuratedFile(directory, location.path, { importedAt: new Date().toISOString() });
|
|
303
|
+
return {
|
|
304
|
+
path: location.path,
|
|
305
|
+
found: bullets.length,
|
|
306
|
+
copied,
|
|
307
|
+
alreadyStored: bullets.length - copied,
|
|
308
|
+
};
|
|
309
|
+
}
|
|
310
|
+
/** Operator notices for a migration; empty when nothing moved, nothing is offered and nothing failed. */
|
|
311
|
+
export function describeMemoryMigration(report, directory) {
|
|
312
|
+
const notices = [];
|
|
313
|
+
if (report.importedRecords > 0) {
|
|
314
|
+
notices.push(`Stored memory: moved ${report.importedRecords} record${report.importedRecords === 1 ? '' : 's'} from the JSON store into Markdown files in ${directory}.`);
|
|
315
|
+
}
|
|
316
|
+
for (const skipped of report.skippedRecords)
|
|
317
|
+
notices.push(`Stored memory: ${skipped}`);
|
|
318
|
+
if (report.notesOffer) {
|
|
319
|
+
const { path, count } = report.notesOffer;
|
|
320
|
+
notices.push(`Stored memory: ${path} has ${count} top-level bullet${count === 1 ? '' : 's'}, some perhaps notes #note saved before notes became typed memory files. They stay curated and still reach every turn. Run /memory import-notes to copy them into ${directory} as typed memories; the curated file is never changed. New #note and /memory add notes are saved there already.`);
|
|
321
|
+
}
|
|
322
|
+
notices.push(...report.problems);
|
|
323
|
+
return notices;
|
|
324
|
+
}
|
|
325
|
+
/** The operator's report for `/memory import-notes`. */
|
|
326
|
+
export function describeCuratedNotesImport(result, directory) {
|
|
327
|
+
if (result.found === 0) {
|
|
328
|
+
return `No top-level bullets to copy in ${result.path}; it is unchanged.`;
|
|
329
|
+
}
|
|
330
|
+
const plural = (n) => (n === 1 ? '' : 's');
|
|
331
|
+
const already = result.alreadyStored > 0
|
|
332
|
+
? ` ${result.alreadyStored} ${result.alreadyStored === 1 ? 'was' : 'were'} already stored and not copied again.`
|
|
333
|
+
: '';
|
|
334
|
+
return `Copied ${result.copied} of ${result.found} bullet${plural(result.found)} from ${result.path} into typed memory files in ${directory}.${already} ${result.path} is unchanged: its bullets are still curated text in every turn. Delete the ones you no longer want there yourself.`;
|
|
335
|
+
}
|
|
336
|
+
//# sourceMappingURL=typed.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"typed.js","sourceRoot":"","sources":["../../src/memory/typed.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AACxC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAA;AACtE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAEhC,OAAO,EACN,eAAe,EAEf,0BAA0B,EAC1B,uBAAuB,EAGvB,iBAAiB,GACjB,MAAM,YAAY,CAAA;AAEnB,OAAO,EAAE,cAAc,EAAE,MAAM,SAAS,CAAA;AACxC,OAAO,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAA;AAalD,SAAS,SAAS,CAAC,IAAY,EAAE,KAAa;IAC7C,MAAM,IAAI,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,CAAA;IAChG,IAAI,IAAI,CAAC,MAAM,IAAI,KAAK;QAAE,OAAO,IAAI,CAAA;IACrC,IAAI,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,GAAG,CAAC,CAAC,CAAA;IACnC,IAAI,kBAAkB,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAA;IAC3D,OAAO,GAAG,IAAI,CAAC,OAAO,EAAE,GAAG,CAAA;AAC5B,CAAC;AAED,SAAS,MAAM,CAAC,IAAY;IAC3B,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;AACvD,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CAClC,KAA0B,EAC1B,IAAY,EACZ,OAAmB,SAAS;IAE5B,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,EAAE,CAAA;IACxB,IAAI,CAAC,IAAI;QAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,CAAA;IACxC,MAAM,UAAU,GAAG,MAAM,KAAK,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,CAAA;IACjF,KAAK,MAAM,KAAK,IAAI,UAAU,CAAC,OAAO,EAAE,CAAC;QACxC,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,CAAC,CAAA;QAC9C,IAAI,MAAM,EAAE,KAAK,CAAC,MAAM,KAAK,QAAQ,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,EAAE,KAAK,IAAI,EAAE,CAAC;YACjF,OAAO;gBACN,KAAK,EAAE,KAAK;gBACZ,SAAS,EAAE,IAAI;gBACf,IAAI,EAAE,MAAM,CAAC,KAAK,CAAC,IAAI,IAAI,IAAI;gBAC/B,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI;oBACpB,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,EAAE;oBAChF,CAAC,CAAC,EAAE,CAAC;aACN,CAAA;QACF,CAAC;IACF,CAAC;IACD,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,KAAK,CAAC,MAAM,CAAC;QACpC,KAAK,EAAE,SAAS,CAAC,IAAI,EAAE,EAAE,CAAC;QAC1B,OAAO,EAAE,SAAS,CAAC,IAAI,EAAE,GAAG,CAAC;QAC7B,WAAW,EAAE,SAAS,CAAC,IAAI,EAAE,GAAG,CAAC;QACjC,OAAO,EAAE,IAAI;QACb,IAAI;QACJ,QAAQ,EAAE,EAAE,MAAM,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,CAAC,IAAI,CAAC,EAAE;KAC/D,CAAC,CAAA;IACF,OAAO;QACN,KAAK,EAAE,IAAI;QACX,IAAI;QACJ,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,GAAG,KAAK,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACvF,CAAA;AACF,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,yBAAyB,CAAC,KAA0B;IACnE,IAAI,CAAC,KAAK,CAAC,IAAI;QAAE,OAAO,IAAI,CAAA;IAC5B,OAAO;QACN,4BAA4B;QAC5B,EAAE;QACF,ybAAyb;QACzb,EAAE;QACF,KAAK,CAAC,IAAI;KACV,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;AACb,CAAC;AA4BD,6FAA6F;AAC7F,MAAM,MAAM,GAAG,gBAAgB,CAAA;AAW/B,KAAK,UAAU,UAAU,CAAC,SAAiB;IAC1C,IAAI,CAAC;QACJ,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,QAAQ,CAAC,IAAI,CAAC,SAAS,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,CAAY,CAAA;QACrF,OAAO,MAAM,KAAK,IAAI,IAAI,OAAO,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAE,MAA0B,CAAC,CAAC,CAAC,EAAE,CAAA;IACxF,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QAChB,IAAK,KAA+B,CAAC,IAAI,KAAK,QAAQ;YAAE,OAAO,EAAE,CAAA;QACjE,MAAM,KAAK,CAAA;IACZ,CAAC;AACF,CAAC;AAED,8EAA8E;AAC9E,KAAK,UAAU,eAAe,CAC7B,SAAiB,EACjB,IAAY,EACZ,KAAuB;IAEvB,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,SAAS,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,CAAoB,CAAC,CAAA;IAC/E,MAAM,KAAK,GAAG,EAAE,GAAG,CAAC,MAAM,CAAC,YAAY,IAAI,EAAE,CAAC,EAAE,CAAA;IAChD,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,EAAE,GAAG,KAAK,EAAE,CAAA;IAClD,MAAM,SAAS,CACd,IAAI,CAAC,SAAS,EAAE,MAAM,CAAC,EACvB,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,GAAG,MAAM,EAAE,YAAY,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAClE,EAAE,IAAI,EAAE,KAAK,EAAE,CACf,CAAA;AACF,CAAC;AAED,KAAK,UAAU,MAAM,CAAC,IAAY;IACjC,IAAI,CAAC;QACJ,MAAM,MAAM,CAAC,IAAI,CAAC,CAAA;QAClB,OAAO,IAAI,CAAA;IACZ,CAAC;IAAC,MAAM,CAAC;QACR,OAAO,KAAK,CAAA;IACb,CAAC;AACF,CAAC;AAED,mFAAmF;AACnF,KAAK,UAAU,MAAM,CAAC,IAAY;IACjC,IAAI,MAAM,GAAG,GAAG,IAAI,WAAW,CAAA;IAC/B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE;QAAE,MAAM,GAAG,GAAG,IAAI,aAAa,CAAC,EAAE,CAAA;IAC3E,IAAI,CAAC;QACJ,MAAM,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,CAAA;IAC3B,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QAChB,oCAAoC;QACpC,IAAK,KAA+B,CAAC,IAAI,KAAK,QAAQ;YAAE,MAAM,KAAK,CAAA;IACpE,CAAC;IACD,OAAO,MAAM,CAAA;AACd,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,cAAc,CAAC,IAAY;IAC1C,MAAM,OAAO,GAAG,IAAI,GAAG,EAAU,CAAA;IACjC,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;QACrC,MAAM,KAAK,GAAG,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,CAAA;QACxD,MAAM,MAAM,GAAG,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAA;QACjC,IAAI,MAAM;YAAE,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAA;IAChC,CAAC;IACD,OAAO,CAAC,GAAG,OAAO,CAAC,CAAA;AACpB,CAAC;AAED;;;;;;;;GAQG;AACH,KAAK,UAAU,UAAU,CACxB,KAA0B,EAC1B,MAAc,EACd,YAAoB,EACpB,YAAoB;IAEpB,MAAM,MAAM,GAAG;QACd,KAAK,EAAE,SAAS,CAAC,MAAM,EAAE,EAAE,CAAC;QAC5B,OAAO,EAAE,SAAS,CAAC,MAAM,EAAE,GAAG,CAAC;QAC/B,WAAW,EAAE,SAAS,CAAC,MAAM,EAAE,GAAG,CAAC;QACnC,OAAO,EAAE,MAAM;QACf,IAAI,EAAE,SAAkB;QACxB,QAAQ,EAAE,EAAE,MAAM,EAAE,gBAAgB,EAAE,YAAY,EAAE,YAAY,EAAE;KAClE,CAAA;IACD,MAAM,IAAI,GAAG,iBAAiB,CAAC,MAAM,CAAC,CAAA;IACtC,IAAI,CAAC;QACJ,MAAM,KAAK,CAAC,MAAM,CAAC,EAAE,GAAG,MAAM,EAAE,IAAI,EAAE,CAAC,CAAA;QACvC,OAAO,IAAI,CAAA;IACZ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QAChB,IAAI,CAAC,CAAC,KAAK,YAAY,uBAAuB,CAAC;YAAE,MAAM,KAAK,CAAA;IAC7D,CAAC;IACD,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,SAAS,CAAC,IAAI,CAAC,CAAA;IAC1C,IACC,MAAM,EAAE,OAAO,CAAC,QAAQ,EAAE,YAAY,KAAK,YAAY;QACvD,MAAM,EAAE,OAAO,CAAC,OAAO,CAAC,IAAI,EAAE,KAAK,MAAM,EACxC,CAAC;QACF,OAAO,KAAK,CAAA;IACb,CAAC;IACD,MAAM,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAA;IAC1B,OAAO,IAAI,CAAA;AACZ,CAAC;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,OAKvC;IACA,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE,GAAG,EAAE,GAAG,OAAO,CAAA;IACzC,MAAM,QAAQ,GAAa,EAAE,CAAA;IAC7B,MAAM,cAAc,GAAa,EAAE,CAAA;IACnC,IAAI,eAAe,GAAG,CAAC,CAAA;IACvB,IAAI,UAA+C,CAAA;IAEnD,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,EAAE,YAAY,CAAC,CAAA;IAC/C,IAAI,MAAM,MAAM,CAAC,SAAS,CAAC,EAAE,CAAC;QAC7B,IAAI,CAAC;YACJ,MAAM,IAAI,GAAG,IAAI,eAAe,CAAC,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,CAAC,CAAA;YACnE,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,IAAI,CAAC,IAAI,EAAE,CAAA;YACrC,MAAM,OAAO,GAAoD,EAAE,CAAA;YACnE,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;gBAC7B,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,CAAC,CAAA;gBAC7C,IAAI,CAAC,MAAM;oBAAE,SAAQ;gBACrB,IAAI,CAAC;oBACJ,IAAI,CAAC,MAAM,KAAK,CAAC,YAAY,CAAC,MAAM,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,CAAC,KAAK,UAAU,EAAE,CAAC;wBAC5E,eAAe,EAAE,CAAA;oBAClB,CAAC;gBACF,CAAC;gBAAC,OAAO,KAAK,EAAE,CAAC;oBAChB,IAAI,CAAC,CAAC,KAAK,YAAY,0BAA0B,CAAC;wBAAE,MAAM,KAAK,CAAA;oBAC/D,OAAO,CAAC,IAAI,CAAC;wBACZ,EAAE,EAAE,KAAK,CAAC,EAAE;wBACZ,KAAK,EAAE,KAAK,CAAC,KAAK;wBAClB,MAAM,EAAE,KAAK,CAAC,OAAO;qBACrB,CAAC,CAAA;gBACH,CAAC;YACF,CAAC;YACD,MAAM,MAAM,CAAC,SAAS,CAAC,CAAA;YACvB,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,EAAE,SAAS,CAAC,CAAA;YAC1C,MAAM,cAAc,GAAG,CAAC,MAAM,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAA;YAChF,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;gBAC9B,cAAc,CAAC,IAAI,CAClB,IAAI,MAAM,CAAC,KAAK,MAAM,MAAM,CAAC,EAAE,oBAAoB,MAAM,CAAC,MAAM,kBAAkB,IAAI,CAAC,cAAc,EAAE,GAAG,MAAM,CAAC,EAAE,OAAO,CAAC,GAAG,CAC9H,CAAA;YACF,CAAC;QACF,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YAChB,QAAQ,CAAC,IAAI,CACZ,4BAA4B,SAAS,sBAAsB,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CACnH,CAAA;QACF,CAAC;IACF,CAAC;IAED,IAAI,CAAC;QACJ,MAAM,QAAQ,GAAG,qBAAqB,CAAC,GAAG,CAAC,CAAA;QAC3C,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,SAAS,CAAC,CAAA;QAC1C,MAAM,KAAK,GAAG,MAAM,CAAC,YAAY,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAA;QAClD,IAAI,CAAC,KAAK,EAAE,SAAS,IAAI,CAAC,KAAK,EAAE,UAAU,EAAE,CAAC;YAC7C,MAAM,IAAI,GAAG,cAAc,CAAC,QAAQ,CAAC,CAAA;YACrC,MAAM,OAAO,GAAG,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,cAAc,CAAC,IAAI,CAAC,CAAA;YACzD,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACxB,UAAU,GAAG,EAAE,IAAI,EAAE,QAAQ,CAAC,IAAI,EAAE,KAAK,EAAE,OAAO,CAAC,MAAM,EAAE,CAAA;gBAC3D,MAAM,eAAe,CAAC,SAAS,EAAE,QAAQ,CAAC,IAAI,EAAE;oBAC/C,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;iBACnC,CAAC,CAAA;YACH,CAAC;QACF,CAAC;IACF,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QAChB,QAAQ,CAAC,IAAI,CACZ,2DAA2D,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CACnH,CAAA;IACF,CAAC;IAED,OAAO;QACN,eAAe;QACf,cAAc;QACd,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACrC,QAAQ;KACR,CAAA;AACF,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,OAIxC;IACA,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE,GAAG,EAAE,GAAG,OAAO,CAAA;IACzC,MAAM,QAAQ,GAAG,qBAAqB,CAAC,GAAG,CAAC,CAAA;IAC3C,MAAM,IAAI,GAAG,cAAc,CAAC,QAAQ,CAAC,CAAA;IACrC,MAAM,OAAO,GAAG,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,cAAc,CAAC,IAAI,CAAC,CAAA;IACzD,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC1B,OAAO,EAAE,IAAI,EAAE,QAAQ,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,aAAa,EAAE,CAAC,EAAE,CAAA;IACtE,CAAC;IACD,wEAAwE;IACxE,gEAAgE;IAChE,MAAM,MAAM,GAAG,IAAI,GAAG,EAAW,CAAA;IACjC,KAAK,MAAM,KAAK,IAAI,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC;QACpD,MAAM,QAAQ,GAAG,CAAC,MAAM,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,EAAE,QAAQ,CAAA;QACtD,MAAM,CAAC,GAAG,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAA;QAClC,MAAM,CAAC,GAAG,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAA;IACjC,CAAC;IACD,IAAI,MAAM,GAAG,CAAC,CAAA;IACd,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC9B,MAAM,YAAY,GAAG,MAAM,CAAC,MAAM,CAAC,CAAA;QACnC,IAAI,MAAM,CAAC,GAAG,CAAC,YAAY,CAAC;YAAE,SAAQ;QACtC,IAAI,MAAM,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,QAAQ,CAAC,IAAI,CAAC;YAAE,MAAM,EAAE,CAAA;QAC1E,MAAM,CAAC,GAAG,CAAC,YAAY,CAAC,CAAA;IACzB,CAAC;IACD,MAAM,eAAe,CAAC,SAAS,EAAE,QAAQ,CAAC,IAAI,EAAE,EAAE,UAAU,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,EAAE,CAAC,CAAA;IACzF,OAAO;QACN,IAAI,EAAE,QAAQ,CAAC,IAAI;QACnB,KAAK,EAAE,OAAO,CAAC,MAAM;QACrB,MAAM;QACN,aAAa,EAAE,OAAO,CAAC,MAAM,GAAG,MAAM;KACtC,CAAA;AACF,CAAC;AAED,yGAAyG;AACzG,MAAM,UAAU,uBAAuB,CACtC,MAA6B,EAC7B,SAAiB;IAEjB,MAAM,OAAO,GAAa,EAAE,CAAA;IAC5B,IAAI,MAAM,CAAC,eAAe,GAAG,CAAC,EAAE,CAAC;QAChC,OAAO,CAAC,IAAI,CACX,wBAAwB,MAAM,CAAC,eAAe,UAAU,MAAM,CAAC,eAAe,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,+CAA+C,SAAS,GAAG,CAC1J,CAAA;IACF,CAAC;IACD,KAAK,MAAM,OAAO,IAAI,MAAM,CAAC,cAAc;QAAE,OAAO,CAAC,IAAI,CAAC,kBAAkB,OAAO,EAAE,CAAC,CAAA;IACtF,IAAI,MAAM,CAAC,UAAU,EAAE,CAAC;QACvB,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,MAAM,CAAC,UAAU,CAAA;QACzC,OAAO,CAAC,IAAI,CACX,kBAAkB,IAAI,QAAQ,KAAK,oBAAoB,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,qKAAqK,SAAS,iHAAiH,CAC5W,CAAA;IACF,CAAC;IACD,OAAO,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAA;IAChC,OAAO,OAAO,CAAA;AACf,CAAC;AAED,wDAAwD;AACxD,MAAM,UAAU,0BAA0B,CAAC,MAA0B,EAAE,SAAiB;IACvF,IAAI,MAAM,CAAC,KAAK,KAAK,CAAC,EAAE,CAAC;QACxB,OAAO,mCAAmC,MAAM,CAAC,IAAI,oBAAoB,CAAA;IAC1E,CAAC;IACD,MAAM,MAAM,GAAG,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAA;IAClD,MAAM,OAAO,GACZ,MAAM,CAAC,aAAa,GAAG,CAAC;QACvB,CAAC,CAAC,IAAI,MAAM,CAAC,aAAa,IAAI,MAAM,CAAC,aAAa,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,uCAAuC;QAChH,CAAC,CAAC,EAAE,CAAA;IACN,OAAO,UAAU,MAAM,CAAC,MAAM,OAAO,MAAM,CAAC,KAAK,UAAU,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,SAAS,MAAM,CAAC,IAAI,+BAA+B,SAAS,IAAI,OAAO,IAAI,MAAM,CAAC,IAAI,qHAAqH,CAAA;AAC3R,CAAC"}
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
*
|
|
35
35
|
* Re-implementing the matching here would check this file against itself. The
|
|
36
36
|
* check compiles the operator's table to rules and hands them to the same
|
|
37
|
-
* `AuthorizationGate` a
|
|
37
|
+
* `AuthorizationGate` a turn uses, so what it verifies is the decision that will
|
|
38
38
|
* actually be taken.
|
|
39
39
|
*
|
|
40
40
|
* The floor is deliberately OFF while checking. `denyDangerousPatterns` would
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
*
|
|
35
35
|
* Re-implementing the matching here would check this file against itself. The
|
|
36
36
|
* check compiles the operator's table to rules and hands them to the same
|
|
37
|
-
* `AuthorizationGate` a
|
|
37
|
+
* `AuthorizationGate` a turn uses, so what it verifies is the decision that will
|
|
38
38
|
* actually be taken.
|
|
39
39
|
*
|
|
40
40
|
* The floor is deliberately OFF while checking. `denyDangerousPatterns` would
|
|
@@ -4,11 +4,11 @@
|
|
|
4
4
|
* `integrations/trust/store.ts` states the contract in its own header: "before
|
|
5
5
|
* namzu reads, runs commands in, or edits files in a directory, the user must
|
|
6
6
|
* trust it." That was true of the TUI and false of everything else —
|
|
7
|
-
* `isTrusted` had exactly one caller, `tui/App.tsx`. `
|
|
7
|
+
* `isTrusted` had exactly one caller, `tui/App.tsx`. `exec` and `exec --json`
|
|
8
8
|
* opened a session in whatever directory they were pointed at, with tools
|
|
9
9
|
* auto-approved because there is nobody to ask, so
|
|
10
10
|
*
|
|
11
|
-
* git clone <a stranger's repository> && cd <it> && namzu
|
|
11
|
+
* git clone <a stranger's repository> && cd <it> && namzu exec "what is this?"
|
|
12
12
|
*
|
|
13
13
|
* ran that repository's code on the machine, unattended, having asked nobody.
|
|
14
14
|
*
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
* Anyone who can write `AGENTS.md` in that repository can write the build
|
|
34
34
|
* script, the test file, the install hook — all of which run with tools
|
|
35
35
|
* auto-approved. Declining to read the attacker's markdown while executing the
|
|
36
|
-
* attacker's code blocks the weaker vector, reports success on a
|
|
36
|
+
* attacker's code blocks the weaker vector, reports success on a turn that is
|
|
37
37
|
* already compromised, and would make the instructions feature silently dead
|
|
38
38
|
* in CI where nothing has ever been trusted.
|
|
39
39
|
*
|
|
@@ -55,7 +55,7 @@ export type TrustDecision = {
|
|
|
55
55
|
};
|
|
56
56
|
export interface TrustCheck {
|
|
57
57
|
readonly cwd: string;
|
|
58
|
-
/** `--trust` was passed: the operator accepts this folder for this
|
|
58
|
+
/** `--trust` was passed: the operator accepts this folder for this turn. */
|
|
59
59
|
readonly trustFlag: boolean;
|
|
60
60
|
/** Injectable for tests. Defaults to the persistent `~/.namzu/trust.json`. */
|
|
61
61
|
readonly trusted?: (dir: string) => boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"headless-trust.d.ts","sourceRoot":"","sources":["../../src/permissions/headless-trust.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6CG;AAKH,MAAM,MAAM,aAAa,GACtB;IACA,QAAQ,CAAC,OAAO,EAAE,IAAI,CAAA;IACtB,mFAAmF;IACnF,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;CACnB,GACD;IACA,QAAQ,CAAC,OAAO,EAAE,KAAK,CAAA;IACvB,8CAA8C;IAC9C,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;CACvB,CAAA;AAEJ,MAAM,WAAW,UAAU;IAC1B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;IACpB,
|
|
1
|
+
{"version":3,"file":"headless-trust.d.ts","sourceRoot":"","sources":["../../src/permissions/headless-trust.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6CG;AAKH,MAAM,MAAM,aAAa,GACtB;IACA,QAAQ,CAAC,OAAO,EAAE,IAAI,CAAA;IACtB,mFAAmF;IACnF,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;CACnB,GACD;IACA,QAAQ,CAAC,OAAO,EAAE,KAAK,CAAA;IACvB,8CAA8C;IAC9C,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;CACvB,CAAA;AAEJ,MAAM,WAAW,UAAU;IAC1B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;IACpB,4EAA4E;IAC5E,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAA;IAC3B,8EAA8E;IAC9E,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAA;CAC3C;AAED,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,UAAU,GAAG,aAAa,CAiCpE"}
|
|
@@ -4,11 +4,11 @@
|
|
|
4
4
|
* `integrations/trust/store.ts` states the contract in its own header: "before
|
|
5
5
|
* namzu reads, runs commands in, or edits files in a directory, the user must
|
|
6
6
|
* trust it." That was true of the TUI and false of everything else —
|
|
7
|
-
* `isTrusted` had exactly one caller, `tui/App.tsx`. `
|
|
7
|
+
* `isTrusted` had exactly one caller, `tui/App.tsx`. `exec` and `exec --json`
|
|
8
8
|
* opened a session in whatever directory they were pointed at, with tools
|
|
9
9
|
* auto-approved because there is nobody to ask, so
|
|
10
10
|
*
|
|
11
|
-
* git clone <a stranger's repository> && cd <it> && namzu
|
|
11
|
+
* git clone <a stranger's repository> && cd <it> && namzu exec "what is this?"
|
|
12
12
|
*
|
|
13
13
|
* ran that repository's code on the machine, unattended, having asked nobody.
|
|
14
14
|
*
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
* Anyone who can write `AGENTS.md` in that repository can write the build
|
|
34
34
|
* script, the test file, the install hook — all of which run with tools
|
|
35
35
|
* auto-approved. Declining to read the attacker's markdown while executing the
|
|
36
|
-
* attacker's code blocks the weaker vector, reports success on a
|
|
36
|
+
* attacker's code blocks the weaker vector, reports success on a turn that is
|
|
37
37
|
* already compromised, and would make the instructions feature silently dead
|
|
38
38
|
* in CI where nothing has ever been trusted.
|
|
39
39
|
*
|
|
@@ -60,7 +60,7 @@ export function decideHeadlessTrust(check) {
|
|
|
60
60
|
message: `refusing to run because the working directory changed or became unavailable while trust was being checked: ${check.cwd}`,
|
|
61
61
|
};
|
|
62
62
|
}
|
|
63
|
-
// `--trust` is per-
|
|
63
|
+
// `--trust` is per-turn and is deliberately NOT written to the trust file.
|
|
64
64
|
// One reflexive use must not change the machine's state forever; the TUI
|
|
65
65
|
// stays the only path that records durable trust, because that is the one
|
|
66
66
|
// where a human is actually looking at a prompt.
|
|
@@ -75,11 +75,11 @@ export function decideHeadlessTrust(check) {
|
|
|
75
75
|
`refusing to run in a folder nobody has trusted: ${cwd}`,
|
|
76
76
|
'',
|
|
77
77
|
"namzu reads this folder's files, runs commands in it and executes its",
|
|
78
|
-
'code, and a headless
|
|
78
|
+
'code, and a headless turn approves those tools without asking because',
|
|
79
79
|
'there is nobody to ask.',
|
|
80
80
|
'',
|
|
81
81
|
'Run `namzu` here once and accept the trust prompt to trust the folder',
|
|
82
|
-
'permanently, or pass --trust to accept it for this
|
|
82
|
+
'permanently, or pass --trust to accept it for this turn only.',
|
|
83
83
|
].join('\n'),
|
|
84
84
|
};
|
|
85
85
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"headless-trust.js","sourceRoot":"","sources":["../../src/permissions/headless-trust.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6CG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,gCAAgC,CAAA;AAC1D,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAA;AAsB7D,MAAM,UAAU,mBAAmB,CAAC,KAAiB;IACpD,2EAA2E;IAC3E,uEAAuE;IACvE,wEAAwE;IACxE,IAAI,GAAW,CAAA;IACf,IAAI,CAAC;QACJ,GAAG,GAAG,oBAAoB,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;IACtC,CAAC;IAAC,MAAM,CAAC;QACR,OAAO;YACN,OAAO,EAAE,KAAK;YACd,OAAO,EAAE,8GAA8G,KAAK,CAAC,GAAG,EAAE;SAClI,CAAA;IACF,CAAC;IACD,
|
|
1
|
+
{"version":3,"file":"headless-trust.js","sourceRoot":"","sources":["../../src/permissions/headless-trust.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6CG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,gCAAgC,CAAA;AAC1D,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAA;AAsB7D,MAAM,UAAU,mBAAmB,CAAC,KAAiB;IACpD,2EAA2E;IAC3E,uEAAuE;IACvE,wEAAwE;IACxE,IAAI,GAAW,CAAA;IACf,IAAI,CAAC;QACJ,GAAG,GAAG,oBAAoB,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;IACtC,CAAC;IAAC,MAAM,CAAC;QACR,OAAO;YACN,OAAO,EAAE,KAAK;YACd,OAAO,EAAE,8GAA8G,KAAK,CAAC,GAAG,EAAE;SAClI,CAAA;IACF,CAAC;IACD,2EAA2E;IAC3E,yEAAyE;IACzE,0EAA0E;IAC1E,iDAAiD;IACjD,IAAI,KAAK,CAAC,SAAS;QAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,CAAA;IAClD,MAAM,YAAY,GAAG,KAAK,CAAC,OAAO,IAAI,CAAC,CAAC,GAAW,EAAE,EAAE,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAA;IACvE,IAAI,YAAY,CAAC,GAAG,CAAC;QAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,CAAA;IACpD,OAAO;QACN,OAAO,EAAE,KAAK;QACd,OAAO,EAAE;YACR,mDAAmD,GAAG,EAAE;YACxD,EAAE;YACF,uEAAuE;YACvE,uEAAuE;YACvE,yBAAyB;YACzB,EAAE;YACF,uEAAuE;YACvE,+DAA+D;SAC/D,CAAC,IAAI,CAAC,IAAI,CAAC;KACZ,CAAA;AACF,CAAC"}
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import { type ReviewMode } from '@namzu/sdk';
|
|
2
2
|
/**
|
|
3
|
-
* How a
|
|
3
|
+
* How a turn resolves the calls no rule decided.
|
|
4
4
|
*
|
|
5
5
|
* The `[permissions]` table says what a tool may do. The kernel's review
|
|
6
6
|
* policy (`createReviewHandler` in `@namzu/sdk`) says what happens to
|
|
7
7
|
* everything it did not cover; the modes and their words live there, and
|
|
8
|
-
* this file resolves which one a
|
|
8
|
+
* this file resolves which one a turn gets from the flag and the terminal.
|
|
9
9
|
*
|
|
10
10
|
* The two axes are separate on purpose: a rule is
|
|
11
11
|
* a durable statement an operator reviewed, and a mode is a property of ONE
|
|
12
|
-
* invocation — the difference between "we never force-push" and "this
|
|
12
|
+
* invocation — the difference between "we never force-push" and "this turn is
|
|
13
13
|
* unattended".
|
|
14
14
|
*
|
|
15
15
|
* ## Precedence between a flag and the config file
|
|
@@ -36,7 +36,7 @@ export declare function effectivePermissionMode(mode: PermissionMode, approvedAl
|
|
|
36
36
|
/** The behavior shown by both the permission selector and the session report. */
|
|
37
37
|
export declare function permissionModeDescription(mode: PermissionMode): string;
|
|
38
38
|
/**
|
|
39
|
-
* The mode for a
|
|
39
|
+
* The mode for a turn, from the flag, the bypass alias, and whether anyone is
|
|
40
40
|
* there to answer.
|
|
41
41
|
*
|
|
42
42
|
* `--yolo` / `--dangerously-skip-permissions` map to `auto`. They were accepted
|
package/dist/permissions/mode.js
CHANGED
|
@@ -36,7 +36,7 @@ export function permissionModeDescription(mode) {
|
|
|
36
36
|
}
|
|
37
37
|
}
|
|
38
38
|
/**
|
|
39
|
-
* The mode for a
|
|
39
|
+
* The mode for a turn, from the flag, the bypass alias, and whether anyone is
|
|
40
40
|
* there to answer.
|
|
41
41
|
*
|
|
42
42
|
* `--yolo` / `--dangerously-skip-permissions` map to `auto`. They were accepted
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* to "ask a human". This turns a `[permissions]` table into that array.
|
|
9
9
|
*
|
|
10
10
|
* The whole surface is pure: config in, rules out. The gate stays the only
|
|
11
|
-
* thing that decides anything, which is what keeps this testable without a
|
|
11
|
+
* thing that decides anything, which is what keeps this testable without a turn.
|
|
12
12
|
*/
|
|
13
13
|
import { type AuthorizationRule } from '@namzu/sdk';
|
|
14
14
|
import { type PermissionChecksConfig } from './checks.js';
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* to "ask a human". This turns a `[permissions]` table into that array.
|
|
9
9
|
*
|
|
10
10
|
* The whole surface is pure: config in, rules out. The gate stays the only
|
|
11
|
-
* thing that decides anything, which is what keeps this testable without a
|
|
11
|
+
* thing that decides anything, which is what keeps this testable without a turn.
|
|
12
12
|
*/
|
|
13
13
|
import { builtinCommandArguments } from '@namzu/sdk';
|
|
14
14
|
import { verifyPermissionChecks } from './checks.js';
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What a turn-running command does when it is told to stop from outside.
|
|
3
|
+
*
|
|
4
|
+
* A turn holds its conversation's writer lease while it runs, renewed for five
|
|
5
|
+
* minutes at a time. Node's default for SIGTERM, SIGHUP and SIGINT is to die
|
|
6
|
+
* on the spot, which settles nothing and releases nothing: the conversation
|
|
7
|
+
* then refuses `/resume`, `/abandon` and a new prompt ("leased by a live
|
|
8
|
+
* writer") until the lease expires, although no process is writing to it.
|
|
9
|
+
* A supervisor stopping a service sends SIGTERM, a closed terminal sends
|
|
10
|
+
* SIGHUP, and Ctrl+C at a shell running `namzu exec` sends SIGINT.
|
|
11
|
+
*
|
|
12
|
+
* So on the first of those signals the command:
|
|
13
|
+
*
|
|
14
|
+
* 1. gives back every session lease the process holds
|
|
15
|
+
* (`releaseHeldSessionLeases`). A running turn is left `interrupted` — no
|
|
16
|
+
* live lease, not paused — which the next writer closes through the
|
|
17
|
+
* explicit flow: `/abandon`, `/resume`, or the TUI's next prompt
|
|
18
|
+
* (`abandonInterrupted`). Nothing is appended for it on the way out: the
|
|
19
|
+
* process cannot know how far the turn got, and `interrupted` says exactly
|
|
20
|
+
* what is known;
|
|
21
|
+
* 2. runs the command's own cleanup, bounded: stop the turn, close the
|
|
22
|
+
* session (tool servers, background jobs, the `session_end` hook) and, for
|
|
23
|
+
* the TUI, hand the terminal back;
|
|
24
|
+
* 3. dies of the signal it was sent, so the parent sees the conventional
|
|
25
|
+
* status (a shell reports 143 for SIGTERM, 129 for SIGHUP, 130 for SIGINT).
|
|
26
|
+
*
|
|
27
|
+
* A second signal while that is under way exits at once. SIGKILL runs no code
|
|
28
|
+
* at all; its lease is freed when it expires.
|
|
29
|
+
*/
|
|
30
|
+
/** The signals a turn-running command answers by giving its conversation back. */
|
|
31
|
+
export declare const TERMINATION_SIGNALS: readonly ["SIGTERM", "SIGHUP", "SIGINT"];
|
|
32
|
+
export type TerminationSignal = (typeof TERMINATION_SIGNALS)[number];
|
|
33
|
+
/**
|
|
34
|
+
* The signal this process is stopping for, or `null`. The binary's own exit
|
|
35
|
+
* path consults it: once a signal is being handled, the handler ends the
|
|
36
|
+
* process, and a command that returns meanwhile must not exit ahead of it.
|
|
37
|
+
*/
|
|
38
|
+
export declare function terminationInProgress(): TerminationSignal | null;
|
|
39
|
+
export interface TerminationHandling {
|
|
40
|
+
/** Add a cleanup step (run in the order added, after the leases are released). */
|
|
41
|
+
onTerminate(cleanup: (signal: TerminationSignal) => Promise<void> | void): void;
|
|
42
|
+
/** Stop listening: the command finished on its own. */
|
|
43
|
+
dispose(): void;
|
|
44
|
+
}
|
|
45
|
+
/** The process surface this uses, for a test to substitute. */
|
|
46
|
+
export interface TerminationProcess {
|
|
47
|
+
on(signal: TerminationSignal, listener: () => void): unknown;
|
|
48
|
+
removeListener(signal: TerminationSignal, listener: () => void): unknown;
|
|
49
|
+
kill(pid: number, signal: TerminationSignal): unknown;
|
|
50
|
+
exit(code: number): never;
|
|
51
|
+
readonly pid: number;
|
|
52
|
+
readonly platform: NodeJS.Platform;
|
|
53
|
+
}
|
|
54
|
+
export interface HandleTerminationOptions {
|
|
55
|
+
readonly process?: TerminationProcess;
|
|
56
|
+
readonly leaseReleaseMs?: number;
|
|
57
|
+
readonly cleanupMs?: number;
|
|
58
|
+
/** Test hook: called instead of the re-raise at the end. */
|
|
59
|
+
readonly onFinished?: (signal: TerminationSignal) => void;
|
|
60
|
+
}
|
|
61
|
+
/** 128 + the signal's number: what a shell reports for a process the signal killed. */
|
|
62
|
+
export declare function signalExitCode(signal: TerminationSignal): number;
|
|
63
|
+
/**
|
|
64
|
+
* Answer SIGTERM, SIGHUP and SIGINT as the module header describes, until
|
|
65
|
+
* {@link TerminationHandling.dispose}.
|
|
66
|
+
*/
|
|
67
|
+
export declare function handleTerminationSignals(options?: HandleTerminationOptions): TerminationHandling;
|
|
68
|
+
/**
|
|
69
|
+
* A command handler that answers the termination signals for as long as it
|
|
70
|
+
* runs. The handler adds its own cleanup once it has something to clean up.
|
|
71
|
+
*/
|
|
72
|
+
export declare function withTerminationHandling<A>(handler: (args: A, termination: TerminationHandling) => Promise<number>): (args: A) => Promise<number>;
|
|
73
|
+
/** @internal For tests: forget a handled signal. */
|
|
74
|
+
export declare function resetTerminationForTests(): void;
|
|
75
|
+
//# sourceMappingURL=termination.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"termination.d.ts","sourceRoot":"","sources":["../src/termination.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAMH,kFAAkF;AAClF,eAAO,MAAM,mBAAmB,0CAA2C,CAAA;AAC3E,MAAM,MAAM,iBAAiB,GAAG,CAAC,OAAO,mBAAmB,CAAC,CAAC,MAAM,CAAC,CAAA;AAWpE;;;;GAIG;AACH,wBAAgB,qBAAqB,IAAI,iBAAiB,GAAG,IAAI,CAEhE;AAED,MAAM,WAAW,mBAAmB;IACnC,kFAAkF;IAClF,WAAW,CAAC,OAAO,EAAE,CAAC,MAAM,EAAE,iBAAiB,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,GAAG,IAAI,CAAA;IAC/E,uDAAuD;IACvD,OAAO,IAAI,IAAI,CAAA;CACf;AAED,+DAA+D;AAC/D,MAAM,WAAW,kBAAkB;IAClC,EAAE,CAAC,MAAM,EAAE,iBAAiB,EAAE,QAAQ,EAAE,MAAM,IAAI,GAAG,OAAO,CAAA;IAC5D,cAAc,CAAC,MAAM,EAAE,iBAAiB,EAAE,QAAQ,EAAE,MAAM,IAAI,GAAG,OAAO,CAAA;IACxE,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,iBAAiB,GAAG,OAAO,CAAA;IACrD,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,KAAK,CAAA;IACzB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC,QAAQ,CAAA;CAClC;AAED,MAAM,WAAW,wBAAwB;IACxC,QAAQ,CAAC,OAAO,CAAC,EAAE,kBAAkB,CAAA;IACrC,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAA;IAChC,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAA;IAC3B,4DAA4D;IAC5D,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC,MAAM,EAAE,iBAAiB,KAAK,IAAI,CAAA;CACzD;AAeD,uFAAuF;AACvF,wBAAgB,cAAc,CAAC,MAAM,EAAE,iBAAiB,GAAG,MAAM,CAEhE;AAED;;;GAGG;AACH,wBAAgB,wBAAwB,CACvC,OAAO,GAAE,wBAA6B,GACpC,mBAAmB,CA6DrB;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,CAAC,CAAC,EACxC,OAAO,EAAE,CAAC,IAAI,EAAE,CAAC,EAAE,WAAW,EAAE,mBAAmB,KAAK,OAAO,CAAC,MAAM,CAAC,GACrE,CAAC,IAAI,EAAE,CAAC,KAAK,OAAO,CAAC,MAAM,CAAC,CAS9B;AAED,oDAAoD;AACpD,wBAAgB,wBAAwB,IAAI,IAAI,CAE/C"}
|