@openrig/cli 0.4.6 → 0.4.7
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/daemon/assets/guidance/CULTURE-default.md +19 -0
- package/daemon/assets/guidance/openrig-start.md +20 -5
- package/daemon/assets/plugins/openrig-core/README.md +1 -1
- package/daemon/assets/plugins/openrig-core/skills/claude-compaction-restore/SKILL.md +9 -6
- package/daemon/assets/plugins/openrig-core/skills/claude-compaction-restore/scripts/precompact-hook.mjs +11 -72
- package/daemon/assets/plugins/openrig-core/skills/forming-an-openrig-mental-model/SKILL.md +34 -22
- package/daemon/assets/plugins/openrig-core/skills/messaging-the-human/SKILL.md +108 -0
- package/daemon/assets/plugins/openrig-core/skills/mission-slice-sop/SKILL.md +11 -14
- package/daemon/assets/plugins/openrig-core/skills/openrig-skills/SKILL.md +95 -0
- package/daemon/assets/plugins/openrig-core/skills/openrig-user/SKILL.md +175 -105
- package/daemon/assets/plugins/openrig-core/skills/queue-handoff/SKILL.md +26 -9
- package/daemon/assets/plugins/openrig-core/skills/seat-continuity-and-handover/SKILL.md +11 -9
- package/daemon/assets/plugins/openrig-core/skills/session-compaction-and-restore/SKILL.md +162 -0
- package/daemon/assets/plugins/openrig-core/skills/software-for-agents/SKILL.md +165 -0
- package/daemon/dist/adapters/cmux-transport.d.ts.map +1 -1
- package/daemon/dist/adapters/cmux-transport.js +8 -1
- package/daemon/dist/adapters/cmux-transport.js.map +1 -1
- package/daemon/dist/adapters/cmux.d.ts +9 -0
- package/daemon/dist/adapters/cmux.d.ts.map +1 -1
- package/daemon/dist/adapters/cmux.js +21 -0
- package/daemon/dist/adapters/cmux.js.map +1 -1
- package/daemon/dist/adapters/codex-runtime-adapter.d.ts +3 -0
- package/daemon/dist/adapters/codex-runtime-adapter.d.ts.map +1 -1
- package/daemon/dist/adapters/codex-runtime-adapter.js +20 -4
- package/daemon/dist/adapters/codex-runtime-adapter.js.map +1 -1
- package/daemon/dist/build-info.js +3 -3
- package/daemon/dist/domain/claude-compaction-enforcer.d.ts +3 -0
- package/daemon/dist/domain/claude-compaction-enforcer.d.ts.map +1 -1
- package/daemon/dist/domain/claude-compaction-enforcer.js +19 -3
- package/daemon/dist/domain/claude-compaction-enforcer.js.map +1 -1
- package/daemon/dist/domain/cmux-layout-service.d.ts +36 -0
- package/daemon/dist/domain/cmux-layout-service.d.ts.map +1 -1
- package/daemon/dist/domain/cmux-layout-service.js +100 -28
- package/daemon/dist/domain/cmux-layout-service.js.map +1 -1
- package/daemon/dist/domain/context-monitor.d.ts +2 -0
- package/daemon/dist/domain/context-monitor.d.ts.map +1 -1
- package/daemon/dist/domain/context-monitor.js +14 -0
- package/daemon/dist/domain/context-monitor.js.map +1 -1
- package/daemon/dist/domain/feed/attention-aggregator.js +1 -1
- package/daemon/dist/domain/feed/attention-aggregator.js.map +1 -1
- package/daemon/dist/domain/hosts/hosts-registry-reader.d.ts.map +1 -1
- package/daemon/dist/domain/hosts/hosts-registry-reader.js +12 -10
- package/daemon/dist/domain/hosts/hosts-registry-reader.js.map +1 -1
- package/daemon/dist/domain/hosts/hosts-registry-writer.d.ts.map +1 -1
- package/daemon/dist/domain/hosts/hosts-registry-writer.js +3 -2
- package/daemon/dist/domain/hosts/hosts-registry-writer.js.map +1 -1
- package/daemon/dist/domain/hosts/read-through.js +1 -1
- package/daemon/dist/domain/hosts/read-through.js.map +1 -1
- package/daemon/dist/domain/hosts/remote-daemon-http.d.ts.map +1 -1
- package/daemon/dist/domain/hosts/remote-daemon-http.js +8 -5
- package/daemon/dist/domain/hosts/remote-daemon-http.js.map +1 -1
- package/daemon/dist/domain/node-inventory.d.ts +3 -12
- package/daemon/dist/domain/node-inventory.d.ts.map +1 -1
- package/daemon/dist/domain/node-inventory.js +55 -13
- package/daemon/dist/domain/node-inventory.js.map +1 -1
- package/daemon/dist/domain/plugin-vendor-service.d.ts +2 -0
- package/daemon/dist/domain/plugin-vendor-service.d.ts.map +1 -1
- package/daemon/dist/domain/plugin-vendor-service.js +23 -0
- package/daemon/dist/domain/plugin-vendor-service.js.map +1 -1
- package/daemon/dist/domain/projection-lane.d.ts +7 -0
- package/daemon/dist/domain/projection-lane.d.ts.map +1 -0
- package/daemon/dist/domain/projection-lane.js +28 -0
- package/daemon/dist/domain/projection-lane.js.map +1 -0
- package/daemon/dist/domain/ps-projection.d.ts +19 -0
- package/daemon/dist/domain/ps-projection.d.ts.map +1 -1
- package/daemon/dist/domain/ps-projection.js +46 -6
- package/daemon/dist/domain/ps-projection.js.map +1 -1
- package/daemon/dist/domain/queue-repository.d.ts +14 -10
- package/daemon/dist/domain/queue-repository.d.ts.map +1 -1
- package/daemon/dist/domain/queue-repository.js +33 -12
- package/daemon/dist/domain/queue-repository.js.map +1 -1
- package/daemon/dist/domain/review/compose.d.ts +77 -4
- package/daemon/dist/domain/review/compose.d.ts.map +1 -1
- package/daemon/dist/domain/review/compose.js +152 -16
- package/daemon/dist/domain/review/compose.js.map +1 -1
- package/daemon/dist/domain/review/fleet-compose.js +1 -1
- package/daemon/dist/domain/review/fleet-compose.js.map +1 -1
- package/daemon/dist/domain/review/gather.d.ts +1 -1
- package/daemon/dist/domain/review/gather.d.ts.map +1 -1
- package/daemon/dist/domain/review/gather.js +92 -67
- package/daemon/dist/domain/review/gather.js.map +1 -1
- package/daemon/dist/domain/review/proof-io.d.ts +2 -0
- package/daemon/dist/domain/review/proof-io.d.ts.map +1 -0
- package/daemon/dist/domain/review/proof-io.js +38 -0
- package/daemon/dist/domain/review/proof-io.js.map +1 -0
- package/daemon/dist/domain/rigspec-instantiator.d.ts.map +1 -1
- package/daemon/dist/domain/rigspec-instantiator.js +15 -2
- package/daemon/dist/domain/rigspec-instantiator.js.map +1 -1
- package/daemon/dist/domain/scope/plan-lock-artifacts.d.ts +8 -0
- package/daemon/dist/domain/scope/plan-lock-artifacts.d.ts.map +1 -0
- package/daemon/dist/domain/scope/plan-lock-artifacts.js +57 -0
- package/daemon/dist/domain/scope/plan-lock-artifacts.js.map +1 -0
- package/daemon/dist/domain/scope/scaffold-placeholder.d.ts +38 -0
- package/daemon/dist/domain/scope/scaffold-placeholder.d.ts.map +1 -0
- package/daemon/dist/domain/scope/scaffold-placeholder.js +98 -0
- package/daemon/dist/domain/scope/scaffold-placeholder.js.map +1 -0
- package/daemon/dist/domain/scope/scope-approve.d.ts.map +1 -1
- package/daemon/dist/domain/scope/scope-approve.js +22 -1
- package/daemon/dist/domain/scope/scope-approve.js.map +1 -1
- package/daemon/dist/domain/scope/scope-audit.d.ts.map +1 -1
- package/daemon/dist/domain/scope/scope-audit.js +57 -20
- package/daemon/dist/domain/scope/scope-audit.js.map +1 -1
- package/daemon/dist/domain/session-transport.d.ts +17 -0
- package/daemon/dist/domain/session-transport.d.ts.map +1 -1
- package/daemon/dist/domain/session-transport.js +44 -0
- package/daemon/dist/domain/session-transport.js.map +1 -1
- package/daemon/dist/domain/slices/qitem-membership.d.ts +17 -0
- package/daemon/dist/domain/slices/qitem-membership.d.ts.map +1 -0
- package/daemon/dist/domain/slices/qitem-membership.js +60 -0
- package/daemon/dist/domain/slices/qitem-membership.js.map +1 -0
- package/daemon/dist/domain/slices/slice-detail-projector.d.ts +5 -0
- package/daemon/dist/domain/slices/slice-detail-projector.d.ts.map +1 -1
- package/daemon/dist/domain/slices/slice-detail-projector.js +157 -11
- package/daemon/dist/domain/slices/slice-detail-projector.js.map +1 -1
- package/daemon/dist/domain/slices/slice-indexer.d.ts +86 -0
- package/daemon/dist/domain/slices/slice-indexer.d.ts.map +1 -1
- package/daemon/dist/domain/slices/slice-indexer.js +422 -45
- package/daemon/dist/domain/slices/slice-indexer.js.map +1 -1
- package/daemon/dist/domain/startup-orchestrator.d.ts +9 -0
- package/daemon/dist/domain/startup-orchestrator.d.ts.map +1 -1
- package/daemon/dist/domain/startup-orchestrator.js +71 -3
- package/daemon/dist/domain/startup-orchestrator.js.map +1 -1
- package/daemon/dist/domain/terminal/cmux-provider-adapter.d.ts +12 -11
- package/daemon/dist/domain/terminal/cmux-provider-adapter.d.ts.map +1 -1
- package/daemon/dist/domain/terminal/cmux-provider-adapter.js +61 -28
- package/daemon/dist/domain/terminal/cmux-provider-adapter.js.map +1 -1
- package/daemon/dist/domain/terminal/herdr-adapter.d.ts +27 -10
- package/daemon/dist/domain/terminal/herdr-adapter.d.ts.map +1 -1
- package/daemon/dist/domain/terminal/herdr-adapter.js +74 -33
- package/daemon/dist/domain/terminal/herdr-adapter.js.map +1 -1
- package/daemon/dist/domain/transcript-capture.d.ts +3 -0
- package/daemon/dist/domain/transcript-capture.d.ts.map +1 -1
- package/daemon/dist/domain/transcript-capture.js +28 -0
- package/daemon/dist/domain/transcript-capture.js.map +1 -1
- package/daemon/dist/domain/transcript-store.d.ts +10 -0
- package/daemon/dist/domain/transcript-store.d.ts.map +1 -1
- package/daemon/dist/domain/transcript-store.js +26 -0
- package/daemon/dist/domain/transcript-store.js.map +1 -1
- package/daemon/dist/domain/types.d.ts +4 -0
- package/daemon/dist/domain/types.d.ts.map +1 -1
- package/daemon/dist/domain/types.js.map +1 -1
- package/daemon/dist/domain/workspace/default-workspace-scaffold.d.ts.map +1 -1
- package/daemon/dist/domain/workspace/default-workspace-scaffold.js +9 -4
- package/daemon/dist/domain/workspace/default-workspace-scaffold.js.map +1 -1
- package/daemon/dist/domain/workspace/workspace-doctor.js +1 -1
- package/daemon/dist/domain/workspace/workspace-doctor.js.map +1 -1
- package/daemon/dist/routes/mission-control.js +1 -1
- package/daemon/dist/routes/mission-control.js.map +1 -1
- package/daemon/dist/routes/missions.d.ts +7 -0
- package/daemon/dist/routes/missions.d.ts.map +1 -1
- package/daemon/dist/routes/missions.js +6 -1
- package/daemon/dist/routes/missions.js.map +1 -1
- package/daemon/dist/routes/ps.d.ts.map +1 -1
- package/daemon/dist/routes/ps.js +5 -1
- package/daemon/dist/routes/ps.js.map +1 -1
- package/daemon/dist/routes/queue.d.ts.map +1 -1
- package/daemon/dist/routes/queue.js +9 -2
- package/daemon/dist/routes/queue.js.map +1 -1
- package/daemon/dist/routes/rigs.d.ts.map +1 -1
- package/daemon/dist/routes/rigs.js +21 -10
- package/daemon/dist/routes/rigs.js.map +1 -1
- package/daemon/dist/routes/scope-audit.d.ts.map +1 -1
- package/daemon/dist/routes/scope-audit.js +141 -135
- package/daemon/dist/routes/scope-audit.js.map +1 -1
- package/daemon/dist/routes/sessions.js +2 -1
- package/daemon/dist/routes/sessions.js.map +1 -1
- package/daemon/dist/routes/slices.d.ts.map +1 -1
- package/daemon/dist/routes/slices.js +48 -38
- package/daemon/dist/routes/slices.js.map +1 -1
- package/daemon/dist/routes/transcripts.d.ts.map +1 -1
- package/daemon/dist/routes/transcripts.js +62 -33
- package/daemon/dist/routes/transcripts.js.map +1 -1
- package/daemon/dist/startup.d.ts.map +1 -1
- package/daemon/dist/startup.js +25 -11
- package/daemon/dist/startup.js.map +1 -1
- package/daemon/docs/reference/agent-startup-guide.md +1 -0
- package/daemon/specs/agents/apps/vault-specialist/agent.yaml +2 -1
- package/daemon/specs/agents/conveyor/builder/agent.yaml +2 -1
- package/daemon/specs/agents/conveyor/lead/agent.yaml +2 -1
- package/daemon/specs/agents/conveyor/planner/agent.yaml +2 -1
- package/daemon/specs/agents/conveyor/reviewer/agent.yaml +2 -1
- package/daemon/specs/agents/design/product-designer/agent.yaml +12 -2
- package/daemon/specs/agents/development/implementer/agent.yaml +12 -2
- package/daemon/specs/agents/development/qa/agent.yaml +12 -2
- package/daemon/specs/agents/development/qa/guidance/role.md +1 -0
- package/daemon/specs/agents/factory-rsi/dogfood/agent.yaml +2 -1
- package/daemon/specs/agents/factory-rsi/release-manager/agent.yaml +2 -1
- package/daemon/specs/agents/orchestration/orchestrator/agent.yaml +12 -2
- package/daemon/specs/agents/product-management/pm/agent.yaml +1 -2
- package/daemon/specs/agents/research/analyst/agent.yaml +2 -1
- package/daemon/specs/agents/research/synthesizer/agent.yaml +2 -1
- package/daemon/specs/agents/review/independent-reviewer/agent.yaml +12 -2
- package/daemon/specs/agents/shared/agent.yaml +5 -8
- package/daemon/specs/agents/shared/runtime/claude-settings.fragment.json +13 -1
- package/daemon/specs/agents/shared/skills/core/agent-starters/SKILL.md +132 -0
- package/daemon/{assets/plugins/openrig-core/skills → specs/agents/shared/skills/core}/agent-startup-and-context-ingestion/SKILL.md +27 -19
- package/daemon/specs/agents/shared/skills/core/attention-queue/SKILL.md +264 -0
- package/daemon/specs/agents/shared/skills/core/cross-host-rig-commands/SKILL.md +190 -0
- package/daemon/specs/agents/shared/skills/core/human-in-the-loop/SKILL.md +104 -0
- package/daemon/specs/agents/shared/skills/core/openrig-architect/SKILL.md +25 -8
- package/daemon/specs/agents/shared/skills/core/openrig-cmux/SKILL.md +0 -5
- package/daemon/specs/agents/shared/skills/core/openrig-herdr/SKILL.md +1 -6
- package/daemon/specs/agents/shared/skills/core/openrig-upgrade/SKILL.md +460 -0
- package/daemon/specs/agents/shared/skills/core/rig-bundles-and-shareable-artifacts/SKILL.md +101 -0
- package/daemon/specs/agents/shared/skills/core/rig-lifecycle/SKILL.md +22 -11
- package/daemon/specs/agents/shared/skills/core/session-source-fork/SKILL.md +160 -0
- package/daemon/specs/agents/shared/skills/core/specification-system/SKILL.md +103 -0
- package/daemon/specs/agents/shared/skills/core/topology-mutation-and-seat-management/SKILL.md +118 -0
- package/daemon/specs/agents/shared/skills/core/watchdog/SKILL.md +125 -0
- package/daemon/specs/agents/shared/skills/pods/orchestration-team/SKILL.md +4 -4
- package/daemon/specs/agents/shared/skills/pods/review-team/SKILL.md +3 -0
- package/daemon/specs/agents/shared/skills/process/brainstorming/OPENRIG.md +3 -3
- package/daemon/specs/agents/shared/skills/process/executing-plans/OPENRIG.md +1 -1
- package/daemon/specs/agents/shared/skills/process/frontend-design/SKILL.md +6 -3
- package/daemon/specs/agents/shared/skills/process/test-driven-development/SKILL.md +1 -1
- package/daemon/specs/agents/shared/skills/process/using-superpowers/OPENRIG.md +1 -1
- package/daemon/specs/agents/shared/skills/process/verification-before-completion/SKILL.md +12 -2
- package/daemon/specs/agents/shared/skills/process/writing-plans/OPENRIG.md +1 -1
- package/daemon/specs/rigs/focused/pm-team/CULTURE.md +1 -1
- package/daemon/specs/rigs/launch/kernel/agents/advisor/lead/agent.yaml +2 -2
- package/daemon/specs/rigs/launch/kernel/agents/advisor/lead/guidance/role.md +5 -4
- package/daemon/specs/rigs/launch/kernel/agents/operator/agent/agent.yaml +2 -2
- package/daemon/specs/rigs/launch/kernel/agents/operator/agent/guidance/role.md +3 -5
- package/daemon/specs/rigs/launch/kernel/agents/queue/worker/agent.yaml +2 -2
- package/daemon/specs/rigs/launch/kernel/culture/CULTURE.md +3 -4
- package/daemon/specs/rigs/preview/product-team/CULTURE.md +1 -1
- package/dist/bin-wrapper.d.ts.map +1 -1
- package/dist/bin-wrapper.js +3 -1
- package/dist/bin-wrapper.js.map +1 -1
- package/dist/build-info.js +3 -3
- package/dist/cli-error.d.ts +33 -0
- package/dist/cli-error.d.ts.map +1 -0
- package/dist/cli-error.js +94 -0
- package/dist/cli-error.js.map +1 -0
- package/dist/commands/config-init-workspace.js +1 -1
- package/dist/commands/doctor.d.ts +1 -1
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +17 -11
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/host.d.ts.map +1 -1
- package/dist/commands/host.js +24 -10
- package/dist/commands/host.js.map +1 -1
- package/dist/commands/proof.js +1 -1
- package/dist/commands/proof.js.map +1 -1
- package/dist/commands/ps.d.ts.map +1 -1
- package/dist/commands/ps.js +16 -2
- package/dist/commands/ps.js.map +1 -1
- package/dist/commands/queue.d.ts.map +1 -1
- package/dist/commands/queue.js +103 -24
- package/dist/commands/queue.js.map +1 -1
- package/dist/commands/rig.d.ts.map +1 -1
- package/dist/commands/rig.js +122 -0
- package/dist/commands/rig.js.map +1 -1
- package/dist/commands/scope.js +2 -2
- package/dist/commands/scope.js.map +1 -1
- package/dist/commands/send.d.ts.map +1 -1
- package/dist/commands/send.js +118 -24
- package/dist/commands/send.js.map +1 -1
- package/dist/commands/slack.d.ts +37 -0
- package/dist/commands/slack.d.ts.map +1 -0
- package/dist/commands/slack.js +274 -0
- package/dist/commands/slack.js.map +1 -0
- package/dist/commands/ui.d.ts +1 -0
- package/dist/commands/ui.d.ts.map +1 -1
- package/dist/commands/ui.js +2 -0
- package/dist/commands/ui.js.map +1 -1
- package/dist/commands/up.js +1 -1
- package/dist/commands/up.js.map +1 -1
- package/dist/commands/whoami.d.ts.map +1 -1
- package/dist/commands/whoami.js +3 -3
- package/dist/commands/whoami.js.map +1 -1
- package/dist/daemon-lifecycle.d.ts.map +1 -1
- package/dist/daemon-lifecycle.js +45 -14
- package/dist/daemon-lifecycle.js.map +1 -1
- package/dist/host-registry.d.ts +6 -1
- package/dist/host-registry.d.ts.map +1 -1
- package/dist/host-registry.js +15 -6
- package/dist/host-registry.js.map +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -1
- package/dist/index.js.map +1 -1
- package/dist/lib/scope/scaffold-placeholder.d.ts +38 -0
- package/dist/lib/scope/scaffold-placeholder.d.ts.map +1 -0
- package/dist/lib/scope/scaffold-placeholder.js +98 -0
- package/dist/lib/scope/scaffold-placeholder.js.map +1 -0
- package/dist/lib/scope/scope-audit.d.ts.map +1 -1
- package/dist/lib/scope/scope-audit.js +57 -20
- package/dist/lib/scope/scope-audit.js.map +1 -1
- package/dist/lib/scope-templates/backlog-deprecation.md +1 -1
- package/dist/lib/scope-templates/backlog-tech-debt.md +1 -1
- package/dist/lib/scope-templates/bug-fix.md +1 -1
- package/dist/lib/scope-templates/implementation-prd.md +1 -1
- package/dist/lib/scope-templates/mission-notes.md +7 -2
- package/dist/lib/scope-templates/mission-placeholder.md +1 -1
- package/dist/lib/scope-templates/mission-progress.md +1 -1
- package/dist/lib/scope-templates/mission-release.md +1 -1
- package/dist/lib/scope-templates/placeholder.md +1 -1
- package/dist/lib/scope-templates/proof.md +1 -1
- package/dist/lib/scope-templates/release-feature.md +1 -1
- package/dist/lib/scope-templates/research.md +1 -1
- package/dist/lib/scope-templates/slice-progress.md +1 -1
- package/dist/remote-host-ops.d.ts.map +1 -1
- package/dist/remote-host-ops.js +2 -2
- package/dist/remote-host-ops.js.map +1 -1
- package/dist/slack/config.d.ts +41 -0
- package/dist/slack/config.d.ts.map +1 -0
- package/dist/slack/config.js +60 -0
- package/dist/slack/config.js.map +1 -0
- package/dist/slack/inbound.d.ts +75 -0
- package/dist/slack/inbound.d.ts.map +1 -0
- package/dist/slack/inbound.js +133 -0
- package/dist/slack/inbound.js.map +1 -0
- package/dist/slack/message.d.ts +26 -0
- package/dist/slack/message.d.ts.map +1 -0
- package/dist/slack/message.js +60 -0
- package/dist/slack/message.js.map +1 -0
- package/dist/slack/outbound.d.ts +39 -0
- package/dist/slack/outbound.d.ts.map +1 -0
- package/dist/slack/outbound.js +52 -0
- package/dist/slack/outbound.js.map +1 -0
- package/dist/slack/queue-bridge.d.ts +56 -0
- package/dist/slack/queue-bridge.d.ts.map +1 -0
- package/dist/slack/queue-bridge.js +114 -0
- package/dist/slack/queue-bridge.js.map +1 -0
- package/dist/slack/secrets.d.ts +21 -0
- package/dist/slack/secrets.d.ts.map +1 -0
- package/dist/slack/secrets.js +73 -0
- package/dist/slack/secrets.js.map +1 -0
- package/dist/slack/slack-api.d.ts +49 -0
- package/dist/slack/slack-api.d.ts.map +1 -0
- package/dist/slack/slack-api.js +110 -0
- package/dist/slack/slack-api.js.map +1 -0
- package/dist/slack/state-store.d.ts +62 -0
- package/dist/slack/state-store.d.ts.map +1 -0
- package/dist/slack/state-store.js +132 -0
- package/dist/slack/state-store.js.map +1 -0
- package/package.json +1 -1
- package/ui/dist/assets/{index-zrFqS7gL.js → index-DkNi0RT8.js} +184 -184
- package/ui/dist/assets/index-N-SdPj-I.css +32 -0
- package/ui/dist/index.html +2 -2
- package/daemon/assets/plugins/openrig-core/skills/openrig-architect/SKILL.md +0 -361
- package/daemon/assets/plugins/openrig-core/skills/openrig-cmux/SKILL.md +0 -86
- package/daemon/assets/plugins/openrig-core/skills/openrig-herdr/SKILL.md +0 -158
- package/daemon/assets/plugins/openrig-core/skills/openrig-operator/SKILL.md +0 -222
- package/daemon/docs/reference/product-factory-vps-runbook.md +0 -132
- package/daemon/specs/agents/shared/skills/core/mission-slice-sop/SKILL.md +0 -113
- package/daemon/specs/agents/shared/skills/core/openrig-installer/SKILL.md +0 -142
- package/daemon/specs/agents/shared/skills/core/openrig-operator/SKILL.md +0 -110
- package/daemon/specs/agents/shared/skills/core/openrig-user/SKILL.md +0 -1245
- package/daemon/specs/agents/shared/skills/core/openrig-user-settings/SKILL.md +0 -153
- package/ui/dist/assets/index-CFqxa0zW.css +0 -32
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import { createQitem } from "./queue-bridge.js";
|
|
2
|
+
/**
|
|
3
|
+
* Loop-safety + non-text ignore. Ingest ONLY genuine human text messages:
|
|
4
|
+
* reject bot posts (our own loop), message subtypes (edits/joins/file_share),
|
|
5
|
+
* and — T1076 — anything carrying files/images. v1 ignores non-text CLEANLY:
|
|
6
|
+
* a false return is a clean skip, never a crash or partial ingestion.
|
|
7
|
+
*/
|
|
8
|
+
export function shouldIngest(ev) {
|
|
9
|
+
if (ev.type !== "message" && ev.type !== "app_mention")
|
|
10
|
+
return false;
|
|
11
|
+
if (ev.bot_id)
|
|
12
|
+
return false; // never ingest our own / any bot post
|
|
13
|
+
if (ev.subtype)
|
|
14
|
+
return false; // edits, joins, file_share, etc.
|
|
15
|
+
if (ev.files && ev.files.length > 0)
|
|
16
|
+
return false; // T1076: image/file events ignored cleanly (Slice-12)
|
|
17
|
+
if (!ev.user || !ev.text || !ev.text.trim())
|
|
18
|
+
return false;
|
|
19
|
+
return true;
|
|
20
|
+
}
|
|
21
|
+
export class InboundRouter {
|
|
22
|
+
deps;
|
|
23
|
+
inflight = new Set(); // same-ts double-dispatch guard (item 8)
|
|
24
|
+
constructor(deps) {
|
|
25
|
+
this.deps = deps;
|
|
26
|
+
}
|
|
27
|
+
summaryOf(ev) {
|
|
28
|
+
const text = String(ev.text ?? "").slice(0, 1800);
|
|
29
|
+
const meta = `slack channel=${ev.channel} user=${ev.user} ts=${ev.ts}`;
|
|
30
|
+
return {
|
|
31
|
+
summary: `Founder via Slack: ${text.slice(0, 90)}`,
|
|
32
|
+
body: `${text}\n\n---\nSource: ${meta}\nRouted by openrig slack-inbound. Default destination per config; re-route via queue as needed.`,
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Core landing attempt — NO dead-letter side effect. Dedup by ts (in-flight +
|
|
37
|
+
* durable seen). `reason` distinguishes a dedup skip from a genuine create
|
|
38
|
+
* failure so callers dead-letter ONLY real failures. On success, marks seen
|
|
39
|
+
* (durable qitem exists → safe).
|
|
40
|
+
*/
|
|
41
|
+
async attemptLand(ev) {
|
|
42
|
+
const ts = ev.ts ?? "";
|
|
43
|
+
if (!ts || this.inflight.has(ts) || this.deps.seen.load().has(ts))
|
|
44
|
+
return { landed: false, reason: "dup" };
|
|
45
|
+
this.inflight.add(ts);
|
|
46
|
+
try {
|
|
47
|
+
const { summary, body } = this.summaryOf(ev);
|
|
48
|
+
let qitemId;
|
|
49
|
+
try {
|
|
50
|
+
qitemId = await createQitem(this.deps.runner, {
|
|
51
|
+
source: `human-${ev.user}@kernel`, // provenance classifies as human (name convention)
|
|
52
|
+
destination: this.deps.destination,
|
|
53
|
+
priority: "routine",
|
|
54
|
+
tags: ["founder-slack", "inbound"],
|
|
55
|
+
summary,
|
|
56
|
+
body,
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
catch (e) {
|
|
60
|
+
this.deps.log?.(`qitem create failed ts=${ts}: ${e.message}`);
|
|
61
|
+
return { landed: false, reason: "create_failed" };
|
|
62
|
+
}
|
|
63
|
+
this.deps.seen.mark(ts, "landed"); // durable qitem exists → safe to mark
|
|
64
|
+
this.deps.log?.(`qitem ${qitemId} -> ${this.deps.destination} (ts=${ts})`);
|
|
65
|
+
return { landed: true, qitemId };
|
|
66
|
+
}
|
|
67
|
+
finally {
|
|
68
|
+
this.inflight.delete(ts);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* LIVE path: attempt to land; on a genuine create failure, dead-letter the
|
|
73
|
+
* event (attempt-counted) BEFORE returning — NOT marked seen (item 8).
|
|
74
|
+
*/
|
|
75
|
+
async route(ev, attempts = 0) {
|
|
76
|
+
const r = await this.attemptLand(ev);
|
|
77
|
+
if (!r.landed && r.reason === "create_failed") {
|
|
78
|
+
this.deps.deadLetter.append(ev, attempts + 1);
|
|
79
|
+
this.deps.log?.(`dead-lettered ts=${ev.ts} (attempt ${attempts + 1})`);
|
|
80
|
+
}
|
|
81
|
+
return { landed: r.landed, qitemId: r.qitemId };
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* INTERRUPTION-SAFE retry (item 8): read the durable set NON-destructively,
|
|
85
|
+
* attempt each, then ATOMICALLY replace the file with only the still-failing
|
|
86
|
+
* entries. The original file stays intact until the atomic replace, so a crash
|
|
87
|
+
* at any point loses nothing (a since-landed event is skipped via the seen-set).
|
|
88
|
+
* Does NOT go through route() (which would double-append) — uses attemptLand.
|
|
89
|
+
*/
|
|
90
|
+
async retryDeadLetters() {
|
|
91
|
+
const entries = this.deps.deadLetter.readAll();
|
|
92
|
+
if (entries.length === 0)
|
|
93
|
+
return { retried: 0, landed: 0 };
|
|
94
|
+
this.deps.log?.(`retrying ${entries.length} dead-letter(s)`);
|
|
95
|
+
const stillFailing = [];
|
|
96
|
+
let landed = 0;
|
|
97
|
+
const seen = this.deps.seen.load();
|
|
98
|
+
for (const e of entries) {
|
|
99
|
+
if (e.ev.ts && seen.has(e.ev.ts))
|
|
100
|
+
continue; // already landed → recovered, drop from set
|
|
101
|
+
const r = await this.attemptLand(e.ev);
|
|
102
|
+
if (r.landed)
|
|
103
|
+
landed++;
|
|
104
|
+
else if (r.reason === "create_failed")
|
|
105
|
+
stillFailing.push({ ev: e.ev, at: e.at, attempts: e.attempts + 1 });
|
|
106
|
+
// reason === "dup" (in-flight) → drop; a concurrent path owns it
|
|
107
|
+
}
|
|
108
|
+
this.deps.deadLetter.replaceAll(stillFailing); // atomic; original intact until here
|
|
109
|
+
return { retried: entries.length, landed };
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Handle one Socket Mode envelope. FAST-ACK first, ALWAYS (item 8: Socket Mode
|
|
114
|
+
* punishes slow acks; transport redelivery is not the safety net). Then filter
|
|
115
|
+
* and route. Ack happens even if routing later fails — the dead-letter, not
|
|
116
|
+
* transport redelivery, is the zero-drop net.
|
|
117
|
+
*/
|
|
118
|
+
export async function handleEnvelope(env, ack, router, log) {
|
|
119
|
+
if (env.envelope_id)
|
|
120
|
+
ack(); // fast-ack, unconditional, first
|
|
121
|
+
if (env.type === "disconnect")
|
|
122
|
+
return;
|
|
123
|
+
if (env.type !== "events_api")
|
|
124
|
+
return;
|
|
125
|
+
const ev = env.payload?.event ?? {};
|
|
126
|
+
if (!shouldIngest(ev)) {
|
|
127
|
+
if (ev.type)
|
|
128
|
+
log?.(`ignored non-ingestible event type=${ev.type} subtype=${ev.subtype ?? "-"} files=${ev.files?.length ?? 0}`);
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
await router.route(ev);
|
|
132
|
+
}
|
|
133
|
+
//# sourceMappingURL=inbound.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"inbound.js","sourceRoot":"","sources":["../../src/slack/inbound.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export declare const SLACK_TEXT_CAP = 3900;
|
|
2
|
+
export declare const DEFAULT_BODY_EXCERPT = 800;
|
|
3
|
+
export interface QitemLike {
|
|
4
|
+
qitemId: string;
|
|
5
|
+
summary?: string | null;
|
|
6
|
+
body?: string | null;
|
|
7
|
+
destinationSession?: string | null;
|
|
8
|
+
}
|
|
9
|
+
export interface OutboundMessageOpts {
|
|
10
|
+
sourceLabel: string;
|
|
11
|
+
bodyExcerpt?: number;
|
|
12
|
+
/** T1076 extension point: extra Block Kit blocks (e.g. future media). v1 unused. */
|
|
13
|
+
extraBlocks?: unknown[];
|
|
14
|
+
}
|
|
15
|
+
export declare function containsSecret(text: string): boolean;
|
|
16
|
+
export declare function redactSecrets(text: string): string;
|
|
17
|
+
export interface SlackMessagePayload {
|
|
18
|
+
text: string;
|
|
19
|
+
blocks: unknown[];
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Build the Slack payload for a human-destined qitem. Pure + deterministic
|
|
23
|
+
* (no clock, no io) so it is trivially testable and safe to snapshot.
|
|
24
|
+
*/
|
|
25
|
+
export declare function buildOutboundMessage(q: QitemLike, opts: OutboundMessageOpts): SlackMessagePayload;
|
|
26
|
+
//# sourceMappingURL=message.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"message.d.ts","sourceRoot":"","sources":["../../src/slack/message.ts"],"names":[],"mappings":"AAaA,eAAO,MAAM,cAAc,OAAO,CAAC;AACnC,eAAO,MAAM,oBAAoB,MAAM,CAAC;AAExC,MAAM,WAAW,SAAS;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,kBAAkB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACpC;AAED,MAAM,WAAW,mBAAmB;IAClC,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,oFAAoF;IACpF,WAAW,CAAC,EAAE,OAAO,EAAE,CAAC;CACzB;AAWD,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAKpD;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAMlD;AAED,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,OAAO,EAAE,CAAC;CACnB;AAMD;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,mBAAmB,GAAG,mBAAmB,CAiBjG"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
// Slice-11 slack-connector — outbound message construction.
|
|
2
|
+
//
|
|
3
|
+
// Locked item 7 (content hygiene): a posted message carries summary + qitem id
|
|
4
|
+
// + source + a BOUNDED body excerpt, and NEVER a token/secret/secret-bearing
|
|
5
|
+
// path. We never add our own credentials (we only render qitem fields), and as
|
|
6
|
+
// defense-in-depth we redact anything that looks like a Slack/bearer secret
|
|
7
|
+
// leaking through a qitem body before it goes out.
|
|
8
|
+
//
|
|
9
|
+
// T1076 (don't preclude Slice-12): construction is BLOCKS/ATTACHMENTS-capable —
|
|
10
|
+
// we always emit Block Kit `blocks` PLUS a plain-text fallback, and accept
|
|
11
|
+
// optional extra blocks / media refs so image relay can extend this later
|
|
12
|
+
// WITHOUT redefining the shape here. v1 ships text only.
|
|
13
|
+
export const SLACK_TEXT_CAP = 3900; // Slack hard-limits ~4000; stay under.
|
|
14
|
+
export const DEFAULT_BODY_EXCERPT = 800;
|
|
15
|
+
// Secret-looking patterns we refuse to forward (item 7 defense-in-depth).
|
|
16
|
+
const SECRET_PATTERNS = [
|
|
17
|
+
/xox[baprs]-[A-Za-z0-9-]+/g, // Slack bot/user/app/refresh tokens
|
|
18
|
+
/xapp-[A-Za-z0-9-]+/g, // Slack app-level (Socket Mode) token
|
|
19
|
+
/https:\/\/hooks\.slack\.com\/services\/[A-Za-z0-9/_-]+/g, // incoming webhook URL
|
|
20
|
+
/\bBearer\s+[A-Za-z0-9._-]{12,}/gi, // bearer tokens
|
|
21
|
+
/xoxe\.xox[bp]-[A-Za-z0-9-]+/g, // rotation tokens
|
|
22
|
+
];
|
|
23
|
+
export function containsSecret(text) {
|
|
24
|
+
return SECRET_PATTERNS.some((p) => {
|
|
25
|
+
p.lastIndex = 0;
|
|
26
|
+
return p.test(text);
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
export function redactSecrets(text) {
|
|
30
|
+
let out = text;
|
|
31
|
+
for (const p of SECRET_PATTERNS) {
|
|
32
|
+
out = out.replace(p, "[redacted-secret]");
|
|
33
|
+
}
|
|
34
|
+
return out;
|
|
35
|
+
}
|
|
36
|
+
function clamp(s, max) {
|
|
37
|
+
return s.length > max ? s.slice(0, max) : s;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Build the Slack payload for a human-destined qitem. Pure + deterministic
|
|
41
|
+
* (no clock, no io) so it is trivially testable and safe to snapshot.
|
|
42
|
+
*/
|
|
43
|
+
export function buildOutboundMessage(q, opts) {
|
|
44
|
+
const summary = redactSecrets(String(q.summary || "(no summary)"));
|
|
45
|
+
const bodyRaw = redactSecrets(String(q.body || ""));
|
|
46
|
+
const body = clamp(bodyRaw, opts.bodyExcerpt ?? DEFAULT_BODY_EXCERPT);
|
|
47
|
+
const dest = q.destinationSession || "(unknown destination)";
|
|
48
|
+
const footer = `qitem ${q.qitemId} → ${dest} on ${opts.sourceLabel}`;
|
|
49
|
+
const text = clamp(`:rotating_light: *${summary}*\n${body}\n_${footer}_`, SLACK_TEXT_CAP);
|
|
50
|
+
const blocks = [
|
|
51
|
+
{ type: "section", text: { type: "mrkdwn", text: clamp(`:rotating_light: *${summary}*`, 3000) } },
|
|
52
|
+
];
|
|
53
|
+
if (body.trim())
|
|
54
|
+
blocks.push({ type: "section", text: { type: "mrkdwn", text: clamp(body, 3000) } });
|
|
55
|
+
blocks.push({ type: "context", elements: [{ type: "mrkdwn", text: footer }] });
|
|
56
|
+
if (opts.extraBlocks?.length)
|
|
57
|
+
blocks.push(...opts.extraBlocks);
|
|
58
|
+
return { text, blocks };
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=message.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"message.js","sourceRoot":"","sources":["../../src/slack/message.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { SeenStore } from "./state-store.js";
|
|
2
|
+
import type { QueueRunner, AlertFilterOpts } from "./queue-bridge.js";
|
|
3
|
+
import { type FetchImpl } from "./slack-api.js";
|
|
4
|
+
export interface OutboundDeps {
|
|
5
|
+
runner: QueueRunner;
|
|
6
|
+
seen: SeenStore;
|
|
7
|
+
webhookUrl: string;
|
|
8
|
+
fetchImpl?: FetchImpl;
|
|
9
|
+
sourceLabel: string;
|
|
10
|
+
filter: AlertFilterOpts;
|
|
11
|
+
bodyExcerpt?: number;
|
|
12
|
+
log?: (msg: string) => void;
|
|
13
|
+
}
|
|
14
|
+
export interface OutboundResult {
|
|
15
|
+
freshCount: number;
|
|
16
|
+
posted: string[];
|
|
17
|
+
failed: {
|
|
18
|
+
id: string;
|
|
19
|
+
error: string;
|
|
20
|
+
}[];
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* One outbound sweep. Posts every FRESH human alert, marking it seen ONLY after
|
|
24
|
+
* a 200. A failed post is logged loudly and left UNSEEN so the next sweep
|
|
25
|
+
* retries it — never a silent drop. Returns failures so the caller exits
|
|
26
|
+
* non-zero (fail-visible).
|
|
27
|
+
*/
|
|
28
|
+
export declare function runOutboundOnce(deps: OutboundDeps): Promise<OutboundResult>;
|
|
29
|
+
export interface SeedResult {
|
|
30
|
+
seeded: number;
|
|
31
|
+
onlineStatus: string;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Item 9: on ENABLE, seed all currently-active human alerts as history/seen
|
|
35
|
+
* WITHOUT posting, so turning the connector on never replays the backlog.
|
|
36
|
+
* Returns an honest online-status line marking the transition.
|
|
37
|
+
*/
|
|
38
|
+
export declare function seedBacklogOnEnable(deps: Pick<OutboundDeps, "runner" | "seen" | "filter" | "log">): Promise<SeedResult>;
|
|
39
|
+
//# sourceMappingURL=outbound.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"outbound.d.ts","sourceRoot":"","sources":["../../src/slack/outbound.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,KAAK,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEtE,OAAO,EAAe,KAAK,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAG7D,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,WAAW,CAAC;IACpB,IAAI,EAAE,SAAS,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,eAAe,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,GAAG,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;CAC7B;AAED,MAAM,WAAW,cAAc;IAC7B,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,MAAM,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;CACzC;AAED;;;;;GAKG;AACH,wBAAsB,eAAe,CAAC,IAAI,EAAE,YAAY,GAAG,OAAO,CAAC,cAAc,CAAC,CA6BjF;AAED,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;CACtB;AAED;;;;GAIG;AACH,wBAAsB,mBAAmB,CAAC,IAAI,EAAE,IAAI,CAAC,YAAY,EAAE,QAAQ,GAAG,MAAM,GAAG,QAAQ,GAAG,KAAK,CAAC,GAAG,OAAO,CAAC,UAAU,CAAC,CAQ7H"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { listHumanAlerts, showFull } from "./queue-bridge.js";
|
|
2
|
+
import { postWebhook } from "./slack-api.js";
|
|
3
|
+
import { buildOutboundMessage } from "./message.js";
|
|
4
|
+
/**
|
|
5
|
+
* One outbound sweep. Posts every FRESH human alert, marking it seen ONLY after
|
|
6
|
+
* a 200. A failed post is logged loudly and left UNSEEN so the next sweep
|
|
7
|
+
* retries it — never a silent drop. Returns failures so the caller exits
|
|
8
|
+
* non-zero (fail-visible).
|
|
9
|
+
*/
|
|
10
|
+
export async function runOutboundOnce(deps) {
|
|
11
|
+
const log = deps.log ?? (() => { });
|
|
12
|
+
const alerts = await listHumanAlerts(deps.runner, deps.filter);
|
|
13
|
+
const seen = deps.seen.load();
|
|
14
|
+
const fresh = alerts.filter((q) => !seen.has(q.qitemId));
|
|
15
|
+
log(`alerts=${alerts.length} fresh=${fresh.length}`);
|
|
16
|
+
const posted = [];
|
|
17
|
+
const failed = [];
|
|
18
|
+
for (const a of fresh) {
|
|
19
|
+
// list bounds bodies (item 9 N+1) — pull the full item for summary+body.
|
|
20
|
+
const full = (await showFull(deps.runner, a.qitemId)) ?? a;
|
|
21
|
+
const payload = buildOutboundMessage({ qitemId: a.qitemId, summary: full.summary ?? a.summary, body: full.body, destinationSession: a.destinationSession }, { sourceLabel: deps.sourceLabel, bodyExcerpt: deps.bodyExcerpt });
|
|
22
|
+
const res = await postWebhook(deps.webhookUrl, payload, deps.fetchImpl);
|
|
23
|
+
if (res.ok) {
|
|
24
|
+
deps.seen.mark(a.qitemId, "posted"); // …seen ONLY after success (item 2)
|
|
25
|
+
posted.push(a.qitemId);
|
|
26
|
+
log(`posted ${a.qitemId}`);
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
// fail-VISIBLE (item 3): loud, NOT marked seen → retried next sweep (no drop).
|
|
30
|
+
log(`ERROR posting ${a.qitemId}: ${res.error}`);
|
|
31
|
+
failed.push({ id: a.qitemId, error: res.error ?? "unknown" });
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
if (fresh.length === 0)
|
|
35
|
+
log("nothing new");
|
|
36
|
+
return { freshCount: fresh.length, posted, failed };
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Item 9: on ENABLE, seed all currently-active human alerts as history/seen
|
|
40
|
+
* WITHOUT posting, so turning the connector on never replays the backlog.
|
|
41
|
+
* Returns an honest online-status line marking the transition.
|
|
42
|
+
*/
|
|
43
|
+
export async function seedBacklogOnEnable(deps) {
|
|
44
|
+
const alerts = await listHumanAlerts(deps.runner, deps.filter);
|
|
45
|
+
const already = deps.seen.load();
|
|
46
|
+
const toSeed = alerts.map((a) => a.qitemId).filter((id) => !already.has(id));
|
|
47
|
+
const seeded = deps.seen.seed(toSeed, "seeded-at-enable");
|
|
48
|
+
const onlineStatus = `slack outbound ENABLED at enable-time: ${seeded} pre-existing alert(s) seeded as history (not reposted); only alerts created after this point will deliver.`;
|
|
49
|
+
deps.log?.(onlineStatus);
|
|
50
|
+
return { seeded, onlineStatus };
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=outbound.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"outbound.js","sourceRoot":"","sources":["../../src/slack/outbound.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
export interface RunResult {
|
|
2
|
+
ok: boolean;
|
|
3
|
+
stdout: string;
|
|
4
|
+
stderr: string;
|
|
5
|
+
code: number;
|
|
6
|
+
}
|
|
7
|
+
/** Injectable: run `rig queue <args>` and return the result. */
|
|
8
|
+
export type QueueRunner = (args: string[]) => Promise<RunResult>;
|
|
9
|
+
/**
|
|
10
|
+
* Default runner: spawn the configured `rig` binary. `env` carries OPENRIG_URL
|
|
11
|
+
* (or nothing, letting rig resolve the local daemon); `baseArgs` can inject
|
|
12
|
+
* `--host <id>` for a registered remote queue. No shell — argv only.
|
|
13
|
+
*/
|
|
14
|
+
export declare function makeExecRunner(opts: {
|
|
15
|
+
rigBin: string;
|
|
16
|
+
baseArgs?: string[];
|
|
17
|
+
env?: NodeJS.ProcessEnv;
|
|
18
|
+
timeoutMs?: number;
|
|
19
|
+
}): QueueRunner;
|
|
20
|
+
export interface QueueItem {
|
|
21
|
+
qitemId: string;
|
|
22
|
+
destinationSession?: string | null;
|
|
23
|
+
sourceSession?: string | null;
|
|
24
|
+
tags?: string[] | null;
|
|
25
|
+
state?: string | null;
|
|
26
|
+
tier?: string | null;
|
|
27
|
+
summary?: string | null;
|
|
28
|
+
body?: string | null;
|
|
29
|
+
}
|
|
30
|
+
export interface AlertFilterOpts {
|
|
31
|
+
alertTag: string;
|
|
32
|
+
/** Optional explicit human-seat allow-list; when empty, any human-seat destination or human-gate tier matches. */
|
|
33
|
+
destinations?: string[];
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* PURE: select the qitems that should alert a human. A qitem alerts iff it is
|
|
37
|
+
* active, carries the alert tag, AND targets a human — either an explicit
|
|
38
|
+
* configured destination, a human-seat session name, or tier `human-gate`.
|
|
39
|
+
*/
|
|
40
|
+
export declare function filterHumanAlerts(items: QueueItem[], opts: AlertFilterOpts): QueueItem[];
|
|
41
|
+
export declare const QUEUE_LIST_LIMIT = 100000;
|
|
42
|
+
/** Read active human alerts across ALL rigs (the -A scope fix) with a full-backlog limit. */
|
|
43
|
+
export declare function listHumanAlerts(runner: QueueRunner, opts: AlertFilterOpts): Promise<QueueItem[]>;
|
|
44
|
+
/** Full single-item read (list omits/bounds body — item 9 N+1). */
|
|
45
|
+
export declare function showFull(runner: QueueRunner, qitemId: string): Promise<QueueItem | null>;
|
|
46
|
+
export interface CreateQitemInput {
|
|
47
|
+
source: string;
|
|
48
|
+
destination: string;
|
|
49
|
+
summary: string;
|
|
50
|
+
body: string;
|
|
51
|
+
priority?: string;
|
|
52
|
+
tags?: string[];
|
|
53
|
+
}
|
|
54
|
+
/** Create a qitem (inbound landing). Returns the created qitem id, or throws. */
|
|
55
|
+
export declare function createQitem(runner: QueueRunner, input: CreateQitemInput): Promise<string>;
|
|
56
|
+
//# sourceMappingURL=queue-bridge.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"queue-bridge.d.ts","sourceRoot":"","sources":["../../src/slack/queue-bridge.ts"],"names":[],"mappings":"AAcA,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,OAAO,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;CACd;AAED,gEAAgE;AAChE,MAAM,MAAM,WAAW,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,OAAO,CAAC,SAAS,CAAC,CAAC;AAEjE;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE;IACnC,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,GAAG,WAAW,CAiBd;AAED,MAAM,WAAW,SAAS;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,kBAAkB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,IAAI,CAAC,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;IACvB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB;AAcD,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB,kHAAkH;IAClH,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;CACzB;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,SAAS,EAAE,EAAE,IAAI,EAAE,eAAe,GAAG,SAAS,EAAE,CAUxF;AASD,eAAO,MAAM,gBAAgB,SAAS,CAAC;AAEvC,6FAA6F;AAC7F,wBAAsB,eAAe,CAAC,MAAM,EAAE,WAAW,EAAE,IAAI,EAAE,eAAe,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC,CAItG;AAED,mEAAmE;AACnE,wBAAsB,QAAQ,CAAC,MAAM,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC,CAQ9F;AAED,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;CACjB;AAED,iFAAiF;AACjF,wBAAsB,WAAW,CAAC,MAAM,EAAE,WAAW,EAAE,KAAK,EAAE,gBAAgB,GAAG,OAAO,CAAC,MAAM,CAAC,CAsB/F"}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
// Slice-11 slack-connector — fleet access via the `rig` CLI ONLY.
|
|
2
|
+
//
|
|
3
|
+
// The connector NEVER imports daemon internals; it shells out to `rig queue`
|
|
4
|
+
// exactly like the reference relay (which ssh'd `rig queue` to the box). That
|
|
5
|
+
// keeps it transport-agnostic (local daemon via OPENRIG_URL, a registered
|
|
6
|
+
// remote via `--host`, or an ssh wrapper) and honors the secret-host axis
|
|
7
|
+
// (item 10): connector-host may differ from the queue/alert host.
|
|
8
|
+
//
|
|
9
|
+
// Productization fix over the reference (proven firsthand): reads use `-A`
|
|
10
|
+
// (all-rigs), because bare `rig queue list --json` is CURRENT-RIG only and
|
|
11
|
+
// silently misses cross-rig human-destined alerts.
|
|
12
|
+
import { execFile } from "node:child_process";
|
|
13
|
+
import { isHumanSeatSessionRef } from "../session-name.js";
|
|
14
|
+
/**
|
|
15
|
+
* Default runner: spawn the configured `rig` binary. `env` carries OPENRIG_URL
|
|
16
|
+
* (or nothing, letting rig resolve the local daemon); `baseArgs` can inject
|
|
17
|
+
* `--host <id>` for a registered remote queue. No shell — argv only.
|
|
18
|
+
*/
|
|
19
|
+
export function makeExecRunner(opts) {
|
|
20
|
+
return (args) => new Promise((resolve) => {
|
|
21
|
+
execFile(opts.rigBin, [...(opts.baseArgs ?? []), ...args], { timeout: opts.timeoutMs ?? 30000, env: opts.env ?? process.env, maxBuffer: 16 * 1024 * 1024 }, (err, stdout, stderr) => {
|
|
22
|
+
resolve({
|
|
23
|
+
ok: !err,
|
|
24
|
+
stdout: String(stdout ?? ""),
|
|
25
|
+
stderr: String(stderr ?? ""),
|
|
26
|
+
code: err && typeof err.code === "number" ? err.code : err ? 1 : 0,
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
function parseArray(stdout) {
|
|
32
|
+
let j;
|
|
33
|
+
try {
|
|
34
|
+
j = JSON.parse(stdout);
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
throw new Error("queue list: non-JSON output");
|
|
38
|
+
}
|
|
39
|
+
if (Array.isArray(j))
|
|
40
|
+
return j;
|
|
41
|
+
const o = j;
|
|
42
|
+
return o.qitems ?? o.items ?? [];
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* PURE: select the qitems that should alert a human. A qitem alerts iff it is
|
|
46
|
+
* active, carries the alert tag, AND targets a human — either an explicit
|
|
47
|
+
* configured destination, a human-seat session name, or tier `human-gate`.
|
|
48
|
+
*/
|
|
49
|
+
export function filterHumanAlerts(items, opts) {
|
|
50
|
+
const active = new Set(["pending", "in-progress", "blocked"]);
|
|
51
|
+
const allow = new Set(opts.destinations ?? []);
|
|
52
|
+
return items.filter((q) => {
|
|
53
|
+
if (q.state && !active.has(q.state))
|
|
54
|
+
return false;
|
|
55
|
+
if (!(q.tags ?? []).includes(opts.alertTag))
|
|
56
|
+
return false;
|
|
57
|
+
const dest = q.destinationSession ?? "";
|
|
58
|
+
const isHuman = allow.size > 0 ? allow.has(dest) : isHumanSeatSessionRef(dest) || q.tier === "human-gate";
|
|
59
|
+
return isHuman;
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
// Cross-host queue targeting is via OPENRIG_URL on the runner's env (supported
|
|
63
|
+
// by ALL queue verbs), NOT `--host` — `queue list`/`queue show` reject `--host`
|
|
64
|
+
// (only write/handoff verbs accept it). See makeExecRunner env / config.queueUrl.
|
|
65
|
+
// `queue list` defaults to --limit 100 and ALWAYS sends it, so an unbounded read
|
|
66
|
+
// silently truncates a large backlog (the B5 defect). Pass an explicit high
|
|
67
|
+
// limit so enable-time seeding + outbound see the COMPLETE matching set.
|
|
68
|
+
export const QUEUE_LIST_LIMIT = 100000;
|
|
69
|
+
/** Read active human alerts across ALL rigs (the -A scope fix) with a full-backlog limit. */
|
|
70
|
+
export async function listHumanAlerts(runner, opts) {
|
|
71
|
+
const r = await runner(["queue", "list", "-A", "--limit", String(QUEUE_LIST_LIMIT), "--json"]);
|
|
72
|
+
if (!r.ok)
|
|
73
|
+
throw new Error(`rig queue list failed (code ${r.code}): ${r.stderr.slice(0, 200)}`);
|
|
74
|
+
return filterHumanAlerts(parseArray(r.stdout), opts);
|
|
75
|
+
}
|
|
76
|
+
/** Full single-item read (list omits/bounds body — item 9 N+1). */
|
|
77
|
+
export async function showFull(runner, qitemId) {
|
|
78
|
+
const r = await runner(["queue", "show", qitemId, "--full", "--json"]);
|
|
79
|
+
if (!r.ok)
|
|
80
|
+
return null;
|
|
81
|
+
try {
|
|
82
|
+
return JSON.parse(r.stdout);
|
|
83
|
+
}
|
|
84
|
+
catch {
|
|
85
|
+
return null;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
/** Create a qitem (inbound landing). Returns the created qitem id, or throws. */
|
|
89
|
+
export async function createQitem(runner, input) {
|
|
90
|
+
const args = [
|
|
91
|
+
"queue",
|
|
92
|
+
"create",
|
|
93
|
+
"--source",
|
|
94
|
+
input.source,
|
|
95
|
+
"--destination",
|
|
96
|
+
input.destination,
|
|
97
|
+
"--priority",
|
|
98
|
+
input.priority ?? "routine",
|
|
99
|
+
"--tags",
|
|
100
|
+
(input.tags ?? ["founder-slack", "inbound"]).join(","),
|
|
101
|
+
"--summary",
|
|
102
|
+
input.summary,
|
|
103
|
+
"--body",
|
|
104
|
+
input.body,
|
|
105
|
+
];
|
|
106
|
+
const r = await runner(args);
|
|
107
|
+
if (!r.ok)
|
|
108
|
+
throw new Error(`rig queue create failed (code ${r.code}): ${r.stderr.slice(0, 200) || r.stdout.slice(0, 200)}`);
|
|
109
|
+
const id = (r.stdout.match(/qitem-[a-z0-9-]+/) ?? [])[0];
|
|
110
|
+
if (!id)
|
|
111
|
+
throw new Error("rig queue create: no qitem id in output");
|
|
112
|
+
return id;
|
|
113
|
+
}
|
|
114
|
+
//# sourceMappingURL=queue-bridge.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"queue-bridge.js","sourceRoot":"","sources":["../../src/slack/queue-bridge.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export interface SecretFsOps {
|
|
2
|
+
readFileSync(p: string): string;
|
|
3
|
+
statMode(p: string): number | null;
|
|
4
|
+
}
|
|
5
|
+
export declare const nodeSecretFs: SecretFsOps;
|
|
6
|
+
/** Parse KEY=VALUE lines (quotes trimmed). Blank lines / #comments ignored. */
|
|
7
|
+
export declare function parseEnvFile(text: string): Record<string, string>;
|
|
8
|
+
export interface SecretLookupOpts {
|
|
9
|
+
envFile?: string;
|
|
10
|
+
env?: NodeJS.ProcessEnv;
|
|
11
|
+
fsops?: SecretFsOps;
|
|
12
|
+
}
|
|
13
|
+
/** Warn if the env file is group/world readable (item 10 hygiene). Returns a warning string or null. */
|
|
14
|
+
export declare function checkEnvFilePermissions(envFile: string, fsops?: SecretFsOps): string | null;
|
|
15
|
+
/**
|
|
16
|
+
* Resolve a secret by logical name. Precedence: explicit env var (OPENRIG_SLACK_<NAME>
|
|
17
|
+
* or the raw name) → env-file key. Returns null when unresolved (honest: callers
|
|
18
|
+
* report "unconfigured", they do NOT fabricate). Never logs the value.
|
|
19
|
+
*/
|
|
20
|
+
export declare function resolveSecret(name: string, opts?: SecretLookupOpts): string | null;
|
|
21
|
+
//# sourceMappingURL=secrets.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"secrets.d.ts","sourceRoot":"","sources":["../../src/slack/secrets.ts"],"names":[],"mappings":"AAUA,MAAM,WAAW,WAAW;IAC1B,YAAY,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAChC,QAAQ,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;CACpC;AAED,eAAO,MAAM,YAAY,EAAE,WAS1B,CAAC;AAEF,+EAA+E;AAC/E,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAYjE;AAED,MAAM,WAAW,gBAAgB;IAC/B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,KAAK,CAAC,EAAE,WAAW,CAAC;CACrB;AAED,wGAAwG;AACxG,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,GAAE,WAA0B,GAAG,MAAM,GAAG,IAAI,CAKzG;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,GAAE,gBAAqB,GAAG,MAAM,GAAG,IAAI,CAmBtF"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
// Slice-11 slack-connector — secret resolution (item 7 + 10).
|
|
2
|
+
//
|
|
3
|
+
// Secrets (Slack bot token / app-level token / incoming-webhook URL) resolve
|
|
4
|
+
// from EITHER an OPENRIG_SLACK_* environment variable OR a 0600 env file, at
|
|
5
|
+
// call time — NEVER stored in the connector config file, NEVER in the repo,
|
|
6
|
+
// NEVER logged. Mirrors the daemon's bearer_file/activity-hook-token posture.
|
|
7
|
+
// The env file lives on the TRUSTED host (item 10 secret-host axis); it may be
|
|
8
|
+
// a different host from the queue/alert host.
|
|
9
|
+
import fs from "node:fs";
|
|
10
|
+
export const nodeSecretFs = {
|
|
11
|
+
readFileSync: (p) => fs.readFileSync(p, "utf8"),
|
|
12
|
+
statMode: (p) => {
|
|
13
|
+
try {
|
|
14
|
+
return fs.statSync(p).mode & 0o777;
|
|
15
|
+
}
|
|
16
|
+
catch {
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
};
|
|
21
|
+
/** Parse KEY=VALUE lines (quotes trimmed). Blank lines / #comments ignored. */
|
|
22
|
+
export function parseEnvFile(text) {
|
|
23
|
+
const out = {};
|
|
24
|
+
for (const line of text.split("\n")) {
|
|
25
|
+
const t = line.trim();
|
|
26
|
+
if (!t || t.startsWith("#") || !t.includes("="))
|
|
27
|
+
continue;
|
|
28
|
+
const i = t.indexOf("=");
|
|
29
|
+
out[t.slice(0, i).trim()] = t
|
|
30
|
+
.slice(i + 1)
|
|
31
|
+
.trim()
|
|
32
|
+
.replace(/^"|"$/g, "");
|
|
33
|
+
}
|
|
34
|
+
return out;
|
|
35
|
+
}
|
|
36
|
+
/** Warn if the env file is group/world readable (item 10 hygiene). Returns a warning string or null. */
|
|
37
|
+
export function checkEnvFilePermissions(envFile, fsops = nodeSecretFs) {
|
|
38
|
+
const mode = fsops.statMode(envFile);
|
|
39
|
+
if (mode === null)
|
|
40
|
+
return null; // absent — a separate "unconfigured" concern
|
|
41
|
+
if (mode & 0o077)
|
|
42
|
+
return `secret env file ${envFile} is mode ${mode.toString(8)} — should be 0600 (group/other must not read secrets)`;
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Resolve a secret by logical name. Precedence: explicit env var (OPENRIG_SLACK_<NAME>
|
|
47
|
+
* or the raw name) → env-file key. Returns null when unresolved (honest: callers
|
|
48
|
+
* report "unconfigured", they do NOT fabricate). Never logs the value.
|
|
49
|
+
*/
|
|
50
|
+
export function resolveSecret(name, opts = {}) {
|
|
51
|
+
const env = opts.env ?? process.env;
|
|
52
|
+
const fsops = opts.fsops ?? nodeSecretFs;
|
|
53
|
+
// Aliases: the raw name (e.g. SLACK_WEBHOOK_URL) and the OPENRIG_-prefixed
|
|
54
|
+
// form (OPENRIG_SLACK_WEBHOOK_URL). NOT OPENRIG_SLACK_<name> — that would
|
|
55
|
+
// double the SLACK_ segment (the B4 defect).
|
|
56
|
+
const envKeys = [name, `OPENRIG_${name.replace(/[^A-Za-z0-9]/g, "_").toUpperCase()}`];
|
|
57
|
+
for (const k of envKeys) {
|
|
58
|
+
if (env[k])
|
|
59
|
+
return env[k];
|
|
60
|
+
}
|
|
61
|
+
if (opts.envFile) {
|
|
62
|
+
try {
|
|
63
|
+
const map = parseEnvFile(fsops.readFileSync(opts.envFile));
|
|
64
|
+
if (map[name])
|
|
65
|
+
return map[name];
|
|
66
|
+
}
|
|
67
|
+
catch {
|
|
68
|
+
/* absent/unreadable → null */
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
73
|
+
//# sourceMappingURL=secrets.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"secrets.js","sourceRoot":"","sources":["../../src/slack/secrets.ts"],"names":[],"mappings":"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"}
|