pi-crew 0.11.0 → 0.11.2
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/CHANGELOG.md +155 -9
- package/README.md +161 -1037
- package/agents/verifier.md +18 -7
- package/dist/index.mjs +744 -90644
- package/docs/README.md +57 -46
- package/docs/architecture.md +87 -33
- package/docs/commands-reference.md +9 -5
- package/docs/troubleshooting.md +3 -2
- package/package.json +1 -3
- package/schema.json +39 -0
- package/skills/real-test-pi-crew/REPORT-TEMPLATE.md +2 -0
- package/skills/real-test-pi-crew/SKILL.md +371 -34
- package/src/agents/agent-config.ts +1 -1
- package/src/agents/discover-agents.ts +1 -1
- package/src/config/config-validation.ts +15 -2
- package/src/config/config.ts +47 -13
- package/src/config/defaults.ts +0 -1
- package/src/config/env-vars.ts +35 -0
- package/src/config/types.ts +19 -5
- package/src/errors.ts +2 -2
- package/src/extension/async-notifier.ts +23 -0
- package/src/extension/crew-vibes/config.ts +0 -21
- package/src/extension/crew-vibes/index.ts +0 -2
- package/src/extension/crew-vibes/render.ts +1 -50
- package/src/extension/help.ts +21 -12
- package/src/extension/knowledge-injection.ts +2 -1
- package/src/extension/management.ts +8 -3
- package/src/extension/notification-sink.ts +17 -0
- package/src/extension/register.ts +7 -2
- package/src/extension/registration/command-utils.ts +28 -2
- package/src/extension/registration/commands/dashboard.ts +11 -1
- package/src/extension/registration/commands/manage.ts +36 -19
- package/src/extension/registration/commands/run.ts +24 -2
- package/src/extension/registration/commands/shared.ts +23 -1
- package/src/extension/registration/commands/status.ts +25 -2
- package/src/extension/registration/context-builder.ts +8 -2
- package/src/extension/registration/health-notify-policy.ts +100 -0
- package/src/extension/registration/lazy-configurers.ts +35 -0
- package/src/extension/registration/lifecycle-handlers.ts +91 -30
- package/src/extension/registration/lifecycle.ts +75 -10
- package/src/extension/registration/observability.ts +98 -35
- package/src/extension/registration/registration-types.ts +7 -5
- package/src/extension/registration/runtime-cleanup.ts +9 -3
- package/src/extension/registration/subagent-helpers.ts +38 -0
- package/src/extension/registration/subagent-tools.ts +16 -6
- package/src/extension/registration/team-tool.ts +10 -3
- package/src/extension/registration/terminal-status-wiring.ts +172 -0
- package/src/extension/registration/viewers.ts +6 -0
- package/src/extension/registration/wire-cross-extension.ts +28 -0
- package/src/extension/run-compare.ts +220 -0
- package/src/extension/run-export.ts +37 -5
- package/src/extension/run-maintenance.ts +155 -5
- package/src/extension/team-tool/dispatch/index.ts +3 -2
- package/src/extension/team-tool/dispatch/manage.ts +5 -2
- package/src/extension/team-tool/goal.ts +4 -1
- package/src/extension/team-tool/handle-settings.ts +33 -4
- package/src/extension/team-tool/health-monitor.ts +21 -7
- package/src/extension/team-tool/lifecycle-actions.ts +49 -1
- package/src/extension/team-tool/plan.ts +10 -0
- package/src/extension/team-tool/routing-hint.ts +63 -0
- package/src/extension/team-tool/status.ts +4 -0
- package/src/extension/team-tool.ts +52 -6
- package/src/extension/webhook-notify.ts +382 -0
- package/src/observability/metric-sink.ts +12 -2
- package/src/prompt/prompt-runtime.ts +82 -31
- package/src/prompt/worker-events-channel.ts +12 -0
- package/src/runtime/README.md +1 -1
- package/src/runtime/async-runner.ts +87 -1
- package/src/runtime/background-runner.ts +313 -234
- package/src/runtime/broker/crew-broker.ts +17 -11
- package/src/runtime/broker/delegate/shadow-lifecycle.ts +92 -0
- package/src/runtime/broker/wait-status-cache.ts +1 -1
- package/src/runtime/child-pi/child-pi-timers.ts +1 -1
- package/src/runtime/child-pi/mock-fixtures.ts +48 -0
- package/src/runtime/crew-agent-records.ts +337 -45
- package/src/runtime/deadletter.ts +43 -1
- package/src/runtime/delegate-spawn.ts +5 -1
- package/src/runtime/dispatch-batch.ts +72 -5
- package/src/runtime/goal-workflow/goal-loop-runner.ts +73 -4
- package/src/runtime/heartbeat/heartbeat-watcher.ts +7 -0
- package/src/runtime/model/model-fallback.ts +21 -1
- package/src/runtime/model/pi-args.ts +8 -10
- package/src/runtime/recovery/crash-recovery.ts +25 -1
- package/src/runtime/run-worker.ts +12 -1
- package/src/runtime/scheduling/global-worker-cap.ts +13 -6
- package/src/runtime/scheduling/run-coalesced-task-group.ts +27 -1
- package/src/runtime/scheduling/scheduler.ts +49 -13
- package/src/runtime/scheduling/semaphore.ts +148 -20
- package/src/runtime/scratchpad/README.md +1 -1
- package/src/runtime/scratchpad/protocol.ts +1 -1
- package/src/runtime/settings-store.ts +1 -1
- package/src/runtime/skill-instructions.ts +22 -0
- package/src/runtime/stale-reconciler.ts +85 -13
- package/src/runtime/task-display.ts +1 -1
- package/src/runtime/task-runner/pre-execution.ts +26 -2
- package/src/runtime/task-runner/prompt-builder.ts +142 -45
- package/src/runtime/task-runner.ts +21 -1
- package/src/runtime/team-runner.ts +38 -1
- package/src/runtime/workspace-lock.ts +4 -1
- package/src/schema/config-schema.ts +18 -0
- package/src/schema/team-tool-schema.ts +17 -0
- package/src/state/atomic-write.ts +53 -0
- package/src/state/contracts.ts +109 -0
- package/src/state/coordination/locks.ts +191 -33
- package/src/state/coordination/mailbox.ts +140 -15
- package/src/state/crew-init.ts +87 -12
- package/src/state/event-log/cursor.ts +37 -1
- package/src/state/event-log/event-log-rotation.ts +72 -7
- package/src/state/stores/active-run-registry.ts +13 -1
- package/src/state/stores/state-store.ts +112 -22
- package/src/state/types.ts +4 -0
- package/src/ui/adaptive-card.ts +65 -0
- package/src/ui/agents-jobs-browser.ts +70 -64
- package/src/ui/card-colors.ts +36 -7
- package/src/ui/dashboard-panes/agents-pane.ts +55 -14
- package/src/ui/dashboard-panes/cancellation-pane.ts +0 -42
- package/src/ui/dashboard-panes/health-pane.ts +7 -5
- package/src/ui/dashboard-panes/mailbox-pane.ts +22 -6
- package/src/ui/dashboard-panes/metrics-pane.ts +15 -7
- package/src/ui/dashboard-panes/pane-theme.ts +21 -0
- package/src/ui/dashboard-panes/plan-pane.ts +63 -30
- package/src/ui/dashboard-panes/progress-pane.ts +3 -2
- package/src/ui/dashboard-panes/schedules-pane.ts +44 -21
- package/src/ui/dashboard-panes/transcript-pane.ts +11 -5
- package/src/ui/dwf-phase-display.ts +3 -20
- package/src/ui/format-helpers.ts +22 -0
- package/src/ui/heartbeat-aggregator.ts +34 -0
- package/src/ui/inline-panel/crew-editor.ts +13 -3
- package/src/ui/inline-panel/index.ts +60 -4
- package/src/ui/keybinding-map.ts +251 -35
- package/src/ui/live-conversation-overlay.ts +180 -47
- package/src/ui/live-run-sidebar.ts +134 -55
- package/src/ui/mascot.ts +32 -16
- package/src/ui/overlays/agent-picker-overlay.ts +81 -26
- package/src/ui/overlays/confirm-overlay.ts +55 -29
- package/src/ui/overlays/help-overlay.ts +108 -53
- package/src/ui/overlays/mailbox-compose-overlay.ts +89 -50
- package/src/ui/overlays/mailbox-detail-overlay.ts +137 -57
- package/src/ui/powerbar-publisher.ts +0 -1
- package/src/ui/rail.ts +333 -0
- package/src/ui/run-dashboard.ts +193 -79
- package/src/ui/run-snapshot-cache.ts +18 -1
- package/src/ui/settings-overlay.ts +81 -39
- package/src/ui/spinner.ts +26 -2
- package/src/ui/terminal-status.ts +7 -1
- package/src/ui/theme-adapter.ts +0 -45
- package/src/ui/theme-discovery.ts +12 -6
- package/src/ui/tool-progress-formatter.ts +128 -9
- package/src/ui/tool-renderers/brief-mode.ts +10 -67
- package/src/ui/tool-renderers/index.ts +374 -523
- package/src/ui/transcript-viewer.ts +30 -12
- package/src/ui/widget/index.ts +32 -52
- package/src/ui/widget/task-list.ts +64 -32
- package/src/ui/widget/widget-formatters.ts +3 -402
- package/src/ui/widget/widget-model.ts +28 -7
- package/src/ui/widget/widget-renderer.ts +201 -128
- package/src/ui/widget/widget-types.ts +0 -2
- package/src/utils/incremental-reader.ts +11 -3
- package/src/utils/paths.ts +94 -12
- package/src/utils/project-markers.ts +40 -0
- package/src/utils/visual.ts +0 -4
- package/src/worktree/worktree-manager.ts +206 -26
- package/workflows/distill.workflow.md +3 -3
- package/workflows/fast-fix.workflow.md +1 -1
- package/workflows/plan-execute.workflow.md +1 -1
- package/workflows/review.workflow.md +1 -1
- package/workflows/strict-fast-fix.workflow.md +1 -1
- package/docs/migration-v0.4-v0.5.md +0 -208
- package/docs/runtime-flow.md +0 -148
- package/src/extension/crew-vibes/figures.ts +0 -22
- package/src/extension/crew-vibes/font-detect.ts +0 -71
- package/src/ui/dynamic-border.ts +0 -35
- package/src/ui/loaders.ts +0 -6
- package/src/ui/overlay-stack.ts +0 -148
package/docs/runtime-flow.md
DELETED
|
@@ -1,148 +0,0 @@
|
|
|
1
|
-
# pi-crew Runtime Flow
|
|
2
|
-
|
|
3
|
-
This document is a compact map of the runtime paths used by `pi-crew`.
|
|
4
|
-
|
|
5
|
-
## Main sequence
|
|
6
|
-
|
|
7
|
-
```text
|
|
8
|
-
User / model
|
|
9
|
-
│ calls team({ action: "run", ... }) or /team-run
|
|
10
|
-
▼
|
|
11
|
-
handleTeamTool()
|
|
12
|
-
│ validates schema and routes action
|
|
13
|
-
▼
|
|
14
|
-
handleRun()
|
|
15
|
-
├─ discoverTeams/discoverWorkflows/discoverAgents
|
|
16
|
-
├─ validateWorkflowForTeam
|
|
17
|
-
├─ expandParallelResearchWorkflow when applicable
|
|
18
|
-
├─ createRunManifest + tasks.json + goal artifact
|
|
19
|
-
├─ if async=true ─────────────────────────────────────────────┐
|
|
20
|
-
│ spawnBackgroundTeamRun() │
|
|
21
|
-
│ ├─ resolve jiti-register.mjs │
|
|
22
|
-
│ ├─ fail-fast if jiti missing │
|
|
23
|
-
│ ├─ node --import jiti-register.mjs background-runner.ts │
|
|
24
|
-
│ └─ parent schedules early-exit guard │
|
|
25
|
-
│ ▼
|
|
26
|
-
│ background-runner.ts
|
|
27
|
-
│ ├─ append async.started
|
|
28
|
-
│ ├─ write async.pid startup marker
|
|
29
|
-
│ ├─ rediscover team/workflow/agents
|
|
30
|
-
│ └─ executeTeamRun()
|
|
31
|
-
│
|
|
32
|
-
└─ if foreground/default
|
|
33
|
-
├─ startForegroundRun schedules session-bound run, or
|
|
34
|
-
└─ executeTeamRun inline for scaffold/non-scheduled paths
|
|
35
|
-
|
|
36
|
-
executeTeamRun()
|
|
37
|
-
├─ write run.running
|
|
38
|
-
├─ materialize queued/running agent records lazily
|
|
39
|
-
├─ build task graph index
|
|
40
|
-
├─ while queued tasks exist
|
|
41
|
-
│ ├─ taskGraphSnapshot
|
|
42
|
-
│ ├─ resolveBatchConcurrency
|
|
43
|
-
│ ├─ getReadyTasks
|
|
44
|
-
│ ├─ append task.progress batch event
|
|
45
|
-
│ ├─ mapConcurrent ready batch
|
|
46
|
-
│ │ └─ runTeamTask()
|
|
47
|
-
│ │ ├─ prepare workspace/worktree
|
|
48
|
-
│ │ ├─ build task packet
|
|
49
|
-
│ │ ├─ render prompt + dependency context
|
|
50
|
-
│ │ ├─ choose model candidates from Pi config
|
|
51
|
-
│ │ ├─ spawn child Pi process
|
|
52
|
-
│ │ ├─ ChildPiLineObserver parses stdout/stderr
|
|
53
|
-
│ │ ├─ append per-agent events/output
|
|
54
|
-
│ │ ├─ update agent progress/task state
|
|
55
|
-
│ │ ├─ parse final JSONL/session usage
|
|
56
|
-
│ │ └─ write result/log/transcript/metadata artifacts
|
|
57
|
-
│ ├─ merge task updates monotonically
|
|
58
|
-
│ ├─ optional adaptive plan injection
|
|
59
|
-
│ ├─ save tasks/agents/progress
|
|
60
|
-
│ └─ write batch artifact
|
|
61
|
-
├─ policy closeout
|
|
62
|
-
└─ run.completed / run.failed / run.blocked / run.cancelled
|
|
63
|
-
```
|
|
64
|
-
|
|
65
|
-
## Action router
|
|
66
|
-
|
|
67
|
-
| Action | Handler | Purpose |
|
|
68
|
-
|---|---|---|
|
|
69
|
-
| `run` | `team-tool/run.ts` | Create and execute a run, foreground or async. |
|
|
70
|
-
| `status` | `team-tool.ts` | Show manifest/tasks/agents/events and mark stale async runs failed. |
|
|
71
|
-
| `summary` | `session-summary.ts`/summary handler | Write/read run summary artifact. |
|
|
72
|
-
| `events` | `team-tool.ts` | Tail durable run events. |
|
|
73
|
-
| `artifacts` | `team-tool.ts` | List run artifacts. |
|
|
74
|
-
| `resume` | `team-tool.ts` | Requeue failed/cancelled/skipped/running tasks. |
|
|
75
|
-
| `cancel` | `team-tool.ts` | Mark queued/running tasks cancelled and request foreground interrupt. |
|
|
76
|
-
| `forget` | `run-maintenance.ts` | Delete run state/artifacts with confirmation. |
|
|
77
|
-
| `prune` | `run-maintenance.ts` | Remove old finished runs with confirmation. |
|
|
78
|
-
| `export` | `run-export.ts` | Create portable run bundle. |
|
|
79
|
-
| `import` / `imports` | `run-import.ts` / `import-index.ts` | Store/list imported bundles. |
|
|
80
|
-
| `config` | `config.ts` + config action | Show/update user/project config. |
|
|
81
|
-
| `doctor` | `team-tool/doctor.ts` | Platform/resource/runtime diagnostics. |
|
|
82
|
-
| `validate` | `validate-resources.ts` | Validate agents/teams/workflows. |
|
|
83
|
-
| `recommend` | `team-recommendation.ts` | Suggest team/workflow/action for a goal. |
|
|
84
|
-
| management | `management.ts` | Create/update/delete/rename teams, agents, workflows. |
|
|
85
|
-
| API | `team-tool/api.ts` | File-backed observability/control/mailbox API. |
|
|
86
|
-
|
|
87
|
-
## Worker modes
|
|
88
|
-
|
|
89
|
-
| Mode | Behavior |
|
|
90
|
-
|---|---|
|
|
91
|
-
| `child-process` | Default. Launches real child `pi` processes per task. |
|
|
92
|
-
| `scaffold` | Explicit dry-run. No child Pi worker execution. |
|
|
93
|
-
| `live-session` | Experimental/gated in-process/live agent path. |
|
|
94
|
-
| `auto` | Resolves to child-process unless config/env requests otherwise. |
|
|
95
|
-
|
|
96
|
-
## Important files
|
|
97
|
-
|
|
98
|
-
```text
|
|
99
|
-
src/extension/register.ts Pi extension entry/wiring
|
|
100
|
-
src/extension/team-tool/run.ts run creation and foreground/async split
|
|
101
|
-
src/runtime/background-runner.ts detached async entrypoint
|
|
102
|
-
src/runtime/async-runner.ts background spawn command/options
|
|
103
|
-
src/runtime/team-runner.ts workflow/task graph scheduler
|
|
104
|
-
src/runtime/task-runner.ts single task execution
|
|
105
|
-
src/runtime/child-pi.ts child Pi process and output observer
|
|
106
|
-
src/runtime/model-fallback.ts configured model candidates/routing
|
|
107
|
-
src/runtime/concurrency.ts batch concurrency decisions
|
|
108
|
-
src/runtime/process-status.ts pid/liveness/stale detection
|
|
109
|
-
src/state/state-store.ts manifest/tasks persistence
|
|
110
|
-
src/state/event-log.ts JSONL run events
|
|
111
|
-
src/runtime/crew-agent-records.ts aggregate + per-agent status files
|
|
112
|
-
```
|
|
113
|
-
|
|
114
|
-
## Environment variables
|
|
115
|
-
|
|
116
|
-
| Env | Effect |
|
|
117
|
-
|---|---|
|
|
118
|
-
| `PI_CREW_EXECUTE_WORKERS=0` | Disable real workers, use scaffold behavior. |
|
|
119
|
-
| `PI_TEAMS_EXECUTE_WORKERS=0` | Legacy alias for worker disable. |
|
|
120
|
-
| `PI_CREW_ENABLE_EXPERIMENTAL_LIVE_SESSION=1` | Allow experimental live-session runtime. |
|
|
121
|
-
| `PI_CREW_MOCK_LIVE_SESSION=success` | Test hook for live-session mock. |
|
|
122
|
-
| `PI_TEAMS_MOCK_CHILD_PI` | Test hook for mocked child Pi execution. |
|
|
123
|
-
| `PI_CREW_DEPTH`, `PI_CREW_MAX_DEPTH` | Canonical subagent recursion guard. |
|
|
124
|
-
| `PI_TEAMS_DEPTH`, `PI_TEAMS_MAX_DEPTH` | Legacy recursion guard aliases. |
|
|
125
|
-
| `PI_TEAMS_HOME` | Override user config/state home in tests. |
|
|
126
|
-
| `PI_TEAMS_PI_BIN` | Override child `pi` executable. |
|
|
127
|
-
| `PI_CODING_AGENT_DIR` | Override Pi settings/models directory for model discovery. |
|
|
128
|
-
| `PI_CREW_ASYNC_EARLY_EXIT_GUARD=0` | Disable 3s background early-exit guard. |
|
|
129
|
-
|
|
130
|
-
## State transition summary
|
|
131
|
-
|
|
132
|
-
```text
|
|
133
|
-
queued/planning/running ── completed
|
|
134
|
-
├─ failed
|
|
135
|
-
├─ blocked
|
|
136
|
-
└─ cancelled
|
|
137
|
-
```
|
|
138
|
-
|
|
139
|
-
Task states follow the same durable contract plus `skipped`. Terminal states are monotonic during parallel merge.
|
|
140
|
-
|
|
141
|
-
## Observability tips
|
|
142
|
-
|
|
143
|
-
- Use `/team-dashboard` for a UI overview.
|
|
144
|
-
- Use `team status runId=...` for canonical state and stale async detection.
|
|
145
|
-
- Read `background.log` for early import/spawn errors.
|
|
146
|
-
- Read `events.jsonl` for event chronology.
|
|
147
|
-
- Read `agents/{taskId}/status.json` for per-agent model/progress/tool status.
|
|
148
|
-
- Read `artifacts/{runId}/transcripts/{taskId}.jsonl` for raw child Pi transcript.
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Capacity-stage helpers (shared by renderCapacity, which remains exported
|
|
3
|
-
* for its unit tests after the footer retirement).
|
|
4
|
-
*
|
|
5
|
-
* The speed-UI parts of this module (braille/PUA spinner frames,
|
|
6
|
-
* intervalForSpeed) were REMOVED with the tok/s speed UI (maintainer
|
|
7
|
-
* decision 2026-09-14) — pi's built-in working indicator is always used.
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* Pick the capacity stage index (0..levels-1) for a context-fill percent.
|
|
12
|
-
* Ported from pi-chonk's chonkIndex.
|
|
13
|
-
*/
|
|
14
|
-
export function capacityIndex(percent: number | null | undefined, levels = 6): number {
|
|
15
|
-
if (percent === null || percent === undefined || !Number.isFinite(percent)) return 0;
|
|
16
|
-
return Math.max(0, Math.min(levels - 1, Math.floor((Math.max(0, Math.min(100, percent)) / 100) * levels)));
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
/** The last two stages are "danger" stages and get the error color. */
|
|
20
|
-
export function isDangerStage(index: number, levels: number): boolean {
|
|
21
|
-
return index >= Math.max(0, levels - 2);
|
|
22
|
-
}
|
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
import { existsSync, readFileSync } from "node:fs";
|
|
2
|
-
import { homedir, platform } from "node:os";
|
|
3
|
-
import { join } from "node:path";
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Detect whether the crew-vibes PUA font (U+E700..U+E70F) file exists
|
|
7
|
-
* on disk. This is a *best-effort* heuristic — file existence does NOT
|
|
8
|
-
* guarantee the terminal can render PUA glyphs (many terminals have their
|
|
9
|
-
* own font stacks). For reliable animation, braille fallback frames are
|
|
10
|
-
* used by default; PUA frames are only activated when the user explicitly
|
|
11
|
-
* (used by the capacity icons).
|
|
12
|
-
*/
|
|
13
|
-
|
|
14
|
-
function fontPath(): string {
|
|
15
|
-
const os = platform();
|
|
16
|
-
const home = homedir();
|
|
17
|
-
if (os === "darwin") return join(home, "Library", "Fonts", "crew-vibes.ttf");
|
|
18
|
-
if (os === "linux") return join(home, ".local", "share", "fonts", "crew-vibes.ttf");
|
|
19
|
-
if (os === "win32") {
|
|
20
|
-
const local = process.env.LOCALAPPDATA ?? join(home, "AppData", "Local");
|
|
21
|
-
return join(local, "Microsoft", "Windows", "Fonts", "crew-vibes.ttf");
|
|
22
|
-
}
|
|
23
|
-
return "";
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
let _hasFontFile: boolean | null = null;
|
|
27
|
-
|
|
28
|
-
/** Returns true when crew-vibes.ttf exists in the platform font directory. */
|
|
29
|
-
export function hasCrewFontFile(): boolean {
|
|
30
|
-
if (_hasFontFile !== null) return _hasFontFile;
|
|
31
|
-
const p = fontPath();
|
|
32
|
-
_hasFontFile = p !== "" && existsSync(p);
|
|
33
|
-
return _hasFontFile;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
let _isWebTerminal: boolean | null = null;
|
|
37
|
-
|
|
38
|
-
/** Returns true when running in a web-based terminal (gotty, wetty, etc.)
|
|
39
|
-
* where system fonts are not available for PUA rendering. */
|
|
40
|
-
export function isWebTerminal(): boolean {
|
|
41
|
-
if (_isWebTerminal !== null) return _isWebTerminal;
|
|
42
|
-
if (process.env.GOTTY || process.env.WEBTERM) {
|
|
43
|
-
_isWebTerminal = true;
|
|
44
|
-
return true;
|
|
45
|
-
}
|
|
46
|
-
if (process.env.TERM === "dumb") {
|
|
47
|
-
_isWebTerminal = true;
|
|
48
|
-
return true;
|
|
49
|
-
}
|
|
50
|
-
try {
|
|
51
|
-
// Check current process and ancestors — gotty is often the grandparent
|
|
52
|
-
// (gotty → tmux → pi), so /proc/self/cgroup may not contain it.
|
|
53
|
-
let pid = process.pid;
|
|
54
|
-
for (let i = 0; i < 6 && pid > 1; i++) {
|
|
55
|
-
const cgroup = readFileSync(`/proc/${pid}/cgroup`, "utf8");
|
|
56
|
-
if (cgroup.includes("gotty") || cgroup.includes("wetty")) {
|
|
57
|
-
_isWebTerminal = true;
|
|
58
|
-
return true;
|
|
59
|
-
}
|
|
60
|
-
const match = cgroup.match(/\d+:.*:(.*)/);
|
|
61
|
-
// Read PPid from status
|
|
62
|
-
const status = readFileSync(`/proc/${pid}/status`, "utf8");
|
|
63
|
-
const ppid = status.match(/^PPid:\s+(\d+)/m);
|
|
64
|
-
pid = ppid ? Number.parseInt(ppid[1], 10) : 1;
|
|
65
|
-
}
|
|
66
|
-
} catch {
|
|
67
|
-
// not Linux or /proc not available
|
|
68
|
-
}
|
|
69
|
-
_isWebTerminal = false;
|
|
70
|
-
return false;
|
|
71
|
-
}
|
package/src/ui/dynamic-border.ts
DELETED
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
import type { CrewTheme } from "./theme-adapter.ts";
|
|
2
|
-
|
|
3
|
-
export interface DynamicCrewBorderOptions {
|
|
4
|
-
color?: (value: string) => string;
|
|
5
|
-
char?: string;
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
export class DynamicCrewBorder {
|
|
9
|
-
private readonly theme: CrewTheme;
|
|
10
|
-
private readonly color?: (value: string) => string;
|
|
11
|
-
private readonly char: string;
|
|
12
|
-
private cachedWidth = -1;
|
|
13
|
-
private cachedLine = "";
|
|
14
|
-
|
|
15
|
-
constructor(theme: CrewTheme, options: DynamicCrewBorderOptions = {}) {
|
|
16
|
-
this.theme = theme;
|
|
17
|
-
this.color = options.color;
|
|
18
|
-
this.char = options.char && options.char.length > 0 ? options.char : "─";
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
render(width: number): string[] {
|
|
22
|
-
const w = Math.max(0, width);
|
|
23
|
-
if (w !== this.cachedWidth) {
|
|
24
|
-
const line = this.char.repeat(w);
|
|
25
|
-
this.cachedLine = this.color ? this.color(line) : this.theme.fg("border", line);
|
|
26
|
-
this.cachedWidth = w;
|
|
27
|
-
}
|
|
28
|
-
return [this.cachedLine];
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
invalidate(): void {
|
|
32
|
-
this.cachedWidth = -1;
|
|
33
|
-
this.cachedLine = "";
|
|
34
|
-
}
|
|
35
|
-
}
|
package/src/ui/loaders.ts
DELETED
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* CrewBorderedLoader and CountdownTimer were removed (UI-animation-audit C9).
|
|
3
|
-
* They were dead production code — referenced only by test/unit/loaders.test.ts
|
|
4
|
-
* (now deleted) and never instantiated in src/ or re-exported from the public
|
|
5
|
-
* index. If a new loader component is needed, add it here.
|
|
6
|
-
*/
|
package/src/ui/overlay-stack.ts
DELETED
|
@@ -1,148 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* PR-G3 (UI-4) — minimal overlay stack for z-order, focus, and dismissal
|
|
3
|
-
* chaining.
|
|
4
|
-
*
|
|
5
|
-
* Before this, src/ui/ had no central router for overlay z-order/focus/
|
|
6
|
-
* dismissal. Overlays (ConfirmOverlay, MailboxDetailOverlay, AgentPickerOverlay,
|
|
7
|
-
* HelpOverlay, …) each manage their own `handleInput`, and a caller that wants
|
|
8
|
-
* two overlays up at once had no way to express "the top one gets input and
|
|
9
|
-
* ESC dismisses it, restoring focus to the one below".
|
|
10
|
-
*
|
|
11
|
-
* The `OverlayStack` is a LIFO stack of overlays. The top of the stack owns
|
|
12
|
-
* input focus and is rendered last (i.e. on top). Popping or dismissing the
|
|
13
|
-
* top restores focus to the next overlay down. Every overlay already exposes
|
|
14
|
-
* the `InteractiveComponent` contract (render + invalidate + handleInput), so
|
|
15
|
-
* existing overlays opt in automatically with zero rewrite.
|
|
16
|
-
*
|
|
17
|
-
* This is intentionally additive: no existing overlay is required to use it.
|
|
18
|
-
* Callers that want centralized z-order/focus management opt in by pushing
|
|
19
|
-
* overlays here.
|
|
20
|
-
*/
|
|
21
|
-
|
|
22
|
-
import type { InteractiveComponent } from "./component.ts";
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* An overlay is an interactive component occupying one z-layer. Anything with
|
|
26
|
-
* `render` + `invalidate` + `handleInput` qualifies (ConfirmOverlay,
|
|
27
|
-
* MailboxDetailOverlay, AgentPickerOverlay, RunDashboard, …).
|
|
28
|
-
*/
|
|
29
|
-
export type Overlay = InteractiveComponent;
|
|
30
|
-
|
|
31
|
-
export interface OverlayStackOptions {
|
|
32
|
-
/**
|
|
33
|
-
* Invoked after the top-of-stack changes (push / pop / dismissTop / clear).
|
|
34
|
-
* Use it to (re)wire host focus or request a repaint. Optional.
|
|
35
|
-
*/
|
|
36
|
-
onTopChanged?: () => void;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* LIFO overlay stack providing z-order, focus, and dismissal chaining.
|
|
41
|
-
*
|
|
42
|
-
* - `push(o)` → `o` becomes the new focus/top layer.
|
|
43
|
-
* - `top()` → the focused overlay (or undefined when empty).
|
|
44
|
-
* - `handleInput(data)` → routed to the top overlay only; returns false when
|
|
45
|
-
* the stack is empty so callers can fall back to base input handling.
|
|
46
|
-
* - `dismissTop()` / `pop()` → removes the top overlay, restoring focus below.
|
|
47
|
-
* - `render(width)` → renders the top overlay by default; `{ composite: true }`
|
|
48
|
-
* returns every layer bottom-to-top for custom compositing.
|
|
49
|
-
*/
|
|
50
|
-
export class OverlayStack {
|
|
51
|
-
private readonly stack: Overlay[] = [];
|
|
52
|
-
private readonly onTopChanged?: () => void;
|
|
53
|
-
|
|
54
|
-
constructor(options: OverlayStackOptions = {}) {
|
|
55
|
-
this.onTopChanged = options.onTopChanged;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
/** Number of overlays currently on the stack. */
|
|
59
|
-
get size(): number {
|
|
60
|
-
return this.stack.length;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
/** Whether the stack currently holds any overlays. */
|
|
64
|
-
isEmpty(): boolean {
|
|
65
|
-
return this.stack.length === 0;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
/** Push a new overlay on top. It becomes the input/render focus. */
|
|
69
|
-
push(overlay: Overlay): void {
|
|
70
|
-
this.stack.push(overlay);
|
|
71
|
-
this.notifyTopChanged();
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
/** Remove and return the top overlay, or undefined if the stack is empty. */
|
|
75
|
-
pop(): Overlay | undefined {
|
|
76
|
-
const overlay = this.stack.pop();
|
|
77
|
-
this.notifyTopChanged();
|
|
78
|
-
return overlay;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
/** The top-of-stack overlay (the focus/render target), or undefined when empty. */
|
|
82
|
-
top(): Overlay | undefined {
|
|
83
|
-
return this.stack.at(-1);
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
/** Peek at the overlay at a given depth (0 = bottom). */
|
|
87
|
-
at(index: number): Overlay | undefined {
|
|
88
|
-
return this.stack[index];
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
/**
|
|
92
|
-
* Dismiss the top overlay. Equivalent to `pop()` but returns a boolean so
|
|
93
|
-
* callers can chain dismissal (e.g. ESC closes the topmost, then the next).
|
|
94
|
-
* Returns true when an overlay was dismissed, false when the stack is empty.
|
|
95
|
-
*/
|
|
96
|
-
dismissTop(): boolean {
|
|
97
|
-
if (this.stack.length === 0) return false;
|
|
98
|
-
this.stack.pop();
|
|
99
|
-
this.notifyTopChanged();
|
|
100
|
-
return true;
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
/**
|
|
104
|
-
* Route a raw input chunk to the top-of-stack overlay.
|
|
105
|
-
* @returns true if an overlay handled it (stack non-empty); false if the
|
|
106
|
-
* stack is empty so the caller may fall back to base input handling.
|
|
107
|
-
*/
|
|
108
|
-
handleInput(data: string): boolean {
|
|
109
|
-
const overlay = this.top();
|
|
110
|
-
if (!overlay) return false;
|
|
111
|
-
overlay.handleInput(data);
|
|
112
|
-
return true;
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
/**
|
|
116
|
-
* Render the stack. By default returns the top overlay's lines (the common
|
|
117
|
-
* modal case where the top covers what is below). Pass `{ composite: true }`
|
|
118
|
-
* to receive every layer's lines in bottom-to-top order for custom
|
|
119
|
-
* compositing. Returns `[]` when the stack is empty.
|
|
120
|
-
*/
|
|
121
|
-
render(width: number, options: { composite?: boolean } = {}): string[] {
|
|
122
|
-
if (this.stack.length === 0) return [];
|
|
123
|
-
if (options.composite) {
|
|
124
|
-
const lines: string[] = [];
|
|
125
|
-
for (const overlay of this.stack) {
|
|
126
|
-
lines.push(...overlay.render(width));
|
|
127
|
-
}
|
|
128
|
-
return lines;
|
|
129
|
-
}
|
|
130
|
-
return this.stack.at(-1)!.render(width);
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
/** Invalidate every overlay on the stack (e.g. on theme change). */
|
|
134
|
-
invalidateAll(): void {
|
|
135
|
-
for (const overlay of this.stack) overlay.invalidate();
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
/** Remove every overlay from the stack. */
|
|
139
|
-
clear(): void {
|
|
140
|
-
const hadOverlays = this.stack.length > 0;
|
|
141
|
-
this.stack.length = 0;
|
|
142
|
-
if (hadOverlays) this.notifyTopChanged();
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
private notifyTopChanged(): void {
|
|
146
|
-
this.onTopChanged?.();
|
|
147
|
-
}
|
|
148
|
-
}
|