opensquid 0.5.441 → 0.5.447
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 +1 -0
- package/dist/functions/arm_scope.d.ts +27 -0
- package/dist/functions/arm_scope.d.ts.map +1 -0
- package/dist/functions/arm_scope.js +52 -0
- package/dist/functions/arm_scope.js.map +1 -0
- package/dist/functions/index.d.ts +1 -0
- package/dist/functions/index.d.ts.map +1 -1
- package/dist/functions/index.js +1 -0
- package/dist/functions/index.js.map +1 -1
- package/dist/runtime/bootstrap.d.ts.map +1 -1
- package/dist/runtime/bootstrap.js +2 -0
- package/dist/runtime/bootstrap.js.map +1 -1
- package/dist/runtime/handoff/render.d.ts +5 -4
- package/dist/runtime/handoff/render.d.ts.map +1 -1
- package/dist/runtime/handoff/render.js +7 -7
- package/dist/runtime/handoff/render.js.map +1 -1
- package/dist/runtime/hooks/active_task_mirror.js +0 -0
- package/dist/runtime/hooks/apply_patch.js +0 -0
- package/dist/runtime/hooks/dispatch.js +0 -0
- package/dist/runtime/hooks/hook_output.js +0 -0
- package/dist/runtime/hooks/memory_reconcile.js +0 -0
- package/dist/runtime/hooks/new_project_detect.js +0 -0
- package/dist/runtime/hooks/profession_resolver.js +0 -0
- package/dist/runtime/hooks/scope_intent.js +0 -0
- package/dist/runtime/hooks/session_id.js +0 -0
- package/dist/runtime/hooks/session_liveness.js +0 -0
- package/dist/runtime/hooks/stop_drive.js +0 -0
- package/dist/runtime/hooks/stop_stream.js +0 -0
- package/dist/runtime/hooks/subagent_guard.js +0 -0
- package/dist/runtime/hooks/transcript.js +0 -0
- package/dist/runtime/hooks/transcript_tasks.js +0 -0
- package/dist/runtime/ralph/orchestrator.d.ts.map +1 -1
- package/dist/runtime/ralph/orchestrator.js +2 -1
- package/dist/runtime/ralph/orchestrator.js.map +1 -1
- package/dist/setup/cli/limits_state.d.ts.map +1 -1
- package/dist/setup/cli/limits_state.js +6 -40
- package/dist/setup/cli/limits_state.js.map +1 -1
- package/dist/setup/cli/pack_walk.d.ts +32 -0
- package/dist/setup/cli/pack_walk.d.ts.map +1 -0
- package/dist/setup/cli/pack_walk.js +76 -0
- package/dist/setup/cli/pack_walk.js.map +1 -0
- package/dist/setup/cli/permissions_state.d.ts.map +1 -1
- package/dist/setup/cli/permissions_state.js +6 -37
- package/dist/setup/cli/permissions_state.js.map +1 -1
- package/dist/setup/cli/triggers_state.d.ts.map +1 -1
- package/dist/setup/cli/triggers_state.js +3 -29
- package/dist/setup/cli/triggers_state.js.map +1 -1
- package/dist/workgraph/events.d.ts.map +1 -1
- package/dist/workgraph/events.js +10 -0
- package/dist/workgraph/events.js.map +1 -1
- package/dist/workgraph/store.d.ts.map +1 -1
- package/dist/workgraph/store.js +5 -0
- package/dist/workgraph/store.js.map +1 -1
- package/dist/workgraph/types.d.ts +2 -1
- package/dist/workgraph/types.d.ts.map +1 -1
- package/docs/ARCHITECTURE.md +268 -0
- package/package.json +5 -3
- package/packs/builtin/coding-flow/skills/entry-and-handoffs/skill.yaml +13 -17
- package/dist/anti-drift/evaluator.d.ts +0 -88
- package/dist/anti-drift/evaluator.d.ts.map +0 -1
- package/dist/anti-drift/evaluator.js +0 -417
- package/dist/anti-drift/evaluator.js.map +0 -1
- package/dist/anti-drift/evaluator.test.js +0 -78
- package/dist/anti-drift/rules.d.ts +0 -80
- package/dist/anti-drift/rules.d.ts.map +0 -1
- package/dist/anti-drift/rules.js +0 -368
- package/dist/anti-drift/rules.js.map +0 -1
- package/dist/anti-drift/rules.test.js +0 -213
- package/dist/anti-drift/state.d.ts +0 -107
- package/dist/anti-drift/state.d.ts.map +0 -1
- package/dist/anti-drift/state.js +0 -177
- package/dist/anti-drift/state.js.map +0 -1
- package/dist/anti-drift/state.test.js +0 -120
- package/dist/chat/adapters/discord.d.ts +0 -41
- package/dist/chat/adapters/discord.d.ts.map +0 -1
- package/dist/chat/adapters/discord.js +0 -176
- package/dist/chat/adapters/discord.js.map +0 -1
- package/dist/chat/adapters/discord.test.js +0 -25
- package/dist/chat/adapters/slack.d.ts +0 -43
- package/dist/chat/adapters/slack.d.ts.map +0 -1
- package/dist/chat/adapters/slack.js +0 -172
- package/dist/chat/adapters/slack.js.map +0 -1
- package/dist/chat/adapters/slack.test.js +0 -30
- package/dist/chat/adapters/telegram.d.ts +0 -148
- package/dist/chat/adapters/telegram.d.ts.map +0 -1
- package/dist/chat/adapters/telegram.js +0 -498
- package/dist/chat/adapters/telegram.js.map +0 -1
- package/dist/chat/adapters/telegram.test.js +0 -94
- package/dist/chat/config.d.ts +0 -98
- package/dist/chat/config.d.ts.map +0 -1
- package/dist/chat/config.js +0 -185
- package/dist/chat/config.js.map +0 -1
- package/dist/chat/daemon/active-project.d.ts +0 -17
- package/dist/chat/daemon/active-project.d.ts.map +0 -1
- package/dist/chat/daemon/active-project.js +0 -23
- package/dist/chat/daemon/active-project.js.map +0 -1
- package/dist/chat/daemon/autospawn.d.ts +0 -40
- package/dist/chat/daemon/autospawn.d.ts.map +0 -1
- package/dist/chat/daemon/autospawn.js +0 -129
- package/dist/chat/daemon/autospawn.js.map +0 -1
- package/dist/chat/daemon/autospawn.test.js +0 -112
- package/dist/chat/daemon/cli.d.ts +0 -18
- package/dist/chat/daemon/cli.d.ts.map +0 -1
- package/dist/chat/daemon/cli.js +0 -71
- package/dist/chat/daemon/cli.js.map +0 -1
- package/dist/chat/daemon/collisions.js +0 -384
- package/dist/chat/daemon/health-check.d.ts +0 -69
- package/dist/chat/daemon/health-check.d.ts.map +0 -1
- package/dist/chat/daemon/health-check.js +0 -112
- package/dist/chat/daemon/health-check.js.map +0 -1
- package/dist/chat/daemon/inbox-read.d.ts +0 -35
- package/dist/chat/daemon/inbox-read.d.ts.map +0 -1
- package/dist/chat/daemon/inbox-read.js +0 -75
- package/dist/chat/daemon/inbox-read.js.map +0 -1
- package/dist/chat/daemon/inbox-read.test.js +0 -97
- package/dist/chat/daemon/inbox.d.ts +0 -63
- package/dist/chat/daemon/inbox.d.ts.map +0 -1
- package/dist/chat/daemon/inbox.js +0 -56
- package/dist/chat/daemon/inbox.js.map +0 -1
- package/dist/chat/daemon/inbox.test.js +0 -110
- package/dist/chat/daemon/lifecycle.d.ts +0 -71
- package/dist/chat/daemon/lifecycle.d.ts.map +0 -1
- package/dist/chat/daemon/lifecycle.js +0 -221
- package/dist/chat/daemon/lifecycle.js.map +0 -1
- package/dist/chat/daemon/lifecycle.test.js +0 -163
- package/dist/chat/daemon/protocol.d.ts +0 -107
- package/dist/chat/daemon/protocol.d.ts.map +0 -1
- package/dist/chat/daemon/protocol.js +0 -54
- package/dist/chat/daemon/protocol.js.map +0 -1
- package/dist/chat/daemon/routing.d.ts +0 -140
- package/dist/chat/daemon/routing.d.ts.map +0 -1
- package/dist/chat/daemon/routing.js +0 -198
- package/dist/chat/daemon/routing.js.map +0 -1
- package/dist/chat/daemon/routing.test.js +0 -259
- package/dist/chat/daemon/rpc-client.d.ts +0 -45
- package/dist/chat/daemon/rpc-client.d.ts.map +0 -1
- package/dist/chat/daemon/rpc-client.js +0 -133
- package/dist/chat/daemon/rpc-client.js.map +0 -1
- package/dist/chat/daemon/rpc-server.d.ts +0 -39
- package/dist/chat/daemon/rpc-server.d.ts.map +0 -1
- package/dist/chat/daemon/rpc-server.js +0 -385
- package/dist/chat/daemon/rpc-server.js.map +0 -1
- package/dist/chat/daemon/rpc.test.js +0 -177
- package/dist/chat/daemon/subscribers.js +0 -257
- package/dist/chat/daemon/worker.d.ts +0 -27
- package/dist/chat/daemon/worker.d.ts.map +0 -1
- package/dist/chat/daemon/worker.js +0 -313
- package/dist/chat/daemon/worker.js.map +0 -1
- package/dist/chat/daemon/workspace-topic.js +0 -324
- package/dist/chat/env-token.d.ts +0 -60
- package/dist/chat/env-token.d.ts.map +0 -1
- package/dist/chat/env-token.js +0 -137
- package/dist/chat/env-token.js.map +0 -1
- package/dist/chat/env-token.test.js +0 -160
- package/dist/chat/factory.d.ts +0 -30
- package/dist/chat/factory.d.ts.map +0 -1
- package/dist/chat/factory.js +0 -50
- package/dist/chat/factory.js.map +0 -1
- package/dist/chat/factory.test.js +0 -55
- package/dist/chat/gateway.d.ts +0 -176
- package/dist/chat/gateway.d.ts.map +0 -1
- package/dist/chat/gateway.js +0 -146
- package/dist/chat/gateway.js.map +0 -1
- package/dist/chat/gateway.test.js +0 -192
- package/dist/claude-md.d.ts +0 -39
- package/dist/claude-md.d.ts.map +0 -1
- package/dist/claude-md.js +0 -113
- package/dist/claude-md.js.map +0 -1
- package/dist/claude-md.test.js +0 -91
- package/dist/codex/activate.d.ts +0 -66
- package/dist/codex/activate.d.ts.map +0 -1
- package/dist/codex/activate.js +0 -329
- package/dist/codex/activate.js.map +0 -1
- package/dist/codex/activate.test.js +0 -229
- package/dist/codex/bundled-default/bundled-default.test.js +0 -161
- package/dist/codex/cli-publish.test.js +0 -133
- package/dist/codex/cli.d.ts +0 -35
- package/dist/codex/cli.d.ts.map +0 -1
- package/dist/codex/cli.js +0 -554
- package/dist/codex/cli.js.map +0 -1
- package/dist/codex/cli.test.js +0 -277
- package/dist/codex/import-skill-md.d.ts +0 -53
- package/dist/codex/import-skill-md.d.ts.map +0 -1
- package/dist/codex/import-skill-md.js +0 -236
- package/dist/codex/import-skill-md.js.map +0 -1
- package/dist/codex/import-skill-md.test.js +0 -225
- package/dist/codex/loader.d.ts +0 -27
- package/dist/codex/loader.d.ts.map +0 -1
- package/dist/codex/loader.js +0 -86
- package/dist/codex/loader.js.map +0 -1
- package/dist/codex/loader.test.js +0 -75
- package/dist/codex/parse.d.ts +0 -28
- package/dist/codex/parse.d.ts.map +0 -1
- package/dist/codex/parse.js +0 -309
- package/dist/codex/parse.js.map +0 -1
- package/dist/codex/parse.test.js +0 -241
- package/dist/codex/store.d.ts +0 -87
- package/dist/codex/store.d.ts.map +0 -1
- package/dist/codex/store.js +0 -205
- package/dist/codex/store.js.map +0 -1
- package/dist/codex/store.test.js +0 -242
- package/dist/codex/types.d.ts +0 -398
- package/dist/codex/types.d.ts.map +0 -1
- package/dist/codex/types.js +0 -21
- package/dist/codex/types.js.map +0 -1
- package/dist/config.d.ts +0 -53
- package/dist/config.d.ts.map +0 -1
- package/dist/config.js +0 -202
- package/dist/config.js.map +0 -1
- package/dist/config.test.js +0 -117
- package/dist/engine/cli.d.ts +0 -14
- package/dist/engine/cli.d.ts.map +0 -1
- package/dist/engine/cli.js +0 -171
- package/dist/engine/cli.js.map +0 -1
- package/dist/engine/client.d.ts +0 -219
- package/dist/engine/client.d.ts.map +0 -1
- package/dist/engine/client.js +0 -312
- package/dist/engine/client.js.map +0 -1
- package/dist/engine/config.d.ts +0 -62
- package/dist/engine/config.d.ts.map +0 -1
- package/dist/engine/config.js +0 -223
- package/dist/engine/config.js.map +0 -1
- package/dist/engine/index.d.ts +0 -17
- package/dist/engine/index.d.ts.map +0 -1
- package/dist/engine/index.js +0 -16
- package/dist/engine/index.js.map +0 -1
- package/dist/engine/resolver.d.ts +0 -62
- package/dist/engine/resolver.d.ts.map +0 -1
- package/dist/engine/resolver.js +0 -103
- package/dist/engine/resolver.js.map +0 -1
- package/dist/engine/singleton.d.ts +0 -95
- package/dist/engine/singleton.d.ts.map +0 -1
- package/dist/engine/singleton.js +0 -325
- package/dist/engine/singleton.js.map +0 -1
- package/dist/engine/types.d.ts +0 -402
- package/dist/engine/types.d.ts.map +0 -1
- package/dist/engine/types.js +0 -22
- package/dist/engine/types.js.map +0 -1
- package/dist/engine-binary-resolver.js +0 -110
- package/dist/engine-binary-resolver.test.js +0 -61
- package/dist/engine-cli.js +0 -60
- package/dist/engine-client.js +0 -301
- package/dist/engine-client.test.js +0 -118
- package/dist/functions/chain_state.d.ts +0 -51
- package/dist/functions/chain_state.d.ts.map +0 -1
- package/dist/functions/chain_state.js +0 -59
- package/dist/functions/chain_state.js.map +0 -1
- package/dist/hooks/drift-catalog.d.ts +0 -68
- package/dist/hooks/drift-catalog.d.ts.map +0 -1
- package/dist/hooks/drift-catalog.js +0 -184
- package/dist/hooks/drift-catalog.js.map +0 -1
- package/dist/hooks/drift-catalog.test.js +0 -154
- package/dist/hooks/drift-patterns.d.ts +0 -110
- package/dist/hooks/drift-patterns.d.ts.map +0 -1
- package/dist/hooks/drift-patterns.js +0 -289
- package/dist/hooks/drift-patterns.js.map +0 -1
- package/dist/hooks/drift-patterns.test.js +0 -325
- package/dist/hooks/engine-vocab-gate.d.ts +0 -108
- package/dist/hooks/engine-vocab-gate.d.ts.map +0 -1
- package/dist/hooks/engine-vocab-gate.js +0 -225
- package/dist/hooks/engine-vocab-gate.js.map +0 -1
- package/dist/hooks/engine-vocab-gate.test.js +0 -170
- package/dist/hooks/heartbeat.d.ts +0 -107
- package/dist/hooks/heartbeat.d.ts.map +0 -1
- package/dist/hooks/heartbeat.js +0 -316
- package/dist/hooks/heartbeat.js.map +0 -1
- package/dist/hooks/heartbeat.test.js +0 -393
- package/dist/hooks/honesty-ledger-session-scope.test.js +0 -100
- package/dist/hooks/honesty-ledger.d.ts +0 -123
- package/dist/hooks/honesty-ledger.d.ts.map +0 -1
- package/dist/hooks/honesty-ledger.js +0 -226
- package/dist/hooks/honesty-ledger.js.map +0 -1
- package/dist/hooks/honesty-ledger.test.js +0 -466
- package/dist/hooks/inline-report-check.d.ts +0 -63
- package/dist/hooks/inline-report-check.d.ts.map +0 -1
- package/dist/hooks/inline-report-check.js +0 -88
- package/dist/hooks/inline-report-check.js.map +0 -1
- package/dist/hooks/inline-report-check.test.js +0 -96
- package/dist/hooks/pre-tool-use.d.ts +0 -62
- package/dist/hooks/pre-tool-use.d.ts.map +0 -1
- package/dist/hooks/pre-tool-use.js +0 -342
- package/dist/hooks/pre-tool-use.js.map +0 -1
- package/dist/hooks/pre-tool-use.test.js +0 -134
- package/dist/hooks/session-end.d.ts +0 -15
- package/dist/hooks/session-end.d.ts.map +0 -1
- package/dist/hooks/session-end.js +0 -60
- package/dist/hooks/session-end.js.map +0 -1
- package/dist/hooks/session-end.test.js +0 -52
- package/dist/hooks/stop.d.ts +0 -35
- package/dist/hooks/stop.d.ts.map +0 -1
- package/dist/hooks/stop.js +0 -136
- package/dist/hooks/stop.js.map +0 -1
- package/dist/hooks/transcript-active-task.test.js +0 -342
- package/dist/hooks/transcript.d.ts +0 -26
- package/dist/hooks/transcript.d.ts.map +0 -1
- package/dist/hooks/transcript.js +0 -266
- package/dist/hooks/transcript.js.map +0 -1
- package/dist/hooks/transcript.test.js +0 -103
- package/dist/hooks/user-prompt-submit.d.ts +0 -74
- package/dist/hooks/user-prompt-submit.d.ts.map +0 -1
- package/dist/hooks/user-prompt-submit.js +0 -256
- package/dist/hooks/user-prompt-submit.js.map +0 -1
- package/dist/hooks/user-prompt-submit.test.js +0 -118
- package/dist/hooks/versioning-gate.d.ts +0 -101
- package/dist/hooks/versioning-gate.d.ts.map +0 -1
- package/dist/hooks/versioning-gate.js +0 -245
- package/dist/hooks/versioning-gate.js.map +0 -1
- package/dist/hooks/versioning-gate.test.js +0 -368
- package/dist/hooks/workflow-gate.d.ts +0 -64
- package/dist/hooks/workflow-gate.d.ts.map +0 -1
- package/dist/hooks/workflow-gate.js +0 -152
- package/dist/hooks/workflow-gate.js.map +0 -1
- package/dist/hooks/workflow-gate.test.js +0 -197
- package/dist/hooks-cli.d.ts +0 -25
- package/dist/hooks-cli.d.ts.map +0 -1
- package/dist/hooks-cli.js +0 -286
- package/dist/hooks-cli.js.map +0 -1
- package/dist/hooks-cli.test.js +0 -148
- package/dist/origin.d.ts +0 -16
- package/dist/origin.d.ts.map +0 -1
- package/dist/origin.js +0 -92
- package/dist/origin.js.map +0 -1
- package/dist/packs/seed_lessons_ingest.d.ts +0 -30
- package/dist/packs/seed_lessons_ingest.d.ts.map +0 -1
- package/dist/packs/seed_lessons_ingest.js +0 -107
- package/dist/packs/seed_lessons_ingest.js.map +0 -1
- package/dist/project-cli.d.ts +0 -7
- package/dist/project-cli.d.ts.map +0 -1
- package/dist/project-cli.js +0 -145
- package/dist/project-cli.js.map +0 -1
- package/dist/project.d.ts +0 -127
- package/dist/project.d.ts.map +0 -1
- package/dist/project.js +0 -281
- package/dist/project.js.map +0 -1
- package/dist/project.test.js +0 -287
- package/dist/rag/backends/loop_engine.d.ts +0 -61
- package/dist/rag/backends/loop_engine.d.ts.map +0 -1
- package/dist/rag/backends/loop_engine.js +0 -160
- package/dist/rag/backends/loop_engine.js.map +0 -1
- package/dist/recall.d.ts +0 -82
- package/dist/recall.d.ts.map +0 -1
- package/dist/recall.js +0 -81
- package/dist/recall.js.map +0 -1
- package/dist/runtime/agent_bridge/autospawn.d.ts +0 -131
- package/dist/runtime/agent_bridge/autospawn.d.ts.map +0 -1
- package/dist/runtime/agent_bridge/autospawn.js +0 -251
- package/dist/runtime/agent_bridge/autospawn.js.map +0 -1
- package/dist/runtime/chain_state.d.ts +0 -124
- package/dist/runtime/chain_state.d.ts.map +0 -1
- package/dist/runtime/chain_state.js +0 -189
- package/dist/runtime/chain_state.js.map +0 -1
- package/dist/runtime/hooks/permission_decision.d.ts +0 -34
- package/dist/runtime/hooks/permission_decision.d.ts.map +0 -1
- package/dist/runtime/hooks/permission_decision.js +0 -39
- package/dist/runtime/hooks/permission_decision.js.map +0 -1
- package/dist/runtime/workflow_fsm.d.ts +0 -21
- package/dist/runtime/workflow_fsm.d.ts.map +0 -1
- package/dist/runtime/workflow_fsm.js +0 -25
- package/dist/runtime/workflow_fsm.js.map +0 -1
- package/dist/runtime/workflow_map.d.ts +0 -26
- package/dist/runtime/workflow_map.d.ts.map +0 -1
- package/dist/runtime/workflow_map.js +0 -38
- package/dist/runtime/workflow_map.js.map +0 -1
- package/dist/scope.d.ts +0 -48
- package/dist/scope.d.ts.map +0 -1
- package/dist/scope.js +0 -111
- package/dist/scope.js.map +0 -1
- package/dist/setup/cli/topic_create_step.d.ts +0 -84
- package/dist/setup/cli/topic_create_step.d.ts.map +0 -1
- package/dist/setup/cli/topic_create_step.js +0 -213
- package/dist/setup/cli/topic_create_step.js.map +0 -1
- package/dist/system-export.d.ts +0 -65
- package/dist/system-export.d.ts.map +0 -1
- package/dist/system-export.js +0 -194
- package/dist/system-export.js.map +0 -1
- package/dist/utterance/classifier.d.ts +0 -53
- package/dist/utterance/classifier.d.ts.map +0 -1
- package/dist/utterance/classifier.js +0 -184
- package/dist/utterance/classifier.js.map +0 -1
- package/dist/utterance/classifier.test.js +0 -147
package/dist/engine-client.js
DELETED
|
@@ -1,301 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Thin JSON-RPC 2.0 client that spawns `loop-engine serve` as a
|
|
3
|
-
* subprocess and talks to it over stdin/stdout.
|
|
4
|
-
*
|
|
5
|
-
* Responsibilities:
|
|
6
|
-
* - Spawn the engine binary lazily on first call.
|
|
7
|
-
* - Map outgoing requests to pending promises by `id`.
|
|
8
|
-
* - Translate JSON-RPC error responses into thrown JS Errors with
|
|
9
|
-
* `.code` and `.data` attached.
|
|
10
|
-
* - Survive crashes: if the subprocess exits, the next call respawns.
|
|
11
|
-
*
|
|
12
|
-
* Binary discovery (v0.4 — see src/config.ts resolveEngineBin):
|
|
13
|
-
* 1. `OPENSQUID_ENGINE_BIN` env var — explicit override
|
|
14
|
-
* 2. `<data-root>/config.json` `engine_bin` field — persisted choice
|
|
15
|
-
* 3. Auto-search common dev paths (~/projects/<*>/engine/target/release/
|
|
16
|
-
* and ~/work/<*>/engine/target/release/)
|
|
17
|
-
* 4. $PATH — system-installed binary
|
|
18
|
-
* 5. Throw with a helpful error message
|
|
19
|
-
*
|
|
20
|
-
* On first successful auto-discovery, the resolved path is written back
|
|
21
|
-
* to config.json so subsequent sessions skip the search. Moving the
|
|
22
|
-
* loop-engine checkout invalidates the cached path; the next start
|
|
23
|
-
* re-discovers automatically.
|
|
24
|
-
*
|
|
25
|
-
* v0.2 keeps the subprocess alive across the MCP session lifetime —
|
|
26
|
-
* a single engine process serves all tool calls until the MCP host
|
|
27
|
-
* disconnects.
|
|
28
|
-
*/
|
|
29
|
-
import { spawn } from "node:child_process";
|
|
30
|
-
import { createInterface } from "node:readline";
|
|
31
|
-
import { resolveEngineBin } from "./config.js";
|
|
32
|
-
export class RpcError extends Error {
|
|
33
|
-
code;
|
|
34
|
-
data;
|
|
35
|
-
constructor(message, code, data) {
|
|
36
|
-
super(message);
|
|
37
|
-
this.name = "RpcError";
|
|
38
|
-
this.code = code;
|
|
39
|
-
this.data = data;
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
export class EngineClient {
|
|
43
|
-
proc = null;
|
|
44
|
-
reader = null;
|
|
45
|
-
pending = new Map();
|
|
46
|
-
nextId = 1;
|
|
47
|
-
startupAck = null;
|
|
48
|
-
/** Lazily spawn the engine subprocess. Idempotent. */
|
|
49
|
-
async ensureStarted() {
|
|
50
|
-
if (this.proc)
|
|
51
|
-
return;
|
|
52
|
-
if (this.startupAck)
|
|
53
|
-
return this.startupAck;
|
|
54
|
-
const bin = await resolveEngineBin();
|
|
55
|
-
if (!bin) {
|
|
56
|
-
throw new Error("loop-engine binary not found. Set OPENSQUID_ENGINE_BIN, or run " +
|
|
57
|
-
"`opensquid engine set-path <path>`, or build the engine at " +
|
|
58
|
-
"~/projects/loop/engine/target/release/loop-engine");
|
|
59
|
-
}
|
|
60
|
-
const proc = spawn(bin, ["serve"], {
|
|
61
|
-
stdio: ["pipe", "pipe", "pipe"],
|
|
62
|
-
env: {
|
|
63
|
-
...process.env,
|
|
64
|
-
// Pin the engine to opensquid's storage root so the on-disk
|
|
65
|
-
// layout is shared across both halves.
|
|
66
|
-
LOOP_HOME: process.env.LOOP_HOME ?? `${process.env.HOME}/.opensquid`,
|
|
67
|
-
},
|
|
68
|
-
});
|
|
69
|
-
this.proc = proc;
|
|
70
|
-
this.reader = createInterface({ input: proc.stdout });
|
|
71
|
-
this.reader.on("line", (line) => this.handleLine(line));
|
|
72
|
-
proc.stderr.on("data", (chunk) => {
|
|
73
|
-
// Engine logs go to stderr; mirror them but tag so they're
|
|
74
|
-
// distinguishable from opensquid's own logs.
|
|
75
|
-
const text = chunk.toString().trimEnd();
|
|
76
|
-
if (text)
|
|
77
|
-
console.error(`[engine] ${text}`);
|
|
78
|
-
});
|
|
79
|
-
proc.on("exit", (code) => {
|
|
80
|
-
const reason = `engine subprocess exited (code=${code ?? "null"})`;
|
|
81
|
-
console.error(`[opensquid] ${reason}`);
|
|
82
|
-
this.proc = null;
|
|
83
|
-
this.reader = null;
|
|
84
|
-
// #170: clear the cached startup promise so the next call's
|
|
85
|
-
// `ensureStarted()` actually respawns instead of returning the
|
|
86
|
-
// stale resolved promise from the previous lifetime. Honors the
|
|
87
|
-
// "Survive crashes: if the subprocess exits, the next call
|
|
88
|
-
// respawns" invariant in this file's header docstring.
|
|
89
|
-
this.startupAck = null;
|
|
90
|
-
// Reject all in-flight calls so callers can retry.
|
|
91
|
-
for (const [, pending] of this.pending) {
|
|
92
|
-
pending.reject(new Error(reason));
|
|
93
|
-
}
|
|
94
|
-
this.pending.clear();
|
|
95
|
-
});
|
|
96
|
-
proc.on("error", (err) => {
|
|
97
|
-
console.error(`[opensquid] engine spawn error: ${err.message}`);
|
|
98
|
-
});
|
|
99
|
-
// Single ping to confirm the engine is live before we return.
|
|
100
|
-
this.startupAck = this.call("ping", {})
|
|
101
|
-
.then(() => undefined)
|
|
102
|
-
.catch((e) => {
|
|
103
|
-
throw new Error(`engine failed to start: ${e.message}`);
|
|
104
|
-
});
|
|
105
|
-
return this.startupAck;
|
|
106
|
-
}
|
|
107
|
-
handleLine(line) {
|
|
108
|
-
const trimmed = line.trim();
|
|
109
|
-
if (!trimmed)
|
|
110
|
-
return;
|
|
111
|
-
let msg;
|
|
112
|
-
try {
|
|
113
|
-
msg = JSON.parse(trimmed);
|
|
114
|
-
}
|
|
115
|
-
catch (e) {
|
|
116
|
-
console.error(`[opensquid] failed to parse engine line: ${e}`);
|
|
117
|
-
return;
|
|
118
|
-
}
|
|
119
|
-
const pending = this.pending.get(msg.id);
|
|
120
|
-
if (!pending) {
|
|
121
|
-
console.error(`[opensquid] response for unknown id=${msg.id}`);
|
|
122
|
-
return;
|
|
123
|
-
}
|
|
124
|
-
this.pending.delete(msg.id);
|
|
125
|
-
if (msg.error) {
|
|
126
|
-
pending.reject(new RpcError(msg.error.message, msg.error.code, msg.error.data));
|
|
127
|
-
}
|
|
128
|
-
else {
|
|
129
|
-
pending.resolve(msg.result);
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
/**
|
|
133
|
-
* Send a JSON-RPC request, await the response. Throws `RpcError` on
|
|
134
|
-
* engine-side errors; throws `Error` on subprocess crashes.
|
|
135
|
-
*/
|
|
136
|
-
async call(method, params) {
|
|
137
|
-
if (method !== "ping")
|
|
138
|
-
await this.ensureStarted();
|
|
139
|
-
const id = this.nextId++;
|
|
140
|
-
return new Promise((resolve, reject) => {
|
|
141
|
-
this.pending.set(id, {
|
|
142
|
-
resolve: (v) => resolve(v),
|
|
143
|
-
reject,
|
|
144
|
-
});
|
|
145
|
-
const req = JSON.stringify({ jsonrpc: "2.0", id, method, params });
|
|
146
|
-
if (!this.proc) {
|
|
147
|
-
reject(new Error("engine subprocess not running"));
|
|
148
|
-
return;
|
|
149
|
-
}
|
|
150
|
-
this.proc.stdin.write(req + "\n");
|
|
151
|
-
});
|
|
152
|
-
}
|
|
153
|
-
/** Graceful shutdown — kill the subprocess. */
|
|
154
|
-
shutdown() {
|
|
155
|
-
if (this.proc) {
|
|
156
|
-
this.proc.kill();
|
|
157
|
-
this.proc = null;
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
export class OpenSquidEngine {
|
|
162
|
-
client = new EngineClient();
|
|
163
|
-
shutdown() {
|
|
164
|
-
this.client.shutdown();
|
|
165
|
-
}
|
|
166
|
-
ping() {
|
|
167
|
-
return this.client.call("ping", {});
|
|
168
|
-
}
|
|
169
|
-
createLesson(args) {
|
|
170
|
-
return this.client.call("lesson.create", args);
|
|
171
|
-
}
|
|
172
|
-
recall(args) {
|
|
173
|
-
return this.client.call("lesson.recall", args);
|
|
174
|
-
}
|
|
175
|
-
promote(args) {
|
|
176
|
-
return this.client.call("lesson.promote", args);
|
|
177
|
-
}
|
|
178
|
-
discard(args) {
|
|
179
|
-
return this.client.call("lesson.discard", args);
|
|
180
|
-
}
|
|
181
|
-
/**
|
|
182
|
-
* v0.5 / engine v1.3: paginated list across the four non-discarded
|
|
183
|
-
* status dirs. Order is deterministic (status then id ascending).
|
|
184
|
-
* Default limit 50, capped at 500. Pass `statuses` to restrict to
|
|
185
|
-
* specific dirs (e.g. `["pending"]` for the pending-candidates flow).
|
|
186
|
-
*/
|
|
187
|
-
listLessons(args) {
|
|
188
|
-
return this.client.call("lesson.list", args);
|
|
189
|
-
}
|
|
190
|
-
/**
|
|
191
|
-
* v0.5 / engine v1.3: record a thumbs-up or thumbs-down on a lesson.
|
|
192
|
-
* Adds to the lesson's `external_signal_sources`, which feeds the
|
|
193
|
-
* wedge gate's signal-diversity check. Idempotent on
|
|
194
|
-
* `source_signal_id` — passing the same signal twice doesn't
|
|
195
|
-
* double-count. If `source_signal_id` is omitted, the engine mints a
|
|
196
|
-
* synthetic one (the call still records).
|
|
197
|
-
*/
|
|
198
|
-
captureFeedback(args) {
|
|
199
|
-
return this.client.call("lesson.capture_feedback", args);
|
|
200
|
-
}
|
|
201
|
-
/**
|
|
202
|
-
* v0.5 / engine v1.3: point an old lesson at a new replacement.
|
|
203
|
-
* Old lesson moves to `superseded/`, new lesson is unaffected. The
|
|
204
|
-
* causal chain is preserved via `superseded_by`. User-authored
|
|
205
|
-
* lessons are protected unless `force: true`.
|
|
206
|
-
*
|
|
207
|
-
* Engine errors:
|
|
208
|
-
* -32004 — supersede blocked (cycle detected, self-reference,
|
|
209
|
-
* or replacement not found)
|
|
210
|
-
* -32001 — user lesson immune (force=true required)
|
|
211
|
-
* -32002 — old or new lesson not found
|
|
212
|
-
*/
|
|
213
|
-
supersedeLesson(args) {
|
|
214
|
-
return this.client.call("lesson.supersede", args);
|
|
215
|
-
}
|
|
216
|
-
createMemory(args) {
|
|
217
|
-
return this.client.call("memory.create", args);
|
|
218
|
-
}
|
|
219
|
-
searchMemory(args) {
|
|
220
|
-
return this.client.call("memory.search", args);
|
|
221
|
-
}
|
|
222
|
-
/**
|
|
223
|
-
* v0.3.1: fetch a single memory by id with full content + scope.
|
|
224
|
-
* Throws `RpcError` with code -32002 if no memory with that id
|
|
225
|
-
* exists (engine returns `DispatchError::NotFound`).
|
|
226
|
-
*/
|
|
227
|
-
getMemory(args) {
|
|
228
|
-
return this.client.call("memory.get", args);
|
|
229
|
-
}
|
|
230
|
-
/**
|
|
231
|
-
* v0.5 / engine v1.4: central RAG-style assembly. Returns active
|
|
232
|
-
* lessons (deterministic-sorted, gate-annotated, applied_count
|
|
233
|
-
* bumped) + optional memory recall in one shot. This is what a host
|
|
234
|
-
* like Hermes calls to get "what rules apply right now" instead of
|
|
235
|
-
* stitching together listLessons + searchMemory.
|
|
236
|
-
*
|
|
237
|
-
* Skill/persona/team activation IDs are not threaded through in v0.5
|
|
238
|
-
* (deferred to a later release per find-simple-solutions). The
|
|
239
|
-
* active_skills / active_personas / active_teams arrays in the
|
|
240
|
-
* response ship empty.
|
|
241
|
-
*/
|
|
242
|
-
assembleManifest(args) {
|
|
243
|
-
return this.client.call("manifest.assemble", args);
|
|
244
|
-
}
|
|
245
|
-
/**
|
|
246
|
-
* v0.5 / engine v1.3: paginated memory enumeration. Filter-optional
|
|
247
|
-
* via scope_filter (same wire shape as searchMemory). Default limit
|
|
248
|
-
* 50, capped at 500. Order is deterministic (id ascending — memory
|
|
249
|
-
* ids are ULID-shaped so this is roughly chronological).
|
|
250
|
-
*
|
|
251
|
-
* Returns frontmatter rows but NOT body — call getMemory(id) for
|
|
252
|
-
* the full content of any single hit. consumed_by_user_lessons is
|
|
253
|
-
* the reverse-citation count enforcing the user-immunity invariant
|
|
254
|
-
* (>0 means a user-authored lesson cites this memory; prune refuses).
|
|
255
|
-
*/
|
|
256
|
-
listMemories(args) {
|
|
257
|
-
return this.client.call("memory.list", args);
|
|
258
|
-
}
|
|
259
|
-
/**
|
|
260
|
-
* v0.4: mutate description / content / scope on an existing memory.
|
|
261
|
-
* Identity, citation counter, derived_from, and origin are always
|
|
262
|
-
* preserved. Re-embeds on content change; cheap path for
|
|
263
|
-
* description/scope-only edits. At least one mutable field must
|
|
264
|
-
* be supplied. Throws `RpcError` -32002 if the id doesn't exist.
|
|
265
|
-
*/
|
|
266
|
-
updateMemory(args) {
|
|
267
|
-
return this.client.call("memory.update", args);
|
|
268
|
-
}
|
|
269
|
-
/**
|
|
270
|
-
* v0.4: `forget` — delete a memory. `force = false` (default)
|
|
271
|
-
* respects user-immunity (returns RpcError -32003 if cited by a
|
|
272
|
-
* user-authored lesson). `force = true` is the user-initiated
|
|
273
|
-
* override.
|
|
274
|
-
*/
|
|
275
|
-
deleteMemory(args) {
|
|
276
|
-
return this.client.call("memory.delete", args);
|
|
277
|
-
}
|
|
278
|
-
// ---- v0.6.1 — phase ledger (engine 0.5.0+) ----------------------
|
|
279
|
-
/**
|
|
280
|
-
* Record a phase entry for `task_id`. Idempotent: re-logging the
|
|
281
|
-
* same phase returns `newly_recorded: false`. `phase` must be one
|
|
282
|
-
* of: pre_research, learn, code, test, audit, post_research, fix.
|
|
283
|
-
*
|
|
284
|
-
* Pre-#166 this also took a `session_id`, but the writer's MCP
|
|
285
|
-
* session id and the reader's Claude Code session UUID were two
|
|
286
|
-
* different id surfaces — the ledger was unreadable across them.
|
|
287
|
-
* Dropped in favor of per-task scoping; a task that spans multiple
|
|
288
|
-
* sessions now accumulates phases correctly.
|
|
289
|
-
*/
|
|
290
|
-
logPhase(args) {
|
|
291
|
-
return this.client.call("task.log_phase", args);
|
|
292
|
-
}
|
|
293
|
-
/**
|
|
294
|
-
* Fetch the workflow phase ledger for `task_id`. Returns the set of
|
|
295
|
-
* phases logged + the entries with timestamps, sorted
|
|
296
|
-
* chronologically.
|
|
297
|
-
*/
|
|
298
|
-
getTaskLedger(args) {
|
|
299
|
-
return this.client.call("task.get_ledger", args);
|
|
300
|
-
}
|
|
301
|
-
}
|
|
@@ -1,118 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* engine-client subprocess lifecycle tests.
|
|
3
|
-
*
|
|
4
|
-
* #170 (2026-05-17): the first test for engine-client.ts. Spawned by the
|
|
5
|
-
* pkill-validation incident that surfaced a permanent-stuck-state bug
|
|
6
|
-
* when the engine subprocess exits externally:
|
|
7
|
-
*
|
|
8
|
-
* 1. ensureStarted() spawns subprocess + caches a resolved
|
|
9
|
-
* `startupAck` promise after the initial ping succeeds.
|
|
10
|
-
* 2. Subprocess dies (pkill / OOM / crash).
|
|
11
|
-
* 3. proc.on("exit") nulls `proc` and `reader` but pre-#170 left
|
|
12
|
-
* `startupAck` truthy.
|
|
13
|
-
* 4. Next call: ensureStarted() returns the cached resolved
|
|
14
|
-
* startupAck without respawning. call() then sees `proc === null`
|
|
15
|
-
* and rejects with "engine subprocess not running" — for the rest
|
|
16
|
-
* of the MCP server's lifetime.
|
|
17
|
-
*
|
|
18
|
-
* This test mocks `node:child_process` so we can simulate the exit
|
|
19
|
-
* event deterministically without spawning a real binary.
|
|
20
|
-
*/
|
|
21
|
-
import { EventEmitter } from "node:events";
|
|
22
|
-
import { PassThrough } from "node:stream";
|
|
23
|
-
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
24
|
-
const mockSpawn = vi.fn();
|
|
25
|
-
vi.mock("node:child_process", () => ({
|
|
26
|
-
spawn: (...args) => mockSpawn(...args),
|
|
27
|
-
}));
|
|
28
|
-
// vi.mock must be set up before the import; dynamic import keeps that ordering.
|
|
29
|
-
const { EngineClient } = await import("./engine-client.js");
|
|
30
|
-
function makeMockProc() {
|
|
31
|
-
const proc = new EventEmitter();
|
|
32
|
-
proc.stdin = new PassThrough();
|
|
33
|
-
proc.stdout = new PassThrough();
|
|
34
|
-
proc.stderr = new PassThrough();
|
|
35
|
-
proc.kill = vi.fn();
|
|
36
|
-
return proc;
|
|
37
|
-
}
|
|
38
|
-
/** Read the next line written to a stream (e.g. mock stdin). */
|
|
39
|
-
function nextLine(stream) {
|
|
40
|
-
return new Promise((resolve) => {
|
|
41
|
-
let buf = "";
|
|
42
|
-
const onData = (chunk) => {
|
|
43
|
-
buf += chunk.toString("utf8");
|
|
44
|
-
const nl = buf.indexOf("\n");
|
|
45
|
-
if (nl >= 0) {
|
|
46
|
-
stream.off("data", onData);
|
|
47
|
-
resolve(buf.slice(0, nl));
|
|
48
|
-
}
|
|
49
|
-
};
|
|
50
|
-
stream.on("data", onData);
|
|
51
|
-
});
|
|
52
|
-
}
|
|
53
|
-
beforeEach(() => {
|
|
54
|
-
mockSpawn.mockReset();
|
|
55
|
-
});
|
|
56
|
-
afterEach(() => {
|
|
57
|
-
vi.useRealTimers();
|
|
58
|
-
});
|
|
59
|
-
describe("OpenSquidEngine subprocess lifecycle (#170)", () => {
|
|
60
|
-
it("respawns the subprocess after an external exit", async () => {
|
|
61
|
-
const proc1 = makeMockProc();
|
|
62
|
-
const proc2 = makeMockProc();
|
|
63
|
-
mockSpawn.mockReturnValueOnce(proc1).mockReturnValueOnce(proc2);
|
|
64
|
-
// Construct engine via fresh import each test so it has no resolveEngineBin
|
|
65
|
-
// memo from a previous test (resolveEngineBin reads the env var on each call).
|
|
66
|
-
process.env.OPENSQUID_ENGINE_BIN = "/fake/path/loop-engine";
|
|
67
|
-
const engine = new EngineClient();
|
|
68
|
-
// --- First call: triggers ensureStarted() → spawns proc1, sends ping ---
|
|
69
|
-
const callP1 = engine.call("task.example", {});
|
|
70
|
-
// Wait for proc1's stdin to receive the startup ping, then ack it.
|
|
71
|
-
const startupPingLine = await nextLine(proc1.stdin);
|
|
72
|
-
const startupReq = JSON.parse(startupPingLine);
|
|
73
|
-
expect(startupReq.method).toBe("ping");
|
|
74
|
-
proc1.stdout.write(JSON.stringify({ jsonrpc: "2.0", id: startupReq.id, result: { ok: true } }) + "\n");
|
|
75
|
-
// Now proc1's stdin will receive the user's actual call. Respond.
|
|
76
|
-
const userReqLine = await nextLine(proc1.stdin);
|
|
77
|
-
const userReq = JSON.parse(userReqLine);
|
|
78
|
-
expect(userReq.method).toBe("task.example");
|
|
79
|
-
proc1.stdout.write(JSON.stringify({ jsonrpc: "2.0", id: userReq.id, result: { ok: true } }) + "\n");
|
|
80
|
-
await expect(callP1).resolves.toEqual({ ok: true });
|
|
81
|
-
// --- Simulate external subprocess exit ---
|
|
82
|
-
proc1.emit("exit", 1);
|
|
83
|
-
// Give the exit handler microtasks a tick to run.
|
|
84
|
-
await new Promise((r) => setImmediate(r));
|
|
85
|
-
// --- Second call: must respawn proc2 (pre-#170 this would have thrown
|
|
86
|
-
// "engine subprocess not running" because startupAck was still cached) ---
|
|
87
|
-
const callP2 = engine.call("task.example", {});
|
|
88
|
-
const startupPing2 = await nextLine(proc2.stdin);
|
|
89
|
-
const startupReq2 = JSON.parse(startupPing2);
|
|
90
|
-
expect(startupReq2.method).toBe("ping");
|
|
91
|
-
proc2.stdout.write(JSON.stringify({ jsonrpc: "2.0", id: startupReq2.id, result: { ok: true } }) + "\n");
|
|
92
|
-
const userReq2Line = await nextLine(proc2.stdin);
|
|
93
|
-
const userReq2 = JSON.parse(userReq2Line);
|
|
94
|
-
expect(userReq2.method).toBe("task.example");
|
|
95
|
-
proc2.stdout.write(JSON.stringify({ jsonrpc: "2.0", id: userReq2.id, result: { ok: true } }) + "\n");
|
|
96
|
-
await expect(callP2).resolves.toEqual({ ok: true });
|
|
97
|
-
expect(mockSpawn).toHaveBeenCalledTimes(2);
|
|
98
|
-
delete process.env.OPENSQUID_ENGINE_BIN;
|
|
99
|
-
});
|
|
100
|
-
it("rejects in-flight pending calls when the subprocess exits", async () => {
|
|
101
|
-
const proc1 = makeMockProc();
|
|
102
|
-
mockSpawn.mockReturnValueOnce(proc1);
|
|
103
|
-
process.env.OPENSQUID_ENGINE_BIN = "/fake/path/loop-engine";
|
|
104
|
-
const engine = new EngineClient();
|
|
105
|
-
// Start a call, ack the startup ping, then DON'T respond to the user
|
|
106
|
-
// call — instead simulate exit.
|
|
107
|
-
const callP = engine.call("task.example", {});
|
|
108
|
-
const startupPing = await nextLine(proc1.stdin);
|
|
109
|
-
const startupReq = JSON.parse(startupPing);
|
|
110
|
-
proc1.stdout.write(JSON.stringify({ jsonrpc: "2.0", id: startupReq.id, result: { ok: true } }) + "\n");
|
|
111
|
-
// Drain the user-call line so the test doesn't hang on backpressure.
|
|
112
|
-
await nextLine(proc1.stdin);
|
|
113
|
-
// Simulate crash.
|
|
114
|
-
proc1.emit("exit", null);
|
|
115
|
-
await expect(callP).rejects.toThrow(/engine subprocess exited/);
|
|
116
|
-
delete process.env.OPENSQUID_ENGINE_BIN;
|
|
117
|
-
});
|
|
118
|
-
});
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* `read_chain_state` primitive (T-ASC, ASC.5).
|
|
3
|
-
*
|
|
4
|
-
* Exposes the persisted T-ASC chain-state (or an idle-default shape) to
|
|
5
|
-
* skill YAML `process:` chains. Used by ASC.5's reframed scope-decomposer
|
|
6
|
-
* chain-handoff rules to read enrichment fields (`pre_research_path`,
|
|
7
|
-
* `spec_path`, `task_ids`) when shaping the structured `directive`
|
|
8
|
-
* verdict's `next_action.args`.
|
|
9
|
-
*
|
|
10
|
-
* Returns a stable shape: a non-null object that always has `stage`
|
|
11
|
-
* (defaulting to `'idle'`) and `history` (defaulting to `[]`), plus
|
|
12
|
-
* optional enrichment fields. The `if:` grammar's field access is
|
|
13
|
-
* dot-notation; a stable shape means rule expressions like
|
|
14
|
-
* `chain.pre_research_path` never trigger an undefined-access on the
|
|
15
|
-
* absent-file path.
|
|
16
|
-
*
|
|
17
|
-
* Side-effect-free, no-throw — the underlying `readChainState` returns
|
|
18
|
-
* null on absent/malformed; this primitive coalesces to the idle-default
|
|
19
|
-
* shape. `memoizable: false` because the chain state changes between
|
|
20
|
-
* turns (writers fire on UserPromptSubmit, PreToolUse, log_phase) — a
|
|
21
|
-
* memoized stage would mask the very transitions we're reading.
|
|
22
|
-
*
|
|
23
|
-
* `durable: false` (pure read, cheap stat+readFile). `costEstimateMs: 1`.
|
|
24
|
-
*
|
|
25
|
-
* Imports from: zod, ../runtime/chain_state.js, ../runtime/result.js,
|
|
26
|
-
* ./registry.js.
|
|
27
|
-
* Imported by: src/runtime/bootstrap.ts (registry wiring).
|
|
28
|
-
*/
|
|
29
|
-
import { z } from 'zod';
|
|
30
|
-
import { type ChainStage } from '../runtime/chain_state.js';
|
|
31
|
-
import type { FunctionDef } from './registry.js';
|
|
32
|
-
declare const NoArgs: z.ZodObject<{}, "strict", z.ZodTypeAny, {}, {}>;
|
|
33
|
-
type NoArgs = z.input<typeof NoArgs>;
|
|
34
|
-
/**
|
|
35
|
-
* The primitive's output shape. `stage` is always present (defaults to
|
|
36
|
-
* 'idle' when no chain file exists). Enrichment fields are optional and
|
|
37
|
-
* appear when their writers populated them.
|
|
38
|
-
*/
|
|
39
|
-
export interface ReadChainStateOutput {
|
|
40
|
-
stage: ChainStage;
|
|
41
|
-
history: {
|
|
42
|
-
stage: ChainStage;
|
|
43
|
-
at: string;
|
|
44
|
-
}[];
|
|
45
|
-
pre_research_path?: string;
|
|
46
|
-
spec_path?: string;
|
|
47
|
-
task_ids?: string[];
|
|
48
|
-
}
|
|
49
|
-
export declare const ReadChainState: FunctionDef<NoArgs, ReadChainStateOutput>;
|
|
50
|
-
export {};
|
|
51
|
-
//# sourceMappingURL=chain_state.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"chain_state.d.ts","sourceRoot":"","sources":["../../src/functions/chain_state.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAkB,KAAK,UAAU,EAAE,MAAM,2BAA2B,CAAC;AAG5E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAEjD,QAAA,MAAM,MAAM,iDAAwB,CAAC;AACrC,KAAK,MAAM,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,MAAM,CAAC,CAAC;AAErC;;;;GAIG;AACH,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,UAAU,CAAC;IAClB,OAAO,EAAE;QAAE,KAAK,EAAE,UAAU,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAC7C,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;CACrB;AAED,eAAO,MAAM,cAAc,EAAE,WAAW,CAAC,MAAM,EAAE,oBAAoB,CAyBpE,CAAC"}
|
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* `read_chain_state` primitive (T-ASC, ASC.5).
|
|
3
|
-
*
|
|
4
|
-
* Exposes the persisted T-ASC chain-state (or an idle-default shape) to
|
|
5
|
-
* skill YAML `process:` chains. Used by ASC.5's reframed scope-decomposer
|
|
6
|
-
* chain-handoff rules to read enrichment fields (`pre_research_path`,
|
|
7
|
-
* `spec_path`, `task_ids`) when shaping the structured `directive`
|
|
8
|
-
* verdict's `next_action.args`.
|
|
9
|
-
*
|
|
10
|
-
* Returns a stable shape: a non-null object that always has `stage`
|
|
11
|
-
* (defaulting to `'idle'`) and `history` (defaulting to `[]`), plus
|
|
12
|
-
* optional enrichment fields. The `if:` grammar's field access is
|
|
13
|
-
* dot-notation; a stable shape means rule expressions like
|
|
14
|
-
* `chain.pre_research_path` never trigger an undefined-access on the
|
|
15
|
-
* absent-file path.
|
|
16
|
-
*
|
|
17
|
-
* Side-effect-free, no-throw — the underlying `readChainState` returns
|
|
18
|
-
* null on absent/malformed; this primitive coalesces to the idle-default
|
|
19
|
-
* shape. `memoizable: false` because the chain state changes between
|
|
20
|
-
* turns (writers fire on UserPromptSubmit, PreToolUse, log_phase) — a
|
|
21
|
-
* memoized stage would mask the very transitions we're reading.
|
|
22
|
-
*
|
|
23
|
-
* `durable: false` (pure read, cheap stat+readFile). `costEstimateMs: 1`.
|
|
24
|
-
*
|
|
25
|
-
* Imports from: zod, ../runtime/chain_state.js, ../runtime/result.js,
|
|
26
|
-
* ./registry.js.
|
|
27
|
-
* Imported by: src/runtime/bootstrap.ts (registry wiring).
|
|
28
|
-
*/
|
|
29
|
-
import { z } from 'zod';
|
|
30
|
-
import { readChainState } from '../runtime/chain_state.js';
|
|
31
|
-
import { ok } from '../runtime/result.js';
|
|
32
|
-
const NoArgs = z.object({}).strict();
|
|
33
|
-
export const ReadChainState = {
|
|
34
|
-
name: 'read_chain_state',
|
|
35
|
-
argSchema: NoArgs,
|
|
36
|
-
durable: false,
|
|
37
|
-
memoizable: false,
|
|
38
|
-
costEstimateMs: 1,
|
|
39
|
-
execute: async (_args, ctx) => {
|
|
40
|
-
const state = await readChainState(ctx.sessionId);
|
|
41
|
-
if (state === null) {
|
|
42
|
-
// Idle-default shape: callers can always access `chain.stage` and
|
|
43
|
-
// `chain.history` without an undefined check. Enrichment fields
|
|
44
|
-
// remain absent (not undefined — the field simply isn't on the
|
|
45
|
-
// object), so the `if:` grammar's existence checks work correctly.
|
|
46
|
-
return ok({ stage: 'idle', history: [] });
|
|
47
|
-
}
|
|
48
|
-
return ok({
|
|
49
|
-
stage: state.stage,
|
|
50
|
-
history: state.history,
|
|
51
|
-
...(state.pre_research_path !== undefined
|
|
52
|
-
? { pre_research_path: state.pre_research_path }
|
|
53
|
-
: {}),
|
|
54
|
-
...(state.spec_path !== undefined ? { spec_path: state.spec_path } : {}),
|
|
55
|
-
...(state.task_ids !== undefined ? { task_ids: state.task_ids } : {}),
|
|
56
|
-
});
|
|
57
|
-
},
|
|
58
|
-
};
|
|
59
|
-
//# sourceMappingURL=chain_state.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"chain_state.js","sourceRoot":"","sources":["../../src/functions/chain_state.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,cAAc,EAAmB,MAAM,2BAA2B,CAAC;AAC5E,OAAO,EAAE,EAAE,EAAE,MAAM,sBAAsB,CAAC;AAI1C,MAAM,MAAM,GAAG,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC;AAgBrC,MAAM,CAAC,MAAM,cAAc,GAA8C;IACvE,IAAI,EAAE,kBAAkB;IACxB,SAAS,EAAE,MAAM;IACjB,OAAO,EAAE,KAAK;IACd,UAAU,EAAE,KAAK;IACjB,cAAc,EAAE,CAAC;IACjB,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE;QAC5B,MAAM,KAAK,GAAG,MAAM,cAAc,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QAClD,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;YACnB,kEAAkE;YAClE,gEAAgE;YAChE,+DAA+D;YAC/D,mEAAmE;YACnE,OAAO,EAAE,CAAC,EAAE,KAAK,EAAE,MAAe,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC,CAAC;QACrD,CAAC;QACD,OAAO,EAAE,CAAC;YACR,KAAK,EAAE,KAAK,CAAC,KAAK;YAClB,OAAO,EAAE,KAAK,CAAC,OAAO;YACtB,GAAG,CAAC,KAAK,CAAC,iBAAiB,KAAK,SAAS;gBACvC,CAAC,CAAC,EAAE,iBAAiB,EAAE,KAAK,CAAC,iBAAiB,EAAE;gBAChD,CAAC,CAAC,EAAE,CAAC;YACP,GAAG,CAAC,KAAK,CAAC,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,KAAK,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACxE,GAAG,CAAC,KAAK,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SACtE,CAAC,CAAC;IACL,CAAC;CACF,CAAC"}
|
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Drift catalog — automated SessionEnd scan that surfaces this session's
|
|
3
|
-
* drift signals (0.7.22 / drift D10).
|
|
4
|
-
*
|
|
5
|
-
* D10 in the catalog: previously the agent only catalogued its drifts
|
|
6
|
-
* AFTER the user prompted "please put in all the drifting issues found
|
|
7
|
-
* recently." The whole project is anti-drift; the agent should be
|
|
8
|
-
* cataloguing its own drifts continuously as the dogfood proof.
|
|
9
|
-
*
|
|
10
|
-
* This module scans the session's JSONL transcript at SessionEnd for
|
|
11
|
-
* three classes of drift markers:
|
|
12
|
-
*
|
|
13
|
-
* 1. User-correction phrases in user messages ("you drifted",
|
|
14
|
-
* "stop X-ing", "no not that", "wrong")
|
|
15
|
-
* 2. Locked-rule citations in user OR assistant messages
|
|
16
|
-
* (feedback_*, mem-*, drift D\d+)
|
|
17
|
-
* 3. Agent mea-culpa phrases in assistant messages ("I should
|
|
18
|
-
* have", "my mistake", "I drifted", "I false-stopped")
|
|
19
|
-
*
|
|
20
|
-
* Hits are appended to `<dataRoot>/projects/<uuid>/drift-catalog.jsonl`.
|
|
21
|
-
* One JSON record per line: `{timestamp, session_id, kind, evidence}`.
|
|
22
|
-
*
|
|
23
|
-
* If the project UUID can't be resolved (no `.opensquid/project.json`
|
|
24
|
-
* card in any ancestor of cwd), entries fall back to
|
|
25
|
-
* `<dataRoot>/sessions/<session_id>/drift-catalog.jsonl` so the data
|
|
26
|
-
* isn't lost.
|
|
27
|
-
*
|
|
28
|
-
* Fail-open: any error (missing transcript, bad JSONL, write failure)
|
|
29
|
-
* is swallowed with a stderr warning. SessionEnd is cleanup, not
|
|
30
|
-
* blocking.
|
|
31
|
-
*/
|
|
32
|
-
export type DriftMarkerKind = "user_correction" | "rule_citation" | "mea_culpa";
|
|
33
|
-
export interface DriftCatalogEntry {
|
|
34
|
-
/** ISO timestamp the entry was recorded. */
|
|
35
|
-
timestamp: string;
|
|
36
|
-
/** Claude Code session id. */
|
|
37
|
-
session_id: string;
|
|
38
|
-
/** Which class of marker fired. */
|
|
39
|
-
kind: DriftMarkerKind;
|
|
40
|
-
/** The matched substring (capped at 200 chars). */
|
|
41
|
-
evidence: string;
|
|
42
|
-
/** Optional surrounding context (up to 200 chars on either side). */
|
|
43
|
-
context?: string;
|
|
44
|
-
}
|
|
45
|
-
/**
|
|
46
|
-
* Scan a transcript and return all detected drift markers. Pure
|
|
47
|
-
* function; exported for direct testing.
|
|
48
|
-
*/
|
|
49
|
-
export declare function scanTranscriptForDrift(lines: string[], sessionId: string, now?: () => Date): DriftCatalogEntry[];
|
|
50
|
-
/**
|
|
51
|
-
* Run the SessionEnd drift-catalog scan + persist results. Returns
|
|
52
|
-
* the number of entries written (0 if nothing matched OR write failed).
|
|
53
|
-
*/
|
|
54
|
-
export declare function runDriftCatalogScan(input: {
|
|
55
|
-
sessionId: string;
|
|
56
|
-
transcriptPath?: string;
|
|
57
|
-
cwd?: string;
|
|
58
|
-
dataRoot?: string;
|
|
59
|
-
now?: () => Date;
|
|
60
|
-
}): Promise<number>;
|
|
61
|
-
/**
|
|
62
|
-
* Decide where to write the catalog: project-scoped if we can resolve
|
|
63
|
-
* a project UUID from cwd; session-scoped fallback otherwise.
|
|
64
|
-
*
|
|
65
|
-
* Exported for testing.
|
|
66
|
-
*/
|
|
67
|
-
export declare function resolveCatalogPath(cwd: string | undefined, sessionId: string, dataRoot?: string): Promise<string>;
|
|
68
|
-
//# sourceMappingURL=drift-catalog.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"drift-catalog.d.ts","sourceRoot":"","sources":["../../src.legacy/hooks/drift-catalog.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAUH,MAAM,MAAM,eAAe,GAAG,iBAAiB,GAAG,eAAe,GAAG,WAAW,CAAC;AAEhF,MAAM,WAAW,iBAAiB;IAChC,4CAA4C;IAC5C,SAAS,EAAE,MAAM,CAAC;IAClB,8BAA8B;IAC9B,UAAU,EAAE,MAAM,CAAC;IACnB,mCAAmC;IACnC,IAAI,EAAE,eAAe,CAAC;IACtB,mDAAmD;IACnD,QAAQ,EAAE,MAAM,CAAC;IACjB,qEAAqE;IACrE,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAiCD;;;GAGG;AACH,wBAAgB,sBAAsB,CACpC,KAAK,EAAE,MAAM,EAAE,EACf,SAAS,EAAE,MAAM,EACjB,GAAG,GAAE,MAAM,IAAuB,GACjC,iBAAiB,EAAE,CAmBrB;AA0BD;;;GAGG;AACH,wBAAsB,mBAAmB,CAAC,KAAK,EAAE;IAC/C,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,GAAG,CAAC,EAAE,MAAM,IAAI,CAAC;CAClB,GAAG,OAAO,CAAC,MAAM,CAAC,CAsBlB;AAED;;;;;GAKG;AACH,wBAAsB,kBAAkB,CACtC,GAAG,EAAE,MAAM,GAAG,SAAS,EACvB,SAAS,EAAE,MAAM,EACjB,QAAQ,CAAC,EAAE,MAAM,GAChB,OAAO,CAAC,MAAM,CAAC,CAajB"}
|