@openrig/cli 0.4.7 → 0.5.0
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/claude-statusline-context.cjs +40 -8
- package/daemon/assets/plugins/openrig-core/hooks/scripts/activity-relay.cjs +0 -0
- package/daemon/assets/plugins/openrig-core/skills/applying-a-permission-policy/SKILL.md +120 -0
- package/daemon/assets/plugins/openrig-core/skills/claude-compaction-restore/scripts/precompact-hook.mjs +0 -0
- package/daemon/assets/plugins/openrig-core/skills/claude-compaction-restore/scripts/restore-from-jsonl.mjs +0 -0
- package/daemon/assets/plugins/openrig-core/skills/delegating-work/SKILL.md +43 -0
- package/daemon/assets/plugins/openrig-core/skills/forming-an-openrig-mental-model/SKILL.md +2 -0
- package/daemon/assets/plugins/openrig-core/skills/openrig-skills/SKILL.md +50 -57
- package/daemon/assets/plugins/openrig-core/skills/openrig-user/SKILL.md +84 -19
- package/daemon/assets/plugins/openrig-core/skills/queue-handoff/SKILL.md +2 -0
- package/daemon/assets/plugins/openrig-core/skills/seat-continuity-and-handover/SKILL.md +2 -1
- package/daemon/assets/plugins/openrig-core/skills/session-compaction-and-restore/SKILL.md +1 -0
- package/daemon/dist/adapters/claude-code-adapter.d.ts +36 -9
- package/daemon/dist/adapters/claude-code-adapter.d.ts.map +1 -1
- package/daemon/dist/adapters/claude-code-adapter.js +216 -49
- package/daemon/dist/adapters/claude-code-adapter.js.map +1 -1
- package/daemon/dist/adapters/claude-resume.d.ts +1 -1
- package/daemon/dist/adapters/claude-resume.d.ts.map +1 -1
- package/daemon/dist/adapters/claude-resume.js +8 -2
- package/daemon/dist/adapters/claude-resume.js.map +1 -1
- package/daemon/dist/adapters/codex-resume.d.ts +1 -1
- package/daemon/dist/adapters/codex-resume.d.ts.map +1 -1
- package/daemon/dist/adapters/codex-resume.js +4 -2
- package/daemon/dist/adapters/codex-resume.js.map +1 -1
- package/daemon/dist/adapters/codex-runtime-adapter.d.ts +12 -0
- package/daemon/dist/adapters/codex-runtime-adapter.d.ts.map +1 -1
- package/daemon/dist/adapters/codex-runtime-adapter.js +34 -7
- package/daemon/dist/adapters/codex-runtime-adapter.js.map +1 -1
- package/daemon/dist/adapters/pi-resume.d.ts +1 -1
- package/daemon/dist/adapters/pi-resume.d.ts.map +1 -1
- package/daemon/dist/adapters/pi-resume.js +7 -2
- package/daemon/dist/adapters/pi-resume.js.map +1 -1
- package/daemon/dist/adapters/pi-runtime-adapter.d.ts.map +1 -1
- package/daemon/dist/adapters/pi-runtime-adapter.js +4 -1
- package/daemon/dist/adapters/pi-runtime-adapter.js.map +1 -1
- package/daemon/dist/adapters/yolo-mode.d.ts +23 -0
- package/daemon/dist/adapters/yolo-mode.d.ts.map +1 -0
- package/daemon/dist/adapters/yolo-mode.js +49 -0
- package/daemon/dist/adapters/yolo-mode.js.map +1 -0
- package/daemon/dist/build-info.js +3 -3
- package/daemon/dist/db/migrations/055_node_permission_policy.d.ts +13 -0
- package/daemon/dist/db/migrations/055_node_permission_policy.d.ts.map +1 -0
- package/daemon/dist/db/migrations/055_node_permission_policy.js +17 -0
- package/daemon/dist/db/migrations/055_node_permission_policy.js.map +1 -0
- package/daemon/dist/db/migrations/056_rig_permission_policy.d.ts +13 -0
- package/daemon/dist/db/migrations/056_rig_permission_policy.d.ts.map +1 -0
- package/daemon/dist/db/migrations/056_rig_permission_policy.js +17 -0
- package/daemon/dist/db/migrations/056_rig_permission_policy.js.map +1 -0
- package/daemon/dist/db/migrations/057_node_policy_provenance.d.ts +19 -0
- package/daemon/dist/db/migrations/057_node_policy_provenance.d.ts.map +1 -0
- package/daemon/dist/db/migrations/057_node_policy_provenance.js +26 -0
- package/daemon/dist/db/migrations/057_node_policy_provenance.js.map +1 -0
- package/daemon/dist/db/migrations/058_rig_policy_provenance.d.ts +15 -0
- package/daemon/dist/db/migrations/058_rig_policy_provenance.d.ts.map +1 -0
- package/daemon/dist/db/migrations/058_rig_policy_provenance.js +22 -0
- package/daemon/dist/db/migrations/058_rig_policy_provenance.js.map +1 -0
- package/daemon/dist/domain/agent-activity-store.d.ts +1 -0
- package/daemon/dist/domain/agent-activity-store.d.ts.map +1 -1
- package/daemon/dist/domain/agent-activity-store.js +2 -2
- package/daemon/dist/domain/agent-activity-store.js.map +1 -1
- package/daemon/dist/domain/builtin-policy-reference.d.ts +13 -0
- package/daemon/dist/domain/builtin-policy-reference.d.ts.map +1 -0
- package/daemon/dist/domain/builtin-policy-reference.js +58 -0
- package/daemon/dist/domain/builtin-policy-reference.js.map +1 -0
- package/daemon/dist/domain/claude-activity-hooks.d.ts +33 -0
- package/daemon/dist/domain/claude-activity-hooks.d.ts.map +1 -0
- package/daemon/dist/domain/claude-activity-hooks.js +60 -0
- package/daemon/dist/domain/claude-activity-hooks.js.map +1 -0
- package/daemon/dist/domain/context-packs/bundle-assembler.d.ts +30 -0
- package/daemon/dist/domain/context-packs/bundle-assembler.d.ts.map +1 -1
- package/daemon/dist/domain/context-packs/bundle-assembler.js +31 -1
- package/daemon/dist/domain/context-packs/bundle-assembler.js.map +1 -1
- package/daemon/dist/domain/context-packs/context-pack-library-service.d.ts +69 -14
- package/daemon/dist/domain/context-packs/context-pack-library-service.d.ts.map +1 -1
- package/daemon/dist/domain/context-packs/context-pack-library-service.js +263 -48
- package/daemon/dist/domain/context-packs/context-pack-library-service.js.map +1 -1
- package/daemon/dist/domain/context-packs/context-pack-types.d.ts +2 -2
- package/daemon/dist/domain/context-packs/context-pack-types.d.ts.map +1 -1
- package/daemon/dist/domain/context-packs/context-pack-types.js.map +1 -1
- package/daemon/dist/domain/context-packs/manifest-parser.d.ts.map +1 -1
- package/daemon/dist/domain/context-packs/manifest-parser.js +11 -0
- package/daemon/dist/domain/context-packs/manifest-parser.js.map +1 -1
- package/daemon/dist/domain/context-packs/ref-safety.d.ts +11 -0
- package/daemon/dist/domain/context-packs/ref-safety.d.ts.map +1 -0
- package/daemon/dist/domain/context-packs/ref-safety.js +46 -0
- package/daemon/dist/domain/context-packs/ref-safety.js.map +1 -0
- package/daemon/dist/domain/context-packs/token-estimate.d.ts +3 -0
- package/daemon/dist/domain/context-packs/token-estimate.d.ts.map +1 -0
- package/daemon/dist/domain/context-packs/token-estimate.js +5 -0
- package/daemon/dist/domain/context-packs/token-estimate.js.map +1 -0
- package/daemon/dist/domain/native-resume-probe.d.ts +1 -1
- package/daemon/dist/domain/native-resume-probe.d.ts.map +1 -1
- package/daemon/dist/domain/native-resume-probe.js +11 -4
- package/daemon/dist/domain/native-resume-probe.js.map +1 -1
- package/daemon/dist/domain/node-inventory.js +2 -2
- package/daemon/dist/domain/node-inventory.js.map +1 -1
- package/daemon/dist/domain/permission-policy/policy-ref.d.ts +89 -0
- package/daemon/dist/domain/permission-policy/policy-ref.d.ts.map +1 -0
- package/daemon/dist/domain/permission-policy/policy-ref.js +171 -0
- package/daemon/dist/domain/permission-policy/policy-ref.js.map +1 -0
- package/daemon/dist/domain/permission-policy/policy-spec.d.ts +34 -0
- package/daemon/dist/domain/permission-policy/policy-spec.d.ts.map +1 -0
- package/daemon/dist/domain/permission-policy/policy-spec.js +106 -0
- package/daemon/dist/domain/permission-policy/policy-spec.js.map +1 -0
- package/daemon/dist/domain/plugin-vendor-service.d.ts +14 -0
- package/daemon/dist/domain/plugin-vendor-service.d.ts.map +1 -1
- package/daemon/dist/domain/plugin-vendor-service.js +26 -2
- package/daemon/dist/domain/plugin-vendor-service.js.map +1 -1
- package/daemon/dist/domain/provider/claude-usage-reader.d.ts +44 -0
- package/daemon/dist/domain/provider/claude-usage-reader.d.ts.map +1 -0
- package/daemon/dist/domain/provider/claude-usage-reader.js +112 -0
- package/daemon/dist/domain/provider/claude-usage-reader.js.map +1 -0
- package/daemon/dist/domain/provider/codex-auth-reader.d.ts +18 -0
- package/daemon/dist/domain/provider/codex-auth-reader.d.ts.map +1 -0
- package/daemon/dist/domain/provider/codex-auth-reader.js +64 -0
- package/daemon/dist/domain/provider/codex-auth-reader.js.map +1 -0
- package/daemon/dist/domain/provider/host-usage-rollup.d.ts +51 -0
- package/daemon/dist/domain/provider/host-usage-rollup.d.ts.map +1 -0
- package/daemon/dist/domain/provider/host-usage-rollup.js +162 -0
- package/daemon/dist/domain/provider/host-usage-rollup.js.map +1 -0
- package/daemon/dist/domain/provider/provider-collect.d.ts +22 -0
- package/daemon/dist/domain/provider/provider-collect.d.ts.map +1 -0
- package/daemon/dist/domain/provider/provider-collect.js +74 -0
- package/daemon/dist/domain/provider/provider-collect.js.map +1 -0
- package/daemon/dist/domain/provider/provider-policy.d.ts +38 -0
- package/daemon/dist/domain/provider/provider-policy.d.ts.map +1 -0
- package/daemon/dist/domain/provider/provider-policy.js +76 -0
- package/daemon/dist/domain/provider/provider-policy.js.map +1 -0
- package/daemon/dist/domain/provider/provider-read-model.d.ts +28 -0
- package/daemon/dist/domain/provider/provider-read-model.d.ts.map +1 -0
- package/daemon/dist/domain/provider/provider-read-model.js +68 -0
- package/daemon/dist/domain/provider/provider-read-model.js.map +1 -0
- package/daemon/dist/domain/provider/provider-service-impl.d.ts +26 -0
- package/daemon/dist/domain/provider/provider-service-impl.d.ts.map +1 -0
- package/daemon/dist/domain/provider/provider-service-impl.js +83 -0
- package/daemon/dist/domain/provider/provider-service-impl.js.map +1 -0
- package/daemon/dist/domain/provider/provider-service.d.ts +33 -0
- package/daemon/dist/domain/provider/provider-service.d.ts.map +1 -0
- package/daemon/dist/domain/provider/provider-service.js +6 -0
- package/daemon/dist/domain/provider/provider-service.js.map +1 -0
- package/daemon/dist/domain/provider/provider-signals.d.ts +76 -0
- package/daemon/dist/domain/provider/provider-signals.d.ts.map +1 -0
- package/daemon/dist/domain/provider/provider-signals.js +144 -0
- package/daemon/dist/domain/provider/provider-signals.js.map +1 -0
- package/daemon/dist/domain/provider/provider-types.d.ts +101 -0
- package/daemon/dist/domain/provider/provider-types.d.ts.map +1 -0
- package/daemon/dist/domain/provider/provider-types.js +7 -0
- package/daemon/dist/domain/provider/provider-types.js.map +1 -0
- package/daemon/dist/domain/provider/reactive-tap.d.ts +29 -0
- package/daemon/dist/domain/provider/reactive-tap.d.ts.map +1 -0
- package/daemon/dist/domain/provider/reactive-tap.js +80 -0
- package/daemon/dist/domain/provider/reactive-tap.js.map +1 -0
- package/daemon/dist/domain/restore-orchestrator.d.ts +14 -0
- package/daemon/dist/domain/restore-orchestrator.d.ts.map +1 -1
- package/daemon/dist/domain/restore-orchestrator.js +90 -6
- package/daemon/dist/domain/restore-orchestrator.js.map +1 -1
- package/daemon/dist/domain/rig-expansion-service.d.ts.map +1 -1
- package/daemon/dist/domain/rig-expansion-service.js +10 -1
- package/daemon/dist/domain/rig-expansion-service.js.map +1 -1
- package/daemon/dist/domain/rig-repository.d.ts +45 -0
- package/daemon/dist/domain/rig-repository.d.ts.map +1 -1
- package/daemon/dist/domain/rig-repository.js +75 -1
- package/daemon/dist/domain/rig-repository.js.map +1 -1
- package/daemon/dist/domain/rigspec-codec.d.ts.map +1 -1
- package/daemon/dist/domain/rigspec-codec.js +6 -0
- package/daemon/dist/domain/rigspec-codec.js.map +1 -1
- package/daemon/dist/domain/rigspec-exporter.d.ts.map +1 -1
- package/daemon/dist/domain/rigspec-exporter.js +8 -0
- package/daemon/dist/domain/rigspec-exporter.js.map +1 -1
- package/daemon/dist/domain/rigspec-instantiator.d.ts +25 -24
- package/daemon/dist/domain/rigspec-instantiator.d.ts.map +1 -1
- package/daemon/dist/domain/rigspec-instantiator.js +190 -69
- package/daemon/dist/domain/rigspec-instantiator.js.map +1 -1
- package/daemon/dist/domain/rigspec-preflight.d.ts +22 -0
- package/daemon/dist/domain/rigspec-preflight.d.ts.map +1 -1
- package/daemon/dist/domain/rigspec-preflight.js +76 -0
- package/daemon/dist/domain/rigspec-preflight.js.map +1 -1
- package/daemon/dist/domain/rigspec-schema.d.ts.map +1 -1
- package/daemon/dist/domain/rigspec-schema.js +25 -0
- package/daemon/dist/domain/rigspec-schema.js.map +1 -1
- package/daemon/dist/domain/runtime-adapter.d.ts +7 -11
- package/daemon/dist/domain/runtime-adapter.d.ts.map +1 -1
- package/daemon/dist/domain/runtime-adapter.js.map +1 -1
- package/daemon/dist/domain/scope/attestation-lineage.generated.d.ts +14 -0
- package/daemon/dist/domain/scope/attestation-lineage.generated.d.ts.map +1 -0
- package/daemon/dist/domain/scope/attestation-lineage.generated.js +26 -0
- package/daemon/dist/domain/scope/attestation-lineage.generated.js.map +1 -0
- package/daemon/dist/domain/scope/scope-approve.d.ts +13 -0
- package/daemon/dist/domain/scope/scope-approve.d.ts.map +1 -1
- package/daemon/dist/domain/scope/scope-approve.js +50 -10
- package/daemon/dist/domain/scope/scope-approve.js.map +1 -1
- package/daemon/dist/domain/seat-handover-service.d.ts.map +1 -1
- package/daemon/dist/domain/seat-handover-service.js +7 -1
- package/daemon/dist/domain/seat-handover-service.js.map +1 -1
- package/daemon/dist/domain/startup-validation.d.ts.map +1 -1
- package/daemon/dist/domain/startup-validation.js +18 -54
- package/daemon/dist/domain/startup-validation.js.map +1 -1
- package/daemon/dist/domain/stream-store.d.ts +4 -0
- package/daemon/dist/domain/stream-store.d.ts.map +1 -1
- package/daemon/dist/domain/stream-store.js +15 -2
- package/daemon/dist/domain/stream-store.js.map +1 -1
- package/daemon/dist/domain/successor-session-launcher.d.ts +4 -0
- package/daemon/dist/domain/successor-session-launcher.d.ts.map +1 -1
- package/daemon/dist/domain/successor-session-launcher.js +2 -0
- package/daemon/dist/domain/successor-session-launcher.js.map +1 -1
- package/daemon/dist/domain/types.d.ts +19 -9
- 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.js +1 -1
- package/daemon/dist/routes/agent-images.d.ts.map +1 -1
- package/daemon/dist/routes/agent-images.js +2 -0
- package/daemon/dist/routes/agent-images.js.map +1 -1
- package/daemon/dist/routes/context-packs.d.ts.map +1 -1
- package/daemon/dist/routes/context-packs.js +157 -75
- package/daemon/dist/routes/context-packs.js.map +1 -1
- package/daemon/dist/routes/provider.d.ts +3 -0
- package/daemon/dist/routes/provider.d.ts.map +1 -0
- package/daemon/dist/routes/provider.js +124 -0
- package/daemon/dist/routes/provider.js.map +1 -0
- package/daemon/dist/routes/rigs.js +8 -0
- package/daemon/dist/routes/rigs.js.map +1 -1
- package/daemon/dist/routes/scope-approve.d.ts.map +1 -1
- package/daemon/dist/routes/scope-approve.js +6 -3
- package/daemon/dist/routes/scope-approve.js.map +1 -1
- package/daemon/dist/routes/scope-audit.d.ts.map +1 -1
- package/daemon/dist/routes/scope-audit.js +4 -1
- package/daemon/dist/routes/scope-audit.js.map +1 -1
- package/daemon/dist/routes/stream.d.ts.map +1 -1
- package/daemon/dist/routes/stream.js +71 -1
- package/daemon/dist/routes/stream.js.map +1 -1
- package/daemon/dist/server.d.ts +3 -0
- package/daemon/dist/server.d.ts.map +1 -1
- package/daemon/dist/server.js +5 -0
- package/daemon/dist/server.js.map +1 -1
- package/daemon/dist/startup.d.ts.map +1 -1
- package/daemon/dist/startup.js +38 -12
- package/daemon/dist/startup.js.map +1 -1
- package/daemon/docs/reference/developing.md +39 -0
- package/daemon/docs/reference/rig-spec.md +19 -0
- package/daemon/policies/builtin/locked.policy.md +24 -0
- package/daemon/policies/builtin/open.policy.md +24 -0
- package/daemon/policies/builtin/standard.policy.md +25 -0
- package/daemon/policies/builtin/yolo.policy.md +20 -0
- package/daemon/policies/examples/my-cautious-dev.policy.md +40 -0
- package/daemon/specs/agents/apps/vault-specialist/agent.yaml +1 -1
- package/daemon/specs/agents/conveyor/builder/agent.yaml +1 -1
- package/daemon/specs/agents/conveyor/lead/agent.yaml +1 -1
- package/daemon/specs/agents/conveyor/planner/agent.yaml +1 -1
- package/daemon/specs/agents/conveyor/reviewer/agent.yaml +1 -1
- package/daemon/specs/agents/design/product-designer/agent.yaml +1 -1
- package/daemon/specs/agents/development/implementer/agent.yaml +1 -1
- package/daemon/specs/agents/development/qa/agent.yaml +1 -1
- package/daemon/specs/agents/factory-rsi/dogfood/agent.yaml +1 -1
- package/daemon/specs/agents/factory-rsi/release-manager/agent.yaml +1 -1
- package/daemon/specs/agents/orchestration/orchestrator/agent.yaml +1 -1
- package/daemon/specs/agents/product-management/pm/agent.yaml +1 -0
- package/daemon/specs/agents/research/analyst/agent.yaml +1 -1
- package/daemon/specs/agents/research/synthesizer/agent.yaml +1 -1
- package/daemon/specs/agents/review/independent-reviewer/agent.yaml +1 -1
- package/daemon/specs/agents/shared/agent.yaml +6 -0
- package/daemon/specs/agents/shared/runtime/claude-activity-hooks.json +4 -0
- package/daemon/specs/agents/shared/runtime/claude-settings.fragment.json +1 -20
- package/daemon/specs/agents/shared/skills/core/openrig-architect/SKILL.md +0 -2
- package/daemon/specs/agents/shared/skills/core/watchdog/SKILL.md +1 -0
- package/daemon/specs/agents/shared/skills/process/systematic-debugging/find-polluter.sh +0 -0
- package/daemon/specs/agents/shared/skills/process/verification-before-completion/SKILL.md +1 -0
- package/dist/bin-wrapper.d.ts.map +1 -1
- package/dist/bin-wrapper.js +7 -0
- package/dist/bin-wrapper.js.map +1 -1
- package/dist/build-info.js +3 -3
- package/dist/commands/agent-image.d.ts.map +1 -1
- package/dist/commands/agent-image.js +2 -1
- package/dist/commands/agent-image.js.map +1 -1
- package/dist/commands/broadcast.d.ts.map +1 -1
- package/dist/commands/broadcast.js +37 -2
- package/dist/commands/broadcast.js.map +1 -1
- package/dist/commands/context.d.ts +2 -7
- package/dist/commands/context.d.ts.map +1 -1
- package/dist/commands/context.js +391 -213
- package/dist/commands/context.js.map +1 -1
- package/dist/commands/provider.d.ts +4 -0
- package/dist/commands/provider.d.ts.map +1 -0
- package/dist/commands/provider.js +218 -0
- package/dist/commands/provider.js.map +1 -0
- package/dist/commands/ps.d.ts +7 -0
- package/dist/commands/ps.d.ts.map +1 -1
- package/dist/commands/ps.js +34 -4
- package/dist/commands/ps.js.map +1 -1
- package/dist/commands/queue.d.ts.map +1 -1
- package/dist/commands/queue.js +38 -8
- package/dist/commands/queue.js.map +1 -1
- package/dist/commands/scope.d.ts.map +1 -1
- package/dist/commands/scope.js +48 -4
- package/dist/commands/scope.js.map +1 -1
- package/dist/commands/send.d.ts.map +1 -1
- package/dist/commands/send.js +70 -11
- package/dist/commands/send.js.map +1 -1
- package/dist/commands/setup.d.ts +14 -0
- package/dist/commands/setup.d.ts.map +1 -1
- package/dist/commands/setup.js +131 -8
- package/dist/commands/setup.js.map +1 -1
- package/dist/commands/stream.d.ts +1 -0
- package/dist/commands/stream.d.ts.map +1 -1
- package/dist/commands/stream.js +93 -0
- package/dist/commands/stream.js.map +1 -1
- package/dist/commands/tui.d.ts +4 -0
- package/dist/commands/tui.d.ts.map +1 -0
- package/dist/commands/tui.js +29 -0
- package/dist/commands/tui.js.map +1 -0
- package/dist/commands/walk.d.ts +19 -0
- package/dist/commands/walk.d.ts.map +1 -0
- package/dist/commands/walk.js +139 -0
- package/dist/commands/walk.js.map +1 -0
- package/dist/context-resolve.d.ts +14 -0
- package/dist/context-resolve.d.ts.map +1 -0
- package/dist/context-resolve.js +40 -0
- package/dist/context-resolve.js.map +1 -0
- package/dist/front-door.d.ts +31 -0
- package/dist/front-door.d.ts.map +1 -0
- package/dist/front-door.js +114 -0
- package/dist/front-door.js.map +1 -0
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +19 -6
- package/dist/index.js.map +1 -1
- package/dist/lib/scope/attestation-lineage.d.ts +14 -0
- package/dist/lib/scope/attestation-lineage.d.ts.map +1 -0
- package/dist/lib/scope/attestation-lineage.js +34 -0
- package/dist/lib/scope/attestation-lineage.js.map +1 -0
- package/package.json +4 -2
- package/tui/dist/daemon-client.d.ts +56 -0
- package/tui/dist/daemon-client.d.ts.map +1 -0
- package/tui/dist/daemon-client.js +99 -0
- package/tui/dist/daemon-client.js.map +1 -0
- package/tui/dist/demo-data.d.ts +3 -0
- package/tui/dist/demo-data.d.ts.map +1 -0
- package/tui/dist/demo-data.js +52 -0
- package/tui/dist/demo-data.js.map +1 -0
- package/tui/dist/detail.d.ts +34 -0
- package/tui/dist/detail.d.ts.map +1 -0
- package/tui/dist/detail.js +47 -0
- package/tui/dist/detail.js.map +1 -0
- package/tui/dist/grammar.d.ts +3 -0
- package/tui/dist/grammar.d.ts.map +1 -0
- package/tui/dist/grammar.js +66 -0
- package/tui/dist/grammar.js.map +1 -0
- package/tui/dist/hydrate.d.ts +78 -0
- package/tui/dist/hydrate.d.ts.map +1 -0
- package/tui/dist/hydrate.js +294 -0
- package/tui/dist/hydrate.js.map +1 -0
- package/tui/dist/index.d.ts +12 -0
- package/tui/dist/index.d.ts.map +1 -0
- package/tui/dist/index.js +12 -0
- package/tui/dist/index.js.map +1 -0
- package/tui/dist/input.d.ts +21 -0
- package/tui/dist/input.d.ts.map +1 -0
- package/tui/dist/input.js +128 -0
- package/tui/dist/input.js.map +1 -0
- package/tui/dist/live.d.ts +20 -0
- package/tui/dist/live.d.ts.map +1 -0
- package/tui/dist/live.js +67 -0
- package/tui/dist/live.js.map +1 -0
- package/tui/dist/main.d.ts +3 -0
- package/tui/dist/main.d.ts.map +1 -0
- package/tui/dist/main.js +184 -0
- package/tui/dist/main.js.map +1 -0
- package/tui/dist/motion.d.ts +13 -0
- package/tui/dist/motion.d.ts.map +1 -0
- package/tui/dist/motion.js +31 -0
- package/tui/dist/motion.js.map +1 -0
- package/tui/dist/navigator.d.ts +21 -0
- package/tui/dist/navigator.d.ts.map +1 -0
- package/tui/dist/navigator.js +168 -0
- package/tui/dist/navigator.js.map +1 -0
- package/tui/dist/refresh.d.ts +3 -0
- package/tui/dist/refresh.d.ts.map +1 -0
- package/tui/dist/refresh.js +9 -0
- package/tui/dist/refresh.js.map +1 -0
- package/tui/dist/render.d.ts +21 -0
- package/tui/dist/render.d.ts.map +1 -0
- package/tui/dist/render.js +807 -0
- package/tui/dist/render.js.map +1 -0
- package/tui/dist/sections.d.ts +4 -0
- package/tui/dist/sections.d.ts.map +1 -0
- package/tui/dist/sections.js +19 -0
- package/tui/dist/sections.js.map +1 -0
- package/tui/dist/socket-server.d.ts +24 -0
- package/tui/dist/socket-server.d.ts.map +1 -0
- package/tui/dist/socket-server.js +85 -0
- package/tui/dist/socket-server.js.map +1 -0
- package/tui/dist/state.d.ts +51 -0
- package/tui/dist/state.d.ts.map +1 -0
- package/tui/dist/state.js +480 -0
- package/tui/dist/state.js.map +1 -0
- package/tui/dist/stylize.d.ts +4 -0
- package/tui/dist/stylize.d.ts.map +1 -0
- package/tui/dist/stylize.js +248 -0
- package/tui/dist/stylize.js.map +1 -0
- package/tui/dist/theme.d.ts +19 -0
- package/tui/dist/theme.d.ts.map +1 -0
- package/tui/dist/theme.js +86 -0
- package/tui/dist/theme.js.map +1 -0
- package/tui/dist/topology/canvas.d.ts +43 -0
- package/tui/dist/topology/canvas.d.ts.map +1 -0
- package/tui/dist/topology/canvas.js +131 -0
- package/tui/dist/topology/canvas.js.map +1 -0
- package/tui/dist/topology/fixture.d.ts +4 -0
- package/tui/dist/topology/fixture.d.ts.map +1 -0
- package/tui/dist/topology/fixture.js +71 -0
- package/tui/dist/topology/fixture.js.map +1 -0
- package/tui/dist/topology/glyphs.d.ts +21 -0
- package/tui/dist/topology/glyphs.d.ts.map +1 -0
- package/tui/dist/topology/glyphs.js +49 -0
- package/tui/dist/topology/glyphs.js.map +1 -0
- package/tui/dist/topology/graph-types.d.ts +39 -0
- package/tui/dist/topology/graph-types.d.ts.map +1 -0
- package/tui/dist/topology/graph-types.js +2 -0
- package/tui/dist/topology/graph-types.js.map +1 -0
- package/tui/dist/topology/layout.d.ts +52 -0
- package/tui/dist/topology/layout.d.ts.map +1 -0
- package/tui/dist/topology/layout.js +118 -0
- package/tui/dist/topology/layout.js.map +1 -0
- package/tui/dist/topology/render-graph.d.ts +8 -0
- package/tui/dist/topology/render-graph.d.ts.map +1 -0
- package/tui/dist/topology/render-graph.js +20 -0
- package/tui/dist/topology/render-graph.js.map +1 -0
- package/tui/dist/topology/runtime-marks.d.ts +53 -0
- package/tui/dist/topology/runtime-marks.d.ts.map +1 -0
- package/tui/dist/topology/runtime-marks.js +185 -0
- package/tui/dist/topology/runtime-marks.js.map +1 -0
- package/tui/dist/topology/styles/braille.d.ts +5 -0
- package/tui/dist/topology/styles/braille.d.ts.map +1 -0
- package/tui/dist/topology/styles/braille.js +84 -0
- package/tui/dist/topology/styles/braille.js.map +1 -0
- package/tui/dist/topology/styles/hatchet.d.ts +41 -0
- package/tui/dist/topology/styles/hatchet.d.ts.map +1 -0
- package/tui/dist/topology/styles/hatchet.js +146 -0
- package/tui/dist/topology/styles/hatchet.js.map +1 -0
- package/tui/dist/types.d.ts +362 -0
- package/tui/dist/types.d.ts.map +1 -0
- package/tui/dist/types.js +6 -0
- package/tui/dist/types.js.map +1 -0
- package/ui/dist/assets/{index-DkNi0RT8.js → index-Dv5VaLCN.js} +135 -135
- package/ui/dist/index.html +1 -1
- package/daemon/specs/agents/shared/skills/pm/backlog-capture/SKILL.md +0 -43
- package/daemon/specs/agents/shared/skills/pm/context-builder/SKILL.md +0 -87
- package/daemon/specs/agents/shared/skills/pm/exec-summary/SKILL.md +0 -84
- package/daemon/specs/agents/shared/skills/pm/office-hours/SKILL.md +0 -129
- package/daemon/specs/agents/shared/skills/pm/plan-review/SKILL.md +0 -98
- package/daemon/specs/agents/shared/skills/pm/requirements-writer/SKILL.md +0 -113
- package/daemon/specs/agents/shared/skills/pm/ui-mockup/SKILL.md +0 -76
- package/daemon/specs/agents/shared/skills/pods/development-team/SKILL.md +0 -148
- package/daemon/specs/agents/shared/skills/pods/orchestration-team/SKILL.md +0 -266
- package/daemon/specs/agents/shared/skills/pods/review-team/SKILL.md +0 -213
- package/daemon/specs/agents/shared/skills/process/systematic-debugging/CREATION-LOG.md +0 -119
- package/daemon/specs/agents/shared/skills/process/systematic-debugging/test-academic.md +0 -14
- package/daemon/specs/agents/shared/skills/process/systematic-debugging/test-pressure-1.md +0 -58
- package/daemon/specs/agents/shared/skills/process/systematic-debugging/test-pressure-2.md +0 -68
- package/daemon/specs/agents/shared/skills/process/systematic-debugging/test-pressure-3.md +0 -69
- package/dist/commands/context-pack.d.ts +0 -4
- package/dist/commands/context-pack.d.ts.map +0 -1
- package/dist/commands/context-pack.js +0 -357
- package/dist/commands/context-pack.js.map +0 -1
|
@@ -0,0 +1,807 @@
|
|
|
1
|
+
// Hand-rolled ANSI renderer (Phase-0 substrate decision). Pure function:
|
|
2
|
+
// (state, snapshot) → {lines, hitMap, explorerRows}. BOTH panes emit hit
|
|
3
|
+
// targets — explorer rows AND content-pane surfaces (table rows, view tabs,
|
|
4
|
+
// agent-refs, Needs-You items) — so a mouse click anywhere resolves to the
|
|
5
|
+
// SAME semantic actions commands produce (PIN 1). Isolated seam: a substrate
|
|
6
|
+
// swap touches only this module (spike verdict revisit trigger).
|
|
7
|
+
import { computeExplorerRows, findAgent, findSpec, findAgentBySession, agentsRunningSpec, agentsRunningSpecTargets, specDetailArrowsScroll } from "./state.js";
|
|
8
|
+
import { navigatorDisplay } from "./navigator.js";
|
|
9
|
+
import { renderGraphStyle } from "./topology/render-graph.js";
|
|
10
|
+
import { runtimeMarkSegs } from "./topology/runtime-marks.js";
|
|
11
|
+
import { barCells, flashActive, reducedMotion, spinnerFrame } from "./motion.js";
|
|
12
|
+
import { detailPage, fieldLine, sectionRule, listItem, alignedRow, LABEL_W } from "./detail.js";
|
|
13
|
+
const EXPL_W = 30;
|
|
14
|
+
function pad(text, width) {
|
|
15
|
+
const t = String(text ?? "");
|
|
16
|
+
if (t.length <= width)
|
|
17
|
+
return t + " ".repeat(width - t.length);
|
|
18
|
+
// never hard-clip mid-word: any truncation reads as an ellipsis (glance honesty)
|
|
19
|
+
return t.slice(0, Math.max(width - 1, 0)) + "…";
|
|
20
|
+
}
|
|
21
|
+
function padLeft(text, width) {
|
|
22
|
+
const t = String(text ?? "");
|
|
23
|
+
if (t.length <= width)
|
|
24
|
+
return " ".repeat(width - t.length) + t;
|
|
25
|
+
return t.slice(0, Math.max(width - 1, 0)) + "…";
|
|
26
|
+
}
|
|
27
|
+
const FULL_AGENT_COLS = [
|
|
28
|
+
["rig", "RIG", 18, "left"],
|
|
29
|
+
["pod", "POD", 8, "left"],
|
|
30
|
+
["agent", "AGENT", 16, "left"],
|
|
31
|
+
["runtime", "RUNTIME", 13, "left"],
|
|
32
|
+
["context", "CTX%", 4, "right"],
|
|
33
|
+
["tokens", "TOKENS", 7, "right"],
|
|
34
|
+
["status", "STATUS", 17, "left"],
|
|
35
|
+
["actions", "ACTIONS", 14, "left"],
|
|
36
|
+
];
|
|
37
|
+
function columnsWidth(columns) {
|
|
38
|
+
return columns.reduce((total, [, , width]) => total + width + 1, -1);
|
|
39
|
+
}
|
|
40
|
+
function agentColumns(contentWidth) {
|
|
41
|
+
if (columnsWidth(FULL_AGENT_COLS) <= contentWidth)
|
|
42
|
+
return FULL_AGENT_COLS;
|
|
43
|
+
// At the 120-column fallback the content pane is 88 cells. Preserve the
|
|
44
|
+
// operable identity/status/action path; telemetry cells yield first.
|
|
45
|
+
const compactRest = [
|
|
46
|
+
["pod", "POD", 8, "left"],
|
|
47
|
+
["agent", "AGENT", 16, "left"],
|
|
48
|
+
["runtime", "RUNTIME", 13, "left"],
|
|
49
|
+
["status", "STATUS", 17, "left"],
|
|
50
|
+
["actions", "ACTIONS", 14, "left"],
|
|
51
|
+
];
|
|
52
|
+
const rigWidth = Math.max(6, Math.min(18, contentWidth - columnsWidth(compactRest) - 1));
|
|
53
|
+
return [["rig", "RIG", rigWidth, "left"], ...compactRest];
|
|
54
|
+
}
|
|
55
|
+
function tableRow(columns, cells) {
|
|
56
|
+
return columns.map(([key, , width, align]) => align === "right" ? padLeft(cells[key], width) : pad(cells[key], width)).join(" ");
|
|
57
|
+
}
|
|
58
|
+
function tabsLine(state, suffix) {
|
|
59
|
+
// slice-17: three tabs, each its own click zone (the first zone starts at
|
|
60
|
+
// content col 0, preserving the focus-marker floor); `tab graph` = the
|
|
61
|
+
// topology graph view (frame-01 hatchet mainline)
|
|
62
|
+
const labels = [
|
|
63
|
+
["table", state.viewTab === "table" ? "[ TABLE ]" : " TABLE "],
|
|
64
|
+
["overview", state.viewTab === "overview" ? "[ OVERVIEW ]" : " OVERVIEW "],
|
|
65
|
+
["graph", state.viewTab === "graph" ? "[ GRAPH ]" : " GRAPH "],
|
|
66
|
+
];
|
|
67
|
+
const text = `${labels.map(([, label]) => label).join("")} ${suffix}`;
|
|
68
|
+
const zones = [];
|
|
69
|
+
let at = 0;
|
|
70
|
+
for (const [tab, label] of labels) {
|
|
71
|
+
zones.push({ start: at, end: at + label.length, action: { type: "tab", tab } });
|
|
72
|
+
at += label.length;
|
|
73
|
+
}
|
|
74
|
+
return [{ text, zones }];
|
|
75
|
+
}
|
|
76
|
+
function specTabsLine(state, name) {
|
|
77
|
+
const active = state.viewTab === "topology" || state.viewTab === "yaml" ? state.viewTab : "configuration";
|
|
78
|
+
const labels = ["topology", "configuration", "yaml"];
|
|
79
|
+
const parts = labels.map((tab) => (tab === active ? `[ ${tab.toUpperCase()} ]` : ` ${tab.toUpperCase()} `));
|
|
80
|
+
const text = `rig spec ${name} ${parts.join(" ")}`;
|
|
81
|
+
return {
|
|
82
|
+
text,
|
|
83
|
+
zones: labels.map((tab, index) => {
|
|
84
|
+
const label = parts[index];
|
|
85
|
+
const start = text.indexOf(label);
|
|
86
|
+
return { start, end: start + label.length, action: { type: "tab", tab } };
|
|
87
|
+
}),
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
function needsLine(prefix, item, snap) {
|
|
91
|
+
// aligned columns (glance speed): kind · host · target · detail — same fact,
|
|
92
|
+
// same visual place, every row
|
|
93
|
+
const found = findAgentBySession(snap, item.target, item.hostId);
|
|
94
|
+
const cols = alignedRow([
|
|
95
|
+
[item.kind, 16],
|
|
96
|
+
[item.hostId ? `[${item.hostId}]` : "", 11],
|
|
97
|
+
[item.target, 34],
|
|
98
|
+
]);
|
|
99
|
+
return {
|
|
100
|
+
text: `${prefix}${cols} ${item.detail}${found ? " (open ▸)" : ""}`,
|
|
101
|
+
...(found ? { action: { type: "drill", resource: "agent", name: found.agent.name, target: { host: found.host.name, rig: found.rig.name, pod: found.pod.name } } } : {}),
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
function sourceProvenance(spec) {
|
|
105
|
+
if (spec.sourceType === "builtin")
|
|
106
|
+
return "built-in library";
|
|
107
|
+
if (spec.sourceType === "user_file")
|
|
108
|
+
return "user library";
|
|
109
|
+
return spec.sourceState === "library_item" ? "library" : "source unknown";
|
|
110
|
+
}
|
|
111
|
+
function displayPath(path, max = 68) {
|
|
112
|
+
if (path.length <= max)
|
|
113
|
+
return path;
|
|
114
|
+
const parts = path.split("/").filter(Boolean);
|
|
115
|
+
const kept = [];
|
|
116
|
+
while (parts.length > 0) {
|
|
117
|
+
const candidate = [parts.at(-1), ...kept];
|
|
118
|
+
if (`…/${candidate.join("/")}`.length > max)
|
|
119
|
+
break;
|
|
120
|
+
kept.unshift(parts.pop());
|
|
121
|
+
}
|
|
122
|
+
return `…/${kept.join("/")}`;
|
|
123
|
+
}
|
|
124
|
+
function wrappedList(prefix, values, max = 84) {
|
|
125
|
+
if (values.length === 0)
|
|
126
|
+
return [{ text: `${prefix}(none)` }];
|
|
127
|
+
const lines = [];
|
|
128
|
+
const indent = " ".repeat(prefix.length);
|
|
129
|
+
let current = prefix;
|
|
130
|
+
for (const value of values) {
|
|
131
|
+
const addition = `${current === prefix ? "" : ", "}${value}`;
|
|
132
|
+
if (current !== prefix && current.length + addition.length > max) {
|
|
133
|
+
lines.push({ text: current });
|
|
134
|
+
current = `${indent}${value}`;
|
|
135
|
+
}
|
|
136
|
+
else {
|
|
137
|
+
current += addition;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
lines.push({ text: current });
|
|
141
|
+
return lines;
|
|
142
|
+
}
|
|
143
|
+
/** field row whose value list wraps at the value column (label rhythm kept) */
|
|
144
|
+
function fieldWrapped(label, values) {
|
|
145
|
+
if (values.length === 0)
|
|
146
|
+
return [fieldLine({ label, value: "(none)" })];
|
|
147
|
+
const valueCol = 2 + 12 + 1; // indent + LABEL_W + gap — where field values start
|
|
148
|
+
const wrapped = wrappedList(" ".repeat(valueCol), values, 92);
|
|
149
|
+
const first = wrapped[0].text.slice(valueCol);
|
|
150
|
+
return [fieldLine({ label, value: first }), ...wrapped.slice(1)];
|
|
151
|
+
}
|
|
152
|
+
function contentLines(state, snap, contentWidth, motion) {
|
|
153
|
+
const contentWidthForGraph = contentWidth;
|
|
154
|
+
void contentWidthForGraph;
|
|
155
|
+
const lines = [];
|
|
156
|
+
if (state.section === "topology") {
|
|
157
|
+
if (state.runningOf) {
|
|
158
|
+
const seats = agentsRunningSpecTargets(snap, state.runningOf);
|
|
159
|
+
return detailPage({ text: `seats running spec ${state.runningOf}` }, [
|
|
160
|
+
{
|
|
161
|
+
lines: seats.length === 0
|
|
162
|
+
? [{ text: " (no seats currently run it)" }]
|
|
163
|
+
: seats.map((seat) => listItem(`${seat.agent.name} · ${seat.rig.name} / ${seat.pod.name} · ${seat.agent.status}`, {
|
|
164
|
+
type: "drill",
|
|
165
|
+
resource: "agent",
|
|
166
|
+
name: seat.agent.name,
|
|
167
|
+
target: { host: seat.host.name, rig: seat.rig.name, pod: seat.pod.name },
|
|
168
|
+
})),
|
|
169
|
+
},
|
|
170
|
+
]);
|
|
171
|
+
}
|
|
172
|
+
const leaf = state.drill.at(-1);
|
|
173
|
+
if (leaf?.kind === "agent") {
|
|
174
|
+
const hostName = state.drill.find((part) => part.kind === "host")?.name;
|
|
175
|
+
const rigName = state.drill.find((part) => part.kind === "rig")?.name;
|
|
176
|
+
const podName = state.drill.find((part) => part.kind === "pod")?.name;
|
|
177
|
+
const found = hostName ? findAgent(snap, leaf.name, { host: hostName, rig: rigName, pod: podName }) : findAgent(snap, leaf.name);
|
|
178
|
+
if (!found)
|
|
179
|
+
return [{ text: `agent "${leaf.name}" not in the current snapshot` }];
|
|
180
|
+
const { agent, rig, pod } = found;
|
|
181
|
+
const specInLibrary = !!agent.spec && !!findSpec(snap, agent.spec);
|
|
182
|
+
// a4c9548a — S19 FOLLOW-ON FOUNDER RULING (binding, bounds the S19 marks
|
|
183
|
+
// ruling): where there is ROOM, WRITE THE NAME — an icon NEVER replaces text
|
|
184
|
+
// as the value. The detail page has room, so the runtime NAME is the VALUE
|
|
185
|
+
// (honest placeholder when unserved); the mark's OWN token segments still ride
|
|
186
|
+
// the seg channel (ROUND-4: colors/background survive stylization) but only
|
|
187
|
+
// ACCOMPANY the name decoratively, never substitute. Topology cards remain
|
|
188
|
+
// mark-only by space (layout.ts/hatchet.ts) — the ruling is bounded, not reversed.
|
|
189
|
+
// LEG-7 LOW 2 (dead-arm cleanup, wave qitem 79159e6f): the daemon coerces a null runtime to the
|
|
190
|
+
// string "unknown" BEFORE the wire (the icon-fix QA at 5a70e200 proved the old "— (not served)"
|
|
191
|
+
// arm unreachable), so the defensive fallback matches that coercion — honest, never a misleading
|
|
192
|
+
// placeholder. (The cwd field below keeps its own "— (not served)" — a legitimately-servable value.)
|
|
193
|
+
const rtName = agent.runtime ?? "unknown";
|
|
194
|
+
const rtSegs = [
|
|
195
|
+
{ text: " " },
|
|
196
|
+
{ text: "runtime:", token: "dim" },
|
|
197
|
+
{ text: " ".repeat(LABEL_W - "runtime:".length + 1) },
|
|
198
|
+
{ text: rtName },
|
|
199
|
+
{ text: " " },
|
|
200
|
+
...runtimeMarkSegs(agent.runtime),
|
|
201
|
+
];
|
|
202
|
+
const runtimeLine = { text: rtSegs.map((g) => g.text).join(""), segs: rtSegs };
|
|
203
|
+
return detailPage({ text: `agent ${agent.name}` }, [
|
|
204
|
+
{
|
|
205
|
+
title: "seat",
|
|
206
|
+
fields: [
|
|
207
|
+
{ label: "state", value: agent.status },
|
|
208
|
+
{ label: "host", value: found.host.name },
|
|
209
|
+
{ label: "rig", value: rig.name },
|
|
210
|
+
{ label: "pod", value: pod.name },
|
|
211
|
+
],
|
|
212
|
+
lines: [
|
|
213
|
+
runtimeLine,
|
|
214
|
+
fieldLine({
|
|
215
|
+
label: "context",
|
|
216
|
+
// ROUND-3 mr7: a quiet determinate bar rides REAL fractions only
|
|
217
|
+
value: agent.context == null
|
|
218
|
+
? "— (not yet known)"
|
|
219
|
+
: `${agent.context}% used · ${agent.tokens ?? "—"} tokens ${barCells(agent.context / 100, 10)}`,
|
|
220
|
+
}),
|
|
221
|
+
// S19 MR4 (§D9, founder: "very important"): the FULL absolute
|
|
222
|
+
// working directory, verbatim; honest — when not served
|
|
223
|
+
fieldLine({ label: "cwd", value: agent.cwd ?? "— (not served)" }),
|
|
224
|
+
],
|
|
225
|
+
},
|
|
226
|
+
{
|
|
227
|
+
title: "spec",
|
|
228
|
+
fields: [
|
|
229
|
+
specInLibrary
|
|
230
|
+
? {
|
|
231
|
+
label: "spec",
|
|
232
|
+
value: agent.spec,
|
|
233
|
+
link: { type: "cross", kind: "spec-of", name: agent.name, target: { host: found.host.name, rig: rig.name, pod: pod.name } },
|
|
234
|
+
}
|
|
235
|
+
: { label: "spec", value: agent.spec ? `${agent.spec} (not in library)` : "—" },
|
|
236
|
+
],
|
|
237
|
+
},
|
|
238
|
+
{
|
|
239
|
+
title: "actions",
|
|
240
|
+
fields: [
|
|
241
|
+
...(agent.attach ? [{ label: "attach", value: agent.attach }] : []),
|
|
242
|
+
{
|
|
243
|
+
label: "terminal",
|
|
244
|
+
value: `term ▸ pod ${pod.name}`,
|
|
245
|
+
link: { type: "act", act: "open-terminal", view: `pod:${rig.name}/${pod.name}` },
|
|
246
|
+
},
|
|
247
|
+
],
|
|
248
|
+
},
|
|
249
|
+
]);
|
|
250
|
+
}
|
|
251
|
+
const rigName = state.drill.find((d) => d.kind === "rig")?.name ?? snap.hosts[0]?.rigs[0]?.name;
|
|
252
|
+
const hostName = state.drill.find((d) => d.kind === "host")?.name;
|
|
253
|
+
const host = (hostName ? snap.hosts.find((candidate) => candidate.name === hostName) : snap.hosts[0]);
|
|
254
|
+
const rig = host?.rigs.find((candidate) => candidate.name === rigName);
|
|
255
|
+
if (!rig || !host) {
|
|
256
|
+
// round-6 (guard): the ROOT topology branch consumes the OWNER's load
|
|
257
|
+
// truth like every other read surface — a real in-flight cold start
|
|
258
|
+
// renders the spinner; after settlement only a NAMED rigs-summary
|
|
259
|
+
// failure or the proven no-rigs truth may render, never "waiting"
|
|
260
|
+
if (motion.loading) {
|
|
261
|
+
if (!motion.reduced)
|
|
262
|
+
motion.used = true;
|
|
263
|
+
return [{ text: `${motion.frame} topology read pending — waiting on the daemon rigs read (honest-empty, not fabricated)` }];
|
|
264
|
+
}
|
|
265
|
+
if (snap.readErrors.some((e) => e.startsWith("rigs-summary"))) {
|
|
266
|
+
return [{ text: "✕ rigs read failed — named in the status line (honest-empty, not fabricated)" }];
|
|
267
|
+
}
|
|
268
|
+
return [{ text: "(no rigs served — proven empty, not fabricated)" }];
|
|
269
|
+
}
|
|
270
|
+
const podFilter = leaf?.kind === "pod" ? leaf.name : null;
|
|
271
|
+
const all = rig.pods.flatMap((p) => p.agents.map((a) => ({ pod: p.name, ...a })));
|
|
272
|
+
const rows = all
|
|
273
|
+
.filter((a) => !podFilter || a.pod === podFilter)
|
|
274
|
+
.filter((a) => !state.filter || a.name.includes(state.filter) || a.pod.includes(state.filter));
|
|
275
|
+
const suffix = `rig ${rig.name}${podFilter ? ` · pod ${podFilter}` : ""}${state.filter ? ` · filter "${state.filter}"` : ""}`;
|
|
276
|
+
lines.push(...tabsLine(state, suffix));
|
|
277
|
+
if (state.viewTab === "graph") {
|
|
278
|
+
// slice-17 topology view (frame-01): the rig's SERVED /graph projection
|
|
279
|
+
// rendered by the style registry; honest-empty until the read answers.
|
|
280
|
+
if (!rig.graph) {
|
|
281
|
+
lines.push({ text: "" });
|
|
282
|
+
// round-5 (guard): the spinner rides the OWNER's in-flight state only;
|
|
283
|
+
// settled absence renders the honest static truth — a NAMED failure or
|
|
284
|
+
// a proven-empty read — and never spins
|
|
285
|
+
if (motion.loading) {
|
|
286
|
+
if (!motion.reduced)
|
|
287
|
+
motion.used = true;
|
|
288
|
+
lines.push({ text: ` ${motion.frame} topology graph read pending (honest-empty, never fabricated)` });
|
|
289
|
+
}
|
|
290
|
+
else if (snap.readErrors.some((e) => e.startsWith(`graph(${rig.name})`))) {
|
|
291
|
+
lines.push({ text: " ✕ topology graph read failed — named in the status line (honest-empty, never fabricated)" });
|
|
292
|
+
}
|
|
293
|
+
else {
|
|
294
|
+
lines.push({ text: " (no topology graph served — honest-empty, never fabricated)" });
|
|
295
|
+
}
|
|
296
|
+
return lines;
|
|
297
|
+
}
|
|
298
|
+
// PER-VIEW zoom (PM b7f95c4b): a pod drill scopes the SAME projection to
|
|
299
|
+
// that pod's containment subgraph — nodes clipped at rig scale become
|
|
300
|
+
// visible AND eligible here; eligibility is always the current view's
|
|
301
|
+
// clipped hit-zone truth, never a global filter.
|
|
302
|
+
let graphView = rig.graph;
|
|
303
|
+
if (podFilter) {
|
|
304
|
+
const podGroup = rig.graph.nodes.find((n) => n.type === "podGroup" && (n.data.podNamespace ?? n.data.logicalId) === podFilter);
|
|
305
|
+
const memberIds = new Set(rig.graph.nodes.filter((n) => n.parentId && n.parentId === podGroup?.id).map((n) => n.id));
|
|
306
|
+
graphView = {
|
|
307
|
+
nodes: rig.graph.nodes.filter((n) => n === podGroup || memberIds.has(n.id)),
|
|
308
|
+
edges: rig.graph.edges.filter((e) => memberIds.has(e.source) && memberIds.has(e.target)),
|
|
309
|
+
};
|
|
310
|
+
}
|
|
311
|
+
const canvas = renderGraphStyle(state.graphStyle, graphView, { host: host.name, rig: rig.name, selected: null }, contentWidth);
|
|
312
|
+
const plain = canvas.plainLines();
|
|
313
|
+
const segs = canvas.segLines();
|
|
314
|
+
for (let row = 0; row < plain.length; row++) {
|
|
315
|
+
lines.push({
|
|
316
|
+
text: plain[row],
|
|
317
|
+
segs: segs[row],
|
|
318
|
+
zones: canvas.zones.filter((z) => z.y === row).map((z) => ({ start: z.start, end: z.end, action: z.action })),
|
|
319
|
+
});
|
|
320
|
+
}
|
|
321
|
+
lines.push({ text: "" });
|
|
322
|
+
lines.push({ text: ` style: ${state.graphStyle} · style hatchet|braille|braille-fallback rides the command bar` });
|
|
323
|
+
return lines;
|
|
324
|
+
}
|
|
325
|
+
lines.push({ text: state.filter ? `/ filter agents: ${state.filter}` : "/ filter agents…" });
|
|
326
|
+
if (state.viewTab === "overview") {
|
|
327
|
+
lines.push(...detailPage({ text: `rig ${rig.name}` }, [
|
|
328
|
+
{
|
|
329
|
+
title: "rig",
|
|
330
|
+
fields: [
|
|
331
|
+
{ label: "host", value: host.name },
|
|
332
|
+
{ label: "shape", value: `${rig.pods.length} pods · ${all.length} agents` },
|
|
333
|
+
...(rig.lifecycleState ? [{ label: "state", value: rig.lifecycleState }] : []),
|
|
334
|
+
],
|
|
335
|
+
},
|
|
336
|
+
{
|
|
337
|
+
title: "pods",
|
|
338
|
+
lines: rig.pods.map((pod) => listItem(alignedRow([[pod.name, 14], [`${pod.agents.length} agents`, 10], [pod.agents.map((a) => a.status).filter((s, i, arr) => arr.indexOf(s) === i).join(" · "), 40]]), { type: "drill", resource: "pod", name: pod.name, target: { host: host.name, rig: rig.name } })),
|
|
339
|
+
},
|
|
340
|
+
]));
|
|
341
|
+
return lines;
|
|
342
|
+
}
|
|
343
|
+
const agentCols = agentColumns(contentWidth);
|
|
344
|
+
lines.push({
|
|
345
|
+
text: tableRow(agentCols, {
|
|
346
|
+
rig: "RIG", pod: "POD", agent: "AGENT", runtime: "RUNTIME",
|
|
347
|
+
context: "CTX%", tokens: "TOKENS", status: "STATUS", actions: "ACTIONS",
|
|
348
|
+
}),
|
|
349
|
+
});
|
|
350
|
+
lines.push({ text: "─".repeat(columnsWidth(agentCols)) });
|
|
351
|
+
const actionsIndex = agentCols.findIndex(([key]) => key === "actions");
|
|
352
|
+
const actionsColStart = agentCols.slice(0, actionsIndex).reduce((n, [, , width]) => n + width + 1, 0);
|
|
353
|
+
for (const a of rows) {
|
|
354
|
+
// ACTIONS = drive-structure ONLY (BR-9), each mapped to an EXISTING
|
|
355
|
+
// write contract: `run ▸` = the rig-restore write (rendered only where
|
|
356
|
+
// it applies — the seat is not running); `term ▸` = the terminal-open
|
|
357
|
+
// view contract (pod-scoped, the web's granularity). No false affordance.
|
|
358
|
+
const canRun = a.canRun ?? !a.live;
|
|
359
|
+
const actionsCell = canRun ? "run ▸ · term ▸" : "term ▸";
|
|
360
|
+
const zones = [];
|
|
361
|
+
const termOffset = actionsColStart + actionsCell.indexOf("term ▸");
|
|
362
|
+
zones.push({ start: termOffset, end: termOffset + "term ▸".length, action: { type: "act", act: "open-terminal", view: `pod:${rig.name}/${a.pod}` } });
|
|
363
|
+
if (canRun)
|
|
364
|
+
zones.push({
|
|
365
|
+
start: actionsColStart,
|
|
366
|
+
end: actionsColStart + "run ▸".length,
|
|
367
|
+
action: { type: "act", act: "run", rigId: rig.id ?? rig.name, agent: a.name },
|
|
368
|
+
});
|
|
369
|
+
lines.push({
|
|
370
|
+
// the WHOLE row is the hit surface (not a testid'd control): clicking
|
|
371
|
+
// any visible cell opens the agent; the ACTIONS zones override.
|
|
372
|
+
text: tableRow(agentCols, {
|
|
373
|
+
rig: rig.name,
|
|
374
|
+
pod: a.pod,
|
|
375
|
+
agent: a.name,
|
|
376
|
+
runtime: a.runtime,
|
|
377
|
+
context: a.context == null ? "—" : `${a.context}%`,
|
|
378
|
+
tokens: a.tokens ?? "—",
|
|
379
|
+
status: a.status,
|
|
380
|
+
actions: actionsCell,
|
|
381
|
+
}),
|
|
382
|
+
action: { type: "drill", resource: "agent", name: a.name, target: { host: host.name, rig: rig.name, pod: a.pod } },
|
|
383
|
+
zones,
|
|
384
|
+
});
|
|
385
|
+
}
|
|
386
|
+
lines.push({ text: "" });
|
|
387
|
+
lines.push({ text: `${rows.length} of ${all.length} / ${rows.filter((agent) => agent.status === "idle").length} idle` });
|
|
388
|
+
return lines;
|
|
389
|
+
}
|
|
390
|
+
if (state.section === "specs") {
|
|
391
|
+
const leaf = state.drill.at(-1);
|
|
392
|
+
if (leaf?.kind === "spec") {
|
|
393
|
+
const spec = findSpec(snap, leaf.name);
|
|
394
|
+
if (!spec)
|
|
395
|
+
return [{ text: `spec "${leaf.name}" not in the current snapshot` }];
|
|
396
|
+
if (spec.kind === "rig") {
|
|
397
|
+
lines.push(specTabsLine(state, spec.name));
|
|
398
|
+
if (spec.sourcePath)
|
|
399
|
+
lines.push(fieldLine({ label: "source", value: `${displayPath(spec.sourcePath, 56)} · ${sourceProvenance(spec)}` }));
|
|
400
|
+
if (state.viewTab === "topology") {
|
|
401
|
+
// ROUND-4 item 1: the established table treatment, not unformatted rows
|
|
402
|
+
const nodes = spec.graph?.nodes ?? [];
|
|
403
|
+
const graphEdges = spec.graph?.edges ?? [];
|
|
404
|
+
const NODE_COLS = [["NODE", 16], ["LABEL", 24], ["POD", 12], ["RUNTIME", 14]];
|
|
405
|
+
lines.push(fieldLine({ label: "shape", value: `${nodes.length} nodes · ${graphEdges.length} edges` }));
|
|
406
|
+
lines.push({ text: "" });
|
|
407
|
+
if (nodes.length === 0) {
|
|
408
|
+
lines.push({ text: " (topology projection is empty)" });
|
|
409
|
+
return lines;
|
|
410
|
+
}
|
|
411
|
+
lines.push({ text: ` ${alignedRow(NODE_COLS)}` });
|
|
412
|
+
lines.push({ text: ` ${"─".repeat(NODE_COLS.reduce((n, [, w]) => n + w + 1, -1))}` });
|
|
413
|
+
for (const node of nodes)
|
|
414
|
+
lines.push({ text: ` ${alignedRow([[node.id, 16], [node.label, 24], [node.pod ?? "—", 12], [node.runtime, 14]])}` });
|
|
415
|
+
if (graphEdges.length > 0) {
|
|
416
|
+
lines.push({ text: "" });
|
|
417
|
+
lines.push(sectionRule("edges"));
|
|
418
|
+
for (const edge of graphEdges)
|
|
419
|
+
lines.push({ text: ` ${alignedRow([[edge.source, 16], ["→", 2], [edge.target, 20]])} (${edge.kind})` });
|
|
420
|
+
}
|
|
421
|
+
return lines;
|
|
422
|
+
}
|
|
423
|
+
if (state.viewTab === "yaml") {
|
|
424
|
+
for (const rawLine of (spec.raw ?? "# raw YAML unavailable").split("\n"))
|
|
425
|
+
lines.push({ text: ` ${rawLine}` });
|
|
426
|
+
return lines;
|
|
427
|
+
}
|
|
428
|
+
const members = spec.pods?.reduce((count, pod) => count + pod.members.length, 0) ?? spec.legacyNodes?.length ?? 0;
|
|
429
|
+
const edges = (spec.edges?.length ?? 0) + (spec.pods?.reduce((count, pod) => count + pod.edges.length, 0) ?? 0);
|
|
430
|
+
lines.push(...detailPage({ text: "" }, [
|
|
431
|
+
{
|
|
432
|
+
fields: [
|
|
433
|
+
...(spec.format ? [{ label: "format", value: spec.format.replace("_", "-") }] : []),
|
|
434
|
+
{ label: "shape", value: `${spec.pods?.length ?? 0} pods · ${members} members · ${edges} edges` },
|
|
435
|
+
],
|
|
436
|
+
},
|
|
437
|
+
...(spec.pods ?? []).map((pod) => ({
|
|
438
|
+
title: `pod ${pod.namespace ?? pod.id}${pod.label ? ` — ${pod.label}` : ""}`,
|
|
439
|
+
lines: [
|
|
440
|
+
...pod.members.map((member) => listItem(`${alignedRow([[member.id, 12], [member.agentRef, 34], [member.runtime, 12]])}${member.profile ? ` profile ${member.profile}` : ""}`, { type: "drill", resource: "spec", name: member.agentRef })),
|
|
441
|
+
...pod.edges.map((edge) => ({ text: ` ${edge.from} → ${edge.to} (${edge.kind})` })),
|
|
442
|
+
// an empty pod still exists — render it honestly, never skip it
|
|
443
|
+
...(pod.members.length === 0 && pod.edges.length === 0 ? [{ text: " (no members)" }] : []),
|
|
444
|
+
],
|
|
445
|
+
})),
|
|
446
|
+
...(spec.legacyNodes?.length
|
|
447
|
+
? [{ title: "nodes", lines: spec.legacyNodes.map((node) => listItem(`${alignedRow([[node.id, 16], [node.runtime, 12]])}${node.role ? ` ${node.role}` : ""}`)) }]
|
|
448
|
+
: []),
|
|
449
|
+
...((spec.edges?.length ?? 0) > 0
|
|
450
|
+
? [{ title: "cross-pod edges", lines: (spec.edges ?? []).map((edge) => ({ text: ` ${edge.from} → ${edge.to} (${edge.kind})` })) }]
|
|
451
|
+
: []),
|
|
452
|
+
]).slice(1));
|
|
453
|
+
}
|
|
454
|
+
else if (spec.kind === "workflow") {
|
|
455
|
+
lines.push(...detailPage({ text: `workflow spec ${spec.name}${spec.version ? ` · v${spec.version}` : ""}` }, [
|
|
456
|
+
{
|
|
457
|
+
title: "workflow",
|
|
458
|
+
fields: [
|
|
459
|
+
{ label: "roles", value: spec.rolesCount != null ? String(spec.rolesCount) : "—" },
|
|
460
|
+
{ label: "steps", value: spec.stepsCount != null ? String(spec.stepsCount) : "—" },
|
|
461
|
+
{ label: "status", value: spec.workflowStatus ?? "—" },
|
|
462
|
+
],
|
|
463
|
+
},
|
|
464
|
+
{
|
|
465
|
+
title: "source",
|
|
466
|
+
fields: [{ label: "source", value: spec.sourcePath ? `${displayPath(spec.sourcePath)} · ${sourceProvenance(spec)}` : "—" }],
|
|
467
|
+
},
|
|
468
|
+
]));
|
|
469
|
+
}
|
|
470
|
+
else {
|
|
471
|
+
// the mockup's agent-spec frame IS the field-grid reference — recreate it
|
|
472
|
+
const seats = agentsRunningSpec(snap, spec.name);
|
|
473
|
+
const resources = [
|
|
474
|
+
spec.resources?.guidance.length ? `guidance ${spec.resources.guidance.join(", ")}` : "",
|
|
475
|
+
spec.resources?.plugins.length ? `plugins ${spec.resources.plugins.join(", ")}` : "",
|
|
476
|
+
spec.resources?.subagents.length ? `subagents ${spec.resources.subagents.join(", ")}` : "",
|
|
477
|
+
].filter(Boolean);
|
|
478
|
+
lines.push(...detailPage({ text: `agent spec ${spec.name}${spec.version ? ` · v${spec.version}` : ""}` }, [
|
|
479
|
+
{
|
|
480
|
+
title: "spec",
|
|
481
|
+
fields: [
|
|
482
|
+
...(spec.description ? [{ label: "about", value: spec.description }] : []),
|
|
483
|
+
{ label: "runtime", value: spec.runtime ?? "—" },
|
|
484
|
+
],
|
|
485
|
+
lines: spec.skills ? fieldWrapped("skills", spec.skills) : [],
|
|
486
|
+
},
|
|
487
|
+
{
|
|
488
|
+
title: "startup",
|
|
489
|
+
fields: [
|
|
490
|
+
...(spec.hasGuidance != null ? [{ label: "guidance", value: spec.hasGuidance ? "yes" : "no" }] : []),
|
|
491
|
+
...(spec.startupFiles ?? []).map((f) => ({ label: "startup", value: `${f.path}${f.required ? " (required)" : ""}` })),
|
|
492
|
+
...(spec.profiles?.length ? [{ label: "profiles", value: spec.profiles.join(", ") }] : []),
|
|
493
|
+
...(spec.resources ? [{ label: "resources", value: resources.join(" · ") || "(none beyond skills)" }] : []),
|
|
494
|
+
],
|
|
495
|
+
},
|
|
496
|
+
{
|
|
497
|
+
title: "source",
|
|
498
|
+
fields: [{ label: "source", value: spec.sourcePath ? `${displayPath(spec.sourcePath, 56)} · ${sourceProvenance(spec)}` : "—" }],
|
|
499
|
+
},
|
|
500
|
+
{
|
|
501
|
+
title: "where it runs",
|
|
502
|
+
fields: [
|
|
503
|
+
...((spec.usedByRigs?.length ?? 0) === 0
|
|
504
|
+
? [{ label: "used by", value: "—" }]
|
|
505
|
+
: (spec.usedByRigs ?? []).map((rig) => ({
|
|
506
|
+
label: "used by",
|
|
507
|
+
value: `rig ${rig}`,
|
|
508
|
+
link: { type: "drill", resource: "spec", name: rig },
|
|
509
|
+
}))),
|
|
510
|
+
{
|
|
511
|
+
label: "seats now",
|
|
512
|
+
value: seats.join(", ") || "(none)",
|
|
513
|
+
link: { type: "cross", kind: "running", name: spec.name },
|
|
514
|
+
},
|
|
515
|
+
],
|
|
516
|
+
},
|
|
517
|
+
]));
|
|
518
|
+
}
|
|
519
|
+
return lines;
|
|
520
|
+
}
|
|
521
|
+
lines.push({ text: "SPEC LIBRARY" });
|
|
522
|
+
lines.push({ text: state.filter ? `/ filter specs: ${state.filter}` : "/ filter specs…" });
|
|
523
|
+
// mirrors the explorer exactly (same grouping, same expansion state, same
|
|
524
|
+
// filter-overrides-collapse rule) — glance consistency across panes
|
|
525
|
+
const expandedSet = new Set(state.expanded);
|
|
526
|
+
for (const kind of ["rig", "agent", "workflow"]) {
|
|
527
|
+
const shown = snap.specs.filter((s) => s.kind === kind).filter((s) => !state.filter || s.name.includes(state.filter));
|
|
528
|
+
if (shown.length === 0 && !snap.specs.some((s) => s.kind === kind))
|
|
529
|
+
continue;
|
|
530
|
+
lines.push({ text: ` ${kind.toUpperCase()} (${shown.length})` });
|
|
531
|
+
if (kind !== "agent") {
|
|
532
|
+
for (const s of shown)
|
|
533
|
+
lines.push({ text: ` ▪ ${s.name}`, action: { type: "drill", resource: "spec", name: s.name } });
|
|
534
|
+
continue;
|
|
535
|
+
}
|
|
536
|
+
const groups = new Map();
|
|
537
|
+
for (const s of shown) {
|
|
538
|
+
const namespace = s.namespace ?? "(root)";
|
|
539
|
+
groups.set(namespace, [...(groups.get(namespace) ?? []), s]);
|
|
540
|
+
}
|
|
541
|
+
for (const [namespace, specs] of [...groups.entries()].sort(([a], [b]) => a.localeCompare(b))) {
|
|
542
|
+
const open = namespace === "(root)" || expandedSet.has(`folder:${namespace}`) || !!state.filter;
|
|
543
|
+
if (namespace !== "(root)")
|
|
544
|
+
lines.push({
|
|
545
|
+
text: ` ${open ? "▾" : "▸"} ${namespace}/ (${specs.length})`,
|
|
546
|
+
action: { type: "toggle-expand", key: `folder:${namespace}` },
|
|
547
|
+
});
|
|
548
|
+
if (!open)
|
|
549
|
+
continue;
|
|
550
|
+
for (const s of specs)
|
|
551
|
+
lines.push({
|
|
552
|
+
text: `${namespace === "(root)" ? " " : " "}▪ ${s.name}`,
|
|
553
|
+
action: { type: "drill", resource: "spec", name: s.name },
|
|
554
|
+
});
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
if (snap.specs.length === 0) {
|
|
558
|
+
// round-5 (guard): spin only while the owner is loading; settled empty
|
|
559
|
+
// is PROVEN empty and a settled failure is named — neither spins
|
|
560
|
+
if (motion.loading) {
|
|
561
|
+
if (!motion.reduced)
|
|
562
|
+
motion.used = true;
|
|
563
|
+
lines.push({ text: ` ${motion.frame} library read pending — honest-empty` });
|
|
564
|
+
}
|
|
565
|
+
else if (snap.readErrors.some((e) => e.startsWith("specs-library"))) {
|
|
566
|
+
lines.push({ text: " ✕ library read failed — named in the status line" });
|
|
567
|
+
}
|
|
568
|
+
else {
|
|
569
|
+
lines.push({ text: " (library empty — proven, no specs served)" });
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
return lines;
|
|
573
|
+
}
|
|
574
|
+
if (state.section === "needs") {
|
|
575
|
+
lines.push({ text: "NEEDS-YOU" });
|
|
576
|
+
for (const item of snap.needs) {
|
|
577
|
+
// open/navigate is the ONLY in-TUI action (B3): the click target joins
|
|
578
|
+
// the item's session back to topology; unresolvable targets never
|
|
579
|
+
// advertise a control that can only fail.
|
|
580
|
+
lines.push(needsLine(item.source === "agent" ? " ☐ " : " ⚑ ", item, snap));
|
|
581
|
+
}
|
|
582
|
+
if (snap.needs.length === 0 && snap.humanQueueProbed)
|
|
583
|
+
lines.push({ text: " (no fleet attention items right now)" });
|
|
584
|
+
if (snap.hostsDown.length > 0) {
|
|
585
|
+
// composed BESIDE the items (a separate shipped read), never into the item shape
|
|
586
|
+
lines.push({ text: "" });
|
|
587
|
+
lines.push({ text: " hosts/rigs down:" });
|
|
588
|
+
// NB: glyphs here must be single-cell — U+26D4 ⛔ is emoji-width (2 cells)
|
|
589
|
+
// and wraps a full-width padded line, shearing every row below it.
|
|
590
|
+
for (const h of snap.hostsDown)
|
|
591
|
+
lines.push({ text: ` ✖ ${alignedRow([[h.hostId, 28], [h.status, 26]])} ${h.error ?? ""}`.trimEnd() });
|
|
592
|
+
}
|
|
593
|
+
lines.push({ text: "" });
|
|
594
|
+
if (!snap.humanQueueProbed) {
|
|
595
|
+
if (motion.loading) {
|
|
596
|
+
// region discipline (max ONE persistent animation): while a derived ⚑
|
|
597
|
+
// item pulses on this page, the pending spinner degrades to the honest
|
|
598
|
+
// static dot instead of animating beside it
|
|
599
|
+
const pulseVisible = snap.needs.some((item) => item.source === "derived") && !motion.reduced;
|
|
600
|
+
const spin = pulseVisible ? "·" : motion.frame;
|
|
601
|
+
if (!pulseVisible && !motion.reduced)
|
|
602
|
+
motion.used = true;
|
|
603
|
+
lines.push({ text: ` ${spin} human-queue: not yet known (read pending)` });
|
|
604
|
+
}
|
|
605
|
+
else {
|
|
606
|
+
// round-5 (guard): settled-unprobed is a static truth (hosts down or
|
|
607
|
+
// registry unavailable) — "(read pending)" would be a false claim
|
|
608
|
+
lines.push({ text: " human-queue: not yet known (hosts unreachable or registry unavailable)" });
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
else if (!snap.needs.some((item) => item.source === "agent"))
|
|
612
|
+
lines.push({ text: " human-queue: no items (proven empty — surfacing adoption pending)" });
|
|
613
|
+
return lines;
|
|
614
|
+
}
|
|
615
|
+
return [{ text: `(${state.section})` }];
|
|
616
|
+
}
|
|
617
|
+
/** replace ONE character at a plain-text position inside a token-segment row
|
|
618
|
+
* with the keyboard focus marker (accent, bold) — keeps plain(segs) equal to
|
|
619
|
+
* the spliced content text (R2 HIGH-3) */
|
|
620
|
+
function spliceMarkerIntoSegs(segs, pos) {
|
|
621
|
+
const out = [];
|
|
622
|
+
let at = 0;
|
|
623
|
+
for (const seg of segs) {
|
|
624
|
+
const end = at + seg.text.length;
|
|
625
|
+
if (pos >= at && pos < end) {
|
|
626
|
+
const off = pos - at;
|
|
627
|
+
if (off > 0)
|
|
628
|
+
out.push({ ...seg, text: seg.text.slice(0, off) });
|
|
629
|
+
out.push({ text: "›", token: "accent", bold: true });
|
|
630
|
+
if (off + 1 < seg.text.length)
|
|
631
|
+
out.push({ ...seg, text: seg.text.slice(off + 1) });
|
|
632
|
+
}
|
|
633
|
+
else {
|
|
634
|
+
out.push(seg);
|
|
635
|
+
}
|
|
636
|
+
at = end;
|
|
637
|
+
}
|
|
638
|
+
return out;
|
|
639
|
+
}
|
|
640
|
+
function paneRule(cols, joint, leftTitle, rightTitle) {
|
|
641
|
+
const left = leftTitle ? `─ ${leftTitle} ` : "";
|
|
642
|
+
const right = rightTitle ? `─ ${rightTitle} ` : "";
|
|
643
|
+
const leftPart = (left + "─".repeat(EXPL_W)).slice(0, EXPL_W);
|
|
644
|
+
const rightPart = (right + "─".repeat(cols)).slice(0, Math.max(cols - EXPL_W - 1, 0));
|
|
645
|
+
return `${leftPart}${joint}${rightPart}`;
|
|
646
|
+
}
|
|
647
|
+
function keybindHints(state) {
|
|
648
|
+
// Affordance surfaces on REAL scrollability (contentMaxOffset), never gated
|
|
649
|
+
// behind already-being-content-focused — that gate was the catch-22 (the
|
|
650
|
+
// hint hid exactly where it was needed). When ↑↓ themselves scroll (a
|
|
651
|
+
// scrollable spec detail), the nav label says so; otherwise ↑↓ move and the
|
|
652
|
+
// page keys carry the scroll.
|
|
653
|
+
const arrowsScroll = specDetailArrowsScroll(state);
|
|
654
|
+
const nav = arrowsScroll ? "↑↓ scroll" : "↑↓ move";
|
|
655
|
+
const pageScroll = state.contentMaxOffset > 0 && !arrowsScroll ? "⇞⇟ scroll · " : "";
|
|
656
|
+
return `${nav} · ←→ pane · ⏎ open · ${pageScroll}: command · / filter · f footer · q quit`;
|
|
657
|
+
}
|
|
658
|
+
export function renderScreen(state, snap, options = {}, inputLine = "") {
|
|
659
|
+
const { cols = 120, rows = 32, nowMs = 0 } = options;
|
|
660
|
+
// S19 round-5 (guard): one spinner frame per render pass from caller time;
|
|
661
|
+
// `loading` comes from the refresh OWNER (omitted = settled — demo/fixture
|
|
662
|
+
// data IS the answer); reduced-motion kills all of it
|
|
663
|
+
const reduced = reducedMotion();
|
|
664
|
+
const load = options.load ?? { inFlight: false, settled: true };
|
|
665
|
+
const motion = {
|
|
666
|
+
frame: spinnerFrame(Math.floor(nowMs / 120), options.colorMode ?? "truecolor", reduced),
|
|
667
|
+
reduced,
|
|
668
|
+
used: false,
|
|
669
|
+
loading: load.inFlight || !load.settled,
|
|
670
|
+
};
|
|
671
|
+
const lines = [];
|
|
672
|
+
const hitMap = [];
|
|
673
|
+
// S19 MR5a (guard-corrected): ONE ▊ insertion cell renders at the bar's
|
|
674
|
+
// current insertion point for EMPTY and non-empty buffers alike — the
|
|
675
|
+
// shell accepts typing from the empty state, so the honest readiness
|
|
676
|
+
// affordance must show BEFORE the first key (no new focus state; stylize
|
|
677
|
+
// gives the cell SGR blink; zero effect on hit geometry).
|
|
678
|
+
lines.push(pad(`cmd ▸ ${inputLine}▊`, cols));
|
|
679
|
+
const sectionTitle = { topology: "TOPOLOGY", specs: "SPECS", needs: "NEEDS-YOU" }[state.section] ?? state.section.toUpperCase();
|
|
680
|
+
// active-pane emphasis (k9s-class chrome): the focused pane's title is bracketed
|
|
681
|
+
const explorerTitle = state.focusedPane === "explorer" ? "[ EXPLORER ]" : "EXPLORER";
|
|
682
|
+
const contentTitle = state.focusedPane === "content" ? `[ ${sectionTitle} ]` : sectionTitle;
|
|
683
|
+
lines.push(paneRule(cols, "┬", explorerTitle, contentTitle));
|
|
684
|
+
const explorer = computeExplorerRows(state, snap);
|
|
685
|
+
// Slice-17: the file-tree re-skin is a DISPLAY transform only — rows, keys,
|
|
686
|
+
// actions, and the hit-map all keep resolving against the row model above.
|
|
687
|
+
const { labels: explorerDisplay, metas: explorerMetas } = navigatorDisplay(explorer, snap, EXPL_W - 1);
|
|
688
|
+
const content = contentLines(state, snap, Math.max(cols - EXPL_W - 2, 0), motion);
|
|
689
|
+
const footer = state.footerOn ? snap.stream.at(-1) : undefined;
|
|
690
|
+
// round-5 (guard): the tmux-style ONE-SHOT activity flash targets the
|
|
691
|
+
// flashed agent's EXPLORER row — per-seat pane-output events from the
|
|
692
|
+
// refresh owner, windowed here. The ambient rig-stream footer is NOT an
|
|
693
|
+
// event source and never flashes. round-6 (guard finding 2): the SGR
|
|
694
|
+
// inverse is the animation (killed under reduced motion), while the
|
|
695
|
+
// acknowledgement WINDOW itself ignores reduced — the plain-layer "≈"
|
|
696
|
+
// marker-slot glyph is the stable static signal reduced motion (and
|
|
697
|
+
// NO_COLOR) keeps, expiring with the same bounded window.
|
|
698
|
+
const liveFlashes = (options.rowFlashes ?? []).filter((f) => flashActive(f.at, nowMs, 600, reduced));
|
|
699
|
+
const ackFlashes = (options.rowFlashes ?? []).filter((f) => flashActive(f.at, nowMs, 600, false));
|
|
700
|
+
const chromeRows = footer ? 4 : 3; // bottom rule + hint bar + status line (+ footer)
|
|
701
|
+
const bodyRows = Math.max(rows - 2 - chromeRows, 1);
|
|
702
|
+
const explorerStart = Math.min(Math.max(state.selection - bodyRows + 1, 0), Math.max(explorer.length - bodyRows, 0));
|
|
703
|
+
const contentRows = content.length > bodyRows ? Math.max(bodyRows - 1, 0) : bodyRows;
|
|
704
|
+
const maxContentOffset = Math.max(content.length - contentRows, 0);
|
|
705
|
+
const contentStart = Math.min(state.contentOffset, maxContentOffset);
|
|
706
|
+
const visibleContent = content.slice(contentStart, contentStart + contentRows);
|
|
707
|
+
if (content.length > bodyRows) {
|
|
708
|
+
const scrollText = `scroll ↑/↓ · ${contentStart + 1}-${contentStart + visibleContent.length} of ${content.length}`;
|
|
709
|
+
const up = scrollText.indexOf("↑");
|
|
710
|
+
const down = scrollText.indexOf("↓");
|
|
711
|
+
visibleContent.push({
|
|
712
|
+
text: scrollText,
|
|
713
|
+
zones: [
|
|
714
|
+
{ start: up, end: up + 1, action: { type: "content-scroll", delta: -10 } },
|
|
715
|
+
{ start: down, end: down + 1, action: { type: "content-scroll", delta: 10 } },
|
|
716
|
+
],
|
|
717
|
+
});
|
|
718
|
+
}
|
|
719
|
+
const explorerRows = [];
|
|
720
|
+
const contentTargets = [];
|
|
721
|
+
const segRows = {};
|
|
722
|
+
const explorerMeta = {};
|
|
723
|
+
const flashRows = [];
|
|
724
|
+
let flashAck = false;
|
|
725
|
+
for (let i = 0; i < bodyRows; i++) {
|
|
726
|
+
const y = lines.length + 1; // 1-based terminal row this line will occupy
|
|
727
|
+
const explorerIndex = explorerStart + i;
|
|
728
|
+
const row = explorer[explorerIndex];
|
|
729
|
+
// round-6/7 (guard): the fresh-output ack rides the marker slot (zero
|
|
730
|
+
// geometry drift). Collision matrix: a SELECTED flashed row shows "»" —
|
|
731
|
+
// still unmistakably the selection chevron, while visibly distinct from
|
|
732
|
+
// both the plain "›" baseline and the unselected "≈" ack — so neither
|
|
733
|
+
// signal is lost under reduced motion / NO_COLOR; expiry returns the
|
|
734
|
+
// exact "›" baseline
|
|
735
|
+
const flashed = row?.key != null && ackFlashes.some((f) => f.key === row.key);
|
|
736
|
+
if (flashed)
|
|
737
|
+
flashAck = true;
|
|
738
|
+
const marker = explorerIndex === state.selection && row ? (flashed ? "»" : "›") : flashed ? "≈" : " ";
|
|
739
|
+
const left = pad(row ? `${marker}${explorerDisplay[explorerIndex] ?? row.label}` : "", EXPL_W);
|
|
740
|
+
const item = visibleContent[i];
|
|
741
|
+
const targetIndex = contentTargets.length;
|
|
742
|
+
const zones = item?.zones ?? [];
|
|
743
|
+
const selectedOnLine = state.focusedPane === "content" ? state.contentSelection - targetIndex : -1;
|
|
744
|
+
const selectedZone = selectedOnLine >= 0 && selectedOnLine < zones.length ? zones[selectedOnLine] : undefined;
|
|
745
|
+
const selectedAction = !!item?.action && selectedOnLine === zones.length;
|
|
746
|
+
let contentText = item?.text ?? "";
|
|
747
|
+
let contentMarker = selectedAction ? "›" : " ";
|
|
748
|
+
let rowSegs = item?.segs;
|
|
749
|
+
if (selectedZone) {
|
|
750
|
+
if (selectedZone.start > 0) {
|
|
751
|
+
contentText = `${contentText.slice(0, selectedZone.start - 1)}›${contentText.slice(selectedZone.start)}`;
|
|
752
|
+
// R2 HIGH-3: a segs row's paint source must carry the SAME splice the
|
|
753
|
+
// plain text carries, or stylization erases the keyboard focus marker
|
|
754
|
+
if (rowSegs)
|
|
755
|
+
rowSegs = spliceMarkerIntoSegs(rowSegs, selectedZone.start - 1);
|
|
756
|
+
}
|
|
757
|
+
else
|
|
758
|
+
contentMarker = "›";
|
|
759
|
+
}
|
|
760
|
+
lines.push(pad(`${left}│${contentMarker}${contentText}`, cols));
|
|
761
|
+
if (row) {
|
|
762
|
+
hitMap.push({ y, x1: 1, x2: EXPL_W, action: row.action });
|
|
763
|
+
explorerRows.push({ ...row, y });
|
|
764
|
+
const em = explorerMetas[explorerIndex];
|
|
765
|
+
if (em && em.length)
|
|
766
|
+
explorerMeta[y] = em.map((run) => ({ start: 1 + run.start, segs: run.segs })); // +1 = marker slot
|
|
767
|
+
if (row.key && liveFlashes.some((f) => f.key === row.key))
|
|
768
|
+
flashRows.push(y);
|
|
769
|
+
}
|
|
770
|
+
// zones first: hit lookup takes the first match, so a zone wins over the row-wide action
|
|
771
|
+
for (const z of zones) {
|
|
772
|
+
const target = { y, x1: EXPL_W + 3 + z.start, x2: EXPL_W + 2 + z.end, action: z.action };
|
|
773
|
+
hitMap.push(target);
|
|
774
|
+
contentTargets.push(target);
|
|
775
|
+
}
|
|
776
|
+
if (item?.action) {
|
|
777
|
+
const target = { y, x1: EXPL_W + 3, x2: cols, action: item.action };
|
|
778
|
+
hitMap.push(target);
|
|
779
|
+
contentTargets.push(target);
|
|
780
|
+
}
|
|
781
|
+
if (rowSegs)
|
|
782
|
+
segRows[y] = rowSegs;
|
|
783
|
+
}
|
|
784
|
+
if (footer)
|
|
785
|
+
lines.push(pad(`≋ ${footer.tsEmitted.slice(11, 16)} ${footer.sourceSession}: ${footer.body}`, cols));
|
|
786
|
+
const drillPath = state.drill.map((d) => d.name).join(" → ");
|
|
787
|
+
const readWarn = snap.readErrors.length > 0 ? ` ⚠ ${snap.readErrors.length} read(s) failed: ${snap.readErrors[0]}` : "";
|
|
788
|
+
lines.push(paneRule(cols, "┴"));
|
|
789
|
+
lines.push(pad(keybindHints(state), cols));
|
|
790
|
+
lines.push(pad(`[${state.instanceId}] ${state.section}${drillPath ? " · " + drillPath : ""}${state.lastError ? " ✗ " + state.lastError : ""}${state.notice ? " ▸ " + state.notice : ""}${readWarn}`, cols));
|
|
791
|
+
while (lines.length < rows)
|
|
792
|
+
lines.push("");
|
|
793
|
+
return {
|
|
794
|
+
lines: lines.slice(0, rows),
|
|
795
|
+
hitMap,
|
|
796
|
+
contentTargets,
|
|
797
|
+
contentMaxOffset: maxContentOffset,
|
|
798
|
+
explorerRows,
|
|
799
|
+
segRows,
|
|
800
|
+
explorerMeta,
|
|
801
|
+
flashRows,
|
|
802
|
+
// an un-expired ack (even the static reduced-motion glyph) schedules the
|
|
803
|
+
// bounded expiry redraw — the acknowledgement must settle cleanly
|
|
804
|
+
motionActive: motion.used || flashRows.length > 0 || flashAck,
|
|
805
|
+
};
|
|
806
|
+
}
|
|
807
|
+
//# sourceMappingURL=render.js.map
|