opensquid 0.5.441 → 0.5.449
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/functions/recall_pre_inject.d.ts.map +1 -1
- package/dist/functions/recall_pre_inject.js +12 -0
- package/dist/functions/recall_pre_inject.js.map +1 -1
- package/dist/rag/store_git.d.ts +23 -0
- package/dist/rag/store_git.d.ts.map +1 -0
- package/dist/rag/store_git.js +57 -0
- package/dist/rag/store_git.js.map +1 -0
- 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-end.js +11 -0
- package/dist/runtime/hooks/session-end.js.map +1 -1
- 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/docs/pack-runtime.md +15 -12
- package/docs/skill-grammar-guide.md +4 -4
- 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
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Read side of the per-project inbox (v0.7.1 Phase E).
|
|
3
|
-
*
|
|
4
|
-
* Daemon writes to ~/.opensquid/projects/<uuid>/inbox/<platform>.jsonl;
|
|
5
|
-
* MCP servers (via the `chat_poll_inbox` tool) read here. Each line is
|
|
6
|
-
* a self-contained `InboxMessage` (see inbox.ts for the schema).
|
|
7
|
-
*
|
|
8
|
-
* `pollInbox` reads the tail of the file. For v0.7.1 the implementation
|
|
9
|
-
* is "read the whole file, take last N lines after `since`" — simple
|
|
10
|
-
* and correct for our expected file sizes (a few KB per project per
|
|
11
|
-
* day). Tail-with-offset can replace this when files routinely exceed
|
|
12
|
-
* 1 MB.
|
|
13
|
-
*/
|
|
14
|
-
import type { InboxMessage } from "./inbox.js";
|
|
15
|
-
import type { ChatPlatform } from "../gateway.js";
|
|
16
|
-
export interface PollInboxParams {
|
|
17
|
-
/** Project uuid whose inbox to read. */
|
|
18
|
-
projectUuid: string;
|
|
19
|
-
/** If set, only this platform; else all platforms with inbox files. */
|
|
20
|
-
platform?: ChatPlatform;
|
|
21
|
-
/** Cap on returned messages. Default 20. */
|
|
22
|
-
limit?: number;
|
|
23
|
-
/** Drop messages with `enqueued_at` ≤ this ISO timestamp. */
|
|
24
|
-
since?: string;
|
|
25
|
-
/** Override data root (tests). */
|
|
26
|
-
dataRoot?: string;
|
|
27
|
-
}
|
|
28
|
-
export interface PollInboxResult {
|
|
29
|
-
/** Messages in chronological order (oldest first). */
|
|
30
|
-
messages: InboxMessage[];
|
|
31
|
-
/** Platforms whose inbox files were scanned. */
|
|
32
|
-
scanned_platforms: ChatPlatform[];
|
|
33
|
-
}
|
|
34
|
-
export declare function pollInbox(params: PollInboxParams): Promise<PollInboxResult>;
|
|
35
|
-
//# sourceMappingURL=inbox-read.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"inbox-read.d.ts","sourceRoot":"","sources":["../../../src.legacy/chat/daemon/inbox-read.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAKH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC/C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAGlD,MAAM,WAAW,eAAe;IAC9B,wCAAwC;IACxC,WAAW,EAAE,MAAM,CAAC;IACpB,uEAAuE;IACvE,QAAQ,CAAC,EAAE,YAAY,CAAC;IACxB,4CAA4C;IAC5C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,6DAA6D;IAC7D,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,kCAAkC;IAClC,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,eAAe;IAC9B,sDAAsD;IACtD,QAAQ,EAAE,YAAY,EAAE,CAAC;IACzB,gDAAgD;IAChD,iBAAiB,EAAE,YAAY,EAAE,CAAC;CACnC;AAED,wBAAsB,SAAS,CAAC,MAAM,EAAE,eAAe,GAAG,OAAO,CAAC,eAAe,CAAC,CAoCjF"}
|
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Read side of the per-project inbox (v0.7.1 Phase E).
|
|
3
|
-
*
|
|
4
|
-
* Daemon writes to ~/.opensquid/projects/<uuid>/inbox/<platform>.jsonl;
|
|
5
|
-
* MCP servers (via the `chat_poll_inbox` tool) read here. Each line is
|
|
6
|
-
* a self-contained `InboxMessage` (see inbox.ts for the schema).
|
|
7
|
-
*
|
|
8
|
-
* `pollInbox` reads the tail of the file. For v0.7.1 the implementation
|
|
9
|
-
* is "read the whole file, take last N lines after `since`" — simple
|
|
10
|
-
* and correct for our expected file sizes (a few KB per project per
|
|
11
|
-
* day). Tail-with-offset can replace this when files routinely exceed
|
|
12
|
-
* 1 MB.
|
|
13
|
-
*/
|
|
14
|
-
import { promises as fs } from "node:fs";
|
|
15
|
-
import * as path from "node:path";
|
|
16
|
-
import { projectInboxDir } from "./routing.js";
|
|
17
|
-
export async function pollInbox(params) {
|
|
18
|
-
const limit = params.limit ?? 20;
|
|
19
|
-
const dir = projectInboxDir(params.projectUuid, params.dataRoot);
|
|
20
|
-
const platforms = params.platform
|
|
21
|
-
? [params.platform]
|
|
22
|
-
: await listPlatformsWithInbox(dir);
|
|
23
|
-
const all = [];
|
|
24
|
-
for (const p of platforms) {
|
|
25
|
-
const file = path.join(dir, `${p}.jsonl`);
|
|
26
|
-
try {
|
|
27
|
-
const raw = await fs.readFile(file, "utf8");
|
|
28
|
-
for (const line of raw.split("\n")) {
|
|
29
|
-
if (!line.trim())
|
|
30
|
-
continue;
|
|
31
|
-
try {
|
|
32
|
-
all.push(JSON.parse(line));
|
|
33
|
-
}
|
|
34
|
-
catch {
|
|
35
|
-
// Skip malformed lines — daemon writes valid JSON only, but
|
|
36
|
-
// a partial write under abnormal shutdown could leave one
|
|
37
|
-
// bad line. Don't crash the poll over it.
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
catch (err) {
|
|
42
|
-
if (err.code === "ENOENT")
|
|
43
|
-
continue;
|
|
44
|
-
throw err;
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
// Filter by `since`, then take the tail up to `limit`.
|
|
48
|
-
const filtered = params.since ? all.filter((m) => m.enqueued_at > params.since) : all;
|
|
49
|
-
// Sort by enqueued_at to give a consistent chronological order even
|
|
50
|
-
// when multiple platforms interleave.
|
|
51
|
-
filtered.sort((a, b) => a.enqueued_at.localeCompare(b.enqueued_at));
|
|
52
|
-
const tail = filtered.slice(-limit);
|
|
53
|
-
return { messages: tail, scanned_platforms: platforms };
|
|
54
|
-
}
|
|
55
|
-
async function listPlatformsWithInbox(dir) {
|
|
56
|
-
try {
|
|
57
|
-
const entries = await fs.readdir(dir);
|
|
58
|
-
const out = [];
|
|
59
|
-
for (const e of entries) {
|
|
60
|
-
if (e === "telegram.jsonl")
|
|
61
|
-
out.push("telegram");
|
|
62
|
-
else if (e === "discord.jsonl")
|
|
63
|
-
out.push("discord");
|
|
64
|
-
else if (e === "slack.jsonl")
|
|
65
|
-
out.push("slack");
|
|
66
|
-
}
|
|
67
|
-
return out;
|
|
68
|
-
}
|
|
69
|
-
catch (err) {
|
|
70
|
-
if (err.code === "ENOENT")
|
|
71
|
-
return [];
|
|
72
|
-
throw err;
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
//# sourceMappingURL=inbox-read.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"inbox-read.js","sourceRoot":"","sources":["../../../src.legacy/chat/daemon/inbox-read.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,97 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* inbox-read.test.ts — pollInbox happy paths (v0.7.1 Phase E).
|
|
3
|
-
*/
|
|
4
|
-
import { promises as fs } from "node:fs";
|
|
5
|
-
import * as os from "node:os";
|
|
6
|
-
import * as path from "node:path";
|
|
7
|
-
import { afterEach, beforeEach, describe, expect, it } from "vitest";
|
|
8
|
-
import { appendToInbox } from "./inbox.js";
|
|
9
|
-
import { pollInbox } from "./inbox-read.js";
|
|
10
|
-
let tmpRoot;
|
|
11
|
-
let prevHome;
|
|
12
|
-
beforeEach(async () => {
|
|
13
|
-
tmpRoot = await fs.mkdtemp(path.join(os.tmpdir(), "opensquid-inbox-read-test-"));
|
|
14
|
-
prevHome = process.env.OPENSQUID_HOME;
|
|
15
|
-
process.env.OPENSQUID_HOME = tmpRoot;
|
|
16
|
-
});
|
|
17
|
-
afterEach(async () => {
|
|
18
|
-
if (prevHome === undefined)
|
|
19
|
-
delete process.env.OPENSQUID_HOME;
|
|
20
|
-
else
|
|
21
|
-
process.env.OPENSQUID_HOME = prevHome;
|
|
22
|
-
await fs.rm(tmpRoot, { recursive: true, force: true });
|
|
23
|
-
});
|
|
24
|
-
function makeMsg(overrides = {}) {
|
|
25
|
-
return {
|
|
26
|
-
id: "m1",
|
|
27
|
-
platform: "telegram",
|
|
28
|
-
channel: "telegram:100",
|
|
29
|
-
sender: "u",
|
|
30
|
-
senderId: "100",
|
|
31
|
-
text: "hello",
|
|
32
|
-
receivedAt: new Date("2026-05-16T10:00:00Z"),
|
|
33
|
-
mentionsBot: false,
|
|
34
|
-
...overrides,
|
|
35
|
-
};
|
|
36
|
-
}
|
|
37
|
-
describe("pollInbox", () => {
|
|
38
|
-
it("returns empty messages + empty platforms list when inbox dir is missing", async () => {
|
|
39
|
-
const r = await pollInbox({ projectUuid: "no-such-uuid", dataRoot: tmpRoot });
|
|
40
|
-
expect(r.messages).toEqual([]);
|
|
41
|
-
expect(r.scanned_platforms).toEqual([]);
|
|
42
|
-
});
|
|
43
|
-
it("returns messages from a single platform inbox", async () => {
|
|
44
|
-
await appendToInbox(makeMsg({ id: "a", text: "first" }), "uuid-1", tmpRoot);
|
|
45
|
-
await appendToInbox(makeMsg({ id: "b", text: "second" }), "uuid-1", tmpRoot);
|
|
46
|
-
const r = await pollInbox({ projectUuid: "uuid-1", dataRoot: tmpRoot });
|
|
47
|
-
expect(r.messages.length).toBe(2);
|
|
48
|
-
expect(r.messages[0].id).toBe("a");
|
|
49
|
-
expect(r.messages[1].id).toBe("b");
|
|
50
|
-
expect(r.scanned_platforms).toEqual(["telegram"]);
|
|
51
|
-
});
|
|
52
|
-
it("scans all platforms when `platform` is omitted", async () => {
|
|
53
|
-
await appendToInbox(makeMsg({ platform: "telegram", channel: "telegram:1" }), "uuid-2", tmpRoot);
|
|
54
|
-
await appendToInbox(makeMsg({ platform: "discord", channel: "discord:2" }), "uuid-2", tmpRoot);
|
|
55
|
-
const r = await pollInbox({ projectUuid: "uuid-2", dataRoot: tmpRoot });
|
|
56
|
-
expect(r.messages.length).toBe(2);
|
|
57
|
-
expect(r.scanned_platforms).toEqual(expect.arrayContaining(["telegram", "discord"]));
|
|
58
|
-
});
|
|
59
|
-
it("restricts to a single platform when `platform` is given", async () => {
|
|
60
|
-
await appendToInbox(makeMsg({ platform: "telegram", channel: "telegram:1" }), "uuid-3", tmpRoot);
|
|
61
|
-
await appendToInbox(makeMsg({ platform: "discord", channel: "discord:2" }), "uuid-3", tmpRoot);
|
|
62
|
-
const r = await pollInbox({ projectUuid: "uuid-3", platform: "discord", dataRoot: tmpRoot });
|
|
63
|
-
expect(r.messages.length).toBe(1);
|
|
64
|
-
expect(r.messages[0].platform).toBe("discord");
|
|
65
|
-
expect(r.scanned_platforms).toEqual(["discord"]);
|
|
66
|
-
});
|
|
67
|
-
it("honors limit (returns the tail)", async () => {
|
|
68
|
-
for (let i = 0; i < 5; i++) {
|
|
69
|
-
await appendToInbox(makeMsg({ id: `m${i}` }), "uuid-4", tmpRoot);
|
|
70
|
-
}
|
|
71
|
-
const r = await pollInbox({ projectUuid: "uuid-4", limit: 2, dataRoot: tmpRoot });
|
|
72
|
-
expect(r.messages.length).toBe(2);
|
|
73
|
-
// Last two by chronological order.
|
|
74
|
-
expect(r.messages[0].id).toBe("m3");
|
|
75
|
-
expect(r.messages[1].id).toBe("m4");
|
|
76
|
-
});
|
|
77
|
-
it("filters by `since` (strict greater-than on enqueued_at)", async () => {
|
|
78
|
-
await appendToInbox(makeMsg({ id: "x" }), "uuid-5", tmpRoot);
|
|
79
|
-
// Small wait so enqueued_at differs.
|
|
80
|
-
await new Promise((r) => setTimeout(r, 5));
|
|
81
|
-
const marker = new Date().toISOString();
|
|
82
|
-
await new Promise((r) => setTimeout(r, 5));
|
|
83
|
-
await appendToInbox(makeMsg({ id: "y" }), "uuid-5", tmpRoot);
|
|
84
|
-
const r = await pollInbox({ projectUuid: "uuid-5", since: marker, dataRoot: tmpRoot });
|
|
85
|
-
expect(r.messages.length).toBe(1);
|
|
86
|
-
expect(r.messages[0].id).toBe("y");
|
|
87
|
-
});
|
|
88
|
-
it("survives a malformed line in the inbox (skips it, returns valid ones)", async () => {
|
|
89
|
-
await appendToInbox(makeMsg({ id: "good-1" }), "uuid-6", tmpRoot);
|
|
90
|
-
// Append a broken line by writing directly.
|
|
91
|
-
const inboxFile = path.join(tmpRoot, "projects", "uuid-6", "inbox", "telegram.jsonl");
|
|
92
|
-
await fs.appendFile(inboxFile, "{ not json\n");
|
|
93
|
-
await appendToInbox(makeMsg({ id: "good-2" }), "uuid-6", tmpRoot);
|
|
94
|
-
const r = await pollInbox({ projectUuid: "uuid-6", dataRoot: tmpRoot });
|
|
95
|
-
expect(r.messages.map((m) => m.id)).toEqual(["good-1", "good-2"]);
|
|
96
|
-
});
|
|
97
|
-
});
|
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Per-project inbound message inbox (v0.7.1 Phase C).
|
|
3
|
-
*
|
|
4
|
-
* The daemon receives inbound messages from all activated chat
|
|
5
|
-
* platforms via gateway.onMessage. This module is the write side:
|
|
6
|
-
* given a destination project (or "orphan" if no routing match),
|
|
7
|
-
* atomically append the message to its JSONL inbox.
|
|
8
|
-
*
|
|
9
|
-
* Read side lives in Phase E (the MCP `chat_poll_inbox` tool that
|
|
10
|
-
* per-project servers call to surface inbound messages to their
|
|
11
|
-
* agent).
|
|
12
|
-
*
|
|
13
|
-
* File layout:
|
|
14
|
-
* ~/.opensquid/projects/<uuid>/inbox/<platform>.jsonl (per-project)
|
|
15
|
-
* ~/.opensquid/inbox/orphan/<platform>.jsonl (catch-all)
|
|
16
|
-
*
|
|
17
|
-
* One line per message; line format is the JSON serialization of the
|
|
18
|
-
* `InboxMessage` shape below. Newline-delimited so consumers can tail
|
|
19
|
-
* incrementally without seeing partial writes (POSIX guarantees O_APPEND
|
|
20
|
-
* writes ≤ PIPE_BUF are atomic; our messages are typically a few
|
|
21
|
-
* hundred bytes, well under the 4096-byte threshold).
|
|
22
|
-
*/
|
|
23
|
-
import type { ChatMessage } from "../gateway.js";
|
|
24
|
-
export interface InboxMessage {
|
|
25
|
-
/** Wire-format version; bump when the line format changes. */
|
|
26
|
-
v: 1;
|
|
27
|
-
/** Platform-stable message id (Telegram message_id, Slack ts, etc.). */
|
|
28
|
-
id: string;
|
|
29
|
-
/** Optional thread / topic id for sub-threaded platforms (v0.7.2). */
|
|
30
|
-
thread_id?: string;
|
|
31
|
-
/** Stable platform identifier. */
|
|
32
|
-
platform: string;
|
|
33
|
-
/** Full channel id (`<platform>:<native>`) the message arrived on. */
|
|
34
|
-
channel: string;
|
|
35
|
-
/** Display name of sender; falls back to native id when display is absent. */
|
|
36
|
-
sender: string;
|
|
37
|
-
/** Native sender id (Telegram user_id, Slack user, etc.). */
|
|
38
|
-
sender_id: string;
|
|
39
|
-
/** Message body text. */
|
|
40
|
-
text: string;
|
|
41
|
-
/** Wall-clock the platform stamped the message with (ISO 8601). */
|
|
42
|
-
received_at: string;
|
|
43
|
-
/** Daemon-side wall-clock the message hit the inbox (ISO 8601). */
|
|
44
|
-
enqueued_at: string;
|
|
45
|
-
/** True when the message contained an @-mention of the bot. */
|
|
46
|
-
mentions_bot: boolean;
|
|
47
|
-
}
|
|
48
|
-
export interface AppendResult {
|
|
49
|
-
/** Where the message ended up. */
|
|
50
|
-
destination: "project" | "orphan";
|
|
51
|
-
/** Project uuid (only when destination=project). */
|
|
52
|
-
project_uuid?: string;
|
|
53
|
-
/** Absolute path of the inbox file we wrote to. */
|
|
54
|
-
inbox_path: string;
|
|
55
|
-
}
|
|
56
|
-
/**
|
|
57
|
-
* Append a single inbound ChatMessage to the appropriate inbox.
|
|
58
|
-
* Caller decides which (route via `routing.RoutingIndex` lookup before
|
|
59
|
-
* calling). If projectUuid is provided, writes to that project's inbox;
|
|
60
|
-
* otherwise to the orphan inbox.
|
|
61
|
-
*/
|
|
62
|
-
export declare function appendToInbox(msg: ChatMessage, projectUuid: string | null, dataRoot?: string): Promise<AppendResult>;
|
|
63
|
-
//# sourceMappingURL=inbox.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"inbox.d.ts","sourceRoot":"","sources":["../../../src.legacy/chat/daemon/inbox.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAKH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAGjD,MAAM,WAAW,YAAY;IAC3B,8DAA8D;IAC9D,CAAC,EAAE,CAAC,CAAC;IACL,wEAAwE;IACxE,EAAE,EAAE,MAAM,CAAC;IACX,sEAAsE;IACtE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,kCAAkC;IAClC,QAAQ,EAAE,MAAM,CAAC;IACjB,sEAAsE;IACtE,OAAO,EAAE,MAAM,CAAC;IAChB,8EAA8E;IAC9E,MAAM,EAAE,MAAM,CAAC;IACf,6DAA6D;IAC7D,SAAS,EAAE,MAAM,CAAC;IAClB,yBAAyB;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,mEAAmE;IACnE,WAAW,EAAE,MAAM,CAAC;IACpB,mEAAmE;IACnE,WAAW,EAAE,MAAM,CAAC;IACpB,+DAA+D;IAC/D,YAAY,EAAE,OAAO,CAAC;CACvB;AAED,MAAM,WAAW,YAAY;IAC3B,kCAAkC;IAClC,WAAW,EAAE,SAAS,GAAG,QAAQ,CAAC;IAClC,oDAAoD;IACpD,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,mDAAmD;IACnD,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;;;;GAKG;AACH,wBAAsB,aAAa,CACjC,GAAG,EAAE,WAAW,EAChB,WAAW,EAAE,MAAM,GAAG,IAAI,EAC1B,QAAQ,CAAC,EAAE,MAAM,GAChB,OAAO,CAAC,YAAY,CAAC,CAwBvB"}
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Per-project inbound message inbox (v0.7.1 Phase C).
|
|
3
|
-
*
|
|
4
|
-
* The daemon receives inbound messages from all activated chat
|
|
5
|
-
* platforms via gateway.onMessage. This module is the write side:
|
|
6
|
-
* given a destination project (or "orphan" if no routing match),
|
|
7
|
-
* atomically append the message to its JSONL inbox.
|
|
8
|
-
*
|
|
9
|
-
* Read side lives in Phase E (the MCP `chat_poll_inbox` tool that
|
|
10
|
-
* per-project servers call to surface inbound messages to their
|
|
11
|
-
* agent).
|
|
12
|
-
*
|
|
13
|
-
* File layout:
|
|
14
|
-
* ~/.opensquid/projects/<uuid>/inbox/<platform>.jsonl (per-project)
|
|
15
|
-
* ~/.opensquid/inbox/orphan/<platform>.jsonl (catch-all)
|
|
16
|
-
*
|
|
17
|
-
* One line per message; line format is the JSON serialization of the
|
|
18
|
-
* `InboxMessage` shape below. Newline-delimited so consumers can tail
|
|
19
|
-
* incrementally without seeing partial writes (POSIX guarantees O_APPEND
|
|
20
|
-
* writes ≤ PIPE_BUF are atomic; our messages are typically a few
|
|
21
|
-
* hundred bytes, well under the 4096-byte threshold).
|
|
22
|
-
*/
|
|
23
|
-
import { promises as fs } from "node:fs";
|
|
24
|
-
import * as path from "node:path";
|
|
25
|
-
import { orphanInboxDir, projectInboxDir } from "./routing.js";
|
|
26
|
-
/**
|
|
27
|
-
* Append a single inbound ChatMessage to the appropriate inbox.
|
|
28
|
-
* Caller decides which (route via `routing.RoutingIndex` lookup before
|
|
29
|
-
* calling). If projectUuid is provided, writes to that project's inbox;
|
|
30
|
-
* otherwise to the orphan inbox.
|
|
31
|
-
*/
|
|
32
|
-
export async function appendToInbox(msg, projectUuid, dataRoot) {
|
|
33
|
-
const destDir = projectUuid ? projectInboxDir(projectUuid, dataRoot) : orphanInboxDir(dataRoot);
|
|
34
|
-
await fs.mkdir(destDir, { recursive: true });
|
|
35
|
-
const inboxFile = path.join(destDir, `${msg.platform}.jsonl`);
|
|
36
|
-
const line = {
|
|
37
|
-
v: 1,
|
|
38
|
-
id: msg.id,
|
|
39
|
-
thread_id: msg.threadId,
|
|
40
|
-
platform: msg.platform,
|
|
41
|
-
channel: msg.channel,
|
|
42
|
-
sender: msg.sender,
|
|
43
|
-
sender_id: msg.senderId,
|
|
44
|
-
text: msg.text,
|
|
45
|
-
received_at: msg.receivedAt.toISOString(),
|
|
46
|
-
enqueued_at: new Date().toISOString(),
|
|
47
|
-
mentions_bot: msg.mentionsBot,
|
|
48
|
-
};
|
|
49
|
-
// appendFile with utf8 uses O_APPEND under the hood; small writes
|
|
50
|
-
// are POSIX-atomic. JSONL line ends with \n so consumers can split
|
|
51
|
-
// safely even if a write straddles a buffer flush.
|
|
52
|
-
await fs.appendFile(inboxFile, `${JSON.stringify(line)}\n`, "utf8");
|
|
53
|
-
return projectUuid
|
|
54
|
-
? { destination: "project", project_uuid: projectUuid, inbox_path: inboxFile }
|
|
55
|
-
: { destination: "orphan", inbox_path: inboxFile };
|
|
56
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"inbox.js","sourceRoot":"","sources":["../../../src.legacy/chat/daemon/inbox.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,EAAE,QAAQ,IAAI,EAAE,EAAE,MAAM,SAAS,CAAC;AACzC,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAGlC,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAoC/D;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,GAAgB,EAChB,WAA0B,EAC1B,QAAiB;IAEjB,MAAM,OAAO,GAAG,WAAW,CAAC,CAAC,CAAC,eAAe,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,cAAc,CAAC,QAAQ,CAAC,CAAC;IAChG,MAAM,EAAE,CAAC,KAAK,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC7C,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,GAAG,CAAC,QAAQ,QAAQ,CAAC,CAAC;IAC9D,MAAM,IAAI,GAAiB;QACzB,CAAC,EAAE,CAAC;QACJ,EAAE,EAAE,GAAG,CAAC,EAAE;QACV,SAAS,EAAE,GAAG,CAAC,QAAQ;QACvB,QAAQ,EAAE,GAAG,CAAC,QAAQ;QACtB,OAAO,EAAE,GAAG,CAAC,OAAO;QACpB,MAAM,EAAE,GAAG,CAAC,MAAM;QAClB,SAAS,EAAE,GAAG,CAAC,QAAQ;QACvB,IAAI,EAAE,GAAG,CAAC,IAAI;QACd,WAAW,EAAE,GAAG,CAAC,UAAU,CAAC,WAAW,EAAE;QACzC,WAAW,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QACrC,YAAY,EAAE,GAAG,CAAC,WAAW;KAC9B,CAAC;IACF,kEAAkE;IAClE,mEAAmE;IACnE,mDAAmD;IACnD,MAAM,EAAE,CAAC,UAAU,CAAC,SAAS,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IACpE,OAAO,WAAW;QAChB,CAAC,CAAC,EAAE,WAAW,EAAE,SAAS,EAAE,YAAY,EAAE,WAAW,EAAE,UAAU,EAAE,SAAS,EAAE;QAC9E,CAAC,CAAC,EAAE,WAAW,EAAE,QAAQ,EAAE,UAAU,EAAE,SAAS,EAAE,CAAC;AACvD,CAAC"}
|
|
@@ -1,110 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* inbox.ts tests (v0.7.1 Phase C) — exercise appendToInbox end-to-end
|
|
3
|
-
* (real files, real JSONL parsing) so the wire format AND the
|
|
4
|
-
* project/orphan routing decision are both covered.
|
|
5
|
-
*/
|
|
6
|
-
import { promises as fs } from "node:fs";
|
|
7
|
-
import * as os from "node:os";
|
|
8
|
-
import * as path from "node:path";
|
|
9
|
-
import { afterEach, beforeEach, describe, expect, it } from "vitest";
|
|
10
|
-
import { appendToInbox } from "./inbox.js";
|
|
11
|
-
import { orphanInboxDir, projectInboxDir } from "./routing.js";
|
|
12
|
-
let tmpRoot;
|
|
13
|
-
let prevHome;
|
|
14
|
-
beforeEach(async () => {
|
|
15
|
-
tmpRoot = await fs.mkdtemp(path.join(os.tmpdir(), "opensquid-inbox-test-"));
|
|
16
|
-
prevHome = process.env.OPENSQUID_HOME;
|
|
17
|
-
process.env.OPENSQUID_HOME = tmpRoot;
|
|
18
|
-
});
|
|
19
|
-
afterEach(async () => {
|
|
20
|
-
if (prevHome === undefined)
|
|
21
|
-
delete process.env.OPENSQUID_HOME;
|
|
22
|
-
else
|
|
23
|
-
process.env.OPENSQUID_HOME = prevHome;
|
|
24
|
-
await fs.rm(tmpRoot, { recursive: true, force: true });
|
|
25
|
-
});
|
|
26
|
-
function makeMsg(overrides = {}) {
|
|
27
|
-
return {
|
|
28
|
-
id: "msg-1",
|
|
29
|
-
platform: "telegram",
|
|
30
|
-
channel: "telegram:8075471258",
|
|
31
|
-
sender: "tester",
|
|
32
|
-
senderId: "8075471258",
|
|
33
|
-
text: "hello inbox",
|
|
34
|
-
receivedAt: new Date("2026-05-16T10:00:00Z"),
|
|
35
|
-
mentionsBot: false,
|
|
36
|
-
...overrides,
|
|
37
|
-
};
|
|
38
|
-
}
|
|
39
|
-
describe("appendToInbox — project path", () => {
|
|
40
|
-
it("writes a JSONL line into projects/<uuid>/inbox/<platform>.jsonl", async () => {
|
|
41
|
-
const res = await appendToInbox(makeMsg(), "uuid-x", tmpRoot);
|
|
42
|
-
expect(res.destination).toBe("project");
|
|
43
|
-
expect(res.project_uuid).toBe("uuid-x");
|
|
44
|
-
expect(res.inbox_path).toBe(path.join(projectInboxDir("uuid-x", tmpRoot), "telegram.jsonl"));
|
|
45
|
-
const content = await fs.readFile(res.inbox_path, "utf8");
|
|
46
|
-
expect(content.endsWith("\n")).toBe(true);
|
|
47
|
-
const parsed = JSON.parse(content.trim());
|
|
48
|
-
expect(parsed.v).toBe(1);
|
|
49
|
-
expect(parsed.id).toBe("msg-1");
|
|
50
|
-
expect(parsed.platform).toBe("telegram");
|
|
51
|
-
expect(parsed.channel).toBe("telegram:8075471258");
|
|
52
|
-
expect(parsed.text).toBe("hello inbox");
|
|
53
|
-
expect(parsed.received_at).toBe("2026-05-16T10:00:00.000Z");
|
|
54
|
-
expect(parsed.enqueued_at).toMatch(/^\d{4}-\d{2}-\d{2}T/);
|
|
55
|
-
expect(parsed.mentions_bot).toBe(false);
|
|
56
|
-
});
|
|
57
|
-
it("appends multiple lines, one per message", async () => {
|
|
58
|
-
const res = await appendToInbox(makeMsg({ id: "a" }), "uuid-y", tmpRoot);
|
|
59
|
-
await appendToInbox(makeMsg({ id: "b", text: "second" }), "uuid-y", tmpRoot);
|
|
60
|
-
const content = await fs.readFile(res.inbox_path, "utf8");
|
|
61
|
-
const lines = content.trim().split("\n");
|
|
62
|
-
expect(lines.length).toBe(2);
|
|
63
|
-
expect(JSON.parse(lines[0]).id).toBe("a");
|
|
64
|
-
expect(JSON.parse(lines[1]).id).toBe("b");
|
|
65
|
-
});
|
|
66
|
-
it("separates inboxes by platform", async () => {
|
|
67
|
-
await appendToInbox(makeMsg({ platform: "telegram", channel: "telegram:1" }), "uuid-z", tmpRoot);
|
|
68
|
-
await appendToInbox(makeMsg({ platform: "discord", channel: "discord:2" }), "uuid-z", tmpRoot);
|
|
69
|
-
const dir = projectInboxDir("uuid-z", tmpRoot);
|
|
70
|
-
const entries = await fs.readdir(dir);
|
|
71
|
-
expect(entries).toEqual(expect.arrayContaining(["telegram.jsonl", "discord.jsonl"]));
|
|
72
|
-
});
|
|
73
|
-
});
|
|
74
|
-
describe("appendToInbox — orphan path", () => {
|
|
75
|
-
it("writes to <dataRoot>/inbox/orphan/<platform>.jsonl when projectUuid is null", async () => {
|
|
76
|
-
const res = await appendToInbox(makeMsg(), null, tmpRoot);
|
|
77
|
-
expect(res.destination).toBe("orphan");
|
|
78
|
-
expect(res.project_uuid).toBeUndefined();
|
|
79
|
-
expect(res.inbox_path).toBe(path.join(orphanInboxDir(tmpRoot), "telegram.jsonl"));
|
|
80
|
-
const exists = await fs
|
|
81
|
-
.stat(res.inbox_path)
|
|
82
|
-
.then(() => true)
|
|
83
|
-
.catch(() => false);
|
|
84
|
-
expect(exists).toBe(true);
|
|
85
|
-
});
|
|
86
|
-
});
|
|
87
|
-
describe("appendToInbox — line format details", () => {
|
|
88
|
-
it("preserves mentions_bot flag", async () => {
|
|
89
|
-
const res = await appendToInbox(makeMsg({ mentionsBot: true }), "uuid-m", tmpRoot);
|
|
90
|
-
const line = (await fs.readFile(res.inbox_path, "utf8")).trim();
|
|
91
|
-
const parsed = JSON.parse(line);
|
|
92
|
-
expect(parsed.mentions_bot).toBe(true);
|
|
93
|
-
});
|
|
94
|
-
it("preserves sender_id (native id) separately from display sender", async () => {
|
|
95
|
-
const res = await appendToInbox(makeMsg({ sender: "Display Name", senderId: "native-987" }), "uuid-s", tmpRoot);
|
|
96
|
-
const line = (await fs.readFile(res.inbox_path, "utf8")).trim();
|
|
97
|
-
const parsed = JSON.parse(line);
|
|
98
|
-
expect(parsed.sender).toBe("Display Name");
|
|
99
|
-
expect(parsed.sender_id).toBe("native-987");
|
|
100
|
-
});
|
|
101
|
-
it("handles multi-line text without breaking JSONL framing", async () => {
|
|
102
|
-
// JSON.stringify escapes newlines as \\n; one logical line on disk.
|
|
103
|
-
const res = await appendToInbox(makeMsg({ text: "line one\nline two\nline three" }), "uuid-multi", tmpRoot);
|
|
104
|
-
const content = await fs.readFile(res.inbox_path, "utf8");
|
|
105
|
-
const lines = content.trim().split("\n");
|
|
106
|
-
expect(lines.length).toBe(1);
|
|
107
|
-
const parsed = JSON.parse(lines[0]);
|
|
108
|
-
expect(parsed.text).toBe("line one\nline two\nline three");
|
|
109
|
-
});
|
|
110
|
-
});
|
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Chat-daemon lifecycle — start / stop / status (v0.7.1 Phase A).
|
|
3
|
-
*
|
|
4
|
-
* The daemon owns the single long-poll connection per chat platform so
|
|
5
|
-
* multiple Claude Code projects sharing the same machine can run their
|
|
6
|
-
* own opensquid MCP servers without colliding on the bot token (Telegram
|
|
7
|
-
* returns 409 Conflict when two consumers long-poll the same token —
|
|
8
|
-
* the v0.7 cause of "last-connected wins" behavior).
|
|
9
|
-
*
|
|
10
|
-
* Lifecycle is single-instance per machine: PID file at
|
|
11
|
-
* ~/.opensquid/chat-daemon.pid, log at ~/.opensquid/chat-daemon.log.
|
|
12
|
-
* A `start` call against a running daemon is a no-op (idempotent);
|
|
13
|
-
* `stop` is also idempotent. `status` is read-only.
|
|
14
|
-
*
|
|
15
|
-
* Outbound RPC (Unix socket) lands in Phase B; routing config + inbox
|
|
16
|
-
* write-out in Phase C; auto-spawn from MCP server in Phase D.
|
|
17
|
-
*/
|
|
18
|
-
export interface DaemonPaths {
|
|
19
|
-
pidFile: string;
|
|
20
|
-
logFile: string;
|
|
21
|
-
sockFile: string;
|
|
22
|
-
}
|
|
23
|
-
export declare function daemonPaths(dataRoot?: string): DaemonPaths;
|
|
24
|
-
export type DaemonStatus = {
|
|
25
|
-
running: true;
|
|
26
|
-
pid: number;
|
|
27
|
-
uptime_ms: number | null;
|
|
28
|
-
} | {
|
|
29
|
-
running: false;
|
|
30
|
-
stale_pid?: number;
|
|
31
|
-
};
|
|
32
|
-
/**
|
|
33
|
-
* Read the pidfile and check whether the recorded process is alive.
|
|
34
|
-
* A pidfile that points at a dead pid is treated as not-running (the
|
|
35
|
-
* caller should clean it up if they want; status itself is read-only).
|
|
36
|
-
*/
|
|
37
|
-
export declare function status(dataRoot?: string): Promise<DaemonStatus>;
|
|
38
|
-
/**
|
|
39
|
-
* Start the daemon by spawning a detached child that runs
|
|
40
|
-
* `node dist/index.js chat-daemon-worker` (the actual long-poll loop
|
|
41
|
-
* lives in worker.ts). Returns immediately once the child has either
|
|
42
|
-
* forked successfully or failed.
|
|
43
|
-
*
|
|
44
|
-
* Idempotent: a start against an already-running daemon returns
|
|
45
|
-
* `{ already_running: true, pid }` without launching a second process.
|
|
46
|
-
*
|
|
47
|
-
* Stale pidfile handling: if the pidfile points at a dead pid, it's
|
|
48
|
-
* silently removed so this call can succeed.
|
|
49
|
-
*/
|
|
50
|
-
export declare function startDaemon(options?: {
|
|
51
|
-
dataRoot?: string;
|
|
52
|
-
nodeBin?: string;
|
|
53
|
-
entrypoint?: string;
|
|
54
|
-
}): Promise<{
|
|
55
|
-
already_running: boolean;
|
|
56
|
-
pid: number;
|
|
57
|
-
}>;
|
|
58
|
-
/**
|
|
59
|
-
* Stop a running daemon by sending SIGTERM, then waiting briefly for
|
|
60
|
-
* the process to exit and the pidfile to disappear. Falls back to
|
|
61
|
-
* SIGKILL after the grace period. Idempotent — a stop against a
|
|
62
|
-
* not-running daemon returns `{ stopped: false }` without error.
|
|
63
|
-
*/
|
|
64
|
-
export declare function stopDaemon(options?: {
|
|
65
|
-
dataRoot?: string;
|
|
66
|
-
graceMs?: number;
|
|
67
|
-
}): Promise<{
|
|
68
|
-
stopped: boolean;
|
|
69
|
-
pid?: number;
|
|
70
|
-
}>;
|
|
71
|
-
//# sourceMappingURL=lifecycle.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"lifecycle.d.ts","sourceRoot":"","sources":["../../../src.legacy/chat/daemon/lifecycle.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAUH,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,wBAAgB,WAAW,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,WAAW,CAO1D;AAED,MAAM,MAAM,YAAY,GACpB;IAAE,OAAO,EAAE,IAAI,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,GACxD;IAAE,OAAO,EAAE,KAAK,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAE3C;;;;GAIG;AACH,wBAAsB,MAAM,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CAoBrE;AAaD;;;;;;;;;;;GAWG;AACH,wBAAsB,WAAW,CAC/B,OAAO,GAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAAO,GACzE,OAAO,CAAC;IAAE,eAAe,EAAE,OAAO,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAAC,CAoEpD;AAED;;;;;GAKG;AACH,wBAAsB,UAAU,CAC9B,OAAO,GAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAO,GACpD,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAmC7C"}
|