@yaag/extension 0.6.0 → 0.6.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/package.json +5 -5
- package/src/index.ts +21 -18
- package/src/process/index.ts +16 -0
- package/src/record/index.ts +24 -0
- package/src/{run-program-param.ts → record/run-program-param.ts} +1 -1
- package/src/{run-record.ts → record/run-record.ts} +1 -1
- package/src/{run-registry.ts → record/run-registry.ts} +31 -12
- package/src/{run-restore.ts → record/run-restore.ts} +10 -3
- package/src/record/run-settle-record.ts +67 -0
- package/src/{run-settlement.ts → record/run-settlement.ts} +1 -1
- package/src/{fake-run-start.ts → testing/fake-run-start.ts} +1 -1
- package/src/testing/index.ts +19 -0
- package/src/{run-call-render.ts → testing/run-call-render.ts} +3 -4
- package/src/{run-tool-test-support.ts → testing/run-tool-test-support.ts} +11 -10
- package/src/{describe-tool.ts → tool/describe-tool.ts} +1 -2
- package/src/tool/index.ts +9 -0
- package/src/{run-tool.ts → tool/run-tool.ts} +32 -17
- package/src/{status-tool.ts → tool/status-tool.ts} +2 -4
- package/src/{stop-tool.ts → tool/stop-tool.ts} +40 -12
- package/src/{background-status.ts → view/background-status.ts} +1 -1
- package/src/view/index.ts +25 -0
- package/src/{restored-run-text.ts → view/restored-run-text.ts} +1 -1
- package/src/{run-call-body.ts → view/run-call-body.ts} +1 -1
- package/src/{run-foreground.ts → view/run-foreground.ts} +2 -2
- package/src/{run-listing.ts → view/run-listing.ts} +1 -1
- package/src/{run-picker.ts → view/run-picker.ts} +1 -1
- package/src/{yaag-command.ts → view/yaag-command.ts} +2 -2
- package/src/workspace/index.ts +8 -0
- package/src/{setup-workspace.ts → workspace/setup-workspace.ts} +6 -2
- /package/src/{cli-child.ts → process/cli-child.ts} +0 -0
- /package/src/{eval-pipe.ts → process/eval-pipe.ts} +0 -0
- /package/src/{event-reader.ts → process/event-reader.ts} +0 -0
- /package/src/{process-liveness.ts → process/process-liveness.ts} +0 -0
- /package/src/{resolve-bun.ts → process/resolve-bun.ts} +0 -0
- /package/src/{resolve-cli.ts → process/resolve-cli.ts} +0 -0
- /package/src/{run-argv.ts → process/run-argv.ts} +0 -0
- /package/src/{spawn-run.ts → process/spawn-run.ts} +0 -0
- /package/src/{status.ts → process/status.ts} +0 -0
- /package/src/{stderr-buffer.ts → process/stderr-buffer.ts} +0 -0
- /package/src/{resume-source.ts → record/resume-source.ts} +0 -0
- /package/src/{run-id.ts → record/run-id.ts} +0 -0
- /package/src/{run-store.ts → record/run-store.ts} +0 -0
- /package/src/{run-summary-parse.ts → record/run-summary-parse.ts} +0 -0
- /package/src/{runs-dir.ts → record/runs-dir.ts} +0 -0
- /package/src/{fake-extension-ui.ts → testing/fake-extension-ui.ts} +0 -0
- /package/src/{fake-theme.ts → testing/fake-theme.ts} +0 -0
- /package/src/{fake-tui.ts → testing/fake-tui.ts} +0 -0
- /package/src/{pi-keybindings.ts → testing/pi-keybindings.ts} +0 -0
- /package/src/{test-extension-context.ts → testing/test-extension-context.ts} +0 -0
- /package/src/{test-tui-context.ts → testing/test-tui-context.ts} +0 -0
- /package/src/{system-prompt-append.ts → tool/system-prompt-append.ts} +0 -0
- /package/src/{run-complete-renderer.ts → view/run-complete-renderer.ts} +0 -0
- /package/src/{run-details.ts → view/run-details.ts} +0 -0
- /package/src/{run-tree-component.ts → view/run-tree-component.ts} +0 -0
- /package/src/{run-tree-host.ts → view/run-tree-host.ts} +0 -0
- /package/src/{run-trees.ts → view/run-trees.ts} +0 -0
- /package/src/{usage.ts → view/usage.ts} +0 -0
- /package/src/{program-directories.ts → workspace/program-directories.ts} +0 -0
- /package/src/{setup-workspace-command.ts → workspace/setup-workspace-command.ts} +0 -0
- /package/src/{setup-workspace-tool.ts → workspace/setup-workspace-tool.ts} +0 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yaag/extension",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.2",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
@@ -19,14 +19,14 @@
|
|
|
19
19
|
},
|
|
20
20
|
"scripts": {
|
|
21
21
|
"typecheck": "tsc --noEmit",
|
|
22
|
-
"test": "for file in src
|
|
22
|
+
"test": "for file in src/*/*.test.ts; do bun test --timeout 30000 \"$file\" || exit 1; done",
|
|
23
23
|
"test:e2e": "bun test --timeout 30000 e2e"
|
|
24
24
|
},
|
|
25
25
|
"dependencies": {
|
|
26
26
|
"@earendil-works/pi-tui": "^0.84.0",
|
|
27
|
-
"@yaag/cli": "0.6.
|
|
28
|
-
"@yaag/runtime": "0.6.
|
|
29
|
-
"@yaag/tui": "0.6.
|
|
27
|
+
"@yaag/cli": "0.6.2",
|
|
28
|
+
"@yaag/runtime": "0.6.2",
|
|
29
|
+
"@yaag/tui": "0.6.2",
|
|
30
30
|
"nanoid": "^6.0.1"
|
|
31
31
|
},
|
|
32
32
|
"peerDependencies": {
|
package/src/index.ts
CHANGED
|
@@ -1,22 +1,25 @@
|
|
|
1
1
|
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
import {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
import {
|
|
18
|
-
|
|
19
|
-
|
|
2
|
+
import { resolveBun, resolveCliEntry, statusReport } from "./process/index.ts";
|
|
3
|
+
import { RunRegistry, RunStore } from "./record/index.ts";
|
|
4
|
+
import {
|
|
5
|
+
createDescribeTool,
|
|
6
|
+
createRunTool,
|
|
7
|
+
createStatusTool,
|
|
8
|
+
createStopTool,
|
|
9
|
+
createSystemPromptAppender,
|
|
10
|
+
} from "./tool/index.ts";
|
|
11
|
+
import {
|
|
12
|
+
createBackgroundStatus,
|
|
13
|
+
createRunCompleteRenderer,
|
|
14
|
+
createYaagCommand,
|
|
15
|
+
RunTreeStore,
|
|
16
|
+
} from "./view/index.ts";
|
|
17
|
+
import {
|
|
18
|
+
createSetupWorkspaceCommand,
|
|
19
|
+
createSetupWorkspaceExecutor,
|
|
20
|
+
createSetupWorkspaceTool,
|
|
21
|
+
findProgramDirectories,
|
|
22
|
+
} from "./workspace/index.ts";
|
|
20
23
|
|
|
21
24
|
/**
|
|
22
25
|
* The yaag pi extension. Loaded by pi through jiti, in Node — nothing here may
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public surface of the `process/` module: child-process plumbing and the Bun-CLI bridge.
|
|
3
|
+
* Files inside this directory import each other directly.
|
|
4
|
+
*/
|
|
5
|
+
export {
|
|
6
|
+
type CliChild,
|
|
7
|
+
type CliChildOptions,
|
|
8
|
+
type CliChildOutcome,
|
|
9
|
+
startCliChild,
|
|
10
|
+
} from "./cli-child.ts";
|
|
11
|
+
export { isProcessAlive, type ProcessIdentity, readProcessStart } from "./process-liveness.ts";
|
|
12
|
+
export { resolveBun } from "./resolve-bun.ts";
|
|
13
|
+
export { resolveCliEntry } from "./resolve-cli.ts";
|
|
14
|
+
export type { ProgramTarget } from "./run-argv.ts";
|
|
15
|
+
export { type RunHandle, type RunOutcome, type StartRunOptions, startRun } from "./spawn-run.ts";
|
|
16
|
+
export { statusReport } from "./status.ts";
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public surface of the `record/` module: the Run record registry, store, restore, and resume.
|
|
3
|
+
* Files inside this directory import each other directly.
|
|
4
|
+
*/
|
|
5
|
+
export { resolveProgramParams } from "./resume-source.ts";
|
|
6
|
+
export { mintRunId } from "./run-id.ts";
|
|
7
|
+
export {
|
|
8
|
+
confirmProgramTarget,
|
|
9
|
+
type ProgramParams,
|
|
10
|
+
programExpansion,
|
|
11
|
+
programLabel,
|
|
12
|
+
programTarget,
|
|
13
|
+
} from "./run-program-param.ts";
|
|
14
|
+
export type { RunLaunch, RunRecord } from "./run-record.ts";
|
|
15
|
+
export {
|
|
16
|
+
type DatedRun,
|
|
17
|
+
type LiveRun,
|
|
18
|
+
type RegisteredRun,
|
|
19
|
+
type RestoredRun,
|
|
20
|
+
RunRegistry,
|
|
21
|
+
type RunSettlement,
|
|
22
|
+
} from "./run-registry.ts";
|
|
23
|
+
export { errorText, failure, observedSettlement, toError, viewResult } from "./run-settlement.ts";
|
|
24
|
+
export { RunStore } from "./run-store.ts";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { access } from "node:fs/promises";
|
|
2
2
|
import { resolve } from "node:path";
|
|
3
3
|
import { clampToWidth, sanitizeTerminalLine, sanitizeTerminalText } from "@yaag/tui";
|
|
4
|
-
import type { ProgramTarget } from "
|
|
4
|
+
import type { ProgramTarget } from "../process/index.ts";
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* The `yaag_run` parameters that name the program; exactly one is given.
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import type { ProcessIdentity } from "
|
|
1
|
+
import type { RunSummary, RunOutcome as SummaryOutcome } from "@yaag/runtime";
|
|
2
|
+
import type { ProcessIdentity, RunOutcome } from "../process/index.ts";
|
|
3
3
|
import { pickInlineResumeSource } from "./resume-source.ts";
|
|
4
4
|
import { type RunLaunch, type RunRecord, startedRecord } from "./run-record.ts";
|
|
5
5
|
import { restoreRecords } from "./run-restore.ts";
|
|
6
|
+
import { failedSummary, settledRecord } from "./run-settle-record.ts";
|
|
6
7
|
import type { RunStore } from "./run-store.ts";
|
|
7
|
-
import type { RunOutcome } from "./spawn-run.ts";
|
|
8
8
|
|
|
9
9
|
export type { RunLaunch } from "./run-record.ts";
|
|
10
10
|
|
|
@@ -149,8 +149,30 @@ export class RunRegistry {
|
|
|
149
149
|
}
|
|
150
150
|
|
|
151
151
|
/**
|
|
152
|
-
*
|
|
153
|
-
*
|
|
152
|
+
* Persists the settled form of a Run read back from disk, and refreshes the
|
|
153
|
+
* retained entry so the next snapshot of this session shows the verdict.
|
|
154
|
+
*
|
|
155
|
+
* Only a `restored` Run settles here: a live Run settles through its own
|
|
156
|
+
* outcome, and a finished Run is history (ADR-0036), so either is refused
|
|
157
|
+
* rather than written over. A Run this session never listed stays unlisted —
|
|
158
|
+
* it is written, but not adopted.
|
|
159
|
+
*/
|
|
160
|
+
async settleRestored(record: RunRecord, outcome: SummaryOutcome): Promise<RestoredRun> {
|
|
161
|
+
const known = this.#runs.get(record.id);
|
|
162
|
+
if (known !== undefined && known.state !== "restored")
|
|
163
|
+
throw new Error(`RunRegistry: Run ${record.id} is ${known.state}, not a restored Run`);
|
|
164
|
+
const settled = settledRecord({ record, outcome, now: this.#now() });
|
|
165
|
+
this.#records.set(settled.id, settled);
|
|
166
|
+
if (known !== undefined)
|
|
167
|
+
this.#runs.set(settled.id, { state: "restored", run: restored(settled) });
|
|
168
|
+
await this.#store?.save(settled);
|
|
169
|
+
return restored(settled);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* `restoreRecords` already settled every stale `live` record, and every
|
|
174
|
+
* `orphaned` record whose process is gone, so this check can never adopt a
|
|
175
|
+
* Run as live (ADR-0036).
|
|
154
176
|
*/
|
|
155
177
|
#adoptable(record: RunRecord): boolean {
|
|
156
178
|
if (record.state === "orphaned" || record.state === "interrupted") return true;
|
|
@@ -229,7 +251,10 @@ export class RunRegistry {
|
|
|
229
251
|
reject(id: string, reason: unknown): void {
|
|
230
252
|
const record = this.#runs.get(id);
|
|
231
253
|
if (record === undefined || record.state !== "live") return;
|
|
232
|
-
this.#settle(id, failedSummary(record.run.summary), {
|
|
254
|
+
this.#settle(id, failedSummary(record.run.summary, this.#now().getTime()), {
|
|
255
|
+
kind: "rejected",
|
|
256
|
+
reason,
|
|
257
|
+
});
|
|
233
258
|
}
|
|
234
259
|
|
|
235
260
|
/**
|
|
@@ -311,9 +336,3 @@ function persistedOutcome(outcome: RunSettlement): RunRecord["outcome"] {
|
|
|
311
336
|
function errorMessage(reason: unknown): string {
|
|
312
337
|
return reason instanceof Error ? reason.message : String(reason);
|
|
313
338
|
}
|
|
314
|
-
|
|
315
|
-
function failedSummary(summary: RunSummary): EndedRunSummary {
|
|
316
|
-
if (summary.runState === "ended")
|
|
317
|
-
return summary.ok ? { ...summary, outcome: "failed", ok: false } : summary;
|
|
318
|
-
return { ...summary, runState: "ended", outcome: "failed", ok: false, endedAt: null };
|
|
319
|
-
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { isProcessAlive, type ProcessIdentity } from "
|
|
1
|
+
import { isProcessAlive, type ProcessIdentity } from "../process/index.ts";
|
|
2
2
|
import type { RunRecord } from "./run-record.ts";
|
|
3
|
+
import { settledRecord } from "./run-settle-record.ts";
|
|
3
4
|
import type { RunStore } from "./run-store.ts";
|
|
4
5
|
|
|
5
6
|
/** Decides whether the process a record names is still running. */
|
|
@@ -19,6 +20,11 @@ export interface RestoreOptions {
|
|
|
19
20
|
* gone: its child is dead and the Run is `interrupted`, or its child still runs
|
|
20
21
|
* without an owner and the Run is `orphaned`. Both re-writes are persisted, so
|
|
21
22
|
* the verdict survives this session too (ticket 02).
|
|
23
|
+
*
|
|
24
|
+
* An `orphaned` record is probed again: its child can have ended since the
|
|
25
|
+
* session that orphaned it, and a dead one settles to `interrupted` with an end
|
|
26
|
+
* instant and an ended Summary. An orphan that still runs is left as it is, so
|
|
27
|
+
* a session start does not rewrite every record.
|
|
22
28
|
*/
|
|
23
29
|
export async function restoreRecords(options: RestoreOptions): Promise<readonly RunRecord[]> {
|
|
24
30
|
const isAlive = options.isAlive ?? isProcessAlive;
|
|
@@ -33,11 +39,12 @@ async function settleStale(
|
|
|
33
39
|
now: () => Date,
|
|
34
40
|
store: RunStore,
|
|
35
41
|
): Promise<RunRecord> {
|
|
36
|
-
if (record.state !== "live") return record;
|
|
42
|
+
if (record.state !== "live" && record.state !== "orphaned") return record;
|
|
37
43
|
const alive = record.process !== null && isAlive(record.process);
|
|
44
|
+
if (alive && record.state === "orphaned") return record;
|
|
38
45
|
const settled: RunRecord = alive
|
|
39
46
|
? { ...record, state: "orphaned" }
|
|
40
|
-
: {
|
|
47
|
+
: settledRecord({ record, outcome: "interrupted", now: now() });
|
|
41
48
|
await store.save(settled);
|
|
42
49
|
return settled;
|
|
43
50
|
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import type { EndedRunSummary, RunOutcome, RunSummary } from "@yaag/runtime";
|
|
2
|
+
import type { RunRecord } from "./run-record.ts";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Marks a folded Summary ended, keeping every accounting fact it holds.
|
|
6
|
+
*
|
|
7
|
+
* An already-ended fold is history and is returned unchanged: a Run keeps the
|
|
8
|
+
* first outcome observed for it, the invariant the registry keeps when it
|
|
9
|
+
* retains a settlement. `endedAt` stays null because it is the `run_end.at`
|
|
10
|
+
* event fact and no such event was seen.
|
|
11
|
+
*/
|
|
12
|
+
export function endedSummary(
|
|
13
|
+
summary: RunSummary,
|
|
14
|
+
outcome: RunOutcome,
|
|
15
|
+
endedAtMs: number,
|
|
16
|
+
): EndedRunSummary {
|
|
17
|
+
if (summary.runState === "ended") return summary;
|
|
18
|
+
return {
|
|
19
|
+
...summary,
|
|
20
|
+
runState: "ended",
|
|
21
|
+
outcome,
|
|
22
|
+
ok: outcome === "completed",
|
|
23
|
+
endedAt: null,
|
|
24
|
+
durationMs: durationOf(summary, endedAtMs),
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* The fold never synthesizes a duration from a clock (architecture §8), so the
|
|
30
|
+
* wall-clock value is supplied here, once, by the caller that settles the Run.
|
|
31
|
+
* Without it a settled Run reads `0s` instead of how long it really ran.
|
|
32
|
+
*/
|
|
33
|
+
function durationOf(summary: RunSummary, endedAtMs: number): number {
|
|
34
|
+
if (summary.durationMs !== 0) return summary.durationMs;
|
|
35
|
+
if (summary.startedAt === null) return 0;
|
|
36
|
+
return Math.max(0, endedAtMs - summary.startedAt);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/** Marks a fold ended as failed, for a Run whose child rejected. */
|
|
40
|
+
export function failedSummary(summary: RunSummary, endedAtMs: number): EndedRunSummary {
|
|
41
|
+
if (summary.runState === "ended")
|
|
42
|
+
return summary.ok ? { ...summary, outcome: "failed", ok: false } : summary;
|
|
43
|
+
return endedSummary(summary, "failed", endedAtMs);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* The settled form of a record no process is attached to any more.
|
|
48
|
+
*
|
|
49
|
+
* The persisted state is `interrupted`: no new state member is added, so an
|
|
50
|
+
* older yaag still reads the record. The verdict lives in the Summary fold —
|
|
51
|
+
* `stopped` when yaag_stop killed the group, `interrupted` when the process was
|
|
52
|
+
* already gone. The persisted outcome stays null, because the Run gave no exit
|
|
53
|
+
* code and no rejection reason.
|
|
54
|
+
*/
|
|
55
|
+
export function settledRecord(options: {
|
|
56
|
+
readonly record: RunRecord;
|
|
57
|
+
readonly outcome: RunOutcome;
|
|
58
|
+
readonly now: Date;
|
|
59
|
+
}): RunRecord {
|
|
60
|
+
const { record, outcome, now } = options;
|
|
61
|
+
return {
|
|
62
|
+
...record,
|
|
63
|
+
state: "interrupted",
|
|
64
|
+
endedAt: now.toISOString(),
|
|
65
|
+
summary: endedSummary(record.summary, outcome, now.getTime()),
|
|
66
|
+
};
|
|
67
|
+
}
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
* the blocking, interactive, and background paths of `yaag_run`.
|
|
4
4
|
*/
|
|
5
5
|
import type { RunViewResult } from "@yaag/tui";
|
|
6
|
+
import type { RunOutcome } from "../process/index.ts";
|
|
6
7
|
import type { RunRegistry, RunSettlement } from "./run-registry.ts";
|
|
7
|
-
import type { RunOutcome } from "./spawn-run.ts";
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* The settlement the registry retained for a Run.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { initialSummary } from "@yaag/runtime";
|
|
2
|
-
import type { RunHandle, StartRunOptions } from "
|
|
2
|
+
import type { RunHandle, StartRunOptions } from "../process/index.ts";
|
|
3
3
|
|
|
4
4
|
/** A start seam that never spawns: it captures its options and ends the Run at once. */
|
|
5
5
|
export function fakeStart(stdout = "{}"): {
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public surface of the `testing/` module: package-spanning test helpers and fakes.
|
|
3
|
+
* Files inside this directory import each other directly.
|
|
4
|
+
*/
|
|
5
|
+
export { fakeStart } from "./fake-run-start.ts";
|
|
6
|
+
export { loadPiKeybindings } from "./pi-keybindings.ts";
|
|
7
|
+
export { renderCallLabel, renderCallLines } from "./run-call-render.ts";
|
|
8
|
+
export {
|
|
9
|
+
asError,
|
|
10
|
+
fixture,
|
|
11
|
+
run,
|
|
12
|
+
running,
|
|
13
|
+
type Sent,
|
|
14
|
+
stop,
|
|
15
|
+
toolDescription,
|
|
16
|
+
until,
|
|
17
|
+
} from "./run-tool-test-support.ts";
|
|
18
|
+
export { TestExtensionContext } from "./test-extension-context.ts";
|
|
19
|
+
export { TestTuiContext } from "./test-tui-context.ts";
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import { stripTerminalSequences } from "@earendil-works/pi-tui";
|
|
2
|
+
import { resolveBun, resolveCliEntry } from "../process/index.ts";
|
|
3
|
+
import { RunRegistry } from "../record/index.ts";
|
|
4
|
+
import { createRunTool } from "../tool/index.ts";
|
|
2
5
|
import { fakeTheme } from "./fake-theme.ts";
|
|
3
|
-
import { resolveBun } from "./resolve-bun.ts";
|
|
4
|
-
import { resolveCliEntry } from "./resolve-cli.ts";
|
|
5
|
-
import { RunRegistry } from "./run-registry.ts";
|
|
6
|
-
import { createRunTool } from "./run-tool.ts";
|
|
7
6
|
|
|
8
7
|
const cli = resolveCliEntry();
|
|
9
8
|
const bun = await resolveBun();
|
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
import { dirname, join } from "node:path";
|
|
2
2
|
import type { AgentToolResult, ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
3
|
-
import type {
|
|
4
|
-
import { resolveBun } from "
|
|
5
|
-
import {
|
|
3
|
+
import type { RunHandle } from "../process/index.ts";
|
|
4
|
+
import { resolveBun, resolveCliEntry } from "../process/index.ts";
|
|
5
|
+
import { RunRegistry } from "../record/index.ts";
|
|
6
|
+
import {
|
|
7
|
+
createRunTool,
|
|
8
|
+
createStopTool,
|
|
9
|
+
type SendMessage,
|
|
10
|
+
type StopDetails,
|
|
11
|
+
} from "../tool/index.ts";
|
|
12
|
+
import type { BackgroundStatus, RunDetails, RunTreeStore } from "../view/index.ts";
|
|
6
13
|
import type { RunParams } from "./run-call-render.ts";
|
|
7
|
-
import type { RunDetails } from "./run-details.ts";
|
|
8
|
-
import { RunRegistry } from "./run-registry.ts";
|
|
9
|
-
import { createRunTool, type SendMessage } from "./run-tool.ts";
|
|
10
|
-
import type { RunTreeStore } from "./run-trees.ts";
|
|
11
|
-
import type { RunHandle } from "./spawn-run.ts";
|
|
12
|
-
import { createStopTool, type StopDetails } from "./stop-tool.ts";
|
|
13
14
|
import { TestExtensionContext } from "./test-extension-context.ts";
|
|
14
15
|
|
|
15
16
|
const cli = resolveCliEntry();
|
|
@@ -34,7 +35,7 @@ export async function run(
|
|
|
34
35
|
readonly onUpdate?: (partial: AgentToolResult<RunDetails>) => void;
|
|
35
36
|
readonly registry?: RunRegistry;
|
|
36
37
|
readonly sent?: Sent[];
|
|
37
|
-
readonly start?: (options: import("
|
|
38
|
+
readonly start?: (options: import("../process/index.ts").StartRunOptions) => RunHandle;
|
|
38
39
|
/** A tui-mode context, for the inline foreground path. */
|
|
39
40
|
readonly ctx?: ExtensionContext;
|
|
40
41
|
readonly store?: RunTreeStore;
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { resolve } from "node:path";
|
|
2
2
|
import type { ToolDefinition } from "@earendil-works/pi-coding-agent";
|
|
3
3
|
import { Type } from "typebox";
|
|
4
|
-
import { startCliChild } from "
|
|
5
|
-
import { statusReport } from "./status.ts";
|
|
4
|
+
import { startCliChild, statusReport } from "../process/index.ts";
|
|
6
5
|
|
|
7
6
|
const parameters = Type.Object({
|
|
8
7
|
file: Type.String({ description: "Path to the Orchestration Program file" }),
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public surface of the `tool/` module: the pi tools the extension registers.
|
|
3
|
+
* Files inside this directory import each other directly.
|
|
4
|
+
*/
|
|
5
|
+
export { createDescribeTool } from "./describe-tool.ts";
|
|
6
|
+
export { createRunTool, type RunDetails, type SendMessage } from "./run-tool.ts";
|
|
7
|
+
export { createStatusTool } from "./status-tool.ts";
|
|
8
|
+
export { createStopTool, type StopDetails } from "./stop-tool.ts";
|
|
9
|
+
export { createSystemPromptAppender } from "./system-prompt-append.ts";
|
|
@@ -3,25 +3,40 @@ import type { ExtensionAPI, ToolDefinition } from "@earendil-works/pi-coding-age
|
|
|
3
3
|
import { Text } from "@earendil-works/pi-tui";
|
|
4
4
|
import { initialSummary } from "@yaag/runtime";
|
|
5
5
|
import { Type } from "typebox";
|
|
6
|
-
import
|
|
7
|
-
import {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
6
|
+
import type { RunDetails } from "../view/index.ts";
|
|
7
|
+
import {
|
|
8
|
+
type BackgroundStatus,
|
|
9
|
+
callBody,
|
|
10
|
+
createBackgroundStatus,
|
|
11
|
+
foregroundInline,
|
|
12
|
+
foregroundResult,
|
|
13
|
+
inlineAvailable,
|
|
14
|
+
RunTreeComponent,
|
|
15
|
+
RunTreeStore,
|
|
16
|
+
} from "../view/index.ts";
|
|
12
17
|
|
|
13
|
-
export type { RunDetails } from "
|
|
18
|
+
export type { RunDetails } from "../view/index.ts";
|
|
14
19
|
|
|
15
|
-
import
|
|
16
|
-
import {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
20
|
+
import type { ProgramTarget } from "../process/index.ts";
|
|
21
|
+
import {
|
|
22
|
+
type ProcessIdentity,
|
|
23
|
+
type RunHandle,
|
|
24
|
+
type RunOutcome,
|
|
25
|
+
readProcessStart,
|
|
26
|
+
type StartRunOptions,
|
|
27
|
+
startRun,
|
|
28
|
+
statusReport,
|
|
29
|
+
} from "../process/index.ts";
|
|
30
|
+
import type { LiveRun, RunLaunch, RunRegistry, RunSettlement } from "../record/index.ts";
|
|
31
|
+
import {
|
|
32
|
+
confirmProgramTarget,
|
|
33
|
+
errorText,
|
|
34
|
+
failure,
|
|
35
|
+
mintRunId,
|
|
36
|
+
observedSettlement,
|
|
37
|
+
programTarget,
|
|
38
|
+
resolveProgramParams,
|
|
39
|
+
} from "../record/index.ts";
|
|
25
40
|
|
|
26
41
|
const parameters = Type.Object({
|
|
27
42
|
file: Type.Optional(
|
|
@@ -2,10 +2,8 @@ import type { AgentToolResult, ToolDefinition } from "@earendil-works/pi-coding-
|
|
|
2
2
|
import type { RunSummary } from "@yaag/runtime";
|
|
3
3
|
import { renderSnapshot, TreeState } from "@yaag/tui";
|
|
4
4
|
import { Type } from "typebox";
|
|
5
|
-
import {
|
|
6
|
-
import { boundedRuns, RUN_LISTING_CAP } from "
|
|
7
|
-
import type { RegisteredRun, RestoredRun, RunRegistry } from "./run-registry.ts";
|
|
8
|
-
import { toUsage } from "./usage.ts";
|
|
5
|
+
import type { RegisteredRun, RestoredRun, RunRegistry } from "../record/index.ts";
|
|
6
|
+
import { boundedRuns, RUN_LISTING_CAP, restoredStateText, toUsage } from "../view/index.ts";
|
|
9
7
|
|
|
10
8
|
const parameters = Type.Object({
|
|
11
9
|
id: Type.Optional(Type.String({ description: "The Run id returned by yaag_run (e.g. r1)" })),
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import type { AgentToolResult, ToolDefinition } from "@earendil-works/pi-coding-agent";
|
|
2
2
|
import type { RunSummary } from "@yaag/runtime";
|
|
3
3
|
import { Type } from "typebox";
|
|
4
|
-
import { isProcessAlive } from "
|
|
5
|
-
import type { RestoredRun, RunRegistry } from "
|
|
6
|
-
import { toUsage } from "
|
|
4
|
+
import { isProcessAlive, type ProcessIdentity } from "../process/index.ts";
|
|
5
|
+
import type { RestoredRun, RunRegistry } from "../record/index.ts";
|
|
6
|
+
import { toUsage } from "../view/index.ts";
|
|
7
7
|
|
|
8
8
|
/** What the stop result carries for rendering — never shown to the model. */
|
|
9
9
|
export interface StopDetails {
|
|
@@ -21,9 +21,22 @@ const DESCRIPTION = [
|
|
|
21
21
|
"it spent before it stopped.",
|
|
22
22
|
"",
|
|
23
23
|
"An orphaned Run left behind by an earlier Host Session is stopped too: its",
|
|
24
|
-
"process group is killed, and the report holds its last
|
|
24
|
+
"process group is killed, its record is settled, and the report holds its last",
|
|
25
|
+
"persisted Summary. If its process already ended, the record is settled too and",
|
|
26
|
+
"the report says the Run was no longer running.",
|
|
25
27
|
].join("\n");
|
|
26
28
|
|
|
29
|
+
/** Seams the tests replace, so no test kills a real process group. */
|
|
30
|
+
export interface StopToolOptions {
|
|
31
|
+
readonly isAlive?: (identity: ProcessIdentity) => boolean;
|
|
32
|
+
readonly kill?: (pid: number) => void;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
interface StopDeps {
|
|
36
|
+
readonly isAlive: (identity: ProcessIdentity) => boolean;
|
|
37
|
+
readonly kill: (pid: number) => void;
|
|
38
|
+
}
|
|
39
|
+
|
|
27
40
|
/** What a stopped Run got through and what it cost, from the fold (ADR-0006). */
|
|
28
41
|
export function stopReport(id: string, summary: RunSummary): string {
|
|
29
42
|
const agents = Object.keys(summary.agents).length;
|
|
@@ -71,18 +84,28 @@ function agentStateReport(agent: RunSummary["agents"][string]): string {
|
|
|
71
84
|
* pipes belong to a dead Host Session — so the process group is killed outright
|
|
72
85
|
* (ADR-0008). The pid is re-probed first, because a record can name a pid that
|
|
73
86
|
* a different process has since inherited (ticket 02).
|
|
87
|
+
*
|
|
88
|
+
* The record is settled either way: a process that already ended is not an
|
|
89
|
+
* error, it only means the verdict is `interrupted` instead of `stopped`.
|
|
74
90
|
*/
|
|
75
|
-
function stopOrphan(
|
|
91
|
+
async function stopOrphan(
|
|
92
|
+
run: RestoredRun,
|
|
93
|
+
registry: RunRegistry,
|
|
94
|
+
deps: StopDeps,
|
|
95
|
+
): Promise<AgentToolResult<StopDetails>> {
|
|
76
96
|
const { record } = run;
|
|
77
97
|
if (record.state !== "orphaned" || record.process === null)
|
|
78
98
|
throw new Error(`yaag_stop: Run ${record.id} has already finished`);
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
99
|
+
const alive = deps.isAlive(record.process);
|
|
100
|
+
if (alive) deps.kill(record.process.pid);
|
|
101
|
+
const settled = await registry.settleRestored(record, alive ? "stopped" : "interrupted");
|
|
102
|
+
const note = alive
|
|
103
|
+
? ""
|
|
104
|
+
: `Run ${record.id} was no longer running; its record is settled as interrupted.\n`;
|
|
82
105
|
return {
|
|
83
|
-
content: [{ type: "text", text: stopReport(record.id,
|
|
84
|
-
details: { summary:
|
|
85
|
-
usage: toUsage(
|
|
106
|
+
content: [{ type: "text", text: `${note}${stopReport(record.id, settled.summary)}` }],
|
|
107
|
+
details: { summary: settled.summary },
|
|
108
|
+
usage: toUsage(settled.summary),
|
|
86
109
|
};
|
|
87
110
|
}
|
|
88
111
|
|
|
@@ -111,7 +134,12 @@ function toError(reason: unknown): Error {
|
|
|
111
134
|
*/
|
|
112
135
|
export function createStopTool(
|
|
113
136
|
registry: RunRegistry,
|
|
137
|
+
options: StopToolOptions = {},
|
|
114
138
|
): ToolDefinition<typeof parameters, StopDetails> {
|
|
139
|
+
const deps: StopDeps = {
|
|
140
|
+
isAlive: options.isAlive ?? isProcessAlive,
|
|
141
|
+
kill: options.kill ?? killGroup,
|
|
142
|
+
};
|
|
115
143
|
return {
|
|
116
144
|
name: "yaag_stop",
|
|
117
145
|
label: "Stop Run",
|
|
@@ -123,7 +151,7 @@ export function createStopTool(
|
|
|
123
151
|
case "unknown":
|
|
124
152
|
throw new Error(`yaag_stop: no Run with id ${params.id}`);
|
|
125
153
|
case "restored":
|
|
126
|
-
return stopOrphan(status.run);
|
|
154
|
+
return await stopOrphan(status.run, registry, deps);
|
|
127
155
|
case "finished":
|
|
128
156
|
throw new Error(`yaag_stop: Run ${params.id} has already finished`);
|
|
129
157
|
case "live": {
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* as the last background Run ends.
|
|
8
8
|
*/
|
|
9
9
|
import { costText } from "@yaag/tui";
|
|
10
|
-
import type { RunRegistry } from "
|
|
10
|
+
import type { RunRegistry } from "../record/index.ts";
|
|
11
11
|
import type { RunTreeStore } from "./run-trees.ts";
|
|
12
12
|
|
|
13
13
|
/** The one footer key this extension owns. */
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public surface of the `view/` module: TUI views, renderers, and the /yaag command.
|
|
3
|
+
* Files inside this directory import each other directly.
|
|
4
|
+
*/
|
|
5
|
+
export {
|
|
6
|
+
type BackgroundStatus,
|
|
7
|
+
createBackgroundStatus,
|
|
8
|
+
STATUS_KEY,
|
|
9
|
+
type StatusSurface,
|
|
10
|
+
} from "./background-status.ts";
|
|
11
|
+
export { restoredStateText } from "./restored-run-text.ts";
|
|
12
|
+
export { callBody } from "./run-call-body.ts";
|
|
13
|
+
export { createRunCompleteRenderer } from "./run-complete-renderer.ts";
|
|
14
|
+
export type { RunDetails } from "./run-details.ts";
|
|
15
|
+
export {
|
|
16
|
+
foregroundInline,
|
|
17
|
+
foregroundResult,
|
|
18
|
+
foregroundWidgetKey,
|
|
19
|
+
inlineAvailable,
|
|
20
|
+
} from "./run-foreground.ts";
|
|
21
|
+
export { boundedRuns, RUN_LISTING_CAP } from "./run-listing.ts";
|
|
22
|
+
export { RunTreeComponent } from "./run-tree-component.ts";
|
|
23
|
+
export { RunTreeStore } from "./run-trees.ts";
|
|
24
|
+
export { toUsage } from "./usage.ts";
|
|
25
|
+
export { createYaagCommand } from "./yaag-command.ts";
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* which shows that source.
|
|
5
5
|
*/
|
|
6
6
|
import { keyText, type Theme } from "@earendil-works/pi-coding-agent";
|
|
7
|
-
import { type ProgramParams, programExpansion, programLabel } from "
|
|
7
|
+
import { type ProgramParams, programExpansion, programLabel } from "../record/index.ts";
|
|
8
8
|
|
|
9
9
|
/** What the call render needs: the call itself, its styling, and its state. */
|
|
10
10
|
export interface CallBodyOptions {
|
|
@@ -8,9 +8,9 @@
|
|
|
8
8
|
*/
|
|
9
9
|
import type { ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
10
10
|
import { renderInlineRun, type TreeState } from "@yaag/tui";
|
|
11
|
+
import type { LiveRun, RunRegistry, RunSettlement } from "../record/index.ts";
|
|
12
|
+
import { failure, observedSettlement, toError } from "../record/index.ts";
|
|
11
13
|
import type { RunDetails } from "./run-details.ts";
|
|
12
|
-
import type { LiveRun, RunRegistry, RunSettlement } from "./run-registry.ts";
|
|
13
|
-
import { failure, observedSettlement, toError } from "./run-settlement.ts";
|
|
14
14
|
import type { RunTreeStore } from "./run-trees.ts";
|
|
15
15
|
import { toUsage } from "./usage.ts";
|
|
16
16
|
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* The one bound both Run listings share: the `/yaag` picker and the
|
|
3
3
|
* `yaag_status` overview must agree on which Runs exist (ADR-0036).
|
|
4
4
|
*/
|
|
5
|
-
import type { DatedRun, RegisteredRun } from "
|
|
5
|
+
import type { DatedRun, RegisteredRun } from "../record/index.ts";
|
|
6
6
|
|
|
7
7
|
/** How many Runs the `/yaag` picker and the `yaag_status` overview list. */
|
|
8
8
|
export const RUN_LISTING_CAP = 5;
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
* the list can be tested without a live UI.
|
|
4
4
|
*/
|
|
5
5
|
import type { RunSummary } from "@yaag/runtime";
|
|
6
|
+
import type { DatedRun } from "../record/index.ts";
|
|
6
7
|
import { boundedRuns } from "./run-listing.ts";
|
|
7
|
-
import type { DatedRun } from "./run-registry.ts";
|
|
8
8
|
|
|
9
9
|
/** One Run the picker can open: its id, latest Summary fold, and liveness. */
|
|
10
10
|
export interface PickableRun {
|
|
@@ -14,10 +14,10 @@ import type {
|
|
|
14
14
|
RegisteredCommand,
|
|
15
15
|
} from "@earendil-works/pi-coding-agent";
|
|
16
16
|
import { createRunTreeView, type RunTreeViewHost, type RunViewResult, TreeState } from "@yaag/tui";
|
|
17
|
+
import type { RunRegistry, RunSettlement } from "../record/index.ts";
|
|
18
|
+
import { observedSettlement, viewResult } from "../record/index.ts";
|
|
17
19
|
import { restoredViewResult } from "./restored-run-text.ts";
|
|
18
20
|
import { type PickableRun, pickableRuns, runFromLabel, runPickerLabel } from "./run-picker.ts";
|
|
19
|
-
import type { RunRegistry, RunSettlement } from "./run-registry.ts";
|
|
20
|
-
import { observedSettlement, viewResult } from "./run-settlement.ts";
|
|
21
21
|
import { createRunTreeHost } from "./run-tree-host.ts";
|
|
22
22
|
import type { RunTreeStore } from "./run-trees.ts";
|
|
23
23
|
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public surface of the `workspace/` module: workspace setup and Program Directory discovery.
|
|
3
|
+
* Files inside this directory import each other directly.
|
|
4
|
+
*/
|
|
5
|
+
export { findProgramDirectories } from "./program-directories.ts";
|
|
6
|
+
export { createSetupWorkspaceExecutor } from "./setup-workspace.ts";
|
|
7
|
+
export { createSetupWorkspaceCommand } from "./setup-workspace-command.ts";
|
|
8
|
+
export { createSetupWorkspaceTool } from "./setup-workspace-tool.ts";
|
|
@@ -1,5 +1,9 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import {
|
|
2
|
+
type CliChild,
|
|
3
|
+
type CliChildOptions,
|
|
4
|
+
startCliChild,
|
|
5
|
+
statusReport,
|
|
6
|
+
} from "../process/index.ts";
|
|
3
7
|
|
|
4
8
|
/** Injectable boundary for starting the Bun CLI child. */
|
|
5
9
|
export type StartCliChild = (options: CliChildOptions) => CliChild;
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|