pi-maestro-teammate 2.4.0 → 2.6.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/README.md +10 -4
- package/agents/analyst.md +0 -1
- package/agents/explorer.md +0 -1
- package/agents/general.md +0 -1
- package/agents/planner.md +2 -2
- package/agents/research.md +0 -1
- package/agents/verifier.md +0 -1
- package/agents/workflow.md +0 -1
- package/package.json +3 -3
- package/src/completion-outbox/coordinator.ts +39 -10
- package/src/completion-outbox/registry.ts +24 -1
- package/src/extension/index.ts +297 -143
- package/src/extension/teammate-core.ts +46 -24
- package/src/extension/teammate-helpers.ts +24 -0
- package/src/extension/teammate-proxy.ts +112 -33
- package/src/models/model-routing.ts +131 -43
- package/src/public/v1/completion-durability.ts +2 -0
- package/src/public/v1/model-routing.ts +4 -0
- package/src/public/v1/ssh-hosts.ts +560 -209
- package/src/public/v1/supervision.ts +9 -0
- package/src/remote/acp-client-operations.ts +1 -1
- package/src/remote/acp-driver.ts +2 -2
- package/src/remote/pi-rpc-driver.ts +1 -1
- package/src/remote/ssh.ts +48 -2
- package/src/runs/execution-infra.ts +29 -5
- package/src/runs/execution.ts +166 -39
- package/src/runs/pi-subprocess-attempt.ts +3279 -2960
- package/src/runs/recovery-protocol.ts +98 -0
- package/src/runs/retry.ts +10 -0
- package/src/runs/runtime-actor.ts +8 -3
- package/src/shared/types.ts +36 -2
- package/src/supervision/advisor-runtime.ts +156 -0
- package/src/transcript/session-history.ts +1 -1
- package/src/tui/attach-overlay.ts +8 -0
- package/src/tui/locale-catalog-model.ts +20 -0
- package/src/tui/locale-catalog-profiles.ts +4 -4
- package/src/tui/model-mapping-overlay.ts +70 -101
- package/src/tui/render.ts +16 -12
- package/types/completion-outbox/coordinator.d.ts +1 -0
- package/types/completion-outbox/registry.d.ts +1 -0
- package/types/extension/teammate-core.d.ts +3 -3
- package/types/extension/teammate-helpers.d.ts +3 -0
- package/types/models/model-routing.d.ts +27 -6
- package/types/public/v1/completion-durability.d.ts +2 -0
- package/types/public/v1/model-routing.d.ts +1 -0
- package/types/public/v1/ssh-hosts.d.ts +45 -1
- package/types/public/v1/supervision.d.ts +2 -0
- package/types/remote/ssh.d.ts +3 -0
- package/types/runs/execution-infra.d.ts +14 -3
- package/types/runs/pi-subprocess-attempt.d.ts +3 -1
- package/types/runs/recovery-protocol.d.ts +60 -0
- package/types/runs/retry.d.ts +10 -0
- package/types/shared/types.d.ts +28 -2
- package/types/supervision/advisor-runtime.d.ts +14 -0
- package/types/transcript/session-history.d.ts +1 -1
- package/types/tui/locale-catalog-model.d.ts +20 -0
- package/types/tui/locale-catalog-profiles.d.ts +4 -4
- package/types/tui/model-mapping-overlay.d.ts +3 -0
package/README.md
CHANGED
|
@@ -189,12 +189,12 @@ project .pi/agents > project .agents > ~/.agents > legacy user directory > bundl
|
|
|
189
189
|
|
|
190
190
|
Configure task-type defaults with `Alt+M` or `/teammate-models`. The Control Center's **Profiles** tab is the saved-template system: it manages multiple named routing Profiles shared by every project. Its **Routing** tab edits the active global Profile and combines built-in task types, discovered agent types, and types already present in that Profile.
|
|
191
191
|
|
|
192
|
-
Switch the current project's template directly by stable Profile ID or display name. With no argument, the command opens the Control Center
|
|
192
|
+
Switch the current project's template directly by stable Profile ID or display name. With no argument, the same command opens the full Control Center:
|
|
193
193
|
|
|
194
194
|
```text
|
|
195
|
-
/teammate-
|
|
196
|
-
/teammate-
|
|
197
|
-
/teammate-
|
|
195
|
+
/teammate-models fast-lane
|
|
196
|
+
/teammate-models Fast Lane
|
|
197
|
+
/teammate-models
|
|
198
198
|
```
|
|
199
199
|
|
|
200
200
|
Command completion lists every saved template and marks the project-active and global-default entries. If display names are duplicated, use the stable ID. Direct switching disables but preserves project overrides, matching the Profiles UI.
|
|
@@ -359,6 +359,12 @@ observe({ action: "watch", targets: [{ kind: "teammate", id: "reviewer" }], time
|
|
|
359
359
|
|
|
360
360
|
A durable, per-workspace-isolated message queue backing cross-session delivery (staging → ready → claimed → accepted, atomic writes + idempotent receipts). Cold resume stays synchronous when the mailbox is authoritative; Windows file-lock renames retry automatically and orphaned state records are garbage-collected. External consumers (the Flow host) integrate through the `pi-maestro-teammate/v1/mailbox` subpath: the extension publishes a live `MailboxHostRegistry` on the shared-process bridge key `Symbol.for("pi-maestro-teammate.mailbox-registry")` (durable `enqueueTaskNotification`, per-recipient `pendingCount`, and `negotiate` capability v1/v2, with `taskId`-keyed dedup); `pi-maestro-flow` consumes it via `mailboxRegistry()` (see `packages/pi-maestro-flow/src/extension/index.ts`) and the contract is covered by `test/mailbox-registry.test.ts`.
|
|
361
361
|
|
|
362
|
+
## Advisor Compatibility
|
|
363
|
+
|
|
364
|
+
When installed by itself, `pi-maestro-teammate` keeps the low-frequency standalone Advisor. Configure its defaults in `.pi/settings.json` under `monitor.advisor` (or the top-level `advisor` key), or with `PI_ADVISOR`, `PI_ADVISOR_COOLDOWN_MS`, and `PI_ADVISOR_MAX_REVIEWS`. `/advisor on|off` is a current-session override; `/advisor status` shows the effective state.
|
|
365
|
+
|
|
366
|
+
When `pi-maestro-flow` is also loaded, its `pi-maestro-flow/advisor` runtime is the canonical owner and this package's priority-10 fallback sleeps, even when the Flow Advisor is disabled. A process-wide registry and one dynamic `/advisor` broker prevent duplicate commands, double dispatch, and stale delivery in either package load order. Flow reads canonical `.pi/advisor.json` first, otherwise the legacy settings above, then defaults, and finally the same environment overrides. See the Flow Advisor guide for manual/hybrid mode, automatic review budgets, and `reviewEveryToolResults: 0`.
|
|
367
|
+
|
|
362
368
|
## Runtime
|
|
363
369
|
|
|
364
370
|
- Foreground dispatch is the default and returns child results directly.
|
package/agents/analyst.md
CHANGED
package/agents/explorer.md
CHANGED
|
@@ -3,7 +3,6 @@ name: explorer
|
|
|
3
3
|
description: "Read-only codebase discovery and call-chain tracing specialist. Use when you need file:line answers fast; not for analysis, planning, or implementation."
|
|
4
4
|
systemPromptMode: replace
|
|
5
5
|
thinking: low
|
|
6
|
-
taskType: explore
|
|
7
6
|
tools: read, grep, find, ls
|
|
8
7
|
inheritProjectContext: false
|
|
9
8
|
inheritSkills: false
|
package/agents/general.md
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: general
|
|
3
3
|
description: "General-purpose teammate for direct implementation, analysis, and verification. Use for direct work in the project; not for read-only discovery, planning, or DAG orchestration."
|
|
4
|
-
taskType: development
|
|
5
4
|
systemPromptMode: append
|
|
6
5
|
inheritProjectContext: true
|
|
7
6
|
tools: read, grep, find, ls, bash, edit, write
|
package/agents/planner.md
CHANGED
|
@@ -4,7 +4,6 @@ description: "Read-only architecture and execution planning specialist. Use to p
|
|
|
4
4
|
systemPromptMode: replace
|
|
5
5
|
inheritProjectContext: true
|
|
6
6
|
thinking: high
|
|
7
|
-
taskType: planning
|
|
8
7
|
tools: read, grep, find, ls
|
|
9
8
|
inheritSkills: false
|
|
10
9
|
---
|
|
@@ -59,7 +58,8 @@ Return only Markdown for the Plan, with no preface, commentary, interview log, o
|
|
|
59
58
|
Dependencies must form an executable DAG and identify safe parallel work. A task is a verifiable outcome, not a command or activity log.
|
|
60
59
|
8. `## Validation`: specify exact commands or observable checks, expected results, requirement coverage, and relevant regression or integration boundaries.
|
|
61
60
|
9. `## Risks and Recovery`: state concrete risks, mitigations, and rollback or recovery behavior.
|
|
62
|
-
10. `##
|
|
61
|
+
10. `## Knowledge Outcome`: require an end-of-execution assessment after implementation and verification. Name plausible candidate topics only when the work may produce a reusable non-obvious pitfall, failure lesson, trade-off, or prescriptive constraint; otherwise write `None expected` with a concrete reason. This section predicts what to assess—it must not fabricate knowledge in advance. Actual staging happens after approval in Act/Run mode, and the executor must explicitly report zero candidates when no result meets the project's knowledge quality bar.
|
|
62
|
+
11. `## Open Decisions`: list unresolved user-owned decisions. Write `None` only after evidence-based review; a Plan with unresolved decisions is not confirmation-ready.
|
|
63
63
|
|
|
64
64
|
Execution ownership: after the Plan is approved, implementation defaults to the project's `general-executor` agent (fallback: `general` when that role is not discovered). State this default in the Plan's Execution Plan section when it helps, and shape each task so a generic executor can consume it without rediscovery — concrete outcome, bounded scope, named files, acceptance criteria, and verification commands. Do not assume a workflow-task pipeline (`.task/TASK-*.json`) exists; the Plan must be executable by `general-executor` from the Plan text alone.
|
|
65
65
|
|
package/agents/research.md
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: research
|
|
3
3
|
description: "Read-only project knowledge and external web research specialist. Use for source-grounded answers from knowledge bases or the web; not for code discovery or implementation."
|
|
4
|
-
taskType: analysis
|
|
5
4
|
thinking: high
|
|
6
5
|
systemPromptMode: replace
|
|
7
6
|
inheritProjectContext: true
|
package/agents/verifier.md
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: verifier
|
|
3
3
|
description: "Independent read-only fallback verifier for Goal completion claims. Use only when a Goal declares no acceptance commands; not for ordinary review."
|
|
4
|
-
taskType: verification
|
|
5
4
|
thinking: low
|
|
6
5
|
systemPromptMode: replace
|
|
7
6
|
inheritProjectContext: false
|
package/agents/workflow.md
CHANGED
|
@@ -4,7 +4,6 @@ description: "Decomposes complex problems and dispatches dependency-aware teamma
|
|
|
4
4
|
systemPromptMode: replace
|
|
5
5
|
inheritProjectContext: true
|
|
6
6
|
thinking: high
|
|
7
|
-
taskType: planning
|
|
8
7
|
tools: read, grep, find, ls, teammate, teammate-send, teammate-list, observe
|
|
9
8
|
inheritSkills: false
|
|
10
9
|
---
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-maestro-teammate",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.6.0",
|
|
4
4
|
"description": "Pi extension — teammate agent dispatch with DAG task graphs, RPC messaging, and compact TUI",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"engines": {
|
|
@@ -195,8 +195,8 @@
|
|
|
195
195
|
"cross-spawn": "7.0.6",
|
|
196
196
|
"jiti": "2.7.0",
|
|
197
197
|
"pi-maestro-settings-core": "0.2.1",
|
|
198
|
-
"pi-maestro-backend-core": "
|
|
199
|
-
"pi-maestro-backends": "
|
|
198
|
+
"pi-maestro-backend-core": "0.1.3",
|
|
199
|
+
"pi-maestro-backends": "0.1.3",
|
|
200
200
|
"proper-lockfile": "4.1.2",
|
|
201
201
|
"ssh2": "1.17.0",
|
|
202
202
|
"zod": "4.4.3"
|
|
@@ -150,6 +150,7 @@ export class CompletionDeliveryCoordinator {
|
|
|
150
150
|
readonly #operations = new Set<Promise<unknown>>();
|
|
151
151
|
#binding: CompletionSessionBinding | undefined;
|
|
152
152
|
#unsubscribe: (() => void) | undefined;
|
|
153
|
+
#accepting = true;
|
|
153
154
|
#disposed = false;
|
|
154
155
|
// Throttle GC attempts inside reconcile(). tryGc() also persists a cross-process
|
|
155
156
|
// page/expiry fence, but this local guard prevents one coordinator from
|
|
@@ -169,8 +170,12 @@ export class CompletionDeliveryCoordinator {
|
|
|
169
170
|
});
|
|
170
171
|
}
|
|
171
172
|
|
|
172
|
-
|
|
173
|
-
|
|
173
|
+
beginDispatch(seed: CompletionDispatchSeed): Promise<CompletionDispatchDurability> {
|
|
174
|
+
return this.#track(this.#beginDispatch(seed));
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
async #beginDispatch(seed: CompletionDispatchSeed): Promise<CompletionDispatchDurability> {
|
|
178
|
+
if (!this.#accepting || this.#disposed || !this.#enabled()) return { durable: false };
|
|
174
179
|
const existing = this.#dispatches.get(seed.dispatchId);
|
|
175
180
|
if (existing) {
|
|
176
181
|
if (existing.handle.reservationId !== seed.reservationId
|
|
@@ -181,21 +186,42 @@ export class CompletionDeliveryCoordinator {
|
|
|
181
186
|
}
|
|
182
187
|
const provider = this.registry.current();
|
|
183
188
|
if (!provider) return { durable: false };
|
|
184
|
-
await
|
|
189
|
+
// Acquire the cross-extension ownership pin before the first await. Flow
|
|
190
|
+
// may retire its current provider as soon as shutdown begins, but capture
|
|
191
|
+
// must retain this exact generation until the admitted begin either commits
|
|
192
|
+
// into #dispatches or rolls back.
|
|
193
|
+
const releaseProviderPin = this.registry.pinDispatch(seed.dispatchId, provider);
|
|
194
|
+
let reserved = false;
|
|
185
195
|
try {
|
|
196
|
+
await this.store.reserve(seed);
|
|
197
|
+
reserved = true;
|
|
186
198
|
const handle = await provider.beginDispatch(seed);
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
199
|
+
if (!this.#accepting || this.#disposed) {
|
|
200
|
+
await provider.abandonDispatch({
|
|
201
|
+
dispatchId: seed.dispatchId,
|
|
202
|
+
reservationId: seed.reservationId,
|
|
203
|
+
reason: "completion coordinator stopped admission during beginDispatch",
|
|
204
|
+
abandonedAt: this.#now(),
|
|
205
|
+
}).catch(() => undefined);
|
|
206
|
+
await this.store.releaseReservation(seed.target, seed.reservationId).catch(() => undefined);
|
|
207
|
+
releaseProviderPin();
|
|
208
|
+
return { durable: false };
|
|
209
|
+
}
|
|
191
210
|
this.#dispatches.set(seed.dispatchId, { handle, seed, provider, releaseProviderPin });
|
|
192
211
|
return { durable: true, handle };
|
|
193
212
|
} catch (error) {
|
|
194
|
-
|
|
213
|
+
if (reserved) {
|
|
214
|
+
await this.store.releaseReservation(seed.target, seed.reservationId).catch(() => undefined);
|
|
215
|
+
}
|
|
216
|
+
releaseProviderPin();
|
|
195
217
|
throw error;
|
|
196
218
|
}
|
|
197
219
|
}
|
|
198
220
|
|
|
221
|
+
stopAdmission(): void {
|
|
222
|
+
this.#accepting = false;
|
|
223
|
+
}
|
|
224
|
+
|
|
199
225
|
async requireNotification(input: CompletionNotificationRequirement): Promise<void> {
|
|
200
226
|
if (!this.#dispatches.has(input.dispatchId)) return;
|
|
201
227
|
const provider = this.#pinnedProvider(input.dispatchId);
|
|
@@ -368,6 +394,7 @@ export class CompletionDeliveryCoordinator {
|
|
|
368
394
|
}
|
|
369
395
|
|
|
370
396
|
dispose(): void {
|
|
397
|
+
this.#accepting = false;
|
|
371
398
|
this.#disposed = true;
|
|
372
399
|
this.#binding = undefined;
|
|
373
400
|
this.#acceptedByHost.clear();
|
|
@@ -595,8 +622,10 @@ export class CompletionDeliveryCoordinator {
|
|
|
595
622
|
if (pinned) return pinned.provider;
|
|
596
623
|
const recovered = this.#recoveredProviderPins.get(dispatchId);
|
|
597
624
|
if (recovered) return recovered.provider;
|
|
598
|
-
const provider = this.registry.providerForDispatch(dispatchId)
|
|
599
|
-
if (!provider)
|
|
625
|
+
const provider = this.registry.providerForDispatch(dispatchId);
|
|
626
|
+
if (!provider) {
|
|
627
|
+
throw new Error(`Completion dispatch ${dispatchId} has no pinned durability provider.`);
|
|
628
|
+
}
|
|
600
629
|
return provider;
|
|
601
630
|
}
|
|
602
631
|
|
|
@@ -20,6 +20,7 @@ export class CompletionDurabilityRegistryImpl implements CompletionDurabilityReg
|
|
|
20
20
|
provider: CompletionDurabilityProvider;
|
|
21
21
|
owners: Set<symbol>;
|
|
22
22
|
}>();
|
|
23
|
+
readonly #providerIdleWaiters = new Map<CompletionDurabilityProvider, Set<() => void>>();
|
|
23
24
|
|
|
24
25
|
current(): CompletionDurabilityProvider | undefined {
|
|
25
26
|
return this.#provider;
|
|
@@ -52,10 +53,24 @@ export class CompletionDurabilityRegistryImpl implements CompletionDurabilityReg
|
|
|
52
53
|
released = true;
|
|
53
54
|
const active = this.#dispatchPins.get(dispatchId);
|
|
54
55
|
if (!active || active.provider !== provider || !active.owners.delete(owner)) return;
|
|
55
|
-
if (active.owners.size === 0)
|
|
56
|
+
if (active.owners.size === 0) {
|
|
57
|
+
this.#dispatchPins.delete(dispatchId);
|
|
58
|
+
this.#resolveProviderIdle(provider);
|
|
59
|
+
}
|
|
56
60
|
};
|
|
57
61
|
}
|
|
58
62
|
|
|
63
|
+
waitForProviderIdle(provider: CompletionDurabilityProvider): Promise<void> {
|
|
64
|
+
if (![...this.#dispatchPins.values()].some((pin) => pin.provider === provider)) {
|
|
65
|
+
return Promise.resolve();
|
|
66
|
+
}
|
|
67
|
+
return new Promise<void>((resolve) => {
|
|
68
|
+
const waiters = this.#providerIdleWaiters.get(provider) ?? new Set<() => void>();
|
|
69
|
+
waiters.add(resolve);
|
|
70
|
+
this.#providerIdleWaiters.set(provider, waiters);
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
|
|
59
74
|
register(provider: CompletionDurabilityProvider): () => void {
|
|
60
75
|
if (!provider || typeof provider !== "object") {
|
|
61
76
|
throw new TypeError("Completion durability provider must be an object.");
|
|
@@ -80,6 +95,14 @@ export class CompletionDurabilityRegistryImpl implements CompletionDurabilityReg
|
|
|
80
95
|
return () => this.#listeners.delete(listener);
|
|
81
96
|
}
|
|
82
97
|
|
|
98
|
+
#resolveProviderIdle(provider: CompletionDurabilityProvider): void {
|
|
99
|
+
if ([...this.#dispatchPins.values()].some((pin) => pin.provider === provider)) return;
|
|
100
|
+
const waiters = this.#providerIdleWaiters.get(provider);
|
|
101
|
+
if (!waiters) return;
|
|
102
|
+
this.#providerIdleWaiters.delete(provider);
|
|
103
|
+
for (const resolve of waiters) resolve();
|
|
104
|
+
}
|
|
105
|
+
|
|
83
106
|
#notify(): void {
|
|
84
107
|
const snapshot = this.snapshot();
|
|
85
108
|
for (const listener of this.#listeners) {
|