pi-maestro-teammate 2.1.0 → 2.2.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/bin/pi-teammate-outbox.mjs +12 -0
- package/package.json +3 -2
- package/src/backends/acp-cli.ts +1 -0
- package/src/cli-tools/cli-tools-config.ts +31 -14
- package/src/completion-outbox/cli.ts +123 -0
- package/src/completion-outbox/file-store.ts +440 -46
- package/src/extension/index.ts +86 -51
- package/src/extension/mailbox/file-store.ts +4 -9
- package/src/extension/mailbox/host.ts +27 -10
- package/src/extension/mailbox/rollout.ts +3 -3
- package/src/extension/mailbox/router.ts +2 -0
- package/src/extension/mailbox/types.ts +3 -1
- package/src/extension/schemas.ts +13 -4
- package/src/extension/task-delegation.ts +2 -2
- package/src/extension/teammate-core.ts +14 -6
- package/src/extension/teammate-helpers.ts +13 -6
- package/src/extension/teammate-proxy.ts +3 -3
- package/src/public/v1/model-routing.ts +6 -0
- package/src/runs/execution-infra.ts +51 -7
- package/src/runs/execution.ts +15 -12
- package/src/runs/pi-subprocess-attempt.ts +2813 -2755
- package/src/runtime-broker/client.ts +4 -10
- package/src/runtime-broker/sqlite-store.ts +52 -2
- package/src/runtime-broker/transport.ts +2 -1
- package/src/sessions/session-core.ts +3 -3
- package/src/shared/turn-ledger.ts +30 -6
- package/src/shared/types.ts +1 -1
- package/src/tui/attach-overlay.ts +23 -14
- package/src/tui/session-send-overlay.ts +6 -1
- package/types/backends/acp-cli.d.ts +1 -0
- package/types/completion-outbox/cli.d.ts +1 -0
- package/types/completion-outbox/file-store.d.ts +18 -0
- package/types/extension/mailbox/host.d.ts +1 -1
- package/types/extension/mailbox/rollout.d.ts +3 -3
- package/types/extension/mailbox/types.d.ts +2 -2
- package/types/extension/schemas.d.ts +6 -5
- package/types/extension/teammate-core.d.ts +2 -2
- package/types/extension/teammate-proxy.d.ts +3 -3
- package/types/public/v1/model-routing.d.ts +1 -0
- package/types/runs/execution-infra.d.ts +17 -0
- package/types/runs/pi-subprocess-attempt.d.ts +1 -1
- package/types/runtime-broker/transport.d.ts +2 -2
- package/types/sessions/session-core.d.ts +2 -2
- package/types/shared/types.d.ts +1 -1
- package/types/tui/attach-overlay.d.ts +2 -0
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { createJiti } from "jiti";
|
|
3
|
+
|
|
4
|
+
const jiti = createJiti(import.meta.url, { interopDefault: true });
|
|
5
|
+
const { main } = await jiti.import("../src/completion-outbox/cli.ts");
|
|
6
|
+
|
|
7
|
+
try {
|
|
8
|
+
process.exitCode = await main(process.argv.slice(2));
|
|
9
|
+
} catch (error) {
|
|
10
|
+
process.stderr.write(`pi-teammate-outbox: ${error instanceof Error ? error.message : String(error)}\n`);
|
|
11
|
+
process.exitCode = 1;
|
|
12
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-maestro-teammate",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.2.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": {
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
"bin": {
|
|
10
10
|
"pi-teammate-broker": "./bin/pi-teammate-broker.mjs",
|
|
11
11
|
"pi-teammate-models": "./bin/pi-teammate-models.mjs",
|
|
12
|
+
"pi-teammate-outbox": "./bin/pi-teammate-outbox.mjs",
|
|
12
13
|
"pi-teammate-remote": "./bin/pi-teammate-remote.mjs"
|
|
13
14
|
},
|
|
14
15
|
"keywords": [
|
|
@@ -19,7 +20,7 @@
|
|
|
19
20
|
"agents"
|
|
20
21
|
],
|
|
21
22
|
"scripts": {
|
|
22
|
-
"test": "node --experimental-transform-types --import ./test/setup.ts --test --test-concurrency=
|
|
23
|
+
"test": "node --experimental-transform-types --import ./test/setup.ts --test --test-concurrency=2 \"test/*.test.ts\"",
|
|
23
24
|
"typecheck": "tsc -p tsconfig.build.json",
|
|
24
25
|
"build:declarations": "tsc -p tsconfig.declarations.json",
|
|
25
26
|
"check:declarations": "node scripts/check-declarations.mjs",
|
package/src/backends/acp-cli.ts
CHANGED
|
@@ -796,6 +796,7 @@ export function createAcpCliBackend(
|
|
|
796
796
|
* registration ship fields whose keys have no text.
|
|
797
797
|
*/
|
|
798
798
|
export { ACP_CLI_SETTINGS_CATALOGS } from "./acp-cli-catalog.ts";
|
|
799
|
+
export { probeSshCliExecutable } from "../remote/ssh-exec.ts";
|
|
799
800
|
|
|
800
801
|
/**
|
|
801
802
|
* The registered instance.
|
|
@@ -17,7 +17,6 @@
|
|
|
17
17
|
* ~/.maestro/cli-tools.json for pi-maestro-flow's original provider registration.
|
|
18
18
|
*/
|
|
19
19
|
|
|
20
|
-
import { execFileSync } from "node:child_process";
|
|
21
20
|
import * as fs from "node:fs";
|
|
22
21
|
import * as os from "node:os";
|
|
23
22
|
import * as path from "node:path";
|
|
@@ -82,7 +81,6 @@ export interface MaestroDelegateConfig {
|
|
|
82
81
|
|
|
83
82
|
const GLOBAL_CONFIG_FILE = "teammate-cli-tools.json";
|
|
84
83
|
const LEGACY_CONFIG_PATH = path.join(os.homedir(), ".maestro", "cli-tools.json");
|
|
85
|
-
const PROBE_TIMEOUT_MS = 2_000;
|
|
86
84
|
const PROBE_CACHE_TTL_MS = 30_000;
|
|
87
85
|
|
|
88
86
|
export function getGlobalCliToolsConfigPath(): string {
|
|
@@ -326,6 +324,34 @@ function adapterInstallHint(command: string): string {
|
|
|
326
324
|
return pkg === undefined ? "" : `; install it with: npm i -g ${pkg}`;
|
|
327
325
|
}
|
|
328
326
|
|
|
327
|
+
function localExecutableCandidates(command: string): string[] {
|
|
328
|
+
const hasPathSeparator = command.includes("/") || command.includes("\\");
|
|
329
|
+
const directories = hasPathSeparator
|
|
330
|
+
? [process.cwd()]
|
|
331
|
+
: (process.env.PATH ?? "").split(path.delimiter).map((entry) => {
|
|
332
|
+
const trimmed = entry.trim();
|
|
333
|
+
return trimmed.replace(/^"|"$/g, "") || process.cwd();
|
|
334
|
+
});
|
|
335
|
+
const extensions = process.platform === "win32" && path.extname(command) === ""
|
|
336
|
+
? ["", ...(process.env.PATHEXT ?? ".COM;.EXE;.BAT;.CMD").split(";")]
|
|
337
|
+
: [""];
|
|
338
|
+
return [...new Set(directories.flatMap((directory) =>
|
|
339
|
+
extensions.map((extension) => path.resolve(directory, `${command}${extension.toLowerCase()}`)),
|
|
340
|
+
))];
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
function localExecutableExists(command: string): boolean {
|
|
344
|
+
return localExecutableCandidates(command).some((candidate) => {
|
|
345
|
+
try {
|
|
346
|
+
if (!fs.statSync(candidate).isFile()) return false;
|
|
347
|
+
fs.accessSync(candidate, process.platform === "win32" ? fs.constants.F_OK : fs.constants.X_OK);
|
|
348
|
+
return true;
|
|
349
|
+
} catch {
|
|
350
|
+
return false;
|
|
351
|
+
}
|
|
352
|
+
});
|
|
353
|
+
}
|
|
354
|
+
|
|
329
355
|
function probeLocalExecutable(key: string, command: string): CliToolProbeResult {
|
|
330
356
|
const quotedCommand = JSON.stringify(command);
|
|
331
357
|
let result: CliToolProbeResult;
|
|
@@ -351,18 +377,9 @@ function probeLocalExecutable(key: string, command: string): CliToolProbeResult
|
|
|
351
377
|
};
|
|
352
378
|
}
|
|
353
379
|
} else {
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
encoding: "utf8",
|
|
358
|
-
timeout: PROBE_TIMEOUT_MS,
|
|
359
|
-
stdio: ["ignore", "ignore", "pipe"],
|
|
360
|
-
windowsHide: true,
|
|
361
|
-
});
|
|
362
|
-
result = { ok: true, command };
|
|
363
|
-
} catch {
|
|
364
|
-
result = { ok: false, command, error: `executable ${quotedCommand} not found on PATH${adapterInstallHint(command)}` };
|
|
365
|
-
}
|
|
380
|
+
result = localExecutableExists(command)
|
|
381
|
+
? { ok: true, command }
|
|
382
|
+
: { ok: false, command, error: `executable ${quotedCommand} not found on PATH${adapterInstallHint(command)}` };
|
|
366
383
|
}
|
|
367
384
|
probeCache.set(key, { result, at: Date.now() });
|
|
368
385
|
return result;
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import * as path from "node:path";
|
|
2
|
+
import { CompletionOutboxFileStore } from "./file-store.ts";
|
|
3
|
+
import { getRuntimeWorkspaceIdentity } from "../runtime-broker/private-state.ts";
|
|
4
|
+
|
|
5
|
+
interface ParsedOptions {
|
|
6
|
+
command?: "cleanup";
|
|
7
|
+
workspace: string;
|
|
8
|
+
rootDir?: string;
|
|
9
|
+
apply: boolean;
|
|
10
|
+
json: boolean;
|
|
11
|
+
maxEntries?: number;
|
|
12
|
+
help: boolean;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function usage(): string {
|
|
16
|
+
return [
|
|
17
|
+
"Usage: pi-teammate-outbox cleanup [options]",
|
|
18
|
+
"",
|
|
19
|
+
"Safely removes obsolete atomic-replacement remnants while preserving the",
|
|
20
|
+
"latest recoverable transaction for every canonical outbox file.",
|
|
21
|
+
"",
|
|
22
|
+
"Options:",
|
|
23
|
+
" --workspace <path> Workspace whose outbox is cleaned (default: cwd)",
|
|
24
|
+
" --root <path> Completion outbox root directory",
|
|
25
|
+
" --apply Delete candidates; without this flag cleanup is dry-run",
|
|
26
|
+
" --max-entries <n> Refuse scans larger than n entries (default: 100000)",
|
|
27
|
+
" --json Emit one JSON result",
|
|
28
|
+
" --help Show this help",
|
|
29
|
+
"",
|
|
30
|
+
"Exit codes: 0 success, 2 usage error, 3 workspace outbox is busy.",
|
|
31
|
+
].join("\n");
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function parsePositiveInteger(value: string | undefined, option: string): number {
|
|
35
|
+
if (!value || !/^\d+$/.test(value)) throw new Error(`${option} requires a positive integer`);
|
|
36
|
+
const parsed = Number(value);
|
|
37
|
+
if (!Number.isSafeInteger(parsed) || parsed < 1 || parsed > 1_000_000) {
|
|
38
|
+
throw new Error(`${option} must be between 1 and 1000000`);
|
|
39
|
+
}
|
|
40
|
+
return parsed;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function parseOptions(args: readonly string[]): ParsedOptions {
|
|
44
|
+
const first = args[0];
|
|
45
|
+
const command = first === "cleanup" ? first : undefined;
|
|
46
|
+
const help = args.includes("--help") || args.includes("-h");
|
|
47
|
+
const options: ParsedOptions = {
|
|
48
|
+
command,
|
|
49
|
+
workspace: process.cwd(),
|
|
50
|
+
apply: false,
|
|
51
|
+
json: false,
|
|
52
|
+
help,
|
|
53
|
+
};
|
|
54
|
+
for (let index = command ? 1 : (help ? 1 : 0); index < args.length; index += 1) {
|
|
55
|
+
const argument = args[index];
|
|
56
|
+
if (argument === "--help" || argument === "-h") continue;
|
|
57
|
+
if (argument === "--apply") {
|
|
58
|
+
options.apply = true;
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
if (argument === "--json") {
|
|
62
|
+
options.json = true;
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
const value = args[++index];
|
|
66
|
+
if (argument === "--workspace") {
|
|
67
|
+
if (!value) throw new Error("--workspace requires a path");
|
|
68
|
+
options.workspace = path.resolve(value);
|
|
69
|
+
} else if (argument === "--root") {
|
|
70
|
+
if (!value) throw new Error("--root requires a path");
|
|
71
|
+
options.rootDir = path.resolve(value);
|
|
72
|
+
} else if (argument === "--max-entries") {
|
|
73
|
+
options.maxEntries = parsePositiveInteger(value, argument);
|
|
74
|
+
} else {
|
|
75
|
+
throw new Error(`Unknown option: ${argument}`);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return options;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export async function main(args = process.argv.slice(2)): Promise<number> {
|
|
82
|
+
const options = parseOptions(args);
|
|
83
|
+
if (options.help || !options.command) {
|
|
84
|
+
process.stdout.write(`${usage()}\n`);
|
|
85
|
+
return options.help ? 0 : 2;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const identity = getRuntimeWorkspaceIdentity(options.workspace);
|
|
89
|
+
const store = new CompletionOutboxFileStore({
|
|
90
|
+
...(options.rootDir === undefined ? {} : { rootDir: options.rootDir }),
|
|
91
|
+
});
|
|
92
|
+
const result = await store.cleanupRemnants(identity.workspaceId, {
|
|
93
|
+
apply: options.apply,
|
|
94
|
+
...(options.maxEntries === undefined ? {} : { maxEntries: options.maxEntries }),
|
|
95
|
+
});
|
|
96
|
+
const output = {
|
|
97
|
+
workspace: identity.canonicalPath,
|
|
98
|
+
workspaceId: identity.workspaceId,
|
|
99
|
+
rootDir: store.rootDir,
|
|
100
|
+
...result,
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
if (options.json) {
|
|
104
|
+
process.stdout.write(`${JSON.stringify(output)}\n`);
|
|
105
|
+
} else if (result.busy) {
|
|
106
|
+
process.stderr.write(`Completion outbox is busy for ${identity.canonicalPath}; nothing was removed.\n`);
|
|
107
|
+
} else {
|
|
108
|
+
process.stdout.write([
|
|
109
|
+
`Completion outbox cleanup: ${result.apply ? "applied" : "dry-run"}`,
|
|
110
|
+
`Workspace: ${identity.canonicalPath}`,
|
|
111
|
+
`Scanned: ${result.scannedEntries} entries (${result.replacementFiles} replacement remnants)`,
|
|
112
|
+
`Preserved: ${result.preservedFiles}`,
|
|
113
|
+
`Candidates: ${result.candidateFiles} files, ${result.candidateBytes} bytes`,
|
|
114
|
+
`Removed: ${result.removedFiles} files, ${result.removedBytes} bytes`,
|
|
115
|
+
...(result.candidateSample.length === 0 ? [] : [
|
|
116
|
+
"Candidate sample:",
|
|
117
|
+
...result.candidateSample.map((candidate) => ` ${candidate}`),
|
|
118
|
+
]),
|
|
119
|
+
...(!result.apply && result.candidateFiles > 0 ? ["Re-run with --apply to remove these candidates."] : []),
|
|
120
|
+
].join("\n") + "\n");
|
|
121
|
+
}
|
|
122
|
+
return result.busy ? 3 : 0;
|
|
123
|
+
}
|