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 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../../../src.legacy/chat/daemon/cli.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAKH,wBAAsB,gBAAgB,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAkD1F;AAED;;;GAGG;AACH,wBAAsB,mBAAmB,IAAI,OAAO,CAAC,KAAK,CAAC,CAE1D"}
|
package/dist/chat/daemon/cli.js
DELETED
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Chat-daemon CLI dispatch (v0.7.1 Phase A).
|
|
3
|
-
*
|
|
4
|
-
* Two entry shapes:
|
|
5
|
-
* `opensquid chat-daemon {start|stop|status}` — user-facing
|
|
6
|
-
* `opensquid chat-daemon-worker` — internal, never type
|
|
7
|
-
*
|
|
8
|
-
* `start` spawns the worker as a detached child and exits. The worker
|
|
9
|
-
* subcommand IS the long-running daemon — never invoke it manually
|
|
10
|
-
* unless you want to inspect logs in the foreground.
|
|
11
|
-
*/
|
|
12
|
-
import { runDaemonWorker } from "./worker.js";
|
|
13
|
-
import { startDaemon, status, stopDaemon } from "./lifecycle.js";
|
|
14
|
-
export async function runChatDaemonCli(subcommand, argv) {
|
|
15
|
-
switch (subcommand) {
|
|
16
|
-
case "start": {
|
|
17
|
-
const res = await startDaemon();
|
|
18
|
-
if (res.already_running) {
|
|
19
|
-
process.stdout.write(`[chat-daemon] already running (pid ${res.pid})\n`);
|
|
20
|
-
}
|
|
21
|
-
else {
|
|
22
|
-
process.stdout.write(`[chat-daemon] started (pid ${res.pid})\n`);
|
|
23
|
-
}
|
|
24
|
-
return 0;
|
|
25
|
-
}
|
|
26
|
-
case "stop": {
|
|
27
|
-
const res = await stopDaemon();
|
|
28
|
-
if (res.stopped) {
|
|
29
|
-
process.stdout.write(`[chat-daemon] stopped (pid ${res.pid})\n`);
|
|
30
|
-
}
|
|
31
|
-
else {
|
|
32
|
-
process.stdout.write(`[chat-daemon] not running\n`);
|
|
33
|
-
}
|
|
34
|
-
return 0;
|
|
35
|
-
}
|
|
36
|
-
case "status": {
|
|
37
|
-
const s = await status();
|
|
38
|
-
if (s.running) {
|
|
39
|
-
const upMin = s.uptime_ms !== null ? (s.uptime_ms / 60000).toFixed(1) : "?";
|
|
40
|
-
process.stdout.write(`[chat-daemon] running (pid ${s.pid}, up ${upMin}m)\n`);
|
|
41
|
-
return 0;
|
|
42
|
-
}
|
|
43
|
-
if (s.stale_pid !== undefined) {
|
|
44
|
-
process.stdout.write(`[chat-daemon] not running (stale pidfile points at ${s.stale_pid})\n`);
|
|
45
|
-
return 1;
|
|
46
|
-
}
|
|
47
|
-
process.stdout.write(`[chat-daemon] not running\n`);
|
|
48
|
-
return 1;
|
|
49
|
-
}
|
|
50
|
-
case "restart": {
|
|
51
|
-
const wasRunning = await status();
|
|
52
|
-
if (wasRunning.running)
|
|
53
|
-
await stopDaemon();
|
|
54
|
-
const res = await startDaemon();
|
|
55
|
-
process.stdout.write(`[chat-daemon] restarted (pid ${res.pid})\n`);
|
|
56
|
-
return 0;
|
|
57
|
-
}
|
|
58
|
-
default:
|
|
59
|
-
process.stderr.write(`[chat-daemon] usage: opensquid chat-daemon {start|stop|status|restart}\n` +
|
|
60
|
-
` argv received: ${JSON.stringify([subcommand, ...argv])}\n`);
|
|
61
|
-
return 1;
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
/**
|
|
65
|
-
* Internal worker entrypoint — not for direct user invocation.
|
|
66
|
-
* Called by the detached child spawned by lifecycle.startDaemon().
|
|
67
|
-
*/
|
|
68
|
-
export async function runChatDaemonWorker() {
|
|
69
|
-
return runDaemonWorker();
|
|
70
|
-
}
|
|
71
|
-
//# sourceMappingURL=cli.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../../../src.legacy/chat/daemon/cli.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAEjE,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,UAAkB,EAAE,IAAc;IACvE,QAAQ,UAAU,EAAE,CAAC;QACnB,KAAK,OAAO,CAAC,CAAC,CAAC;YACb,MAAM,GAAG,GAAG,MAAM,WAAW,EAAE,CAAC;YAChC,IAAI,GAAG,CAAC,eAAe,EAAE,CAAC;gBACxB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,sCAAsC,GAAG,CAAC,GAAG,KAAK,CAAC,CAAC;YAC3E,CAAC;iBAAM,CAAC;gBACN,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,8BAA8B,GAAG,CAAC,GAAG,KAAK,CAAC,CAAC;YACnE,CAAC;YACD,OAAO,CAAC,CAAC;QACX,CAAC;QACD,KAAK,MAAM,CAAC,CAAC,CAAC;YACZ,MAAM,GAAG,GAAG,MAAM,UAAU,EAAE,CAAC;YAC/B,IAAI,GAAG,CAAC,OAAO,EAAE,CAAC;gBAChB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,8BAA8B,GAAG,CAAC,GAAG,KAAK,CAAC,CAAC;YACnE,CAAC;iBAAM,CAAC;gBACN,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,6BAA6B,CAAC,CAAC;YACtD,CAAC;YACD,OAAO,CAAC,CAAC;QACX,CAAC;QACD,KAAK,QAAQ,CAAC,CAAC,CAAC;YACd,MAAM,CAAC,GAAG,MAAM,MAAM,EAAE,CAAC;YACzB,IAAI,CAAC,CAAC,OAAO,EAAE,CAAC;gBACd,MAAM,KAAK,GAAG,CAAC,CAAC,SAAS,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,GAAG,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;gBAC5E,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,8BAA8B,CAAC,CAAC,GAAG,QAAQ,KAAK,MAAM,CAAC,CAAC;gBAC7E,OAAO,CAAC,CAAC;YACX,CAAC;YACD,IAAI,CAAC,CAAC,SAAS,KAAK,SAAS,EAAE,CAAC;gBAC9B,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,sDAAsD,CAAC,CAAC,SAAS,KAAK,CACvE,CAAC;gBACF,OAAO,CAAC,CAAC;YACX,CAAC;YACD,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,6BAA6B,CAAC,CAAC;YACpD,OAAO,CAAC,CAAC;QACX,CAAC;QACD,KAAK,SAAS,CAAC,CAAC,CAAC;YACf,MAAM,UAAU,GAAG,MAAM,MAAM,EAAE,CAAC;YAClC,IAAI,UAAU,CAAC,OAAO;gBAAE,MAAM,UAAU,EAAE,CAAC;YAC3C,MAAM,GAAG,GAAG,MAAM,WAAW,EAAE,CAAC;YAChC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,gCAAgC,GAAG,CAAC,GAAG,KAAK,CAAC,CAAC;YACnE,OAAO,CAAC,CAAC;QACX,CAAC;QACD;YACE,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,0EAA0E;gBACxE,oBAAoB,IAAI,CAAC,SAAS,CAAC,CAAC,UAAU,EAAE,GAAG,IAAI,CAAC,CAAC,IAAI,CAChE,CAAC;YACF,OAAO,CAAC,CAAC;IACb,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB;IACvC,OAAO,eAAe,EAAE,CAAC;AAC3B,CAAC"}
|
|
@@ -1,384 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* collisions.ts — TPS.5 (v0.5.124).
|
|
3
|
-
*
|
|
4
|
-
* Surfaces `buildRoutingIndex` collisions through three durable channels
|
|
5
|
-
* instead of the one (daemon log) v0.5.x had. Replaces the "warning lost
|
|
6
|
-
* in a log nobody tails" failure mode with:
|
|
7
|
-
*
|
|
8
|
-
* 1. `~/.opensquid/collisions.jsonl` — append-only audit trail.
|
|
9
|
-
* 2. Telegram general-topic notification — debounced 60min per key
|
|
10
|
-
* so a long-standing collision pings the operator once an hour,
|
|
11
|
-
* not every routing reload.
|
|
12
|
-
* 3. MCP `chat_poll_inbox` — prepends warning lines to the poll
|
|
13
|
-
* response when an unresolved collision affects the active
|
|
14
|
-
* workspace (read path lives in `src/mcp/chat-bridge-server.ts`).
|
|
15
|
-
*
|
|
16
|
-
* Source of truth is the JSONL file: write-once-on-every-collision +
|
|
17
|
-
* read-tail-on-every-poll. Debounce state is derived from the records
|
|
18
|
-
* themselves (last `notified_via_telegram=true` timestamp for the same
|
|
19
|
-
* channel_key) so daemon restarts don't reset the cooldown.
|
|
20
|
-
*
|
|
21
|
-
* Concurrency: single writer (the chat-daemon worker), many readers
|
|
22
|
-
* (per-project MCP bridge subprocesses). POSIX O_APPEND keeps
|
|
23
|
-
* sub-PIPE_BUF writes atomic. Malformed lines are skipped on read.
|
|
24
|
-
*
|
|
25
|
-
* Failure isolation: NEVER block the routing rebuild. Disk full →
|
|
26
|
-
* stderr log + continue. Telegram send failure → log + the JSONL line
|
|
27
|
-
* (which already wrote) still surfaces the collision on next MCP poll.
|
|
28
|
-
*
|
|
29
|
-
* Rebuild path: same ad-hoc tsc invocation as the other src.legacy/
|
|
30
|
-
* modules — see `src.legacy/chat/adapters/telegram.ts` header.
|
|
31
|
-
*/
|
|
32
|
-
import { promises as fs } from "node:fs";
|
|
33
|
-
import * as path from "node:path";
|
|
34
|
-
import { loadAllProjectChatRouting } from "./routing.js";
|
|
35
|
-
export const DEBOUNCE_WINDOW_MS = 60 * 60 * 1000;
|
|
36
|
-
// ---------------------------------------------------------------------
|
|
37
|
-
// Paths
|
|
38
|
-
// ---------------------------------------------------------------------
|
|
39
|
-
export function collisionsPath(dataRoot) {
|
|
40
|
-
const root = dataRoot ?? process.env.OPENSQUID_HOME;
|
|
41
|
-
if (!root || root.length === 0) {
|
|
42
|
-
throw new Error("collisionsPath: dataRoot not provided and OPENSQUID_HOME unset");
|
|
43
|
-
}
|
|
44
|
-
return path.join(root, "collisions.jsonl");
|
|
45
|
-
}
|
|
46
|
-
// ---------------------------------------------------------------------
|
|
47
|
-
// Read / debounce
|
|
48
|
-
// ---------------------------------------------------------------------
|
|
49
|
-
/**
|
|
50
|
-
* Read the full discriminated union from `collisions.jsonl`, dropping
|
|
51
|
-
* malformed lines and unknown-shape records. Returns [] on missing
|
|
52
|
-
* file. TPS.7 (v0.5.130) — supersedes pre-TPS.7 single-type readers.
|
|
53
|
-
*
|
|
54
|
-
* Records without an explicit `kind` are treated as `CollisionEntry`
|
|
55
|
-
* (back-compat with TPS.5 writes).
|
|
56
|
-
*/
|
|
57
|
-
export async function loadAllCollisionsLines(dataRoot) {
|
|
58
|
-
const p = collisionsPath(dataRoot);
|
|
59
|
-
let raw;
|
|
60
|
-
try {
|
|
61
|
-
raw = await fs.readFile(p, "utf8");
|
|
62
|
-
}
|
|
63
|
-
catch (err) {
|
|
64
|
-
if (err.code === "ENOENT")
|
|
65
|
-
return [];
|
|
66
|
-
throw err;
|
|
67
|
-
}
|
|
68
|
-
const out = [];
|
|
69
|
-
for (const line of raw.split("\n")) {
|
|
70
|
-
if (line.length === 0)
|
|
71
|
-
continue;
|
|
72
|
-
try {
|
|
73
|
-
const parsed = JSON.parse(line);
|
|
74
|
-
if (parsed.v !== 1 || typeof parsed.channel_key !== "string")
|
|
75
|
-
continue;
|
|
76
|
-
const kind = parsed.kind;
|
|
77
|
-
if (kind === "topic_gone") {
|
|
78
|
-
const ev = parsed;
|
|
79
|
-
if (typeof ev.workspace_uuid === "string" &&
|
|
80
|
-
typeof ev.chat_id === "string" &&
|
|
81
|
-
typeof ev.topic_id === "number") {
|
|
82
|
-
out.push(ev);
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
else {
|
|
86
|
-
// kind missing OR explicitly "collision" — treat as CollisionEntry.
|
|
87
|
-
const ent = parsed;
|
|
88
|
-
if (Array.isArray(ent.claimants) && typeof ent.winner_uuid === "string") {
|
|
89
|
-
out.push(ent);
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
catch {
|
|
94
|
-
/* skip malformed line */
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
return out;
|
|
98
|
-
}
|
|
99
|
-
/**
|
|
100
|
-
* TPS.5 back-compat reader — filters `loadAllCollisionsLines` to just
|
|
101
|
-
* `CollisionEntry` records (drops TPS.7 `TopicGoneEvent` lines). Used
|
|
102
|
-
* by the debounce scan in `recordCollision` so a recent topic-gone
|
|
103
|
-
* event doesn't suppress a fresh collision notification.
|
|
104
|
-
*/
|
|
105
|
-
export async function loadAllCollisions(dataRoot) {
|
|
106
|
-
const all = await loadAllCollisionsLines(dataRoot);
|
|
107
|
-
return all.filter((line) => {
|
|
108
|
-
const kind = line.kind;
|
|
109
|
-
return kind === undefined || kind === "collision";
|
|
110
|
-
});
|
|
111
|
-
}
|
|
112
|
-
/**
|
|
113
|
-
* TPS.7 (v0.5.130) — read `TopicGoneEvent` records only. Used by the
|
|
114
|
-
* debounce scan in `recordTopicGoneEvent` and by MCP `chat_poll_inbox`
|
|
115
|
-
* for stale-topic warnings.
|
|
116
|
-
*/
|
|
117
|
-
export async function loadAllTopicGoneEvents(dataRoot) {
|
|
118
|
-
const all = await loadAllCollisionsLines(dataRoot);
|
|
119
|
-
return all.filter((line) => {
|
|
120
|
-
return line.kind === "topic_gone";
|
|
121
|
-
});
|
|
122
|
-
}
|
|
123
|
-
/**
|
|
124
|
-
* MCP-side helper: return collisions whose `occurred_at` is within
|
|
125
|
-
* `maxAgeMinutes`. Used by `chat_poll_inbox` to prepend warnings
|
|
126
|
-
* about ACTIVE (still-recent) collisions to its response.
|
|
127
|
-
*
|
|
128
|
-
* Default window is 24 hours — long enough that the user sees the
|
|
129
|
-
* warning across a typical work session without surfacing ancient
|
|
130
|
-
* collisions that the user already fixed.
|
|
131
|
-
*/
|
|
132
|
-
export async function getRecentCollisions(maxAgeMinutes = 24 * 60, dataRoot) {
|
|
133
|
-
const cutoff = Date.now() - maxAgeMinutes * 60 * 1000;
|
|
134
|
-
const all = await loadAllCollisions(dataRoot);
|
|
135
|
-
return all.filter((e) => {
|
|
136
|
-
const t = Date.parse(e.occurred_at);
|
|
137
|
-
return Number.isFinite(t) && t >= cutoff;
|
|
138
|
-
});
|
|
139
|
-
}
|
|
140
|
-
/**
|
|
141
|
-
* TPS.7 (v0.5.130) — same default window as `getRecentCollisions` but
|
|
142
|
-
* for `TopicGoneEvent` records. Surfaced through MCP `chat_poll_inbox`
|
|
143
|
-
* so the agent learns "your topic was deleted; daemon cleared the
|
|
144
|
-
* binding; next session will rebind automatically" within the same
|
|
145
|
-
* 24h window.
|
|
146
|
-
*/
|
|
147
|
-
export async function getRecentTopicGoneEvents(maxAgeMinutes = 24 * 60, dataRoot) {
|
|
148
|
-
const cutoff = Date.now() - maxAgeMinutes * 60 * 1000;
|
|
149
|
-
const all = await loadAllTopicGoneEvents(dataRoot);
|
|
150
|
-
return all.filter((e) => {
|
|
151
|
-
const t = Date.parse(e.occurred_at);
|
|
152
|
-
return Number.isFinite(t) && t >= cutoff;
|
|
153
|
-
});
|
|
154
|
-
}
|
|
155
|
-
/**
|
|
156
|
-
* Find the most recent record (if any) that fired a Telegram
|
|
157
|
-
* notification for the same channel_key. Used to decide whether a
|
|
158
|
-
* new collision is within the debounce window.
|
|
159
|
-
*/
|
|
160
|
-
function lastNotifiedAt(entries, channelKey) {
|
|
161
|
-
let best = null;
|
|
162
|
-
for (const e of entries) {
|
|
163
|
-
if (e.channel_key !== channelKey)
|
|
164
|
-
continue;
|
|
165
|
-
if (!e.notified_via_telegram)
|
|
166
|
-
continue;
|
|
167
|
-
const t = Date.parse(e.occurred_at);
|
|
168
|
-
if (!Number.isFinite(t))
|
|
169
|
-
continue;
|
|
170
|
-
if (best === null || t > best)
|
|
171
|
-
best = t;
|
|
172
|
-
}
|
|
173
|
-
return best;
|
|
174
|
-
}
|
|
175
|
-
/**
|
|
176
|
-
* Record a collision: append a structured JSONL entry, and (if outside
|
|
177
|
-
* the debounce window + a Telegram report_channel exists) fire a
|
|
178
|
-
* one-shot notification to the supergroup's general topic. Returns
|
|
179
|
-
* the entry that was appended.
|
|
180
|
-
*
|
|
181
|
-
* NEVER throws past the caller: persist failures log to stderr; send
|
|
182
|
-
* failures log + flip the `notified_via_telegram` flag back to false
|
|
183
|
-
* for the persisted record. The routing rebuild that triggered this
|
|
184
|
-
* call must always complete.
|
|
185
|
-
*/
|
|
186
|
-
export async function recordCollision(args) {
|
|
187
|
-
const now = (args.nowMs ?? Date.now)();
|
|
188
|
-
const existing = await loadAllCollisions(args.dataRoot).catch(() => []);
|
|
189
|
-
const lastNotified = lastNotifiedAt(existing, args.info.channel_key);
|
|
190
|
-
const withinDebounce = lastNotified !== null && now - lastNotified < DEBOUNCE_WINDOW_MS;
|
|
191
|
-
// Decide whether we WILL notify this time. The final
|
|
192
|
-
// `notified_via_telegram` value reflects the send result (see below).
|
|
193
|
-
const shouldNotify = !withinDebounce && args.gateway !== undefined;
|
|
194
|
-
// Try Telegram notification BEFORE appending so the persisted flag
|
|
195
|
-
// reflects reality. If gateway send fails (rate limit, bot kicked),
|
|
196
|
-
// we still record the collision with notified=false so the next
|
|
197
|
-
// routing reload may retry past the debounce window.
|
|
198
|
-
let didNotify = false;
|
|
199
|
-
if (shouldNotify && args.gateway) {
|
|
200
|
-
try {
|
|
201
|
-
didNotify = await notifyCollisionViaTelegram({
|
|
202
|
-
gateway: args.gateway,
|
|
203
|
-
info: args.info,
|
|
204
|
-
dataRoot: args.dataRoot,
|
|
205
|
-
});
|
|
206
|
-
}
|
|
207
|
-
catch (err) {
|
|
208
|
-
process.stderr.write(`[collisions] telegram notify failed for ${args.info.channel_key}: ${err instanceof Error ? err.message : String(err)}\n`);
|
|
209
|
-
didNotify = false;
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
const entry = {
|
|
213
|
-
v: 1,
|
|
214
|
-
occurred_at: new Date(now).toISOString(),
|
|
215
|
-
channel_key: args.info.channel_key,
|
|
216
|
-
claimants: [args.info.existing_uuid, args.info.newcomer_uuid],
|
|
217
|
-
winner_uuid: args.info.newcomer_uuid,
|
|
218
|
-
notified_via_telegram: didNotify,
|
|
219
|
-
};
|
|
220
|
-
try {
|
|
221
|
-
await appendCollisionsLine(entry, args.dataRoot);
|
|
222
|
-
}
|
|
223
|
-
catch (err) {
|
|
224
|
-
process.stderr.write(`[collisions] persist failed for ${args.info.channel_key}: ${err instanceof Error ? err.message : String(err)}\n`);
|
|
225
|
-
}
|
|
226
|
-
return entry;
|
|
227
|
-
}
|
|
228
|
-
/**
|
|
229
|
-
* Find ANY project with a Telegram `report_channel` configured and
|
|
230
|
-
* send the collision notification to its general topic. Picks the
|
|
231
|
-
* first match deterministically (Map insertion order, which is
|
|
232
|
-
* filename-sorted in `loadAllProjectChatRouting`) so notifications
|
|
233
|
-
* are stable across daemon restarts.
|
|
234
|
-
*
|
|
235
|
-
* Returns true iff the send succeeded. Catches everything — caller
|
|
236
|
-
* folds the failure into the JSONL record via `notified_via_telegram`.
|
|
237
|
-
*/
|
|
238
|
-
async function notifyCollisionViaTelegram(args) {
|
|
239
|
-
const configs = await loadAllProjectChatRouting(args.dataRoot);
|
|
240
|
-
const target = pickNotificationTarget(configs);
|
|
241
|
-
if (target === null)
|
|
242
|
-
return false;
|
|
243
|
-
const text = formatCollisionMessage(args.info, target.workspaceLabel);
|
|
244
|
-
try {
|
|
245
|
-
// Force the general topic — collisions are admin-tier notifications,
|
|
246
|
-
// not workspace-scoped chatter. Telegram represents the general
|
|
247
|
-
// topic as the chat itself with NO threadId, so we intentionally
|
|
248
|
-
// omit it (don't pass report_topic_id even if set).
|
|
249
|
-
await args.gateway.send({ channel: target.channel, text });
|
|
250
|
-
return true;
|
|
251
|
-
}
|
|
252
|
-
catch {
|
|
253
|
-
return false;
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
function pickNotificationTarget(configs) {
|
|
257
|
-
for (const [uuid, cfg] of configs) {
|
|
258
|
-
const ch = cfg.telegram?.report_channel;
|
|
259
|
-
if (ch && ch.length > 0) {
|
|
260
|
-
return { channel: ch, workspaceLabel: uuid };
|
|
261
|
-
}
|
|
262
|
-
}
|
|
263
|
-
return null;
|
|
264
|
-
}
|
|
265
|
-
function formatCollisionMessage(info, sourceLabel) {
|
|
266
|
-
return [
|
|
267
|
-
"⚠️ opensquid routing collision detected",
|
|
268
|
-
"",
|
|
269
|
-
` channel: ${info.channel_key}`,
|
|
270
|
-
` existing: ${info.existing_uuid}`,
|
|
271
|
-
` newcomer: ${info.newcomer_uuid} (will win)`,
|
|
272
|
-
"",
|
|
273
|
-
`Two workspaces claim the same inbound channel. Inbound messages route to`,
|
|
274
|
-
`the newer claimant; the older one will see nothing. Edit one of the`,
|
|
275
|
-
`chat-routing.json files under ~/.opensquid/projects/ to resolve.`,
|
|
276
|
-
"",
|
|
277
|
-
`(notified by ${sourceLabel})`,
|
|
278
|
-
].join("\n");
|
|
279
|
-
}
|
|
280
|
-
/**
|
|
281
|
-
* Record a topic-gone event: append a structured JSONL entry to
|
|
282
|
-
* collisions.jsonl, and (if outside the debounce window + a Telegram
|
|
283
|
-
* report_channel exists) fire a one-shot notification to the
|
|
284
|
-
* supergroup's general topic. Returns the entry that was appended.
|
|
285
|
-
*
|
|
286
|
-
* Mirrors `recordCollision` semantics — NEVER throws past the caller.
|
|
287
|
-
* Persist failures log to stderr; send failures flip the
|
|
288
|
-
* `notified_via_telegram` flag to false. The async caller in
|
|
289
|
-
* `rpc-server.ts:handleTopicGone` doesn't await any user-visible work.
|
|
290
|
-
*
|
|
291
|
-
* Debounce key: the same `channel_key` shape used by collisions
|
|
292
|
-
* (`telegram:<chat_id>:<topic_id>`). Within `DEBOUNCE_WINDOW_MS`,
|
|
293
|
-
* additional topic-gone events for the same channel record to JSONL
|
|
294
|
-
* but skip the Telegram ping — the user already got the alert.
|
|
295
|
-
*/
|
|
296
|
-
export async function recordTopicGoneEvent(args) {
|
|
297
|
-
const now = (args.nowMs ?? Date.now)();
|
|
298
|
-
const channelKey = `telegram:${args.chatId}:${args.topicId}`;
|
|
299
|
-
const existing = await loadAllTopicGoneEvents(args.dataRoot).catch(() => []);
|
|
300
|
-
const lastNotified = lastTopicGoneNotifiedAt(existing, channelKey);
|
|
301
|
-
const withinDebounce = lastNotified !== null && now - lastNotified < DEBOUNCE_WINDOW_MS;
|
|
302
|
-
const shouldNotify = !withinDebounce && args.gateway !== undefined;
|
|
303
|
-
let didNotify = false;
|
|
304
|
-
if (shouldNotify && args.gateway) {
|
|
305
|
-
try {
|
|
306
|
-
didNotify = await notifyTopicGoneViaTelegram({
|
|
307
|
-
gateway: args.gateway,
|
|
308
|
-
workspaceUuid: args.workspaceUuid,
|
|
309
|
-
chatId: args.chatId,
|
|
310
|
-
topicId: args.topicId,
|
|
311
|
-
dataRoot: args.dataRoot,
|
|
312
|
-
});
|
|
313
|
-
}
|
|
314
|
-
catch (err) {
|
|
315
|
-
process.stderr.write(`[collisions] topic-gone telegram notify failed for ${channelKey}: ${err instanceof Error ? err.message : String(err)}\n`);
|
|
316
|
-
didNotify = false;
|
|
317
|
-
}
|
|
318
|
-
}
|
|
319
|
-
const entry = {
|
|
320
|
-
v: 1,
|
|
321
|
-
kind: "topic_gone",
|
|
322
|
-
occurred_at: new Date(now).toISOString(),
|
|
323
|
-
channel_key: channelKey,
|
|
324
|
-
workspace_uuid: args.workspaceUuid,
|
|
325
|
-
chat_id: args.chatId,
|
|
326
|
-
topic_id: args.topicId,
|
|
327
|
-
underlying_description: args.underlyingDescription,
|
|
328
|
-
notified_via_telegram: didNotify,
|
|
329
|
-
};
|
|
330
|
-
try {
|
|
331
|
-
await appendCollisionsLine(entry, args.dataRoot);
|
|
332
|
-
}
|
|
333
|
-
catch (err) {
|
|
334
|
-
process.stderr.write(`[collisions] topic-gone persist failed for ${channelKey}: ${err instanceof Error ? err.message : String(err)}\n`);
|
|
335
|
-
}
|
|
336
|
-
return entry;
|
|
337
|
-
}
|
|
338
|
-
function lastTopicGoneNotifiedAt(events, channelKey) {
|
|
339
|
-
let best = null;
|
|
340
|
-
for (const e of events) {
|
|
341
|
-
if (e.channel_key !== channelKey)
|
|
342
|
-
continue;
|
|
343
|
-
if (!e.notified_via_telegram)
|
|
344
|
-
continue;
|
|
345
|
-
const t = Date.parse(e.occurred_at);
|
|
346
|
-
if (!Number.isFinite(t))
|
|
347
|
-
continue;
|
|
348
|
-
if (best === null || t > best)
|
|
349
|
-
best = t;
|
|
350
|
-
}
|
|
351
|
-
return best;
|
|
352
|
-
}
|
|
353
|
-
async function appendCollisionsLine(line, dataRoot) {
|
|
354
|
-
const p = collisionsPath(dataRoot);
|
|
355
|
-
await fs.mkdir(path.dirname(p), { recursive: true });
|
|
356
|
-
await fs.appendFile(p, JSON.stringify(line) + "\n", "utf8");
|
|
357
|
-
}
|
|
358
|
-
async function notifyTopicGoneViaTelegram(args) {
|
|
359
|
-
const configs = await loadAllProjectChatRouting(args.dataRoot);
|
|
360
|
-
const target = pickNotificationTarget(configs);
|
|
361
|
-
if (target === null)
|
|
362
|
-
return false;
|
|
363
|
-
const text = formatTopicGoneMessage(args);
|
|
364
|
-
try {
|
|
365
|
-
await args.gateway.send({ channel: target.channel, text });
|
|
366
|
-
return true;
|
|
367
|
-
}
|
|
368
|
-
catch {
|
|
369
|
-
return false;
|
|
370
|
-
}
|
|
371
|
-
}
|
|
372
|
-
function formatTopicGoneMessage(args) {
|
|
373
|
-
return [
|
|
374
|
-
"🧹 opensquid topic binding cleared (topic was deleted)",
|
|
375
|
-
"",
|
|
376
|
-
` workspace: ${args.workspaceUuid}`,
|
|
377
|
-
` chat_id: ${args.chatId}`,
|
|
378
|
-
` topic_id: ${args.topicId} (no longer exists)`,
|
|
379
|
-
"",
|
|
380
|
-
`The bound forum topic was deleted from the supergroup. The daemon`,
|
|
381
|
-
`cleared the stale binding; the next MCP-bridge subscribe for this`,
|
|
382
|
-
`workspace will auto-rebind to a fresh topic (TPS.6 auto-boot).`,
|
|
383
|
-
].join("\n");
|
|
384
|
-
}
|
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Startup health checks for chat-daemon's configured inbound channels
|
|
3
|
-
* (v0.5.89 / TG.2).
|
|
4
|
-
*
|
|
5
|
-
* Why this exists: the daemon's inbound path silently accepts whatever
|
|
6
|
-
* Telegram delivers via long-poll. If the bot has been kicked from a
|
|
7
|
-
* supergroup, or the supergroup_id in chat-routing.json is stale, or
|
|
8
|
-
* the bot doesn't have read permission, the symptom is identical:
|
|
9
|
-
* "no inbound messages from that chat ever arrive". The daemon log
|
|
10
|
-
* looks healthy. The user assumes their routing is broken.
|
|
11
|
-
*
|
|
12
|
-
* This module adds one round-trip per unique inbound chat_id at
|
|
13
|
-
* daemon startup, calling Telegram's `getChat` HTTPS endpoint, and
|
|
14
|
-
* logs a clear reachability verdict per chat_id. Catches:
|
|
15
|
-
*
|
|
16
|
-
* - 403 Forbidden ("bot was kicked from the supergroup chat") — the
|
|
17
|
-
* load-bearing case this module was written to catch.
|
|
18
|
-
* - 400 Bad Request (chat_id doesn't exist or bot can't see it) —
|
|
19
|
-
* surfaces typo'd or stale chat_ids.
|
|
20
|
-
* - Network failures — distinguishes config error from connectivity
|
|
21
|
-
* issues.
|
|
22
|
-
*
|
|
23
|
-
* Scope discipline:
|
|
24
|
-
* - Telegram-only. Discord + Slack health checks deferred (their
|
|
25
|
-
* SDKs require different shapes; one-platform-at-a-time).
|
|
26
|
-
* - Best-effort. Health-check failures DO NOT block daemon startup;
|
|
27
|
-
* they log warnings and let the daemon continue. A bot that's
|
|
28
|
-
* kicked from one chat may still be fine for outbound to others.
|
|
29
|
-
* - No grammy dependency. Uses native fetch so this module can run
|
|
30
|
-
* even if grammy isn't loaded yet (it's a dynamic import elsewhere).
|
|
31
|
-
*
|
|
32
|
-
* Imports from: nothing (fetch is global in Node 20+).
|
|
33
|
-
* Imported by: src.legacy/chat/daemon/worker.ts (post-gateway-start).
|
|
34
|
-
*/
|
|
35
|
-
export interface ChatReachability {
|
|
36
|
-
/** The chat_id we tested, in raw string form (e.g. `-1001234567890` for a supergroup). */
|
|
37
|
-
chatId: string;
|
|
38
|
-
/** True iff Telegram returned `ok: true` on getChat. */
|
|
39
|
-
ok: boolean;
|
|
40
|
-
/** Chat title when known (supergroups + channels carry it). */
|
|
41
|
-
title?: string;
|
|
42
|
-
/** Chat type when known (`supergroup`, `group`, `channel`, `private`). */
|
|
43
|
-
chatType?: string;
|
|
44
|
-
/** Telegram error_code when not ok (typically 403 or 400). */
|
|
45
|
-
errorCode?: number;
|
|
46
|
-
/** Telegram description string when not ok. */
|
|
47
|
-
errorDescription?: string;
|
|
48
|
-
/** Set when the round-trip itself failed (DNS, TLS, timeout). */
|
|
49
|
-
networkError?: string;
|
|
50
|
-
}
|
|
51
|
-
/**
|
|
52
|
-
* Call Telegram getChat for each chat_id and return per-chat
|
|
53
|
-
* reachability. Sequential because the call count is small (typically
|
|
54
|
-
* 1–3 chats per project, 1–10 projects per host) and Telegram's bot
|
|
55
|
-
* API rate limits favor sequential calls over bursts. Per-call
|
|
56
|
-
* timeout is 5s — enough for legitimate latency, short enough that
|
|
57
|
-
* a hung API doesn't block daemon startup forever.
|
|
58
|
-
*
|
|
59
|
-
* `botToken` is the loaded Telegram bot token. If absent or empty,
|
|
60
|
-
* returns an empty array (no point health-checking without a token).
|
|
61
|
-
*/
|
|
62
|
-
export declare function verifyTelegramChats(botToken: string | undefined, chatIds: readonly string[]): Promise<ChatReachability[]>;
|
|
63
|
-
/**
|
|
64
|
-
* Render a single reachability verdict as a one-line log message.
|
|
65
|
-
* Stays formatting-stable so operators can grep daemon logs for
|
|
66
|
-
* `[chat-daemon] chat-reachability` to find all verdicts in one pass.
|
|
67
|
-
*/
|
|
68
|
-
export declare function formatReachabilityLine(r: ChatReachability): string;
|
|
69
|
-
//# sourceMappingURL=health-check.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"health-check.d.ts","sourceRoot":"","sources":["../../../src.legacy/chat/daemon/health-check.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAEH,MAAM,WAAW,gBAAgB;IAC/B,0FAA0F;IAC1F,MAAM,EAAE,MAAM,CAAC;IACf,wDAAwD;IACxD,EAAE,EAAE,OAAO,CAAC;IACZ,+DAA+D;IAC/D,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,0EAA0E;IAC1E,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,8DAA8D;IAC9D,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,+CAA+C;IAC/C,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,iEAAiE;IACjE,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAaD;;;;;;;;;;GAUG;AACH,wBAAsB,mBAAmB,CACvC,QAAQ,EAAE,MAAM,GAAG,SAAS,EAC5B,OAAO,EAAE,SAAS,MAAM,EAAE,GACzB,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAU7B;AAiCD;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,CAAC,EAAE,gBAAgB,GAAG,MAAM,CAclE"}
|
|
@@ -1,112 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Startup health checks for chat-daemon's configured inbound channels
|
|
3
|
-
* (v0.5.89 / TG.2).
|
|
4
|
-
*
|
|
5
|
-
* Why this exists: the daemon's inbound path silently accepts whatever
|
|
6
|
-
* Telegram delivers via long-poll. If the bot has been kicked from a
|
|
7
|
-
* supergroup, or the supergroup_id in chat-routing.json is stale, or
|
|
8
|
-
* the bot doesn't have read permission, the symptom is identical:
|
|
9
|
-
* "no inbound messages from that chat ever arrive". The daemon log
|
|
10
|
-
* looks healthy. The user assumes their routing is broken.
|
|
11
|
-
*
|
|
12
|
-
* This module adds one round-trip per unique inbound chat_id at
|
|
13
|
-
* daemon startup, calling Telegram's `getChat` HTTPS endpoint, and
|
|
14
|
-
* logs a clear reachability verdict per chat_id. Catches:
|
|
15
|
-
*
|
|
16
|
-
* - 403 Forbidden ("bot was kicked from the supergroup chat") — the
|
|
17
|
-
* load-bearing case this module was written to catch.
|
|
18
|
-
* - 400 Bad Request (chat_id doesn't exist or bot can't see it) —
|
|
19
|
-
* surfaces typo'd or stale chat_ids.
|
|
20
|
-
* - Network failures — distinguishes config error from connectivity
|
|
21
|
-
* issues.
|
|
22
|
-
*
|
|
23
|
-
* Scope discipline:
|
|
24
|
-
* - Telegram-only. Discord + Slack health checks deferred (their
|
|
25
|
-
* SDKs require different shapes; one-platform-at-a-time).
|
|
26
|
-
* - Best-effort. Health-check failures DO NOT block daemon startup;
|
|
27
|
-
* they log warnings and let the daemon continue. A bot that's
|
|
28
|
-
* kicked from one chat may still be fine for outbound to others.
|
|
29
|
-
* - No grammy dependency. Uses native fetch so this module can run
|
|
30
|
-
* even if grammy isn't loaded yet (it's a dynamic import elsewhere).
|
|
31
|
-
*
|
|
32
|
-
* Imports from: nothing (fetch is global in Node 20+).
|
|
33
|
-
* Imported by: src.legacy/chat/daemon/worker.ts (post-gateway-start).
|
|
34
|
-
*/
|
|
35
|
-
/**
|
|
36
|
-
* Call Telegram getChat for each chat_id and return per-chat
|
|
37
|
-
* reachability. Sequential because the call count is small (typically
|
|
38
|
-
* 1–3 chats per project, 1–10 projects per host) and Telegram's bot
|
|
39
|
-
* API rate limits favor sequential calls over bursts. Per-call
|
|
40
|
-
* timeout is 5s — enough for legitimate latency, short enough that
|
|
41
|
-
* a hung API doesn't block daemon startup forever.
|
|
42
|
-
*
|
|
43
|
-
* `botToken` is the loaded Telegram bot token. If absent or empty,
|
|
44
|
-
* returns an empty array (no point health-checking without a token).
|
|
45
|
-
*/
|
|
46
|
-
export async function verifyTelegramChats(botToken, chatIds) {
|
|
47
|
-
if (!botToken || botToken.trim().length === 0)
|
|
48
|
-
return [];
|
|
49
|
-
if (chatIds.length === 0)
|
|
50
|
-
return [];
|
|
51
|
-
const unique = Array.from(new Set(chatIds));
|
|
52
|
-
const results = [];
|
|
53
|
-
for (const chatId of unique) {
|
|
54
|
-
results.push(await checkOne(botToken, chatId));
|
|
55
|
-
}
|
|
56
|
-
return results;
|
|
57
|
-
}
|
|
58
|
-
async function checkOne(token, chatId) {
|
|
59
|
-
// 5s timeout via AbortController — keeps a hung Telegram API from
|
|
60
|
-
// wedging daemon startup indefinitely. The daemon doesn't actually
|
|
61
|
-
// need health-check results to be useful; if all calls time out, we
|
|
62
|
-
// just log "skipped due to timeouts" and continue.
|
|
63
|
-
const controller = new AbortController();
|
|
64
|
-
const timer = setTimeout(() => controller.abort(), 5_000);
|
|
65
|
-
try {
|
|
66
|
-
const url = `https://api.telegram.org/bot${token}/getChat?chat_id=${encodeURIComponent(chatId)}`;
|
|
67
|
-
const res = await fetch(url, { method: "GET", signal: controller.signal });
|
|
68
|
-
const body = (await res.json());
|
|
69
|
-
if (body.ok && body.result) {
|
|
70
|
-
const r = { chatId, ok: true, chatType: body.result.type };
|
|
71
|
-
if (body.result.title)
|
|
72
|
-
r.title = body.result.title;
|
|
73
|
-
return r;
|
|
74
|
-
}
|
|
75
|
-
const r = { chatId, ok: false };
|
|
76
|
-
if (body.error_code !== undefined)
|
|
77
|
-
r.errorCode = body.error_code;
|
|
78
|
-
if (body.description)
|
|
79
|
-
r.errorDescription = body.description;
|
|
80
|
-
return r;
|
|
81
|
-
}
|
|
82
|
-
catch (err) {
|
|
83
|
-
return {
|
|
84
|
-
chatId,
|
|
85
|
-
ok: false,
|
|
86
|
-
networkError: err instanceof Error ? err.message : String(err),
|
|
87
|
-
};
|
|
88
|
-
}
|
|
89
|
-
finally {
|
|
90
|
-
clearTimeout(timer);
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
/**
|
|
94
|
-
* Render a single reachability verdict as a one-line log message.
|
|
95
|
-
* Stays formatting-stable so operators can grep daemon logs for
|
|
96
|
-
* `[chat-daemon] chat-reachability` to find all verdicts in one pass.
|
|
97
|
-
*/
|
|
98
|
-
export function formatReachabilityLine(r) {
|
|
99
|
-
if (r.ok) {
|
|
100
|
-
const title = r.title ? ` "${r.title}"` : "";
|
|
101
|
-
const type = r.chatType ? ` (${r.chatType})` : "";
|
|
102
|
-
return `[chat-daemon] chat-reachability ${r.chatId}${title}${type}: OK`;
|
|
103
|
-
}
|
|
104
|
-
if (r.networkError) {
|
|
105
|
-
return `[chat-daemon] chat-reachability ${r.chatId}: NETWORK_ERROR ${r.networkError}`;
|
|
106
|
-
}
|
|
107
|
-
// Common 403 = "Forbidden: bot was kicked from the supergroup chat"
|
|
108
|
-
// Common 400 = "Bad Request: chat not found" (typo'd or stale id)
|
|
109
|
-
const code = r.errorCode !== undefined ? `${r.errorCode}` : "?";
|
|
110
|
-
const desc = r.errorDescription ?? "(no description)";
|
|
111
|
-
return `[chat-daemon] chat-reachability ${r.chatId}: ERROR ${code} ${desc}`;
|
|
112
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"health-check.js","sourceRoot":"","sources":["../../../src.legacy/chat/daemon/health-check.ts"],"names":[],"mappings":"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"}
|