pi-daddy 0.47.1 → 0.48.1
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 +12 -0
- package/README.md +40 -5
- package/dist/executors/child-final.d.ts +3 -0
- package/dist/executors/child-final.d.ts.map +1 -1
- package/dist/executors/child-final.js +13 -1
- package/dist/executors/child-final.js.map +1 -1
- package/dist/executors/herdr-cli.d.ts.map +1 -1
- package/dist/executors/herdr-cli.js +5 -1
- package/dist/executors/herdr-cli.js.map +1 -1
- package/dist/executors/herdr-qualification.d.ts +1 -3
- package/dist/executors/herdr-qualification.d.ts.map +1 -1
- package/dist/executors/herdr-qualification.js +14 -19
- package/dist/executors/herdr-qualification.js.map +1 -1
- package/dist/governance/auto-mode-policy.d.ts.map +1 -1
- package/dist/governance/auto-mode-policy.js +32 -1
- package/dist/governance/auto-mode-policy.js.map +1 -1
- package/dist/governance/dispatch-operation-client.d.ts +4 -0
- package/dist/governance/dispatch-operation-client.d.ts.map +1 -0
- package/dist/governance/dispatch-operation-client.js +93 -0
- package/dist/governance/dispatch-operation-client.js.map +1 -0
- package/dist/governance/dispatch-operations.d.ts +17 -0
- package/dist/governance/dispatch-operations.d.ts.map +1 -0
- package/dist/governance/dispatch-operations.js +81 -0
- package/dist/governance/dispatch-operations.js.map +1 -0
- package/dist/governance/execution-retention.d.ts +5 -4
- package/dist/governance/execution-retention.d.ts.map +1 -1
- package/dist/governance/execution-retention.js +3 -1
- package/dist/governance/execution-retention.js.map +1 -1
- package/dist/governance/native-session.d.ts +10 -1
- package/dist/governance/native-session.d.ts.map +1 -1
- package/dist/governance/native-session.js +15 -0
- package/dist/governance/native-session.js.map +1 -1
- package/dist/governance/retention-contract.d.ts +30 -0
- package/dist/governance/retention-contract.d.ts.map +1 -1
- package/dist/governance/retention-contract.js +9 -4
- package/dist/governance/retention-contract.js.map +1 -1
- package/dist/kernel/auto-mode.d.ts +1 -0
- package/dist/kernel/auto-mode.d.ts.map +1 -1
- package/dist/kernel/auto-mode.js.map +1 -1
- package/dist/kernel/chain.d.ts +1 -0
- package/dist/kernel/chain.d.ts.map +1 -1
- package/dist/kernel/chain.js.map +1 -1
- package/dist/kernel/delegate.d.ts.map +1 -1
- package/dist/kernel/delegate.js +8 -0
- package/dist/kernel/delegate.js.map +1 -1
- package/dist/kernel/dispatch-operation.d.ts +47 -0
- package/dist/kernel/dispatch-operation.d.ts.map +1 -0
- package/dist/kernel/dispatch-operation.js +4 -0
- package/dist/kernel/dispatch-operation.js.map +1 -0
- package/dist/kernel/propagation.d.ts +4 -1
- package/dist/kernel/propagation.d.ts.map +1 -1
- package/dist/kernel/propagation.js +11 -1
- package/dist/kernel/propagation.js.map +1 -1
- package/dist/products/activity-timeline.d.ts +8 -0
- package/dist/products/activity-timeline.d.ts.map +1 -1
- package/dist/products/activity-timeline.js +8 -1
- package/dist/products/activity-timeline.js.map +1 -1
- package/dist/products/dashboard-screen.d.ts +1 -0
- package/dist/products/dashboard-screen.d.ts.map +1 -1
- package/dist/products/dashboard-screen.js +20 -2
- package/dist/products/dashboard-screen.js.map +1 -1
- package/extensions/activity-timeline.ts +12 -2
- package/extensions/delegate-chain.ts +46 -4
- package/extensions/delegation-operations.ts +171 -0
- package/extensions/delegation.ts +34 -10
- package/extensions/execute-child.ts +21 -3
- package/extensions/execution-evidence.ts +3 -0
- package/extensions/fanout-outcome.ts +1 -0
- package/extensions/grants.ts +2 -3
- package/extensions/run-delegation.ts +58 -3
- package/extensions/runtime-snapshot.ts +59 -1
- package/package.json +1 -1
- package/src/executors/child-final.ts +17 -1
- package/src/executors/herdr-cli.ts +4 -1
- package/src/executors/herdr-qualification.ts +14 -21
- package/src/governance/auto-mode-policy.ts +27 -1
- package/src/governance/dispatch-operation-client.ts +96 -0
- package/src/governance/dispatch-operations.ts +81 -0
- package/src/governance/execution-retention.ts +7 -3
- package/src/governance/native-session.ts +28 -1
- package/src/governance/retention-contract.ts +9 -4
- package/src/kernel/auto-mode.ts +1 -0
- package/src/kernel/chain.ts +1 -0
- package/src/kernel/delegate.ts +14 -0
- package/src/kernel/dispatch-operation.ts +38 -0
- package/src/kernel/propagation.ts +18 -1
- package/src/products/activity-timeline.ts +10 -0
- package/src/products/dashboard-screen.ts +21 -2
package/src/kernel/delegate.ts
CHANGED
|
@@ -201,6 +201,20 @@ export function planDelegation(request: DelegationRequest, ctx: DelegationContex
|
|
|
201
201
|
requested = (request.tools ?? []).map(normaliseCapability);
|
|
202
202
|
}
|
|
203
203
|
|
|
204
|
+
// Coordinator-only qualification does not authorize loading native Codemode or its raw model API in children.
|
|
205
|
+
const coordinatorOnly = requested.filter((capability) =>
|
|
206
|
+
["tool:codemode", "ext:codemode", "tool:principal_codemode", "ext:principal_codemode"].includes(capability),
|
|
207
|
+
);
|
|
208
|
+
if (coordinatorOnly.length)
|
|
209
|
+
return denied(
|
|
210
|
+
{
|
|
211
|
+
...empty,
|
|
212
|
+
requested,
|
|
213
|
+
reason: `Codemode is qualified only for the coordinator; governed children cannot receive ${coordinatorOnly.join(", ")}`,
|
|
214
|
+
},
|
|
215
|
+
"UNKNOWN_TOOL",
|
|
216
|
+
);
|
|
217
|
+
|
|
204
218
|
// ADR-0078. A declared `context:` id is a CEILING, not a request: a definition that permits forking must not
|
|
205
219
|
// fork on every spawn. So the declared modes come out of `requested` and exactly the one this call asked for
|
|
206
220
|
// goes back in.
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/** Explicit operation identity prevents duplicate dispatch, never authorizes work or caches results. */
|
|
2
|
+
export interface OperationReference {
|
|
3
|
+
operationId: string;
|
|
4
|
+
executionId: string;
|
|
5
|
+
state: "admitting" | "running" | "settled" | "not-started" | "uncertain";
|
|
6
|
+
cwd: string;
|
|
7
|
+
workspaceId: string | null;
|
|
8
|
+
startedAt: string;
|
|
9
|
+
updatedAt: string;
|
|
10
|
+
runtime?: {
|
|
11
|
+
control?: "failed";
|
|
12
|
+
work?: "succeeded" | "failed" | "unknown";
|
|
13
|
+
final?: { state: string; sessionId?: string; messageId?: string; leafId?: string; sha256?: string };
|
|
14
|
+
cleanup?: { state: string; receiptPath?: string; executionId?: string };
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
export interface OperationRequest {
|
|
18
|
+
operationId: string;
|
|
19
|
+
requestDigest: string;
|
|
20
|
+
executionId: string;
|
|
21
|
+
cwd: string;
|
|
22
|
+
workspaceId: string | null;
|
|
23
|
+
}
|
|
24
|
+
export interface OperationClaim {
|
|
25
|
+
operation: OperationReference;
|
|
26
|
+
reused: boolean;
|
|
27
|
+
/** Only the elected caller receives these methods. Neither grants execution authority. */
|
|
28
|
+
started?(cwd: string, workspaceId: string | null): Promise<void>;
|
|
29
|
+
finish?(state: "settled" | "not-started" | "uncertain", runtime?: OperationReference["runtime"]): Promise<void>;
|
|
30
|
+
}
|
|
31
|
+
export interface OperationAccess {
|
|
32
|
+
claim(request: OperationRequest, signal?: AbortSignal): Promise<OperationClaim>;
|
|
33
|
+
read(operationId: string): Promise<OperationReference | null>;
|
|
34
|
+
close(): void;
|
|
35
|
+
}
|
|
36
|
+
export function validOperationId(value: unknown): value is string {
|
|
37
|
+
return typeof value === "string" && /^[a-zA-Z0-9][a-zA-Z0-9._:/-]{0,159}$/.test(value);
|
|
38
|
+
}
|
|
@@ -410,7 +410,24 @@ export function mergeChildEnv(parentEnv: NodeJS.ProcessEnv, planEnv: Record<stri
|
|
|
410
410
|
}
|
|
411
411
|
|
|
412
412
|
/** Extract bare tool names from a provider payload's tool array, tolerating provider shape differences. */
|
|
413
|
-
export function observeToolNames(
|
|
413
|
+
export function observeToolNames(
|
|
414
|
+
payload: unknown,
|
|
415
|
+
registered?: readonly { name: string; exposure?: string }[],
|
|
416
|
+
active?: readonly string[],
|
|
417
|
+
): string[] | null {
|
|
418
|
+
// Pi's provider projection may hide declarations while tools remain callable from Codemode.
|
|
419
|
+
// Exposure metadata is native inventory, not authorization; deriveOwnGrant still intersects inheritance.
|
|
420
|
+
if (registered && active && registered.length > 0 && registered.every((tool) => typeof tool.exposure === "string")) {
|
|
421
|
+
const declared = new Set(active);
|
|
422
|
+
return registered
|
|
423
|
+
.filter(
|
|
424
|
+
(tool) =>
|
|
425
|
+
tool.exposure === "codemode" ||
|
|
426
|
+
tool.exposure === "deferred" ||
|
|
427
|
+
((tool.exposure === "direct" || tool.exposure === "model-only") && declared.has(tool.name)),
|
|
428
|
+
)
|
|
429
|
+
.map((tool) => tool.name);
|
|
430
|
+
}
|
|
414
431
|
if (!payload || typeof payload !== "object") return null;
|
|
415
432
|
const record = payload as Record<string, unknown>;
|
|
416
433
|
for (const key of ["tools", "functions"]) {
|
|
@@ -44,6 +44,8 @@ export interface ActivityEvent {
|
|
|
44
44
|
agentId?: string;
|
|
45
45
|
agent?: string;
|
|
46
46
|
outcome?: string;
|
|
47
|
+
tool?: string;
|
|
48
|
+
cwd?: string;
|
|
47
49
|
model?: string;
|
|
48
50
|
thinking?: string;
|
|
49
51
|
prompt?: ContentReference;
|
|
@@ -63,6 +65,8 @@ export interface TimelineTask {
|
|
|
63
65
|
agent?: string;
|
|
64
66
|
startedAt: string;
|
|
65
67
|
endedAt?: string;
|
|
68
|
+
lastEvent?: { at: string; kind: string; tool?: string };
|
|
69
|
+
cwd?: string;
|
|
66
70
|
status: "active" | "finished" | "failed" | "cancelled" | "needs-you";
|
|
67
71
|
model?: string;
|
|
68
72
|
thinking?: string;
|
|
@@ -122,6 +126,8 @@ function eventOf(value: unknown): ActivityEvent | null {
|
|
|
122
126
|
)
|
|
123
127
|
return null;
|
|
124
128
|
if (
|
|
129
|
+
(event.tool !== undefined && !validId(event.tool)) ||
|
|
130
|
+
(event.cwd !== undefined && (typeof event.cwd !== "string" || !event.cwd || event.cwd.length > 4096)) ||
|
|
125
131
|
(event.parentTaskId && !validId(event.parentTaskId)) ||
|
|
126
132
|
(event.agentId && !validId(event.agentId)) ||
|
|
127
133
|
(event.agent && !validId(event.agent)) ||
|
|
@@ -170,6 +176,10 @@ export function parseActivityTimeline(text: string): ActivityTimeline {
|
|
|
170
176
|
};
|
|
171
177
|
tasks.set(key, task);
|
|
172
178
|
}
|
|
179
|
+
if (!task.lastEvent || Date.parse(event.at) >= Date.parse(task.lastEvent.at)) {
|
|
180
|
+
task.lastEvent = { at: event.at, kind: event.kind, ...(event.tool ? { tool: event.tool } : {}) };
|
|
181
|
+
if (event.cwd) task.cwd = event.cwd;
|
|
182
|
+
}
|
|
173
183
|
if (event.kind === "task_started") {
|
|
174
184
|
task.model = event.model;
|
|
175
185
|
task.thinking = event.thinking;
|
|
@@ -11,6 +11,7 @@ export interface DashboardItem {
|
|
|
11
11
|
status: string;
|
|
12
12
|
elapsed: string;
|
|
13
13
|
details: string[];
|
|
14
|
+
observation?: string;
|
|
14
15
|
taskKey?: string;
|
|
15
16
|
timelinePath?: string;
|
|
16
17
|
approval?: boolean;
|
|
@@ -49,7 +50,10 @@ function wrapped(lines: string[], width: number): string[] {
|
|
|
49
50
|
}
|
|
50
51
|
function elapsed(ms: number): string {
|
|
51
52
|
const seconds = Math.max(0, Math.floor(ms / 1000));
|
|
52
|
-
|
|
53
|
+
const minutes = Math.floor(seconds / 60);
|
|
54
|
+
return seconds >= 3600
|
|
55
|
+
? `${Math.floor(minutes / 60)}:${String(minutes % 60).padStart(2, "0")}:${String(seconds % 60).padStart(2, "0")}`
|
|
56
|
+
: `${minutes}:${String(seconds % 60).padStart(2, "0")}`;
|
|
53
57
|
}
|
|
54
58
|
const friendlyStatus = (status: string) =>
|
|
55
59
|
({
|
|
@@ -87,7 +91,10 @@ export function ledgerDashboardItems(projection: DashboardProjection): Dashboard
|
|
|
87
91
|
`Execution: ${node.executionId}`,
|
|
88
92
|
`State: ${friendlyStatus(node.state)} (observation, not acceptance)`,
|
|
89
93
|
`Grant: ${node.effectiveGrant.join(", ") || "none"}`,
|
|
90
|
-
...(node.workspace
|
|
94
|
+
...(node.workspace
|
|
95
|
+
? [`Workspace: ${node.workspace.id} (${node.workspace.access})`, `Root: ${node.workspace.root}`]
|
|
96
|
+
: ["Workspace binding: none recorded"]),
|
|
97
|
+
`Last lifecycle event: ${node.updatedAt}`,
|
|
91
98
|
...(node.runtime?.herdrPaneId ? [`Pane: ${node.runtime.herdrPaneId}`] : []),
|
|
92
99
|
...(node.correlation?.phase ? [`Phase: ${node.correlation.phase}`] : []),
|
|
93
100
|
...(node.executor ? [`Executor: ${node.executor}`] : []),
|
|
@@ -105,11 +112,21 @@ export function activityDashboardItems(
|
|
|
105
112
|
label: `${task.agent || "User turn"} [${aliases.selector(task)}]`,
|
|
106
113
|
status: task.status,
|
|
107
114
|
elapsed: elapsed(Date.parse(task.endedAt ?? now.toISOString()) - Date.parse(task.startedAt)),
|
|
115
|
+
observation: task.lastEvent
|
|
116
|
+
? `${task.lastEvent.tool ? `${task.lastEvent.tool} ` : ""}${task.lastEvent.kind.replaceAll("_", " ")} · ${elapsed(Date.parse(now.toISOString()) - Date.parse(task.lastEvent.at))} ago`
|
|
117
|
+
: undefined,
|
|
108
118
|
agent: Boolean(task.agent || task.agents.length),
|
|
109
119
|
skills: task.skills.length > 0,
|
|
110
120
|
details: [
|
|
111
121
|
`Task: ${aliases.selector(task)}`,
|
|
112
122
|
`State: ${friendlyStatus(task.status)} (observation, not acceptance)`,
|
|
123
|
+
...(task.cwd ? [`Working directory: ${task.cwd}`] : ["Working directory: not recorded"]),
|
|
124
|
+
...(task.lastEvent
|
|
125
|
+
? [
|
|
126
|
+
`Last observed: ${task.lastEvent.kind}${task.lastEvent.tool ? ` (${task.lastEvent.tool})` : ""} at ${task.lastEvent.at}`,
|
|
127
|
+
]
|
|
128
|
+
: []),
|
|
129
|
+
"Silence is not proof of a stalled process. Finished is not review approval.",
|
|
113
130
|
...(task.parentTaskId ? [`Parent: ${task.parentTaskId}`] : []),
|
|
114
131
|
...(task.model ? [`Model: ${task.model}`] : []),
|
|
115
132
|
...(task.thinking ? [`Thinking: ${task.thinking}`] : []),
|
|
@@ -281,6 +298,8 @@ export function renderDashboardScreen(options: DashboardScreenOptions): string {
|
|
|
281
298
|
}
|
|
282
299
|
const tail = `${friendlyStatus(item.status)} ${item.elapsed}`.trim(),
|
|
283
300
|
labelWidth = Math.max(1, width - tail.length - 4);
|
|
301
|
+
if (item.key === screen.selectedKey && item.observation)
|
|
302
|
+
rows.push({ text: ` Observed: ${clean(item.observation)}` });
|
|
284
303
|
rows.push({
|
|
285
304
|
key: item.key,
|
|
286
305
|
text: `${item.key === screen.selectedKey ? ">" : " "} ${truncate(clean(item.label), labelWidth)} ${tail}`,
|