@openrig/cli 0.3.0 → 0.3.1
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/plugins/openrig-core/.claude-plugin/plugin.json +15 -0
- package/daemon/assets/plugins/openrig-core/.codex-plugin/plugin.json +24 -0
- package/daemon/assets/plugins/openrig-core/LICENSE +200 -0
- package/daemon/assets/plugins/openrig-core/README.md +42 -0
- package/daemon/assets/plugins/openrig-core/hooks/claude.json +78 -0
- package/daemon/assets/plugins/openrig-core/hooks/codex.json +37 -0
- package/daemon/assets/{openrig-activity-hook-relay.cjs → plugins/openrig-core/hooks/scripts/activity-relay.cjs} +12 -0
- package/daemon/assets/plugins/openrig-core/hooks/scripts/compaction-restore-bridge.cjs +172 -0
- package/daemon/assets/plugins/openrig-core/skills/agent-startup-and-context-ingestion/SKILL.md +104 -0
- package/daemon/assets/plugins/openrig-core/skills/claude-compaction-restore/SKILL.md +131 -0
- package/daemon/assets/plugins/openrig-core/skills/claude-compaction-restore/scripts/precompact-hook.mjs +174 -0
- package/daemon/assets/plugins/openrig-core/skills/claude-compaction-restore/scripts/restore-from-jsonl.mjs +433 -0
- package/daemon/assets/plugins/openrig-core/skills/claude-compaction-restore/templates/compact-instruction.md +1 -0
- package/daemon/assets/plugins/openrig-core/skills/claude-compaction-restore/templates/post-compact-restore-instruction.md +1 -0
- package/daemon/assets/plugins/openrig-core/skills/forming-an-openrig-mental-model/SKILL.md +305 -0
- package/daemon/{specs/agents/shared/skills/rig-architect → assets/plugins/openrig-core/skills/openrig-architect}/SKILL.md +38 -19
- package/daemon/assets/plugins/openrig-core/skills/openrig-operator/SKILL.md +222 -0
- package/daemon/assets/plugins/openrig-core/skills/openrig-user/SKILL.md +597 -0
- package/daemon/assets/plugins/openrig-core/skills/queue-handoff/SKILL.md +122 -0
- package/daemon/assets/plugins/openrig-core/skills/seat-continuity-and-handover/SKILL.md +137 -0
- package/daemon/assets/vm-preview-fixtures/README.md +48 -0
- package/daemon/assets/vm-preview-fixtures/workflows/sample-basic-loop.yaml +79 -0
- package/daemon/dist/adapters/claude-code-adapter.d.ts +1 -3
- package/daemon/dist/adapters/claude-code-adapter.d.ts.map +1 -1
- package/daemon/dist/adapters/claude-code-adapter.js +17 -57
- package/daemon/dist/adapters/claude-code-adapter.js.map +1 -1
- package/daemon/dist/adapters/cmux-transport.d.ts.map +1 -1
- package/daemon/dist/adapters/cmux-transport.js +81 -2
- package/daemon/dist/adapters/cmux-transport.js.map +1 -1
- package/daemon/dist/adapters/cmux.d.ts +4 -0
- package/daemon/dist/adapters/cmux.d.ts.map +1 -1
- package/daemon/dist/adapters/cmux.js +87 -0
- package/daemon/dist/adapters/cmux.js.map +1 -1
- package/daemon/dist/adapters/codex-runtime-adapter.d.ts +14 -3
- package/daemon/dist/adapters/codex-runtime-adapter.d.ts.map +1 -1
- package/daemon/dist/adapters/codex-runtime-adapter.js +43 -57
- package/daemon/dist/adapters/codex-runtime-adapter.js.map +1 -1
- package/daemon/dist/db/migrations/040_workflow_specs_diagnostic.d.ts +32 -0
- package/daemon/dist/db/migrations/040_workflow_specs_diagnostic.d.ts.map +1 -0
- package/daemon/dist/db/migrations/040_workflow_specs_diagnostic.js +37 -0
- package/daemon/dist/db/migrations/040_workflow_specs_diagnostic.js.map +1 -0
- package/daemon/dist/domain/agent-manifest.d.ts.map +1 -1
- package/daemon/dist/domain/agent-manifest.js +116 -37
- package/daemon/dist/domain/agent-manifest.js.map +1 -1
- package/daemon/dist/domain/agent-resolver.js +1 -1
- package/daemon/dist/domain/agent-resolver.js.map +1 -1
- package/daemon/dist/domain/claude-compaction-enforcer.d.ts +81 -0
- package/daemon/dist/domain/claude-compaction-enforcer.d.ts.map +1 -0
- package/daemon/dist/domain/claude-compaction-enforcer.js +242 -0
- package/daemon/dist/domain/claude-compaction-enforcer.js.map +1 -0
- package/daemon/dist/domain/cmux-layout-service.d.ts +41 -0
- package/daemon/dist/domain/cmux-layout-service.d.ts.map +1 -0
- package/daemon/dist/domain/cmux-layout-service.js +184 -0
- package/daemon/dist/domain/cmux-layout-service.js.map +1 -0
- package/daemon/dist/domain/context-monitor.d.ts +15 -1
- package/daemon/dist/domain/context-monitor.d.ts.map +1 -1
- package/daemon/dist/domain/context-monitor.js +38 -3
- package/daemon/dist/domain/context-monitor.js.map +1 -1
- package/daemon/dist/domain/kernel-boot-tracker.d.ts +74 -0
- package/daemon/dist/domain/kernel-boot-tracker.d.ts.map +1 -0
- package/daemon/dist/domain/kernel-boot-tracker.js +213 -0
- package/daemon/dist/domain/kernel-boot-tracker.js.map +1 -0
- package/daemon/dist/domain/kernel-boot.d.ts +50 -0
- package/daemon/dist/domain/kernel-boot.d.ts.map +1 -0
- package/daemon/dist/domain/kernel-boot.js +147 -0
- package/daemon/dist/domain/kernel-boot.js.map +1 -0
- package/daemon/dist/domain/mission-control/mission-control-read-layer.d.ts +5 -0
- package/daemon/dist/domain/mission-control/mission-control-read-layer.d.ts.map +1 -1
- package/daemon/dist/domain/mission-control/mission-control-read-layer.js +16 -2
- package/daemon/dist/domain/mission-control/mission-control-read-layer.js.map +1 -1
- package/daemon/dist/domain/mission-control/mission-control-write-contract.d.ts.map +1 -1
- package/daemon/dist/domain/mission-control/mission-control-write-contract.js +3 -1
- package/daemon/dist/domain/mission-control/mission-control-write-contract.js.map +1 -1
- package/daemon/dist/domain/plugin-discovery-service.d.ts +150 -0
- package/daemon/dist/domain/plugin-discovery-service.d.ts.map +1 -0
- package/daemon/dist/domain/plugin-discovery-service.js +468 -0
- package/daemon/dist/domain/plugin-discovery-service.js.map +1 -0
- package/daemon/dist/domain/plugin-vendor-service.d.ts +54 -0
- package/daemon/dist/domain/plugin-vendor-service.d.ts.map +1 -0
- package/daemon/dist/domain/plugin-vendor-service.js +111 -0
- package/daemon/dist/domain/plugin-vendor-service.js.map +1 -0
- package/daemon/dist/domain/profile-resolver.d.ts +3 -3
- package/daemon/dist/domain/profile-resolver.d.ts.map +1 -1
- package/daemon/dist/domain/profile-resolver.js +7 -7
- package/daemon/dist/domain/profile-resolver.js.map +1 -1
- package/daemon/dist/domain/projection-planner.d.ts +7 -1
- package/daemon/dist/domain/projection-planner.d.ts.map +1 -1
- package/daemon/dist/domain/projection-planner.js +44 -4
- package/daemon/dist/domain/projection-planner.js.map +1 -1
- package/daemon/dist/domain/queue-repository.d.ts +8 -1
- package/daemon/dist/domain/queue-repository.d.ts.map +1 -1
- package/daemon/dist/domain/queue-repository.js +14 -5
- package/daemon/dist/domain/queue-repository.js.map +1 -1
- package/daemon/dist/domain/session-transport.d.ts.map +1 -1
- package/daemon/dist/domain/session-transport.js +33 -0
- package/daemon/dist/domain/session-transport.js.map +1 -1
- package/daemon/dist/domain/skill-library-discovery.d.ts +68 -0
- package/daemon/dist/domain/skill-library-discovery.d.ts.map +1 -0
- package/daemon/dist/domain/skill-library-discovery.js +144 -0
- package/daemon/dist/domain/skill-library-discovery.js.map +1 -0
- package/daemon/dist/domain/slices/slice-indexer.d.ts +19 -0
- package/daemon/dist/domain/slices/slice-indexer.d.ts.map +1 -1
- package/daemon/dist/domain/slices/slice-indexer.js +88 -6
- package/daemon/dist/domain/slices/slice-indexer.js.map +1 -1
- package/daemon/dist/domain/spec-library-service.d.ts +6 -0
- package/daemon/dist/domain/spec-library-service.d.ts.map +1 -1
- package/daemon/dist/domain/spec-library-service.js.map +1 -1
- package/daemon/dist/domain/spec-library-workflow-scanner.d.ts +43 -0
- package/daemon/dist/domain/spec-library-workflow-scanner.d.ts.map +1 -1
- package/daemon/dist/domain/spec-library-workflow-scanner.js +157 -3
- package/daemon/dist/domain/spec-library-workflow-scanner.js.map +1 -1
- package/daemon/dist/domain/spec-review-service.d.ts +1 -1
- package/daemon/dist/domain/spec-review-service.d.ts.map +1 -1
- package/daemon/dist/domain/spec-review-service.js +14 -1
- package/daemon/dist/domain/spec-review-service.js.map +1 -1
- package/daemon/dist/domain/types.d.ts +27 -7
- package/daemon/dist/domain/types.d.ts.map +1 -1
- package/daemon/dist/domain/types.js.map +1 -1
- package/daemon/dist/domain/user-settings/settings-store.d.ts +25 -1
- package/daemon/dist/domain/user-settings/settings-store.d.ts.map +1 -1
- package/daemon/dist/domain/user-settings/settings-store.js +186 -4
- package/daemon/dist/domain/user-settings/settings-store.js.map +1 -1
- package/daemon/dist/domain/workflow-spec-cache.d.ts +27 -0
- package/daemon/dist/domain/workflow-spec-cache.d.ts.map +1 -1
- package/daemon/dist/domain/workflow-spec-cache.js +59 -0
- package/daemon/dist/domain/workflow-spec-cache.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 +45 -0
- package/daemon/dist/domain/workspace/default-workspace-scaffold.js.map +1 -1
- package/daemon/dist/domain/workspace/getting-started-narrative.d.ts +15 -0
- package/daemon/dist/domain/workspace/getting-started-narrative.d.ts.map +1 -0
- package/daemon/dist/domain/workspace/getting-started-narrative.js +237 -0
- package/daemon/dist/domain/workspace/getting-started-narrative.js.map +1 -0
- package/daemon/dist/index.d.ts +2 -1
- package/daemon/dist/index.d.ts.map +1 -1
- package/daemon/dist/index.js +52 -17
- package/daemon/dist/index.js.map +1 -1
- package/daemon/dist/lib/pane-envelope.d.ts +7 -0
- package/daemon/dist/lib/pane-envelope.d.ts.map +1 -0
- package/daemon/dist/lib/pane-envelope.js +38 -0
- package/daemon/dist/lib/pane-envelope.js.map +1 -0
- package/daemon/dist/middleware/auth-bearer-token.d.ts +47 -5
- package/daemon/dist/middleware/auth-bearer-token.d.ts.map +1 -1
- package/daemon/dist/middleware/auth-bearer-token.js +109 -8
- package/daemon/dist/middleware/auth-bearer-token.js.map +1 -1
- package/daemon/dist/routes/kernel-status.d.ts +3 -0
- package/daemon/dist/routes/kernel-status.d.ts.map +1 -0
- package/daemon/dist/routes/kernel-status.js +40 -0
- package/daemon/dist/routes/kernel-status.js.map +1 -0
- package/daemon/dist/routes/mission-control.d.ts.map +1 -1
- package/daemon/dist/routes/mission-control.js +25 -2
- package/daemon/dist/routes/mission-control.js.map +1 -1
- package/daemon/dist/routes/missions.d.ts +3 -0
- package/daemon/dist/routes/missions.d.ts.map +1 -0
- package/daemon/dist/routes/missions.js +195 -0
- package/daemon/dist/routes/missions.js.map +1 -0
- package/daemon/dist/routes/plugins.d.ts +3 -0
- package/daemon/dist/routes/plugins.d.ts.map +1 -0
- package/daemon/dist/routes/plugins.js +223 -0
- package/daemon/dist/routes/plugins.js.map +1 -0
- package/daemon/dist/routes/rig-cmux.d.ts +3 -0
- package/daemon/dist/routes/rig-cmux.d.ts.map +1 -0
- package/daemon/dist/routes/rig-cmux.js +121 -0
- package/daemon/dist/routes/rig-cmux.js.map +1 -0
- package/daemon/dist/routes/skills.d.ts +3 -0
- package/daemon/dist/routes/skills.d.ts.map +1 -0
- package/daemon/dist/routes/skills.js +147 -0
- package/daemon/dist/routes/skills.js.map +1 -0
- package/daemon/dist/routes/slices.d.ts.map +1 -1
- package/daemon/dist/routes/slices.js +15 -0
- package/daemon/dist/routes/slices.js.map +1 -1
- package/daemon/dist/routes/spec-library.d.ts.map +1 -1
- package/daemon/dist/routes/spec-library.js +16 -1
- package/daemon/dist/routes/spec-library.js.map +1 -1
- package/daemon/dist/server.d.ts +31 -0
- package/daemon/dist/server.d.ts.map +1 -1
- package/daemon/dist/server.js +30 -0
- package/daemon/dist/server.js.map +1 -1
- package/daemon/dist/startup.d.ts.map +1 -1
- package/daemon/dist/startup.js +194 -5
- package/daemon/dist/startup.js.map +1 -1
- package/daemon/specs/agents/apps/vault-specialist/agent.yaml +0 -1
- package/daemon/specs/agents/conveyor/builder/agent.yaml +0 -1
- package/daemon/specs/agents/conveyor/lead/agent.yaml +0 -1
- package/daemon/specs/agents/conveyor/planner/agent.yaml +0 -1
- package/daemon/specs/agents/conveyor/reviewer/agent.yaml +0 -1
- package/daemon/specs/agents/design/product-designer/agent.yaml +0 -1
- package/daemon/specs/agents/development/implementer/agent.yaml +0 -1
- package/daemon/specs/agents/development/qa/agent.yaml +0 -1
- package/daemon/specs/agents/development/qa/guidance/role.md +0 -2
- package/daemon/specs/agents/orchestration/orchestrator/agent.yaml +0 -1
- package/daemon/specs/agents/research/analyst/agent.yaml +0 -1
- package/daemon/specs/agents/research/synthesizer/agent.yaml +0 -1
- package/daemon/specs/agents/review/independent-reviewer/agent.yaml +0 -1
- package/daemon/specs/agents/shared/agent.yaml +6 -6
- package/daemon/specs/agents/shared/skills/core/openrig-architect/SKILL.md +361 -0
- package/daemon/specs/agents/shared/skills/core/openrig-installer/SKILL.md +142 -0
- package/daemon/specs/agents/shared/skills/core/openrig-user/SKILL.md +6 -1
- package/daemon/specs/agents/shared/skills/core/openrig-user-settings/SKILL.md +4 -4
- package/daemon/specs/agents/shared/skills/core/rig-lifecycle/SKILL.md +116 -0
- package/daemon/specs/agents/shared/skills/pods/development-team/SKILL.md +0 -1
- package/daemon/specs/agents/shared/skills/pods/orchestration-team/SKILL.md +2 -2
- package/daemon/specs/agents/shared/skills/process/agent-browser/LOCAL-INSIGHTS.md +6 -6
- package/daemon/specs/agents/shared/skills/process/agent-browser/OPENRIG.md +40 -0
- package/daemon/specs/agents/shared/skills/process/agent-browser/SKILL.md +10 -0
- package/daemon/specs/agents/shared/skills/process/brainstorming/OPENRIG.md +48 -0
- package/daemon/specs/agents/shared/skills/process/brainstorming/SKILL.md +11 -0
- package/daemon/specs/agents/shared/skills/process/dogfood/SKILL.md +5 -0
- package/daemon/specs/agents/shared/skills/process/executing-plans/OPENRIG.md +56 -0
- package/daemon/specs/agents/shared/skills/process/executing-plans/SKILL.md +10 -0
- package/daemon/specs/agents/shared/skills/process/frontend-design/SKILL.md +5 -0
- package/daemon/specs/agents/shared/skills/process/systematic-debugging/SKILL.md +5 -0
- package/daemon/specs/agents/shared/skills/process/test-driven-development/SKILL.md +5 -0
- package/daemon/specs/agents/shared/skills/process/using-superpowers/OPENRIG.md +48 -0
- package/daemon/specs/agents/shared/skills/process/using-superpowers/SKILL.md +11 -0
- package/daemon/specs/agents/shared/skills/process/verification-before-completion/SKILL.md +5 -0
- package/daemon/specs/agents/shared/skills/process/writing-plans/OPENRIG.md +52 -0
- package/daemon/specs/agents/shared/skills/process/writing-plans/SKILL.md +12 -2
- package/daemon/specs/rigs/launch/kernel/agents/advisor/lead/agent.yaml +35 -0
- package/daemon/specs/rigs/launch/kernel/agents/advisor/lead/guidance/role.md +50 -0
- package/daemon/specs/rigs/launch/kernel/agents/advisor/lead/startup/context.md +37 -0
- package/daemon/specs/rigs/launch/kernel/agents/operator/agent/agent.yaml +35 -0
- package/daemon/specs/rigs/launch/kernel/agents/operator/agent/guidance/role.md +49 -0
- package/daemon/specs/rigs/launch/kernel/agents/operator/agent/startup/context.md +63 -0
- package/daemon/specs/rigs/launch/kernel/agents/queue/worker/agent.yaml +35 -0
- package/daemon/specs/rigs/launch/kernel/agents/queue/worker/guidance/role.md +33 -0
- package/daemon/specs/rigs/launch/kernel/agents/queue/worker/startup/context.md +30 -0
- package/daemon/specs/rigs/launch/kernel/culture/CULTURE.md +69 -0
- package/daemon/specs/rigs/launch/kernel/rig-claude-only.yaml +59 -0
- package/daemon/specs/rigs/launch/kernel/rig-codex-only.yaml +59 -0
- package/daemon/specs/rigs/launch/kernel/rig.yaml +69 -0
- package/dist/commands/config-init-workspace.d.ts.map +1 -1
- package/dist/commands/config-init-workspace.js +253 -0
- package/dist/commands/config-init-workspace.js.map +1 -1
- package/dist/commands/config.d.ts.map +1 -1
- package/dist/commands/config.js +11 -3
- package/dist/commands/config.js.map +1 -1
- package/dist/commands/daemon.d.ts.map +1 -1
- package/dist/commands/daemon.js +53 -1
- package/dist/commands/daemon.js.map +1 -1
- package/dist/commands/heartbeat.d.ts.map +1 -1
- package/dist/commands/heartbeat.js +0 -5
- package/dist/commands/heartbeat.js.map +1 -1
- package/dist/commands/plugin.d.ts +4 -0
- package/dist/commands/plugin.d.ts.map +1 -0
- package/dist/commands/plugin.js +395 -0
- package/dist/commands/plugin.js.map +1 -0
- package/dist/commands/send.d.ts +8 -0
- package/dist/commands/send.d.ts.map +1 -1
- package/dist/commands/send.js +8 -0
- package/dist/commands/send.js.map +1 -1
- package/dist/commands/up.d.ts.map +1 -1
- package/dist/commands/up.js +13 -1
- package/dist/commands/up.js.map +1 -1
- package/dist/config-store.d.ts +18 -1
- package/dist/config-store.d.ts.map +1 -1
- package/dist/config-store.js +167 -4
- package/dist/config-store.js.map +1 -1
- package/dist/daemon-lifecycle.d.ts +20 -1
- package/dist/daemon-lifecycle.d.ts.map +1 -1
- package/dist/daemon-lifecycle.js +57 -7
- package/dist/daemon-lifecycle.js.map +1 -1
- package/dist/host-registry.d.ts +1 -1
- package/dist/host-registry.js +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/ui/dist/assets/index-C_Q5FczU.css +1 -0
- package/ui/dist/assets/index-Rl3ZBrUg.js +547 -0
- package/ui/dist/index.html +2 -2
- package/daemon/specs/agents/shared/skills/claude-compact-in-place/SKILL.md +0 -100
- package/daemon/specs/agents/shared/skills/process/containerized-e2e/SKILL.md +0 -256
- package/daemon/specs/agents/shared/skills/process/containerized-e2e/scripts/Dockerfile +0 -39
- package/daemon/specs/agents/shared/skills/process/containerized-e2e/scripts/build-e2e-image.sh +0 -37
- package/daemon/specs/agents/shared/skills/process/containerized-e2e/templates/control-plane-test.yaml +0 -40
- package/daemon/specs/agents/shared/skills/process/containerized-e2e/templates/e2e-report-template.md +0 -94
- package/daemon/specs/agents/shared/skills/process/containerized-e2e/templates/expansion-collision-fragment.yaml +0 -13
- package/daemon/specs/agents/shared/skills/process/containerized-e2e/templates/expansion-pod-fragment.yaml +0 -14
- package/ui/dist/assets/index-BDHU1JUK.js +0 -412
- package/ui/dist/assets/index-DXTyJSqu.css +0 -1
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
// Slice 24 — CmuxLayoutService.
|
|
2
|
+
//
|
|
3
|
+
// Algorithmic core of the "Launch in CMUX" feature. Three pure helpers
|
|
4
|
+
// (computeLayout / chunkAgents / orderAgentsFromRigSpec) + one
|
|
5
|
+
// coordinated method (buildWorkspace) that drives the CmuxAdapter
|
|
6
|
+
// through workspace.create + N-1 surface.split + N surface.sendText
|
|
7
|
+
// calls to populate a freshly-created cmux workspace with one tmux-
|
|
8
|
+
// attach panel per agent.
|
|
9
|
+
//
|
|
10
|
+
// Timing strategy (per slice 24 README §Daemon-side + cmux-rig-layout
|
|
11
|
+
// skill §5 gotchas):
|
|
12
|
+
// - After every splitSurface, wait OP_DELAY_MS so the freshly-created
|
|
13
|
+
// surface's shell reaches its prompt before the next operation
|
|
14
|
+
// (skill §5 gotcha 3 — surface-not-ready-for-input window).
|
|
15
|
+
// - After the LAST sendText, wait FINAL_SETTLE_MS to defeat the
|
|
16
|
+
// last-send-key race (skill §5 gotcha 2).
|
|
17
|
+
// - listSurfaces immediately after createWorkspace retries with
|
|
18
|
+
// small backoff to absorb the workspace-default-surface attach
|
|
19
|
+
// latency. The default surface is created by cmux daemon at
|
|
20
|
+
// workspace.create time but the listing may not reflect it for
|
|
21
|
+
// a beat.
|
|
22
|
+
// Sleep is injected via constructor so tests stub it to no-op.
|
|
23
|
+
//
|
|
24
|
+
// Constants live at the top of the file per slice 24 README §Layout
|
|
25
|
+
// algorithm §"Configurability posture". v0 ships them as hardcoded
|
|
26
|
+
// constants; v0.3.2 follow-on graduates to settings keys.
|
|
27
|
+
//
|
|
28
|
+
// TODO(0.3.2): graduate MAX_COLS + MAX_PER_WORKSPACE to settings keys
|
|
29
|
+
// cmux.workspace_columns + cmux.workspace_max_panels (slice 08 settings
|
|
30
|
+
// infra is ready; this is a 2-keys-plus-optional-UI-surface follow-on).
|
|
31
|
+
export const MAX_COLS = 2;
|
|
32
|
+
export const MAX_PER_WORKSPACE = 12;
|
|
33
|
+
export const OP_DELAY_MS = 500;
|
|
34
|
+
export const FINAL_SETTLE_MS = 1000;
|
|
35
|
+
export const LIST_SURFACES_RETRY_DELAY_MS = 100;
|
|
36
|
+
export const LIST_SURFACES_MAX_ATTEMPTS = 5;
|
|
37
|
+
const defaultSleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
38
|
+
export class CmuxLayoutService {
|
|
39
|
+
cmuxAdapter;
|
|
40
|
+
sleep;
|
|
41
|
+
constructor(cmuxAdapter, opts = {}) {
|
|
42
|
+
this.cmuxAdapter = cmuxAdapter;
|
|
43
|
+
this.sleep = opts.sleep ?? defaultSleep;
|
|
44
|
+
}
|
|
45
|
+
static computeLayout(n) {
|
|
46
|
+
if (!Number.isInteger(n) || n <= 0) {
|
|
47
|
+
throw new Error(`CmuxLayoutService.computeLayout: N must be a positive integer (got ${n})`);
|
|
48
|
+
}
|
|
49
|
+
if (n > MAX_PER_WORKSPACE) {
|
|
50
|
+
throw new Error(`CmuxLayoutService.computeLayout: N=${n} exceeds MAX_PER_WORKSPACE=${MAX_PER_WORKSPACE}; caller should chunk first`);
|
|
51
|
+
}
|
|
52
|
+
if (n === 1) {
|
|
53
|
+
return { rows: 1, cols: 1, blanks: 0 };
|
|
54
|
+
}
|
|
55
|
+
const cols = MAX_COLS;
|
|
56
|
+
const rows = Math.ceil(n / cols);
|
|
57
|
+
const blanks = rows * cols - n;
|
|
58
|
+
return { rows, cols, blanks };
|
|
59
|
+
}
|
|
60
|
+
static chunkAgents(agents) {
|
|
61
|
+
if (agents.length === 0)
|
|
62
|
+
return [];
|
|
63
|
+
const chunks = [];
|
|
64
|
+
for (let i = 0; i < agents.length; i += MAX_PER_WORKSPACE) {
|
|
65
|
+
chunks.push(agents.slice(i, i + MAX_PER_WORKSPACE));
|
|
66
|
+
}
|
|
67
|
+
return chunks;
|
|
68
|
+
}
|
|
69
|
+
static orderAgentsFromRigSpec(rigSpec) {
|
|
70
|
+
const out = [];
|
|
71
|
+
for (const pod of rigSpec.pods ?? []) {
|
|
72
|
+
for (const member of pod.members ?? []) {
|
|
73
|
+
out.push(`${pod.id}.${member.id}`);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return out;
|
|
77
|
+
}
|
|
78
|
+
async buildWorkspace(workspaceName, cwd, agentSessions) {
|
|
79
|
+
if (agentSessions.length === 0) {
|
|
80
|
+
const ws = await this.cmuxAdapter.createWorkspace(workspaceName, cwd);
|
|
81
|
+
if (!ws.ok)
|
|
82
|
+
return ws;
|
|
83
|
+
return {
|
|
84
|
+
ok: true,
|
|
85
|
+
data: { workspaceId: ws.data, workspaceName, agents: [], blanks: 0 },
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
if (agentSessions.length > MAX_PER_WORKSPACE) {
|
|
89
|
+
return {
|
|
90
|
+
ok: false,
|
|
91
|
+
code: "invalid_input",
|
|
92
|
+
message: `buildWorkspace: ${agentSessions.length} agents exceeds MAX_PER_WORKSPACE=${MAX_PER_WORKSPACE}; caller should chunk first`,
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
const layout = CmuxLayoutService.computeLayout(agentSessions.length);
|
|
96
|
+
// 1. Create the workspace.
|
|
97
|
+
const wsResult = await this.cmuxAdapter.createWorkspace(workspaceName, cwd);
|
|
98
|
+
if (!wsResult.ok)
|
|
99
|
+
return wsResult;
|
|
100
|
+
const workspaceId = wsResult.data;
|
|
101
|
+
// 2. Discover the workspace's default surface. workspace.create
|
|
102
|
+
// auto-creates one terminal surface but the listing may not
|
|
103
|
+
// reflect it immediately. Retry with small backoff (skill §5
|
|
104
|
+
// gotcha 3 — surface-not-ready-for-input window also applies
|
|
105
|
+
// to surface enumeration).
|
|
106
|
+
const initialSurface = await this.discoverInitialSurface(workspaceId);
|
|
107
|
+
if (!initialSurface.ok)
|
|
108
|
+
return initialSurface;
|
|
109
|
+
// 3. Build the grid. grid[col][row] holds the surface id. Layout
|
|
110
|
+
// shape determines the split sequence:
|
|
111
|
+
// - col 1: 1 initial surface + (rows-1) down splits below it
|
|
112
|
+
// - col 2: 1 right split off initial + (rows-1) down splits
|
|
113
|
+
// Sleep OP_DELAY_MS after every split so the freshly created
|
|
114
|
+
// surface's shell reaches its prompt before the next op.
|
|
115
|
+
const grid = [[initialSurface.data]];
|
|
116
|
+
if (layout.cols === 2) {
|
|
117
|
+
const rightSplit = await this.cmuxAdapter.splitSurface(initialSurface.data, "right", workspaceId);
|
|
118
|
+
if (!rightSplit.ok)
|
|
119
|
+
return rightSplit;
|
|
120
|
+
grid.push([rightSplit.data]);
|
|
121
|
+
await this.sleep(OP_DELAY_MS);
|
|
122
|
+
}
|
|
123
|
+
for (let r = 1; r < layout.rows; r++) {
|
|
124
|
+
for (let c = 0; c < layout.cols; c++) {
|
|
125
|
+
const prevSurfaceInCol = grid[c][r - 1];
|
|
126
|
+
const downSplit = await this.cmuxAdapter.splitSurface(prevSurfaceInCol, "down", workspaceId);
|
|
127
|
+
if (!downSplit.ok)
|
|
128
|
+
return downSplit;
|
|
129
|
+
grid[c].push(downSplit.data);
|
|
130
|
+
await this.sleep(OP_DELAY_MS);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
// 4. Send tmux-attach to each agent's surface in COLUMN-MAJOR
|
|
134
|
+
// order: fill column 0 top-to-bottom first, then column 1
|
|
135
|
+
// top-to-bottom. Matches README §52 "Fill ... (top-to-bottom,
|
|
136
|
+
// left-to-right)" — each column's contents in reading order,
|
|
137
|
+
// moving left-to-right across columns.
|
|
138
|
+
// Any unpopulated surfaces in column 1's last row(s) remain
|
|
139
|
+
// as "blanks" (cmux still shows them as empty terminals).
|
|
140
|
+
let agentIndex = 0;
|
|
141
|
+
for (let c = 0; c < layout.cols && agentIndex < agentSessions.length; c++) {
|
|
142
|
+
for (let r = 0; r < layout.rows && agentIndex < agentSessions.length; r++) {
|
|
143
|
+
const surface = grid[c][r];
|
|
144
|
+
const session = agentSessions[agentIndex];
|
|
145
|
+
const sendResult = await this.cmuxAdapter.sendText(surface, `tmux attach -t ${session}\n`, workspaceId);
|
|
146
|
+
if (!sendResult.ok)
|
|
147
|
+
return sendResult;
|
|
148
|
+
agentIndex += 1;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
// 5. Final settle. Per skill §5 gotcha 2 the very last send-key
|
|
152
|
+
// can drop if the script exits immediately; the sleep
|
|
153
|
+
// guarantees the terminal flushes the Enter character.
|
|
154
|
+
await this.sleep(FINAL_SETTLE_MS);
|
|
155
|
+
return {
|
|
156
|
+
ok: true,
|
|
157
|
+
data: {
|
|
158
|
+
workspaceId,
|
|
159
|
+
workspaceName,
|
|
160
|
+
agents: agentSessions.slice(),
|
|
161
|
+
blanks: layout.blanks,
|
|
162
|
+
},
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
async discoverInitialSurface(workspaceId) {
|
|
166
|
+
for (let attempt = 0; attempt < LIST_SURFACES_MAX_ATTEMPTS; attempt++) {
|
|
167
|
+
const result = await this.cmuxAdapter.listSurfaces(workspaceId);
|
|
168
|
+
if (!result.ok)
|
|
169
|
+
return result;
|
|
170
|
+
if (result.data.length > 0) {
|
|
171
|
+
return { ok: true, data: result.data[0].id };
|
|
172
|
+
}
|
|
173
|
+
if (attempt < LIST_SURFACES_MAX_ATTEMPTS - 1) {
|
|
174
|
+
await this.sleep(LIST_SURFACES_RETRY_DELAY_MS);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
return {
|
|
178
|
+
ok: false,
|
|
179
|
+
code: "request_failed",
|
|
180
|
+
message: `buildWorkspace: workspace ${workspaceId} had no default surface after ${LIST_SURFACES_MAX_ATTEMPTS} attempts; cmux daemon may not be ready`,
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
//# sourceMappingURL=cmux-layout-service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cmux-layout-service.js","sourceRoot":"","sources":["../../src/domain/cmux-layout-service.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type Database from "better-sqlite3";
|
|
2
|
+
import type { ClaudeCompactionEnforcer } from "./claude-compaction-enforcer.js";
|
|
2
3
|
import type { ContextUsageStore } from "./context-usage-store.js";
|
|
3
4
|
import { type NodeBinding, type ReadinessResult } from "./runtime-adapter.js";
|
|
4
5
|
/** Default polling interval: 30 seconds. */
|
|
@@ -14,15 +15,28 @@ interface ClaudeContextProvisioner {
|
|
|
14
15
|
* Polls known managed runtime context sources and persists the latest
|
|
15
16
|
* normalized telemetry. Scheduler-only: no queries, no response shaping,
|
|
16
17
|
* no in-memory truth.
|
|
18
|
+
*
|
|
19
|
+
* Slice 27: optional `compactionEnforcer` participates in each polling
|
|
20
|
+
* tick after persistence so policy-driven /compact triggers fire on the
|
|
21
|
+
* same observation the operator sees in the UI. Without an enforcer
|
|
22
|
+
* provided, polling behavior is unchanged.
|
|
17
23
|
*/
|
|
18
24
|
export declare class ContextMonitor {
|
|
19
25
|
private db;
|
|
20
26
|
private store;
|
|
21
27
|
private claudeContextProvisioner;
|
|
28
|
+
private compactionEnforcer;
|
|
22
29
|
private timer;
|
|
23
|
-
constructor(db: Database.Database, store: ContextUsageStore, claudeContextProvisioner?: ClaudeContextProvisioner);
|
|
30
|
+
constructor(db: Database.Database, store: ContextUsageStore, claudeContextProvisioner?: ClaudeContextProvisioner, compactionEnforcer?: ClaudeCompactionEnforcer);
|
|
24
31
|
/** Discover active managed Claude sessions and poll their sidecar files. */
|
|
25
32
|
pollOnce(): Promise<void>;
|
|
33
|
+
/**
|
|
34
|
+
* Slice 27 — invoke the enforcer with the latest observation. The
|
|
35
|
+
* enforcer owns policy + dedup + send; ContextMonitor only relays
|
|
36
|
+
* data and absorbs enforcer errors so a trigger-path fault never
|
|
37
|
+
* crashes telemetry polling.
|
|
38
|
+
*/
|
|
39
|
+
private maybeAutoCompact;
|
|
26
40
|
/** Start polling at the given interval. Idempotent. */
|
|
27
41
|
start(intervalMs?: number): void;
|
|
28
42
|
/** Stop polling. Safe to call before start or multiple times. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"context-monitor.d.ts","sourceRoot":"","sources":["../../src/domain/context-monitor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,QAAQ,MAAM,gBAAgB,CAAC;AAC3C,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAClE,OAAO,EAEL,KAAK,WAAW,EAChB,KAAK,eAAe,EACrB,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"context-monitor.d.ts","sourceRoot":"","sources":["../../src/domain/context-monitor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,QAAQ,MAAM,gBAAgB,CAAC;AAC3C,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,iCAAiC,CAAC;AAChF,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAClE,OAAO,EAEL,KAAK,WAAW,EAChB,KAAK,eAAe,EACrB,MAAM,sBAAsB,CAAC;AAG9B,4CAA4C;AAC5C,eAAO,MAAM,wBAAwB,QAAS,CAAC;AAY/C,UAAU,wBAAwB;IAChC,sBAAsB,CAAC,OAAO,EAAE;QAAE,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,GAAG,IAAI,CAAC;IAC5F,UAAU,CAAC,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,eAAe,CAAC,CAAC;CAC7D;AAED;;;;;;;;;GASG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,EAAE,CAAoB;IAC9B,OAAO,CAAC,KAAK,CAAoB;IACjC,OAAO,CAAC,wBAAwB,CAAkC;IAClE,OAAO,CAAC,kBAAkB,CAAkC;IAC5D,OAAO,CAAC,KAAK,CAA+C;gBAG1D,EAAE,EAAE,QAAQ,CAAC,QAAQ,EACrB,KAAK,EAAE,iBAAiB,EACxB,wBAAwB,CAAC,EAAE,wBAAwB,EACnD,kBAAkB,CAAC,EAAE,wBAAwB;IAQ/C,4EAA4E;IACtE,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAoB/B;;;;;OAKG;YACW,gBAAgB;IAoB9B,uDAAuD;IACvD,KAAK,CAAC,UAAU,GAAE,MAAiC,GAAG,IAAI;IAW1D,iEAAiE;IACjE,IAAI,IAAI,IAAI;IAOZ,wEAAwE;IACxE,OAAO,CAAC,mBAAmB;IAuB3B,OAAO,CAAC,gBAAgB;YAeV,sBAAsB;CAuCrC"}
|
|
@@ -5,26 +5,35 @@ export const DEFAULT_POLL_INTERVAL_MS = 30_000;
|
|
|
5
5
|
* Polls known managed runtime context sources and persists the latest
|
|
6
6
|
* normalized telemetry. Scheduler-only: no queries, no response shaping,
|
|
7
7
|
* no in-memory truth.
|
|
8
|
+
*
|
|
9
|
+
* Slice 27: optional `compactionEnforcer` participates in each polling
|
|
10
|
+
* tick after persistence so policy-driven /compact triggers fire on the
|
|
11
|
+
* same observation the operator sees in the UI. Without an enforcer
|
|
12
|
+
* provided, polling behavior is unchanged.
|
|
8
13
|
*/
|
|
9
14
|
export class ContextMonitor {
|
|
10
15
|
db;
|
|
11
16
|
store;
|
|
12
17
|
claudeContextProvisioner;
|
|
18
|
+
compactionEnforcer;
|
|
13
19
|
timer = null;
|
|
14
|
-
constructor(db, store, claudeContextProvisioner) {
|
|
20
|
+
constructor(db, store, claudeContextProvisioner, compactionEnforcer) {
|
|
15
21
|
this.db = db;
|
|
16
22
|
this.store = store;
|
|
17
23
|
this.claudeContextProvisioner = claudeContextProvisioner ?? null;
|
|
24
|
+
this.compactionEnforcer = compactionEnforcer ?? null;
|
|
18
25
|
}
|
|
19
26
|
/** Discover active managed Claude sessions and poll their sidecar files. */
|
|
20
27
|
async pollOnce() {
|
|
21
28
|
const sessions = this.getEligibleSessions();
|
|
22
29
|
for (const session of sessions) {
|
|
30
|
+
let observed = null;
|
|
23
31
|
try {
|
|
24
|
-
|
|
25
|
-
this.store.persist(session.node_id,
|
|
32
|
+
observed = this.readContextUsage(session);
|
|
33
|
+
this.store.persist(session.node_id, observed);
|
|
26
34
|
}
|
|
27
35
|
catch {
|
|
36
|
+
observed = null;
|
|
28
37
|
// One bad session must not crash polling for others
|
|
29
38
|
try {
|
|
30
39
|
this.store.persist(session.node_id, this.store.unknownUsage("parse_error"));
|
|
@@ -32,6 +41,32 @@ export class ContextMonitor {
|
|
|
32
41
|
catch { /* give up on this session */ }
|
|
33
42
|
}
|
|
34
43
|
await this.normalizeStartupStatus(session);
|
|
44
|
+
await this.maybeAutoCompact(session, observed);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Slice 27 — invoke the enforcer with the latest observation. The
|
|
49
|
+
* enforcer owns policy + dedup + send; ContextMonitor only relays
|
|
50
|
+
* data and absorbs enforcer errors so a trigger-path fault never
|
|
51
|
+
* crashes telemetry polling.
|
|
52
|
+
*/
|
|
53
|
+
async maybeAutoCompact(session, usage) {
|
|
54
|
+
if (!this.compactionEnforcer)
|
|
55
|
+
return;
|
|
56
|
+
if (!usage || usage.availability !== "known")
|
|
57
|
+
return;
|
|
58
|
+
try {
|
|
59
|
+
await this.compactionEnforcer.maybeAutoCompact({
|
|
60
|
+
sessionName: session.session_name,
|
|
61
|
+
runtime: session.runtime,
|
|
62
|
+
usedPercentage: usage.usedPercentage,
|
|
63
|
+
transcriptPath: usage.transcriptPath,
|
|
64
|
+
sessionId: usage.sessionId,
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
catch {
|
|
68
|
+
// Defensive: enforcer should not throw, but absorb here so the
|
|
69
|
+
// polling loop continues to make progress for remaining sessions.
|
|
35
70
|
}
|
|
36
71
|
}
|
|
37
72
|
/** Start polling at the given interval. Idempotent. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"context-monitor.js","sourceRoot":"","sources":["../../src/domain/context-monitor.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"context-monitor.js","sourceRoot":"","sources":["../../src/domain/context-monitor.ts"],"names":[],"mappings":"AAGA,OAAO,EACL,gCAAgC,GAGjC,MAAM,sBAAsB,CAAC;AAG9B,4CAA4C;AAC5C,MAAM,CAAC,MAAM,wBAAwB,GAAG,MAAM,CAAC;AAiB/C;;;;;;;;;GASG;AACH,MAAM,OAAO,cAAc;IACjB,EAAE,CAAoB;IACtB,KAAK,CAAoB;IACzB,wBAAwB,CAAkC;IAC1D,kBAAkB,CAAkC;IACpD,KAAK,GAA0C,IAAI,CAAC;IAE5D,YACE,EAAqB,EACrB,KAAwB,EACxB,wBAAmD,EACnD,kBAA6C;QAE7C,IAAI,CAAC,EAAE,GAAG,EAAE,CAAC;QACb,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,wBAAwB,GAAG,wBAAwB,IAAI,IAAI,CAAC;QACjE,IAAI,CAAC,kBAAkB,GAAG,kBAAkB,IAAI,IAAI,CAAC;IACvD,CAAC;IAED,4EAA4E;IAC5E,KAAK,CAAC,QAAQ;QACZ,MAAM,QAAQ,GAAG,IAAI,CAAC,mBAAmB,EAAE,CAAC;QAC5C,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;YAC/B,IAAI,QAAQ,GAAwB,IAAI,CAAC;YACzC,IAAI,CAAC;gBACH,QAAQ,GAAG,IAAI,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC;gBAC1C,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;YAChD,CAAC;YAAC,MAAM,CAAC;gBACP,QAAQ,GAAG,IAAI,CAAC;gBAChB,oDAAoD;gBACpD,IAAI,CAAC;oBACH,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,aAAa,CAAC,CAAC,CAAC;gBAC9E,CAAC;gBAAC,MAAM,CAAC,CAAC,6BAA6B,CAAC,CAAC;YAC3C,CAAC;YAED,MAAM,IAAI,CAAC,sBAAsB,CAAC,OAAO,CAAC,CAAC;YAC3C,MAAM,IAAI,CAAC,gBAAgB,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;QACjD,CAAC;IACH,CAAC;IAED;;;;;OAKG;IACK,KAAK,CAAC,gBAAgB,CAC5B,OAAwB,EACxB,KAA0B;QAE1B,IAAI,CAAC,IAAI,CAAC,kBAAkB;YAAE,OAAO;QACrC,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,YAAY,KAAK,OAAO;YAAE,OAAO;QACrD,IAAI,CAAC;YACH,MAAM,IAAI,CAAC,kBAAkB,CAAC,gBAAgB,CAAC;gBAC7C,WAAW,EAAE,OAAO,CAAC,YAAY;gBACjC,OAAO,EAAE,OAAO,CAAC,OAAO;gBACxB,cAAc,EAAE,KAAK,CAAC,cAAc;gBACpC,cAAc,EAAE,KAAK,CAAC,cAAc;gBACpC,SAAS,EAAE,KAAK,CAAC,SAAS;aAC3B,CAAC,CAAC;QACL,CAAC;QAAC,MAAM,CAAC;YACP,+DAA+D;YAC/D,kEAAkE;QACpE,CAAC;IACH,CAAC;IAED,uDAAuD;IACvD,KAAK,CAAC,aAAqB,wBAAwB;QACjD,IAAI,IAAI,CAAC,KAAK;YAAE,OAAO,CAAC,kBAAkB;QAC1C,IAAI,CAAC,KAAK,GAAG,WAAW,CAAC,GAAG,EAAE;YAC5B,KAAK,IAAI,CAAC,QAAQ,EAAE,CAAC;QACvB,CAAC,EAAE,UAAU,CAAC,CAAC;QACf,oDAAoD;QACpD,IAAI,IAAI,CAAC,KAAK,IAAI,OAAO,IAAI,CAAC,KAAK,KAAK,QAAQ,IAAI,OAAO,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YACzE,IAAI,CAAC,KAAwB,CAAC,KAAK,EAAE,CAAC;QACzC,CAAC;IACH,CAAC;IAED,iEAAiE;IACjE,IAAI;QACF,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YACf,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAC1B,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;QACpB,CAAC;IACH,CAAC;IAED,wEAAwE;IAChE,mBAAmB;QACzB,OAAO,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC;;;;;;;;;;;;;;;;;;;KAmBtB,CAAC,CAAC,GAAG,EAAuB,CAAC;IAChC,CAAC;IAEO,gBAAgB,CAAC,OAAwB;QAC/C,IAAI,OAAO,CAAC,OAAO,KAAK,OAAO,EAAE,CAAC;YAChC,OAAO,IAAI,CAAC,KAAK,CAAC,qBAAqB,CAAC;gBACtC,QAAQ,EAAE,OAAO,CAAC,YAAY;gBAC9B,WAAW,EAAE,OAAO,CAAC,YAAY;aAClC,CAAC,CAAC;QACL,CAAC;QAED,IAAI,CAAC,wBAAwB,EAAE,sBAAsB,CAAC;YACpD,GAAG,EAAE,OAAO,CAAC,GAAG,IAAI,SAAS;YAC7B,WAAW,EAAE,OAAO,CAAC,YAAY;SAClC,CAAC,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,gBAAgB,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;IAC3D,CAAC;IAEO,KAAK,CAAC,sBAAsB,CAAC,OAAwB;QAC3D,IAAI,OAAO,CAAC,OAAO,KAAK,aAAa;YAAE,OAAO;QAC9C,IAAI,CAAC,IAAI,CAAC,wBAAwB,EAAE,UAAU;YAAE,OAAO;QACvD,IAAI,OAAO,CAAC,cAAc,KAAK,QAAQ,IAAI,OAAO,CAAC,cAAc,KAAK,oBAAoB;YAAE,OAAO;QAEnG,IAAI,CAAC;YACH,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,wBAAwB,CAAC,UAAU,CAAC;gBAC/D,EAAE,EAAE,mBAAmB,OAAO,CAAC,UAAU,EAAE;gBAC3C,MAAM,EAAE,OAAO,CAAC,OAAO;gBACvB,cAAc,EAAE,MAAM;gBACtB,WAAW,EAAE,OAAO,CAAC,YAAY;gBACjC,UAAU,EAAE,IAAI;gBAChB,QAAQ,EAAE,IAAI;gBACd,aAAa,EAAE,IAAI;gBACnB,WAAW,EAAE,IAAI;gBACjB,SAAS,EAAE,EAAE;gBACb,GAAG,EAAE,OAAO,CAAC,GAAG,IAAI,EAAE;aACvB,CAAC,CAAC;YACH,IAAI,SAAS,CAAC,KAAK,EAAE,CAAC;gBACpB,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC;;;;;SAKf,CAAC,CAAC,GAAG,CAAC,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC;gBACrD,OAAO;YACT,CAAC;YAED,IAAI,gCAAgC,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC;gBACrD,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC;;;;SAIf,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;YAC7B,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,oEAAoE;QACtE,CAAC;IACH,CAAC;CACF"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import type { EventBus } from "./event-bus.js";
|
|
2
|
+
import type { SessionRegistry } from "./session-registry.js";
|
|
3
|
+
import type { RigRepository } from "./rig-repository.js";
|
|
4
|
+
import type { BootstrapResult } from "./bootstrap-orchestrator.js";
|
|
5
|
+
export type KernelState = "skipped" | "auth_blocked" | "spec_missing" | "booting" | "partial_ready" | "ready" | "bootstrap_failed" | "degraded";
|
|
6
|
+
export interface KernelAgentStatus {
|
|
7
|
+
/** Session name (e.g. `advisor-lead@kernel`). */
|
|
8
|
+
sessionName: string;
|
|
9
|
+
/** Runtime declared in the agent profile (claude-code / codex / terminal). */
|
|
10
|
+
runtime: string;
|
|
11
|
+
/** Startup status from the sessions table. Same enum as session-registry. */
|
|
12
|
+
startupStatus: "pending" | "ready" | "attention_required" | "failed";
|
|
13
|
+
}
|
|
14
|
+
export interface KernelBootStatus {
|
|
15
|
+
kernelState: KernelState;
|
|
16
|
+
agents: KernelAgentStatus[];
|
|
17
|
+
/** ISO timestamp of when the kernel first entered booting; null in
|
|
18
|
+
* terminal/skipped states. */
|
|
19
|
+
firstUnreadySince: string | null;
|
|
20
|
+
/** Filename of the picked variant (rig.yaml / rig-claude-only.yaml /
|
|
21
|
+
* rig-codex-only.yaml). null when no variant was selected. */
|
|
22
|
+
variant: string | null;
|
|
23
|
+
/** Human-readable detail for auth_blocked / spec_missing /
|
|
24
|
+
* bootstrap_failed / degraded states. null otherwise. */
|
|
25
|
+
detail: string | null;
|
|
26
|
+
}
|
|
27
|
+
export interface KernelBootTrackerDeps {
|
|
28
|
+
eventBus: EventBus;
|
|
29
|
+
sessionRegistry: SessionRegistry;
|
|
30
|
+
rigRepo: RigRepository;
|
|
31
|
+
/** Milliseconds the tracker waits in `booting` before emitting
|
|
32
|
+
* `kernel.agent.degraded` and transitioning to the `degraded` state.
|
|
33
|
+
* Default 90_000 (90s) per IMPL-PRD §6.3 amendment. Tests pass
|
|
34
|
+
* shorter values; daemon startup honors the OPENRIG_KERNEL_DEGRADED_MS
|
|
35
|
+
* env override resolved by startup.ts. */
|
|
36
|
+
degradedTimeoutMs?: number;
|
|
37
|
+
}
|
|
38
|
+
export declare class KernelBootTracker {
|
|
39
|
+
private readonly deps;
|
|
40
|
+
private state;
|
|
41
|
+
private variant;
|
|
42
|
+
private detail;
|
|
43
|
+
private firstUnreadySince;
|
|
44
|
+
private degradedTimer;
|
|
45
|
+
private degradedEmitted;
|
|
46
|
+
private bootstrapInFlight;
|
|
47
|
+
constructor(deps: KernelBootTrackerDeps);
|
|
48
|
+
/** Mark the tracker as having intentionally not booted (--no-kernel,
|
|
49
|
+
* already-managed short-circuit, VITEST auto-skip). Terminal state;
|
|
50
|
+
* no degraded timer. */
|
|
51
|
+
setSkipped(detail: string): void;
|
|
52
|
+
/** Auth-blocked terminal. Operator sees the 3-part error in detail. */
|
|
53
|
+
setAuthBlocked(message: string): void;
|
|
54
|
+
/** Spec-missing terminal. Path is in detail for ops triage. */
|
|
55
|
+
setSpecMissing(specPath: string): void;
|
|
56
|
+
/** Begin tracking an in-flight bootstrap. The bootstrap promise
|
|
57
|
+
* is awaited internally; the caller does NOT block on it. */
|
|
58
|
+
startBooting(variant: string, bootstrapPromise: Promise<BootstrapResult>): void;
|
|
59
|
+
/** Read current status. Computes agents[] live from the sessions
|
|
60
|
+
* table so the response always reflects the freshest startup_status. */
|
|
61
|
+
getStatus(): KernelBootStatus;
|
|
62
|
+
/** Stop the degraded timer. Safe to call from anywhere (idempotent).
|
|
63
|
+
* Production callers don't need this; tests + graceful daemon
|
|
64
|
+
* shutdown do. */
|
|
65
|
+
stop(): void;
|
|
66
|
+
private onBootstrapComplete;
|
|
67
|
+
private onBootstrapError;
|
|
68
|
+
private aggregateReadinessFromAgents;
|
|
69
|
+
private computeAgents;
|
|
70
|
+
private scheduleDegradedTimer;
|
|
71
|
+
private cancelTimer;
|
|
72
|
+
private checkDegraded;
|
|
73
|
+
}
|
|
74
|
+
//# sourceMappingURL=kernel-boot-tracker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"kernel-boot-tracker.d.ts","sourceRoot":"","sources":["../../src/domain/kernel-boot-tracker.ts"],"names":[],"mappings":"AAqBA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC/C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAEnE,MAAM,MAAM,WAAW,GACnB,SAAS,GACT,cAAc,GACd,cAAc,GACd,SAAS,GACT,eAAe,GACf,OAAO,GACP,kBAAkB,GAClB,UAAU,CAAC;AAEf,MAAM,WAAW,iBAAiB;IAChC,iDAAiD;IACjD,WAAW,EAAE,MAAM,CAAC;IACpB,8EAA8E;IAC9E,OAAO,EAAE,MAAM,CAAC;IAChB,6EAA6E;IAC7E,aAAa,EAAE,SAAS,GAAG,OAAO,GAAG,oBAAoB,GAAG,QAAQ,CAAC;CACtE;AAED,MAAM,WAAW,gBAAgB;IAC/B,WAAW,EAAE,WAAW,CAAC;IACzB,MAAM,EAAE,iBAAiB,EAAE,CAAC;IAC5B;mCAC+B;IAC/B,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC;mEAC+D;IAC/D,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB;8DAC0D;IAC1D,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB;AAED,MAAM,WAAW,qBAAqB;IACpC,QAAQ,EAAE,QAAQ,CAAC;IACnB,eAAe,EAAE,eAAe,CAAC;IACjC,OAAO,EAAE,aAAa,CAAC;IACvB;;;;+CAI2C;IAC3C,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED,qBAAa,iBAAiB;IAShB,OAAO,CAAC,QAAQ,CAAC,IAAI;IARjC,OAAO,CAAC,KAAK,CAA0B;IACvC,OAAO,CAAC,OAAO,CAAuB;IACtC,OAAO,CAAC,MAAM,CAAuB;IACrC,OAAO,CAAC,iBAAiB,CAAuB;IAChD,OAAO,CAAC,aAAa,CAA8C;IACnE,OAAO,CAAC,eAAe,CAAS;IAChC,OAAO,CAAC,iBAAiB,CAAS;gBAEL,IAAI,EAAE,qBAAqB;IAExD;;6BAEyB;IACzB,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAOhC,uEAAuE;IACvE,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAOrC,+DAA+D;IAC/D,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;IAOtC;kEAC8D;IAC9D,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,gBAAgB,EAAE,OAAO,CAAC,eAAe,CAAC,GAAG,IAAI;IAe/E;6EACyE;IACzE,SAAS,IAAI,gBAAgB;IAoB7B;;uBAEmB;IACnB,IAAI,IAAI,IAAI;IAIZ,OAAO,CAAC,mBAAmB;IAoB3B,OAAO,CAAC,gBAAgB;IAOxB,OAAO,CAAC,4BAA4B;IAepC,OAAO,CAAC,aAAa;IA2BrB,OAAO,CAAC,qBAAqB;IAW7B,OAAO,CAAC,WAAW;IAOnB,OAAO,CAAC,aAAa;CA6BtB"}
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
// V0.3.1 slice 05 kernel-rig-as-default — forward-fix #3 architectural.
|
|
2
|
+
// Decouples daemon health/listen from kernel-agent readiness.
|
|
3
|
+
//
|
|
4
|
+
// Prior behavior: `bootKernelIfNeeded` awaited `bootstrapOrchestrator.bootstrap(...)`
|
|
5
|
+
// inside `createDaemon`, so the daemon process couldn't reach `serve()` until
|
|
6
|
+
// the kernel rig's members had been launched + their startup deliveries
|
|
7
|
+
// completed. A broken kernel agent (e.g., Codex unauthenticated mid-boot)
|
|
8
|
+
// stalled healthz too. The CLI then reported "daemon failed to start" even
|
|
9
|
+
// though the daemon itself was perfectly happy — only the *kernel* was sad.
|
|
10
|
+
//
|
|
11
|
+
// New behavior: `bootKernelIfNeeded` builds a tracker, fires the bootstrap
|
|
12
|
+
// in the background, and returns immediately. The daemon binds healthz as
|
|
13
|
+
// soon as `createDaemon` completes (HTTP server bind happens in server.ts
|
|
14
|
+
// right after). Tracker state is published via GET /api/kernel/status so
|
|
15
|
+
// operators (and CLI flags like `--wait-for-kernel`) can observe progress.
|
|
16
|
+
//
|
|
17
|
+
// A configurable degraded-timer (default 90s) emits a single
|
|
18
|
+
// `kernel.agent.degraded` event if the kernel doesn't reach a ready / partial-
|
|
19
|
+
// ready state in time — telemetry that something is keeping the kernel
|
|
20
|
+
// stuck (auth / spec / tmux / etc.).
|
|
21
|
+
export class KernelBootTracker {
|
|
22
|
+
deps;
|
|
23
|
+
state = "skipped";
|
|
24
|
+
variant = null;
|
|
25
|
+
detail = null;
|
|
26
|
+
firstUnreadySince = null;
|
|
27
|
+
degradedTimer = null;
|
|
28
|
+
degradedEmitted = false;
|
|
29
|
+
bootstrapInFlight = false;
|
|
30
|
+
constructor(deps) {
|
|
31
|
+
this.deps = deps;
|
|
32
|
+
}
|
|
33
|
+
/** Mark the tracker as having intentionally not booted (--no-kernel,
|
|
34
|
+
* already-managed short-circuit, VITEST auto-skip). Terminal state;
|
|
35
|
+
* no degraded timer. */
|
|
36
|
+
setSkipped(detail) {
|
|
37
|
+
this.cancelTimer();
|
|
38
|
+
this.state = "skipped";
|
|
39
|
+
this.detail = detail;
|
|
40
|
+
this.firstUnreadySince = null;
|
|
41
|
+
}
|
|
42
|
+
/** Auth-blocked terminal. Operator sees the 3-part error in detail. */
|
|
43
|
+
setAuthBlocked(message) {
|
|
44
|
+
this.cancelTimer();
|
|
45
|
+
this.state = "auth_blocked";
|
|
46
|
+
this.detail = message;
|
|
47
|
+
this.firstUnreadySince = null;
|
|
48
|
+
}
|
|
49
|
+
/** Spec-missing terminal. Path is in detail for ops triage. */
|
|
50
|
+
setSpecMissing(specPath) {
|
|
51
|
+
this.cancelTimer();
|
|
52
|
+
this.state = "spec_missing";
|
|
53
|
+
this.detail = specPath;
|
|
54
|
+
this.firstUnreadySince = null;
|
|
55
|
+
}
|
|
56
|
+
/** Begin tracking an in-flight bootstrap. The bootstrap promise
|
|
57
|
+
* is awaited internally; the caller does NOT block on it. */
|
|
58
|
+
startBooting(variant, bootstrapPromise) {
|
|
59
|
+
if (this.bootstrapInFlight)
|
|
60
|
+
return;
|
|
61
|
+
this.bootstrapInFlight = true;
|
|
62
|
+
this.state = "booting";
|
|
63
|
+
this.variant = variant;
|
|
64
|
+
this.detail = null;
|
|
65
|
+
this.firstUnreadySince = new Date().toISOString();
|
|
66
|
+
this.degradedEmitted = false;
|
|
67
|
+
this.scheduleDegradedTimer();
|
|
68
|
+
bootstrapPromise
|
|
69
|
+
.then((result) => this.onBootstrapComplete(result))
|
|
70
|
+
.catch((err) => this.onBootstrapError(err));
|
|
71
|
+
}
|
|
72
|
+
/** Read current status. Computes agents[] live from the sessions
|
|
73
|
+
* table so the response always reflects the freshest startup_status. */
|
|
74
|
+
getStatus() {
|
|
75
|
+
const agents = this.computeAgents();
|
|
76
|
+
let kernelState = this.state;
|
|
77
|
+
// Once bootstrap has completed (state == 'booting' before then),
|
|
78
|
+
// promote to ready / partial_ready based on agent startup_status.
|
|
79
|
+
if (this.state === "booting" && !this.bootstrapInFlight) {
|
|
80
|
+
kernelState = this.aggregateReadinessFromAgents(agents);
|
|
81
|
+
}
|
|
82
|
+
return {
|
|
83
|
+
kernelState,
|
|
84
|
+
agents,
|
|
85
|
+
firstUnreadySince: kernelState === "ready" || kernelState === "skipped"
|
|
86
|
+
? null
|
|
87
|
+
: this.firstUnreadySince,
|
|
88
|
+
variant: this.variant,
|
|
89
|
+
detail: this.detail,
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
/** Stop the degraded timer. Safe to call from anywhere (idempotent).
|
|
93
|
+
* Production callers don't need this; tests + graceful daemon
|
|
94
|
+
* shutdown do. */
|
|
95
|
+
stop() {
|
|
96
|
+
this.cancelTimer();
|
|
97
|
+
}
|
|
98
|
+
onBootstrapComplete(result) {
|
|
99
|
+
this.bootstrapInFlight = false;
|
|
100
|
+
if (result.errors && result.errors.length > 0) {
|
|
101
|
+
this.cancelTimer();
|
|
102
|
+
this.state = "bootstrap_failed";
|
|
103
|
+
this.detail = result.errors.join("; ");
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
// Bootstrap returned cleanly. State transitions to ready /
|
|
107
|
+
// partial_ready are computed on read from agents[]. Cancel the
|
|
108
|
+
// degraded timer ONLY when at least one agent is ready — until
|
|
109
|
+
// then, the kernel is still effectively booting and the operator
|
|
110
|
+
// wants the degraded telemetry if no agent ever reaches ready.
|
|
111
|
+
const agents = this.computeAgents();
|
|
112
|
+
const aggregated = this.aggregateReadinessFromAgents(agents);
|
|
113
|
+
if (aggregated === "ready" || aggregated === "partial_ready") {
|
|
114
|
+
this.cancelTimer();
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
onBootstrapError(err) {
|
|
118
|
+
this.bootstrapInFlight = false;
|
|
119
|
+
this.cancelTimer();
|
|
120
|
+
this.state = "bootstrap_failed";
|
|
121
|
+
this.detail = err instanceof Error ? err.message : String(err);
|
|
122
|
+
}
|
|
123
|
+
aggregateReadinessFromAgents(agents) {
|
|
124
|
+
if (agents.length === 0) {
|
|
125
|
+
// Bootstrap finished but no agents are registered yet (race
|
|
126
|
+
// window between session insert + status update). Keep state
|
|
127
|
+
// as booting so the operator sees progress, not a false ready.
|
|
128
|
+
return "booting";
|
|
129
|
+
}
|
|
130
|
+
const readyCount = agents.filter((a) => a.startupStatus === "ready").length;
|
|
131
|
+
if (readyCount === agents.length)
|
|
132
|
+
return "ready";
|
|
133
|
+
if (readyCount === 0)
|
|
134
|
+
return "booting";
|
|
135
|
+
return "partial_ready";
|
|
136
|
+
}
|
|
137
|
+
computeAgents() {
|
|
138
|
+
try {
|
|
139
|
+
const kernelRigs = this.deps.rigRepo.findRigsByName("kernel");
|
|
140
|
+
if (kernelRigs.length === 0)
|
|
141
|
+
return [];
|
|
142
|
+
const out = [];
|
|
143
|
+
for (const rig of kernelRigs) {
|
|
144
|
+
const sessions = this.deps.sessionRegistry.getSessionsForRig(rig.id);
|
|
145
|
+
for (const s of sessions) {
|
|
146
|
+
// session-registry's Session shape carries startupStatus +
|
|
147
|
+
// sessionName; runtime comes from the node row. Read minimal
|
|
148
|
+
// fields here so the tracker doesn't pull in node-repository.
|
|
149
|
+
out.push({
|
|
150
|
+
sessionName: s.sessionName,
|
|
151
|
+
runtime: s.runtime ?? "unknown",
|
|
152
|
+
startupStatus: s.startupStatus,
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
return out;
|
|
157
|
+
}
|
|
158
|
+
catch {
|
|
159
|
+
// Tracker must NEVER throw — /api/kernel/status returning a
|
|
160
|
+
// valid envelope with empty agents[] is more useful than a 500
|
|
161
|
+
// when the DB has a transient hiccup.
|
|
162
|
+
return [];
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
scheduleDegradedTimer() {
|
|
166
|
+
const ms = this.deps.degradedTimeoutMs ?? 90_000;
|
|
167
|
+
if (ms <= 0)
|
|
168
|
+
return;
|
|
169
|
+
this.cancelTimer();
|
|
170
|
+
this.degradedTimer = setTimeout(() => this.checkDegraded(), ms);
|
|
171
|
+
// Allow the daemon to exit cleanly without waiting on the timer.
|
|
172
|
+
if (typeof this.degradedTimer === "object" && "unref" in this.degradedTimer) {
|
|
173
|
+
this.degradedTimer.unref();
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
cancelTimer() {
|
|
177
|
+
if (this.degradedTimer !== null) {
|
|
178
|
+
clearTimeout(this.degradedTimer);
|
|
179
|
+
this.degradedTimer = null;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
checkDegraded() {
|
|
183
|
+
const agents = this.computeAgents();
|
|
184
|
+
const aggregated = this.state === "booting"
|
|
185
|
+
? this.aggregateReadinessFromAgents(agents)
|
|
186
|
+
: this.state;
|
|
187
|
+
if (aggregated === "ready" || aggregated === "partial_ready") {
|
|
188
|
+
// Made it before the deadline; no degraded emission.
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
191
|
+
// Promote to degraded + emit telemetry exactly once.
|
|
192
|
+
if (this.degradedEmitted)
|
|
193
|
+
return;
|
|
194
|
+
this.degradedEmitted = true;
|
|
195
|
+
this.state = "degraded";
|
|
196
|
+
try {
|
|
197
|
+
this.deps.eventBus.emit({
|
|
198
|
+
type: "kernel.agent.degraded",
|
|
199
|
+
agents: agents.map((a) => ({
|
|
200
|
+
sessionName: a.sessionName,
|
|
201
|
+
runtime: a.runtime,
|
|
202
|
+
startupStatus: a.startupStatus,
|
|
203
|
+
})),
|
|
204
|
+
firstUnreadySince: this.firstUnreadySince,
|
|
205
|
+
detail: this.detail,
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
catch {
|
|
209
|
+
// Best-effort telemetry; tracker must not throw.
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
//# sourceMappingURL=kernel-boot-tracker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"kernel-boot-tracker.js","sourceRoot":"","sources":["../../src/domain/kernel-boot-tracker.ts"],"names":[],"mappings":"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"}
|