@davidorex/pi-agent-dispatch 0.28.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/CHANGELOG.md +25 -0
- package/README.md +37 -0
- package/dist/attested-commit.d.ts +32 -0
- package/dist/attested-commit.d.ts.map +1 -0
- package/dist/attested-commit.js +61 -0
- package/dist/attested-commit.js.map +1 -0
- package/dist/auth-gate.d.ts +92 -0
- package/dist/auth-gate.d.ts.map +1 -0
- package/dist/auth-gate.js +210 -0
- package/dist/auth-gate.js.map +1 -0
- package/dist/author-agent-spec-tool.d.ts +33 -0
- package/dist/author-agent-spec-tool.d.ts.map +1 -0
- package/dist/author-agent-spec-tool.js +98 -0
- package/dist/author-agent-spec-tool.js.map +1 -0
- package/dist/author-tool-grant-tool.d.ts +47 -0
- package/dist/author-tool-grant-tool.d.ts.map +1 -0
- package/dist/author-tool-grant-tool.js +87 -0
- package/dist/author-tool-grant-tool.js.map +1 -0
- package/dist/call-agent-tool.d.ts +42 -0
- package/dist/call-agent-tool.d.ts.map +1 -0
- package/dist/call-agent-tool.js +90 -0
- package/dist/call-agent-tool.js.map +1 -0
- package/dist/capability-composer.d.ts +11 -0
- package/dist/capability-composer.d.ts.map +1 -0
- package/dist/capability-composer.js +35 -0
- package/dist/capability-composer.js.map +1 -0
- package/dist/commit-attested-tool.d.ts +29 -0
- package/dist/commit-attested-tool.d.ts.map +1 -0
- package/dist/commit-attested-tool.js +45 -0
- package/dist/commit-attested-tool.js.map +1 -0
- package/dist/composite-loader.d.ts +36 -0
- package/dist/composite-loader.d.ts.map +1 -0
- package/dist/composite-loader.js +137 -0
- package/dist/composite-loader.js.map +1 -0
- package/dist/composites/command-allowlist.d.ts +29 -0
- package/dist/composites/command-allowlist.d.ts.map +1 -0
- package/dist/composites/command-allowlist.js +36 -0
- package/dist/composites/command-allowlist.js.map +1 -0
- package/dist/composites/git-log.d.ts +31 -0
- package/dist/composites/git-log.d.ts.map +1 -0
- package/dist/composites/git-log.js +39 -0
- package/dist/composites/git-log.js.map +1 -0
- package/dist/composites/grep-paths.d.ts +26 -0
- package/dist/composites/grep-paths.d.ts.map +1 -0
- package/dist/composites/grep-paths.js +34 -0
- package/dist/composites/grep-paths.js.map +1 -0
- package/dist/composites/read-files.d.ts +24 -0
- package/dist/composites/read-files.d.ts.map +1 -0
- package/dist/composites/read-files.js +35 -0
- package/dist/composites/read-files.js.map +1 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +77 -0
- package/dist/index.js.map +1 -0
- package/dist/operation-vocab.d.ts +25 -0
- package/dist/operation-vocab.d.ts.map +1 -0
- package/dist/operation-vocab.js +78 -0
- package/dist/operation-vocab.js.map +1 -0
- package/dist/read-truncation-gate.d.ts +143 -0
- package/dist/read-truncation-gate.d.ts.map +1 -0
- package/dist/read-truncation-gate.js +175 -0
- package/dist/read-truncation-gate.js.map +1 -0
- package/dist/real-check-runner.d.ts +66 -0
- package/dist/real-check-runner.d.ts.map +1 -0
- package/dist/real-check-runner.js +133 -0
- package/dist/real-check-runner.js.map +1 -0
- package/dist/run-real-checks-tool.d.ts +28 -0
- package/dist/run-real-checks-tool.d.ts.map +1 -0
- package/dist/run-real-checks-tool.js +47 -0
- package/dist/run-real-checks-tool.js.map +1 -0
- package/dist/run-work-order-loop-tool.d.ts +35 -0
- package/dist/run-work-order-loop-tool.d.ts.map +1 -0
- package/dist/run-work-order-loop-tool.js +46 -0
- package/dist/run-work-order-loop-tool.js.map +1 -0
- package/dist/verified-identity.d.ts +54 -0
- package/dist/verified-identity.d.ts.map +1 -0
- package/dist/verified-identity.js +133 -0
- package/dist/verified-identity.js.map +1 -0
- package/dist/work-order-loop.d.ts +82 -0
- package/dist/work-order-loop.d.ts.map +1 -0
- package/dist/work-order-loop.js +149 -0
- package/dist/work-order-loop.js.map +1 -0
- package/package.json +59 -0
- package/skill-narrative.md +53 -0
- package/skills/pi-agent-dispatch/SKILL.md +138 -0
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* run-work-order-loop Pi tool — single-call wrapper around the FEAT-006
|
|
3
|
+
* north-star loop. The orchestrator names a work-order id (loaded from
|
|
4
|
+
* .project/work-orders.json per TASK-088 schema) and the loop drives:
|
|
5
|
+
* dispatch the target_agent → run-real-checks → on pass commit-attested
|
|
6
|
+
* → on fail human-OK retry. Bounded iterations (default 3) per FEAT-006;
|
|
7
|
+
* human-OK gate per DEC-0047 governance.
|
|
8
|
+
*
|
|
9
|
+
* Per DEC-0014 this tool is the harness-confined orchestrator's positive-
|
|
10
|
+
* clause shortcut: previously the orchestrator hand-chained call-agent /
|
|
11
|
+
* run-real-checks / commit-attested per iteration; now one Pi call closes
|
|
12
|
+
* the loop while preserving every gate (capability composition at the
|
|
13
|
+
* call boundary, deterministic real-check verdict, human-OK retry, writer-
|
|
14
|
+
* attestation footer).
|
|
15
|
+
*/
|
|
16
|
+
import { Type } from "@earendil-works/pi-ai";
|
|
17
|
+
import type { AgentToolResult, AgentToolUpdateCallback, ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
18
|
+
import { type WorkOrderLoopResult } from "./work-order-loop.js";
|
|
19
|
+
export declare const runWorkOrderLoopTool: {
|
|
20
|
+
name: string;
|
|
21
|
+
label: string;
|
|
22
|
+
description: string;
|
|
23
|
+
promptSnippet: string;
|
|
24
|
+
parameters: Type.TObject<{
|
|
25
|
+
work_order_id: Type.TString;
|
|
26
|
+
max_iterations: Type.TOptional<Type.TNumber>;
|
|
27
|
+
agent_grant: Type.TOptional<Type.TArray<Type.TString>>;
|
|
28
|
+
}>;
|
|
29
|
+
execute(_toolCallId: string, params: {
|
|
30
|
+
work_order_id: string;
|
|
31
|
+
max_iterations?: number;
|
|
32
|
+
agent_grant?: string[];
|
|
33
|
+
}, _signal: AbortSignal, _onUpdate: AgentToolUpdateCallback, ctx: ExtensionContext): Promise<AgentToolResult<WorkOrderLoopResult>>;
|
|
34
|
+
};
|
|
35
|
+
//# sourceMappingURL=run-work-order-loop-tool.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run-work-order-loop-tool.d.ts","sourceRoot":"","sources":["../src/run-work-order-loop-tool.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,uBAAuB,CAAC;AAC7C,OAAO,KAAK,EAAE,eAAe,EAAE,uBAAuB,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AAClH,OAAO,EAAoB,KAAK,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAElF,eAAO,MAAM,oBAAoB;;;;;;;;;;yBAkBlB,MAAM,UACX;QAAE,aAAa,EAAE,MAAM,CAAC;QAAC,cAAc,CAAC,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,EAAE,CAAA;KAAE,WACzE,WAAW,aACT,uBAAuB,OAC7B,gBAAgB,GACnB,OAAO,CAAC,eAAe,CAAC,mBAAmB,CAAC,CAAC;CAahD,CAAC"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* run-work-order-loop Pi tool — single-call wrapper around the FEAT-006
|
|
3
|
+
* north-star loop. The orchestrator names a work-order id (loaded from
|
|
4
|
+
* .project/work-orders.json per TASK-088 schema) and the loop drives:
|
|
5
|
+
* dispatch the target_agent → run-real-checks → on pass commit-attested
|
|
6
|
+
* → on fail human-OK retry. Bounded iterations (default 3) per FEAT-006;
|
|
7
|
+
* human-OK gate per DEC-0047 governance.
|
|
8
|
+
*
|
|
9
|
+
* Per DEC-0014 this tool is the harness-confined orchestrator's positive-
|
|
10
|
+
* clause shortcut: previously the orchestrator hand-chained call-agent /
|
|
11
|
+
* run-real-checks / commit-attested per iteration; now one Pi call closes
|
|
12
|
+
* the loop while preserving every gate (capability composition at the
|
|
13
|
+
* call boundary, deterministic real-check verdict, human-OK retry, writer-
|
|
14
|
+
* attestation footer).
|
|
15
|
+
*/
|
|
16
|
+
import { Type } from "@earendil-works/pi-ai";
|
|
17
|
+
import { runWorkOrderLoop } from "./work-order-loop.js";
|
|
18
|
+
export const runWorkOrderLoopTool = {
|
|
19
|
+
name: "run-work-order-loop",
|
|
20
|
+
label: "Run Work-Order Loop",
|
|
21
|
+
description: "Execute the bounded work-order loop: dispatch target_agent (via direct pi-jit-agents library) → run-real-checks (deterministic verdict — the actual exit code, never an LLM self-report) → on-pass commit-attested → on-fail human-OK retry at the iteration boundary. Bounded iterations (default 3); human-OK gate governs retry.",
|
|
22
|
+
promptSnippet: "Execute the end-to-end work-order loop for a declared spec.",
|
|
23
|
+
parameters: Type.Object({
|
|
24
|
+
work_order_id: Type.String({
|
|
25
|
+
description: "ID of the work-order to execute (loads from .project/work-orders.json schema).",
|
|
26
|
+
}),
|
|
27
|
+
max_iterations: Type.Optional(Type.Number({ description: "Max iteration count before fail-final. Default 3." })),
|
|
28
|
+
agent_grant: Type.Optional(Type.Array(Type.String(), {
|
|
29
|
+
description: "Tool grant for the dispatched privileged agent (capability composition). Default empty.",
|
|
30
|
+
})),
|
|
31
|
+
}),
|
|
32
|
+
async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
|
|
33
|
+
const result = await runWorkOrderLoop(ctx.cwd, params, ctx);
|
|
34
|
+
const commitFragment = result.commit_sha ? `, commit ${result.commit_sha}` : "";
|
|
35
|
+
return {
|
|
36
|
+
details: result,
|
|
37
|
+
content: [
|
|
38
|
+
{
|
|
39
|
+
type: "text",
|
|
40
|
+
text: `run-work-order-loop ${params.work_order_id}: ${result.final_status} (${result.iterations.length} iterations${commitFragment})`,
|
|
41
|
+
},
|
|
42
|
+
],
|
|
43
|
+
};
|
|
44
|
+
},
|
|
45
|
+
};
|
|
46
|
+
//# sourceMappingURL=run-work-order-loop-tool.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run-work-order-loop-tool.js","sourceRoot":"","sources":["../src/run-work-order-loop-tool.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,uBAAuB,CAAC;AAE7C,OAAO,EAAE,gBAAgB,EAA4B,MAAM,sBAAsB,CAAC;AAElF,MAAM,CAAC,MAAM,oBAAoB,GAAG;IACnC,IAAI,EAAE,qBAAqB;IAC3B,KAAK,EAAE,qBAAqB;IAC5B,WAAW,EACV,qUAAqU;IACtU,aAAa,EAAE,6DAA6D;IAC5E,UAAU,EAAE,IAAI,CAAC,MAAM,CAAC;QACvB,aAAa,EAAE,IAAI,CAAC,MAAM,CAAC;YAC1B,WAAW,EAAE,gFAAgF;SAC7F,CAAC;QACF,cAAc,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,WAAW,EAAE,mDAAmD,EAAE,CAAC,CAAC;QAChH,WAAW,EAAE,IAAI,CAAC,QAAQ,CACzB,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE;YACzB,WAAW,EAAE,yFAAyF;SACtG,CAAC,CACF;KACD,CAAC;IACF,KAAK,CAAC,OAAO,CACZ,WAAmB,EACnB,MAAkF,EAClF,OAAoB,EACpB,SAAkC,EAClC,GAAqB;QAErB,MAAM,MAAM,GAAG,MAAM,gBAAgB,CAAC,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,CAAC,CAAC;QAC5D,MAAM,cAAc,GAAG,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,YAAY,MAAM,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAChF,OAAO;YACN,OAAO,EAAE,MAAM;YACf,OAAO,EAAE;gBACR;oBACC,IAAI,EAAE,MAAM;oBACZ,IAAI,EAAE,uBAAuB,MAAM,CAAC,aAAa,KAAK,MAAM,CAAC,YAAY,KAAK,MAAM,CAAC,UAAU,CAAC,MAAM,cAAc,cAAc,GAAG;iBACrI;aACD;SACD,CAAC;IACH,CAAC;CACD,CAAC"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* verified-identity — terminal-operator identity discovered from process
|
|
3
|
+
* environment, used by the auth-gate handler to overwrite caller-supplied
|
|
4
|
+
* writer.user with a verified value at the canonical authorization point
|
|
5
|
+
* (the pi-dispatch tool_call boundary).
|
|
6
|
+
*
|
|
7
|
+
* Aim: the auth-gate's interactive confirm verifies that SOMEONE at the
|
|
8
|
+
* terminal authorized the call; this module supplies the identity of that
|
|
9
|
+
* someone so the substrate attestation stamp reflects the actually-
|
|
10
|
+
* confirming operator rather than a caller-claimed value. The intended
|
|
11
|
+
* source chain is:
|
|
12
|
+
*
|
|
13
|
+
* 1. `git config user.email` — the typical canonical contributor identity
|
|
14
|
+
* anchored on this checkout's git configuration; preferred because it
|
|
15
|
+
* mirrors the identity the same operator commits under.
|
|
16
|
+
* 2. `process.env.USER` — POSIX login name; coarser but always present in
|
|
17
|
+
* a normally-launched interactive shell.
|
|
18
|
+
* 3. `null` + a structured warning trace — the operator-visible signal
|
|
19
|
+
* that no verifiable identity was discoverable; the auth-gate
|
|
20
|
+
* preserves the caller-supplied identity in that case (last-resort
|
|
21
|
+
* fall-through; auditable via the warning).
|
|
22
|
+
*
|
|
23
|
+
* The resolution is module-level cached. Caching means a config drift
|
|
24
|
+
* mid-process does not change later attestations; tests cover the cache
|
|
25
|
+
* via the exported `_resetVerifiedIdentityCache` helper.
|
|
26
|
+
*
|
|
27
|
+
* Dependency-injection design: `getVerifiedOperatorIdentity` accepts an
|
|
28
|
+
* optional `deps` argument shaped `{ runGitConfig, getEnvUser, emitWarning }`
|
|
29
|
+
* so tests can substitute stubs without spawning a real git or mutating
|
|
30
|
+
* process.env. Production callers pass nothing; the defaults bind the real
|
|
31
|
+
* execSync / process.env.USER / writeAgentTrace pipeline.
|
|
32
|
+
*/
|
|
33
|
+
export interface VerifiedIdentityDeps {
|
|
34
|
+
runGitConfig?: () => string | null;
|
|
35
|
+
getEnvUser?: () => string | null;
|
|
36
|
+
emitWarning?: (message: string) => void;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Reset the module-level cache so a subsequent call re-resolves identity.
|
|
40
|
+
* Test-only surface — production callers should never invoke this.
|
|
41
|
+
*/
|
|
42
|
+
export declare function _resetVerifiedIdentityCache(): void;
|
|
43
|
+
/**
|
|
44
|
+
* Resolve a verified operator identity. Lazy-cached at module level on
|
|
45
|
+
* first call; subsequent calls return the cached value (including a cached
|
|
46
|
+
* null when both sources were absent on first resolution).
|
|
47
|
+
*
|
|
48
|
+
* Returns the discovered identity string, or null if neither source
|
|
49
|
+
* yielded a value. When the result is null, a structured warning is
|
|
50
|
+
* emitted via the supplied (or default) trace pipeline so the absence is
|
|
51
|
+
* operator-visible rather than silent.
|
|
52
|
+
*/
|
|
53
|
+
export declare function getVerifiedOperatorIdentity(deps?: VerifiedIdentityDeps): string | null;
|
|
54
|
+
//# sourceMappingURL=verified-identity.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"verified-identity.d.ts","sourceRoot":"","sources":["../src/verified-identity.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AASH,MAAM,WAAW,oBAAoB;IACpC,YAAY,CAAC,EAAE,MAAM,MAAM,GAAG,IAAI,CAAC;IACnC,UAAU,CAAC,EAAE,MAAM,MAAM,GAAG,IAAI,CAAC;IACjC,WAAW,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CACxC;AAID;;;GAGG;AACH,wBAAgB,2BAA2B,IAAI,IAAI,CAElD;AA+DD;;;;;;;;;GASG;AACH,wBAAgB,2BAA2B,CAAC,IAAI,CAAC,EAAE,oBAAoB,GAAG,MAAM,GAAG,IAAI,CAwBtF"}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* verified-identity — terminal-operator identity discovered from process
|
|
3
|
+
* environment, used by the auth-gate handler to overwrite caller-supplied
|
|
4
|
+
* writer.user with a verified value at the canonical authorization point
|
|
5
|
+
* (the pi-dispatch tool_call boundary).
|
|
6
|
+
*
|
|
7
|
+
* Aim: the auth-gate's interactive confirm verifies that SOMEONE at the
|
|
8
|
+
* terminal authorized the call; this module supplies the identity of that
|
|
9
|
+
* someone so the substrate attestation stamp reflects the actually-
|
|
10
|
+
* confirming operator rather than a caller-claimed value. The intended
|
|
11
|
+
* source chain is:
|
|
12
|
+
*
|
|
13
|
+
* 1. `git config user.email` — the typical canonical contributor identity
|
|
14
|
+
* anchored on this checkout's git configuration; preferred because it
|
|
15
|
+
* mirrors the identity the same operator commits under.
|
|
16
|
+
* 2. `process.env.USER` — POSIX login name; coarser but always present in
|
|
17
|
+
* a normally-launched interactive shell.
|
|
18
|
+
* 3. `null` + a structured warning trace — the operator-visible signal
|
|
19
|
+
* that no verifiable identity was discoverable; the auth-gate
|
|
20
|
+
* preserves the caller-supplied identity in that case (last-resort
|
|
21
|
+
* fall-through; auditable via the warning).
|
|
22
|
+
*
|
|
23
|
+
* The resolution is module-level cached. Caching means a config drift
|
|
24
|
+
* mid-process does not change later attestations; tests cover the cache
|
|
25
|
+
* via the exported `_resetVerifiedIdentityCache` helper.
|
|
26
|
+
*
|
|
27
|
+
* Dependency-injection design: `getVerifiedOperatorIdentity` accepts an
|
|
28
|
+
* optional `deps` argument shaped `{ runGitConfig, getEnvUser, emitWarning }`
|
|
29
|
+
* so tests can substitute stubs without spawning a real git or mutating
|
|
30
|
+
* process.env. Production callers pass nothing; the defaults bind the real
|
|
31
|
+
* execSync / process.env.USER / writeAgentTrace pipeline.
|
|
32
|
+
*/
|
|
33
|
+
import { execSync } from "node:child_process";
|
|
34
|
+
import { randomUUID } from "node:crypto";
|
|
35
|
+
import { homedir } from "node:os";
|
|
36
|
+
import path from "node:path";
|
|
37
|
+
import { cleanGitEnv } from "@davidorex/pi-context/git-env";
|
|
38
|
+
import { writeAgentTrace } from "@davidorex/pi-jit-agents";
|
|
39
|
+
let cached; // undefined = not yet resolved
|
|
40
|
+
/**
|
|
41
|
+
* Reset the module-level cache so a subsequent call re-resolves identity.
|
|
42
|
+
* Test-only surface — production callers should never invoke this.
|
|
43
|
+
*/
|
|
44
|
+
export function _resetVerifiedIdentityCache() {
|
|
45
|
+
cached = undefined;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* ULID-shape placeholder for the trace entry id. Mirrors the precedent in
|
|
49
|
+
* composite-loader.ts: the trace pipeline schema requires a 26-character
|
|
50
|
+
* Crockford-base32 ULID; we mint a regex-shaped value without taking a
|
|
51
|
+
* dependency on a real ULID library. Identifier collisions on the trace
|
|
52
|
+
* surface are tolerated by downstream consumers.
|
|
53
|
+
*/
|
|
54
|
+
function placeholderTraceId() {
|
|
55
|
+
const hex = randomUUID().replace(/-/g, "");
|
|
56
|
+
const alphabet = "0123456789ABCDEFGHJKMNPQRSTVWXYZ";
|
|
57
|
+
let out = "";
|
|
58
|
+
for (let i = 0; i < 26; i++) {
|
|
59
|
+
out += alphabet[Number.parseInt(hex[i % hex.length], 16) % alphabet.length];
|
|
60
|
+
}
|
|
61
|
+
return out;
|
|
62
|
+
}
|
|
63
|
+
function defaultTracePath() {
|
|
64
|
+
const env = process.env.PI_AGENT_TRACE_PATH;
|
|
65
|
+
if (env && env.length > 0)
|
|
66
|
+
return env;
|
|
67
|
+
return path.join(homedir(), ".pi", "traces", "extension-load.jsonl");
|
|
68
|
+
}
|
|
69
|
+
function defaultEmitWarning(message) {
|
|
70
|
+
try {
|
|
71
|
+
writeAgentTrace({
|
|
72
|
+
type: "extension_load_warning",
|
|
73
|
+
id: placeholderTraceId(),
|
|
74
|
+
parentId: null,
|
|
75
|
+
timestamp: new Date().toISOString(),
|
|
76
|
+
extension_name: "pi-agent-dispatch",
|
|
77
|
+
message,
|
|
78
|
+
severity: "warning",
|
|
79
|
+
}, { tracePath: defaultTracePath() });
|
|
80
|
+
}
|
|
81
|
+
catch {
|
|
82
|
+
// Trace failures are observability-only; never let them mask the
|
|
83
|
+
// missing-identity condition or abort the gate.
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
function defaultRunGitConfig() {
|
|
87
|
+
try {
|
|
88
|
+
const out = execSync("git config user.email", {
|
|
89
|
+
encoding: "utf8",
|
|
90
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
91
|
+
env: cleanGitEnv(),
|
|
92
|
+
}).trim();
|
|
93
|
+
return out.length > 0 ? out : null;
|
|
94
|
+
}
|
|
95
|
+
catch {
|
|
96
|
+
return null;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
function defaultGetEnvUser() {
|
|
100
|
+
const u = process.env.USER;
|
|
101
|
+
return u && u.length > 0 ? u : null;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Resolve a verified operator identity. Lazy-cached at module level on
|
|
105
|
+
* first call; subsequent calls return the cached value (including a cached
|
|
106
|
+
* null when both sources were absent on first resolution).
|
|
107
|
+
*
|
|
108
|
+
* Returns the discovered identity string, or null if neither source
|
|
109
|
+
* yielded a value. When the result is null, a structured warning is
|
|
110
|
+
* emitted via the supplied (or default) trace pipeline so the absence is
|
|
111
|
+
* operator-visible rather than silent.
|
|
112
|
+
*/
|
|
113
|
+
export function getVerifiedOperatorIdentity(deps) {
|
|
114
|
+
if (cached !== undefined)
|
|
115
|
+
return cached;
|
|
116
|
+
const runGitConfig = deps?.runGitConfig ?? defaultRunGitConfig;
|
|
117
|
+
const getEnvUser = deps?.getEnvUser ?? defaultGetEnvUser;
|
|
118
|
+
const emitWarning = deps?.emitWarning ?? defaultEmitWarning;
|
|
119
|
+
const fromGit = runGitConfig();
|
|
120
|
+
if (fromGit !== null && fromGit.length > 0) {
|
|
121
|
+
cached = fromGit;
|
|
122
|
+
return cached;
|
|
123
|
+
}
|
|
124
|
+
const fromEnv = getEnvUser();
|
|
125
|
+
if (fromEnv !== null && fromEnv.length > 0) {
|
|
126
|
+
cached = fromEnv;
|
|
127
|
+
return cached;
|
|
128
|
+
}
|
|
129
|
+
cached = null;
|
|
130
|
+
emitWarning("verified-identity: neither git config user.email nor process.env.USER yielded a value; auth-gate identity-stamp will preserve caller-supplied writer.user (unverified)");
|
|
131
|
+
return cached;
|
|
132
|
+
}
|
|
133
|
+
//# sourceMappingURL=verified-identity.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"verified-identity.js","sourceRoot":"","sources":["../src/verified-identity.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* work-order-loop — bounded FEAT-006 north-star loop implementation.
|
|
3
|
+
*
|
|
4
|
+
* The orchestrator declares a work-order (TASK-088 schema). This library
|
|
5
|
+
* drives the end-to-end loop the work-order encodes:
|
|
6
|
+
*
|
|
7
|
+
* for iteration in 0..max_iterations:
|
|
8
|
+
* 1. dispatch the work-order's target_agent via the jit-agents library
|
|
9
|
+
* (DEC-0044 narrowed; pi-jit-agents stays a library import per JI-021).
|
|
10
|
+
* 2. run the work-order's real_check_criteria via runRealChecks
|
|
11
|
+
* (deterministic verdict per DEC-0018 + DEC-0047 clause 5 — never the
|
|
12
|
+
* executing agent's self-report).
|
|
13
|
+
* 3. on pass: commit-attested with writer-identity footer; final_status
|
|
14
|
+
* = "completed".
|
|
15
|
+
* 4. on fail: ask the human at the iteration boundary (ctx.ui.confirm)
|
|
16
|
+
* whether to retry. !confirm → final_status = "aborted-by-human".
|
|
17
|
+
*
|
|
18
|
+
* If the loop exhausts max_iterations without a pass → final_status =
|
|
19
|
+
* "failed". The aim is one Pi tool invocation that closes the entire loop
|
|
20
|
+
* — the orchestrator no longer manually chains call-agent / run-real-checks
|
|
21
|
+
* / commit-attested per iteration.
|
|
22
|
+
*
|
|
23
|
+
* Per DEC-0014 the orchestrator-side composite is the only authorized
|
|
24
|
+
* driver of this loop; per FEAT-005 the agent_grant the orchestrator
|
|
25
|
+
* passes is composed (intersected) at the call-agent dispatch boundary.
|
|
26
|
+
*/
|
|
27
|
+
import type { CompiledAgent, DispatchContext, JitAgentResult } from "@davidorex/pi-jit-agents/types";
|
|
28
|
+
import type { ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
29
|
+
import { type AttestedCommitResult, attestedCommit as canonicalAttestedCommit } from "./attested-commit.js";
|
|
30
|
+
import { runRealChecks as canonicalRunRealChecks, type RealCheckCriteria, type RealCheckResult } from "./real-check-runner.js";
|
|
31
|
+
export declare class WorkOrderNotFoundError extends Error {
|
|
32
|
+
constructor(workOrderId: string);
|
|
33
|
+
}
|
|
34
|
+
export interface WorkOrderIteration {
|
|
35
|
+
iteration: number;
|
|
36
|
+
agent_output: unknown;
|
|
37
|
+
real_check_result: RealCheckResult;
|
|
38
|
+
commit_attested_result?: AttestedCommitResult;
|
|
39
|
+
status: "passed" | "failed";
|
|
40
|
+
}
|
|
41
|
+
export interface WorkOrderLoopResult {
|
|
42
|
+
work_order_id: string;
|
|
43
|
+
iterations: WorkOrderIteration[];
|
|
44
|
+
final_status: "completed" | "failed" | "aborted-by-human";
|
|
45
|
+
commit_sha?: string;
|
|
46
|
+
total_duration_ms: number;
|
|
47
|
+
}
|
|
48
|
+
export interface WorkOrderLoopOptions {
|
|
49
|
+
work_order_id: string;
|
|
50
|
+
max_iterations?: number;
|
|
51
|
+
agent_grant?: string[];
|
|
52
|
+
}
|
|
53
|
+
interface WorkOrderRecord {
|
|
54
|
+
id: string;
|
|
55
|
+
target_agent: string;
|
|
56
|
+
real_check_criteria?: RealCheckCriteria;
|
|
57
|
+
scope?: {
|
|
58
|
+
files?: string[];
|
|
59
|
+
directories?: string[];
|
|
60
|
+
operations?: string[];
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Internal indirection — tests substitute these to short-circuit the
|
|
65
|
+
* jit-agents / real-check / commit paths. Production code path never
|
|
66
|
+
* reassigns; the same indirection pattern as call-agent-tool._internals.
|
|
67
|
+
*/
|
|
68
|
+
type DispatchTargetAgent = (cwd: string, wo: WorkOrderRecord, agentGrant: string[], ctx: ExtensionContext) => Promise<JitAgentResult>;
|
|
69
|
+
export declare const _internals: {
|
|
70
|
+
executeAgent: (c: CompiledAgent, d: DispatchContext) => Promise<JitAgentResult>;
|
|
71
|
+
runRealChecks: typeof canonicalRunRealChecks;
|
|
72
|
+
attestedCommit: typeof canonicalAttestedCommit;
|
|
73
|
+
/**
|
|
74
|
+
* Tests reassign this to short-circuit the model/auth resolution +
|
|
75
|
+
* jit-agents compile/dispatch chain. Production code path runs the
|
|
76
|
+
* default canonical implementation.
|
|
77
|
+
*/
|
|
78
|
+
dispatchTargetAgent: DispatchTargetAgent | undefined;
|
|
79
|
+
};
|
|
80
|
+
export declare function runWorkOrderLoop(cwd: string, options: WorkOrderLoopOptions, ctx: ExtensionContext): Promise<WorkOrderLoopResult>;
|
|
81
|
+
export {};
|
|
82
|
+
//# sourceMappingURL=work-order-loop.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"work-order-loop.d.ts","sourceRoot":"","sources":["../src/work-order-loop.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAOH,OAAO,KAAK,EAAE,aAAa,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AAErG,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AACxE,OAAO,EAAE,KAAK,oBAAoB,EAAE,cAAc,IAAI,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AAE5G,OAAO,EACN,aAAa,IAAI,sBAAsB,EACvC,KAAK,iBAAiB,EACtB,KAAK,eAAe,EACpB,MAAM,wBAAwB,CAAC;AAEhC,qBAAa,sBAAuB,SAAQ,KAAK;gBACpC,WAAW,EAAE,MAAM;CAI/B;AAED,MAAM,WAAW,kBAAkB;IAClC,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,OAAO,CAAC;IACtB,iBAAiB,EAAE,eAAe,CAAC;IACnC,sBAAsB,CAAC,EAAE,oBAAoB,CAAC;IAC9C,MAAM,EAAE,QAAQ,GAAG,QAAQ,CAAC;CAC5B;AAED,MAAM,WAAW,mBAAmB;IACnC,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,kBAAkB,EAAE,CAAC;IACjC,YAAY,EAAE,WAAW,GAAG,QAAQ,GAAG,kBAAkB,CAAC;IAC1D,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,iBAAiB,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,oBAAoB;IACpC,aAAa,EAAE,MAAM,CAAC;IACtB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;CACvB;AAED,UAAU,eAAe;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,YAAY,EAAE,MAAM,CAAC;IACrB,mBAAmB,CAAC,EAAE,iBAAiB,CAAC;IACxC,KAAK,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;CAC5E;AAQD;;;;GAIG;AACH,KAAK,mBAAmB,GAAG,CAC1B,GAAG,EAAE,MAAM,EACX,EAAE,EAAE,eAAe,EACnB,UAAU,EAAE,MAAM,EAAE,EACpB,GAAG,EAAE,gBAAgB,KACjB,OAAO,CAAC,cAAc,CAAC,CAAC;AAE7B,eAAO,MAAM,UAAU;kBACiB,CAAC,CAAC,EAAE,aAAa,EAAE,CAAC,EAAE,eAAe,KAAK,OAAO,CAAC,cAAc,CAAC;;;IAGxG;;;;OAIG;yBAC+B,mBAAmB,GAAG,SAAS;CACjE,CAAC;AAoCF,wBAAsB,gBAAgB,CACrC,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,oBAAoB,EAC7B,GAAG,EAAE,gBAAgB,GACnB,OAAO,CAAC,mBAAmB,CAAC,CAwE9B"}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* work-order-loop — bounded FEAT-006 north-star loop implementation.
|
|
3
|
+
*
|
|
4
|
+
* The orchestrator declares a work-order (TASK-088 schema). This library
|
|
5
|
+
* drives the end-to-end loop the work-order encodes:
|
|
6
|
+
*
|
|
7
|
+
* for iteration in 0..max_iterations:
|
|
8
|
+
* 1. dispatch the work-order's target_agent via the jit-agents library
|
|
9
|
+
* (DEC-0044 narrowed; pi-jit-agents stays a library import per JI-021).
|
|
10
|
+
* 2. run the work-order's real_check_criteria via runRealChecks
|
|
11
|
+
* (deterministic verdict per DEC-0018 + DEC-0047 clause 5 — never the
|
|
12
|
+
* executing agent's self-report).
|
|
13
|
+
* 3. on pass: commit-attested with writer-identity footer; final_status
|
|
14
|
+
* = "completed".
|
|
15
|
+
* 4. on fail: ask the human at the iteration boundary (ctx.ui.confirm)
|
|
16
|
+
* whether to retry. !confirm → final_status = "aborted-by-human".
|
|
17
|
+
*
|
|
18
|
+
* If the loop exhausts max_iterations without a pass → final_status =
|
|
19
|
+
* "failed". The aim is one Pi tool invocation that closes the entire loop
|
|
20
|
+
* — the orchestrator no longer manually chains call-agent / run-real-checks
|
|
21
|
+
* / commit-attested per iteration.
|
|
22
|
+
*
|
|
23
|
+
* Per DEC-0014 the orchestrator-side composite is the only authorized
|
|
24
|
+
* driver of this loop; per FEAT-005 the agent_grant the orchestrator
|
|
25
|
+
* passes is composed (intersected) at the call-agent dispatch boundary.
|
|
26
|
+
*/
|
|
27
|
+
import { readBlock } from "@davidorex/pi-context/block-api";
|
|
28
|
+
import { createAgentLoader } from "@davidorex/pi-jit-agents/agent-spec";
|
|
29
|
+
import { compileAgent } from "@davidorex/pi-jit-agents/compile";
|
|
30
|
+
import { executeAgent as canonicalExecuteAgent } from "@davidorex/pi-jit-agents/runtime";
|
|
31
|
+
import { createTemplateEnv } from "@davidorex/pi-jit-agents/template";
|
|
32
|
+
import { attestedCommit as canonicalAttestedCommit } from "./attested-commit.js";
|
|
33
|
+
import { composeToolGrant } from "./capability-composer.js";
|
|
34
|
+
import { runRealChecks as canonicalRunRealChecks, } from "./real-check-runner.js";
|
|
35
|
+
export class WorkOrderNotFoundError extends Error {
|
|
36
|
+
constructor(workOrderId) {
|
|
37
|
+
super(`work-order-loop: work-order '${workOrderId}' not found in work-orders block`);
|
|
38
|
+
this.name = "WorkOrderNotFoundError";
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
function parseModelSpec(spec) {
|
|
42
|
+
const slashIndex = spec.indexOf("/");
|
|
43
|
+
if (slashIndex !== -1)
|
|
44
|
+
return { provider: spec.slice(0, slashIndex), modelId: spec.slice(slashIndex + 1) };
|
|
45
|
+
return { provider: "anthropic", modelId: spec };
|
|
46
|
+
}
|
|
47
|
+
export const _internals = {
|
|
48
|
+
executeAgent: canonicalExecuteAgent,
|
|
49
|
+
runRealChecks: canonicalRunRealChecks,
|
|
50
|
+
attestedCommit: canonicalAttestedCommit,
|
|
51
|
+
/**
|
|
52
|
+
* Tests reassign this to short-circuit the model/auth resolution +
|
|
53
|
+
* jit-agents compile/dispatch chain. Production code path runs the
|
|
54
|
+
* default canonical implementation.
|
|
55
|
+
*/
|
|
56
|
+
dispatchTargetAgent: undefined,
|
|
57
|
+
};
|
|
58
|
+
async function dispatchTargetAgent(cwd, wo, agentGrant, ctx) {
|
|
59
|
+
const loadAgent = createAgentLoader({ cwd });
|
|
60
|
+
const spec = loadAgent(wo.target_agent);
|
|
61
|
+
const env = createTemplateEnv({ cwd });
|
|
62
|
+
const compiled = compileAgent(spec, { env, input: { work_order_id: wo.id }, cwd });
|
|
63
|
+
const modelSpec = compiled.model ?? spec.model;
|
|
64
|
+
if (!modelSpec) {
|
|
65
|
+
throw new Error(`work-order-loop: agent '${wo.target_agent}' has no model specified.`);
|
|
66
|
+
}
|
|
67
|
+
const { provider, modelId } = parseModelSpec(modelSpec);
|
|
68
|
+
const model = ctx.modelRegistry.find(provider, modelId);
|
|
69
|
+
if (!model) {
|
|
70
|
+
throw new Error(`work-order-loop: model '${modelSpec}' not found for agent '${wo.target_agent}'.`);
|
|
71
|
+
}
|
|
72
|
+
const auth = await ctx.modelRegistry.getApiKeyAndHeaders(model);
|
|
73
|
+
if (!auth.ok) {
|
|
74
|
+
throw new Error(`work-order-loop: auth resolution failed for '${modelSpec}': ${auth.error}`);
|
|
75
|
+
}
|
|
76
|
+
// Intersect at dispatch boundary per FEAT-005 (parent ∩ requested = agentGrant ∩ spec.tools).
|
|
77
|
+
const composedGrant = composeToolGrant(agentGrant, spec.tools);
|
|
78
|
+
const dispatch = {
|
|
79
|
+
model: model,
|
|
80
|
+
auth: { apiKey: auth.apiKey ?? "", headers: auth.headers ?? {} },
|
|
81
|
+
parentGrant: composedGrant,
|
|
82
|
+
maxTokens: 1024,
|
|
83
|
+
};
|
|
84
|
+
return _internals.executeAgent(compiled, dispatch);
|
|
85
|
+
}
|
|
86
|
+
export async function runWorkOrderLoop(cwd, options, ctx) {
|
|
87
|
+
const start = Date.now();
|
|
88
|
+
const maxIterations = options.max_iterations ?? 3;
|
|
89
|
+
const data = readBlock(cwd, "work-orders");
|
|
90
|
+
const wo = data.work_orders.find((w) => w.id === options.work_order_id);
|
|
91
|
+
if (!wo)
|
|
92
|
+
throw new WorkOrderNotFoundError(options.work_order_id);
|
|
93
|
+
const iterations = [];
|
|
94
|
+
let finalStatus = "failed";
|
|
95
|
+
let commitSha;
|
|
96
|
+
const dispatch = _internals.dispatchTargetAgent ?? dispatchTargetAgent;
|
|
97
|
+
for (let i = 0; i < maxIterations; i++) {
|
|
98
|
+
const agentResult = await dispatch(cwd, wo, options.agent_grant ?? [], ctx);
|
|
99
|
+
const realCheck = await _internals.runRealChecks(cwd, wo.id, wo.real_check_criteria ?? { build_check_test: true });
|
|
100
|
+
if (realCheck.passed) {
|
|
101
|
+
const files = wo.scope?.files ?? [];
|
|
102
|
+
const commitMessage = `feat(work-order-${wo.id}): completion under FEAT-006 loop (iteration ${i + 1}/${maxIterations})`;
|
|
103
|
+
let commit;
|
|
104
|
+
if (files.length > 0) {
|
|
105
|
+
commit = await _internals.attestedCommit(cwd, {
|
|
106
|
+
files,
|
|
107
|
+
message: commitMessage,
|
|
108
|
+
agent_id: wo.target_agent,
|
|
109
|
+
work_order_id: wo.id,
|
|
110
|
+
});
|
|
111
|
+
commitSha = commit.commit_sha;
|
|
112
|
+
}
|
|
113
|
+
iterations.push({
|
|
114
|
+
iteration: i,
|
|
115
|
+
agent_output: agentResult.output,
|
|
116
|
+
real_check_result: realCheck,
|
|
117
|
+
commit_attested_result: commit,
|
|
118
|
+
status: "passed",
|
|
119
|
+
});
|
|
120
|
+
finalStatus = "completed";
|
|
121
|
+
break;
|
|
122
|
+
}
|
|
123
|
+
iterations.push({
|
|
124
|
+
iteration: i,
|
|
125
|
+
agent_output: agentResult.output,
|
|
126
|
+
real_check_result: realCheck,
|
|
127
|
+
status: "failed",
|
|
128
|
+
});
|
|
129
|
+
// Human-OK gate at iteration boundary. Skip after final iteration —
|
|
130
|
+
// the loop will exit naturally as "failed" without asking the user
|
|
131
|
+
// whether to retry past max_iterations.
|
|
132
|
+
if (i < maxIterations - 1) {
|
|
133
|
+
const failExcerpt = JSON.stringify(realCheck.details, null, 2).slice(0, 500);
|
|
134
|
+
const proceed = await ctx.ui.confirm("Real-check failed", `Iteration ${i + 1}/${maxIterations} failed. Retry?\nFail-report: ${failExcerpt}`);
|
|
135
|
+
if (!proceed) {
|
|
136
|
+
finalStatus = "aborted-by-human";
|
|
137
|
+
break;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
return {
|
|
142
|
+
work_order_id: wo.id,
|
|
143
|
+
iterations,
|
|
144
|
+
final_status: finalStatus,
|
|
145
|
+
commit_sha: commitSha,
|
|
146
|
+
total_duration_ms: Date.now() - start,
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
//# sourceMappingURL=work-order-loop.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"work-order-loop.js","sourceRoot":"","sources":["../src/work-order-loop.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@davidorex/pi-agent-dispatch",
|
|
3
|
+
"version": "0.28.0",
|
|
4
|
+
"publishConfig": {
|
|
5
|
+
"access": "public"
|
|
6
|
+
},
|
|
7
|
+
"description": "In-pi agent-as-tool dispatch + capability composition extension",
|
|
8
|
+
"type": "module",
|
|
9
|
+
"keywords": [
|
|
10
|
+
"pi-package"
|
|
11
|
+
],
|
|
12
|
+
"license": "MIT",
|
|
13
|
+
"author": "David Ryan",
|
|
14
|
+
"repository": {
|
|
15
|
+
"type": "git",
|
|
16
|
+
"url": "git+https://github.com/davidorex/pi-project-workflows.git",
|
|
17
|
+
"directory": "packages/pi-agent-dispatch"
|
|
18
|
+
},
|
|
19
|
+
"homepage": "https://github.com/davidorex/pi-project-workflows/tree/main/packages/pi-agent-dispatch",
|
|
20
|
+
"main": "./dist/index.js",
|
|
21
|
+
"types": "./dist/index.d.ts",
|
|
22
|
+
"exports": {
|
|
23
|
+
".": {
|
|
24
|
+
"types": "./dist/index.d.ts",
|
|
25
|
+
"default": "./dist/index.js"
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
"files": [
|
|
29
|
+
"dist/",
|
|
30
|
+
"*.md",
|
|
31
|
+
"skills/"
|
|
32
|
+
],
|
|
33
|
+
"pi": {
|
|
34
|
+
"extensions": [
|
|
35
|
+
"./dist/index.js"
|
|
36
|
+
],
|
|
37
|
+
"skills": [
|
|
38
|
+
"./skills"
|
|
39
|
+
]
|
|
40
|
+
},
|
|
41
|
+
"scripts": {
|
|
42
|
+
"clean": "rm -rf dist",
|
|
43
|
+
"build": "rm -rf dist && tsc -p tsconfig.build.json",
|
|
44
|
+
"prepublishOnly": "npm run clean && npm run build",
|
|
45
|
+
"test": "tsx --test src/*.test.ts"
|
|
46
|
+
},
|
|
47
|
+
"dependencies": {
|
|
48
|
+
"@davidorex/pi-behavior-monitors": "^0.28.0",
|
|
49
|
+
"@davidorex/pi-context": "^0.28.0",
|
|
50
|
+
"@davidorex/pi-jit-agents": "^0.28.0",
|
|
51
|
+
"@davidorex/pi-workflows": "^0.28.0",
|
|
52
|
+
"@earendil-works/pi-ai": "^0.75.4",
|
|
53
|
+
"@earendil-works/pi-coding-agent": "^0.75.4",
|
|
54
|
+
"yaml": "^2.7.1"
|
|
55
|
+
},
|
|
56
|
+
"engines": {
|
|
57
|
+
"node": ">=22.19.0"
|
|
58
|
+
}
|
|
59
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: pi-agent-dispatch
|
|
3
|
+
description: >
|
|
4
|
+
Sibling Pi extension that registers in-pi agent-as-tool dispatch, capability
|
|
5
|
+
composition, real-check execution, attested commits, and the bounded
|
|
6
|
+
north-star work-order loop. Use when authoring agent specs, granting tool
|
|
7
|
+
capabilities, running deterministic checks, committing with writer attestation,
|
|
8
|
+
loading config-declared composite operations, or driving end-to-end
|
|
9
|
+
work-orders through their bounded retry loop.
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
<objective>
|
|
13
|
+
pi-agent-dispatch is the harness-confined orchestrator's in-pi surface. It registers Pi tools the orchestrator agent invokes to dispatch sub-agents, author specs and tool grants, run deterministic checks the executive cannot fake, commit with writer attestation, and drive bounded work-order loops. It is the sibling-consumer registration site; pi-jit-agents stays a library consumed directly by this package and by pi-workflows.
|
|
14
|
+
</objective>
|
|
15
|
+
|
|
16
|
+
<dispatch_tools>
|
|
17
|
+
| Tool | Purpose |
|
|
18
|
+
|------|---------|
|
|
19
|
+
| `call-agent` | Dispatch a declared agent spec with a composed tool grant (parent ∩ requested ∩ spec.tools). |
|
|
20
|
+
| `author-agent-spec` | Write an `.agent.yaml` spec to the substrate. Human-authorized via auth-gate confirm at the pi-dispatch layer; the verified terminal-operator identity is stamped as writer on confirm. |
|
|
21
|
+
| `run-work-order-loop` | Execute the bounded work-order loop: dispatch → run-real-checks → on-pass commit-attested → on-fail human-OK retry. |
|
|
22
|
+
</dispatch_tools>
|
|
23
|
+
|
|
24
|
+
<real_check_tools>
|
|
25
|
+
| Tool | Purpose |
|
|
26
|
+
|------|---------|
|
|
27
|
+
| `run-real-checks` | Execute declared deterministic checks (build/check/test exit codes, schema validations, git diff probes, runtime event probes). Verdict is the actual exit code, never an LLM self-report. |
|
|
28
|
+
| `commit-attested` | Stage + commit with writer-identity footer. Refuses on missing agent_id, files, or message. |
|
|
29
|
+
</real_check_tools>
|
|
30
|
+
|
|
31
|
+
<capability_authoring>
|
|
32
|
+
Tool grants are config-declared (bounded composites) and authored only via the `author-tool-grant` Pi tool, which is human-authorized at the pi-dispatch auth-gate (interactive confirmation; on confirm the verified terminal-operator identity is stamped as writer). Default grant is empty; widening goes through the auth-gate. The FORBIDDEN_WHOLESALE_OPERATIONS set blocks shipping wholesale L1 surfaces (bash, write, edit) as a single composite token; the L1 ∪ L5 forbidden union check refuses tokens that already appear on the L1 wholesale-forbidden list.
|
|
33
|
+
</capability_authoring>
|
|
34
|
+
|
|
35
|
+
<composite_loader>
|
|
36
|
+
On extension load, `composite-loader` reads the active substrate's `config.tool_operations[]` and dynamically registers each declared bounded composite as a Pi tool. Config-absent (no pointer or unbootstrapped substrate) degrades gracefully: extension still registers the 6 static tools; the absence is observed via the `extension_load_warning` TraceEntry and (when available) surfaced through `pi.ui.notify`. The substrate is the single source of truth — no parallel ungated path widens capability outside the loader.
|
|
37
|
+
</composite_loader>
|
|
38
|
+
|
|
39
|
+
<canonical_intention>
|
|
40
|
+
Anchors:
|
|
41
|
+
- Harness-confined orchestrator (positive clause: substrate-write + call-agent + author-agent-spec + run-real-checks + commit-attested + author-tool-grant + run-work-order-loop + declared composites; negative clause: NO bash/edit/write).
|
|
42
|
+
- Sibling-consumer scope; pi-jit-agents stays a library.
|
|
43
|
+
- Human-authorized authoring at the pi-dispatch auth-gate; default empty; terminal verdict = real deterministic checks.
|
|
44
|
+
- Capability composition + end-to-end work-order loop + bounded-composite vocabulary + launch-chain integration.
|
|
45
|
+
- Orchestrator uses jit-agents directly; capability composition lives in the dispatch layer.
|
|
46
|
+
</canonical_intention>
|
|
47
|
+
|
|
48
|
+
<success_criteria>
|
|
49
|
+
- 6 static tools register on every load: call-agent, author-agent-spec, author-tool-grant, run-real-checks, commit-attested, run-work-order-loop.
|
|
50
|
+
- Composite tools register from config.tool_operations[] when present; load proceeds with warning when absent.
|
|
51
|
+
- Every write-bearing tool routes through the pi-dispatch auth-gate; the verified terminal-operator identity is stamped as writer on confirm.
|
|
52
|
+
- Work-order loop honors max_iterations + human-OK retry gate + on-pass attested commit.
|
|
53
|
+
</success_criteria>
|