pi-subagents 0.80.0 → 0.81.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.
Files changed (87) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/bundle/agents.js +18 -0
  3. package/bundle/background-work.js +16 -0
  4. package/bundle/capability-ceiling.js +22 -0
  5. package/bundle/child-tool-plan.js +11 -0
  6. package/bundle/chunk-26C3WLYQ.js +8388 -0
  7. package/bundle/chunk-2XYWN7QJ.js +128 -0
  8. package/bundle/chunk-2ZSNH26H.js +4164 -0
  9. package/bundle/chunk-3DC5KBVP.js +235 -0
  10. package/bundle/chunk-3IF2PGW7.js +380 -0
  11. package/bundle/chunk-4QFZZV3O.js +57 -0
  12. package/bundle/chunk-563BHAZ5.js +1365 -0
  13. package/bundle/chunk-5LFLVSTM.js +260 -0
  14. package/bundle/chunk-62OCY2S4.js +14 -0
  15. package/bundle/chunk-74RT5YQE.js +326 -0
  16. package/bundle/chunk-7F6RKT6W.js +132 -0
  17. package/bundle/chunk-7J4ZXMY7.js +18 -0
  18. package/bundle/chunk-ARRKBB2B.js +179 -0
  19. package/bundle/chunk-BJN5LUQY.js +458 -0
  20. package/bundle/chunk-BPS2AGBZ.js +5421 -0
  21. package/bundle/chunk-CEKS3TFO.js +1337 -0
  22. package/bundle/chunk-CTPAE36Y.js +94 -0
  23. package/bundle/chunk-D4EHT5SJ.js +14 -0
  24. package/bundle/chunk-EYNJ6VL6.js +526 -0
  25. package/bundle/chunk-G5DKFLLI.js +1185 -0
  26. package/bundle/chunk-KSWQVGDW.js +1027 -0
  27. package/bundle/chunk-L5ZHE4L4.js +946 -0
  28. package/bundle/chunk-LSRUTHT7.js +57 -0
  29. package/bundle/chunk-N2BN7BF5.js +159 -0
  30. package/bundle/chunk-NF7IEKBH.js +490 -0
  31. package/bundle/chunk-NIXWDZZV.js +9 -0
  32. package/bundle/chunk-NNLASTQE.js +4082 -0
  33. package/bundle/chunk-TUWLXTAM.js +935 -0
  34. package/bundle/chunk-UKG4V45O.js +228 -0
  35. package/bundle/chunk-V2JWDB5U.js +753 -0
  36. package/bundle/chunk-V3BIUPLU.js +9163 -0
  37. package/bundle/chunk-V6MR5TOQ.js +270 -0
  38. package/bundle/chunk-VJHOELQP.js +8245 -0
  39. package/bundle/chunk-WSBNENFS.js +732 -0
  40. package/bundle/chunk-XMFLCKMQ.js +16664 -0
  41. package/bundle/chunk-YFCK7H2S.js +129 -0
  42. package/bundle/chunk-YYREO77V.js +137 -0
  43. package/bundle/chunk-Z7KVHQHL.js +173 -0
  44. package/bundle/chunk-ZBC44JJ3.js +8606 -0
  45. package/bundle/chunk-ZP3HODFH.js +175 -0
  46. package/bundle/control-channel.js +11 -0
  47. package/bundle/delegation.js +14 -0
  48. package/bundle/external-job-provider.js +20 -0
  49. package/bundle/external-runs.js +21 -0
  50. package/bundle/index.js +30 -0
  51. package/bundle/inspectors.js +8 -0
  52. package/bundle/intercom-bridge.js +11 -0
  53. package/bundle/preflight.js +425 -0
  54. package/bundle/project-panes.js +28 -0
  55. package/bundle/required-child-extensions.js +6 -0
  56. package/bundle/shared-types.js +8 -0
  57. package/bundle/workflow-resources.js +7 -0
  58. package/docs/extension-api.md +27 -0
  59. package/docs/observability.md +6 -2
  60. package/package.json +18 -18
  61. package/src/agents/frontmatter.d.ts +2 -0
  62. package/src/agents/frontmatter.js +9 -2
  63. package/src/api/delegation.d.ts +20 -0
  64. package/src/extension/index.js +27 -7
  65. package/src/runs/background/run-child-session.js +18 -0
  66. package/src/runs/background/stale-run-reconciler.js +2 -0
  67. package/src/runs/foreground/execution.js +39 -2
  68. package/src/runs/shared/structured-output.d.ts +1 -0
  69. package/src/runs/shared/structured-output.js +1 -0
  70. package/src/shared/accessible-dir.js +4 -1
  71. package/src/shared/provider-diagnostics.d.ts +9 -0
  72. package/src/shared/provider-diagnostics.js +75 -0
  73. package/src/shared/types.d.ts +3 -0
  74. package/src/slash/delegation-adapters.d.ts +3 -1
  75. package/src/slash/delegation-adapters.js +7 -0
  76. package/src/slash/prompt-template-bridge.js +3 -1
  77. package/src/slash/subagents-admin.d.ts +1 -0
  78. package/src/slash/subagents-admin.js +1 -1
  79. package/src/tui/fleet-layout.d.ts +20 -0
  80. package/src/tui/fleet-layout.js +17 -0
  81. package/src/tui/fleet-viewport.d.ts +12 -0
  82. package/src/tui/fleet-viewport.js +35 -0
  83. package/src/tui/fleet.d.ts +5 -6
  84. package/src/tui/fleet.js +69 -51
  85. package/src/workflows/structured-workflow-scripts.d.ts +1 -0
  86. package/src/workflows/structured-workflow-scripts.js +5 -4
  87. package/src/workflows/workflow-resources.js +2 -2
@@ -0,0 +1,228 @@
1
+ import {
2
+ previewDisplayText,
3
+ safeTerminalText,
4
+ sanitizeDisplayText,
5
+ truncateDisplayText
6
+ } from "./chunk-YFCK7H2S.js";
7
+
8
+ // src/api/external-runs.ts
9
+ var EXTERNAL_RUN_REGISTRY_VERSION = 2;
10
+ var EXTERNAL_RUN_REGISTRY_KEY = "pi-subagents.external-runs.v2";
11
+ var EXTERNAL_RUN_LIMITS = {
12
+ maxCachedRuns: 100,
13
+ maxSnapshotRuns: 20,
14
+ maxIdentityLength: 160,
15
+ /**
16
+ * A Pi session id is the session file path, which routinely exceeds a short
17
+ * identity budget in nested worktrees, so it is bounded like the other paths.
18
+ */
19
+ maxSessionIdLength: 4096,
20
+ maxTextLength: 160,
21
+ maxPreviewLength: 4096,
22
+ maxPathLength: 4096,
23
+ maxSerializedBytes: 32 * 1024
24
+ };
25
+ var trustedRecordsByRegistry = /* @__PURE__ */ new WeakMap();
26
+ var RUN_FIELD_NAMES = [
27
+ "id",
28
+ "sessionId",
29
+ "source",
30
+ "label",
31
+ "state",
32
+ "startedAt",
33
+ "updatedAt",
34
+ "endedAt",
35
+ "currentAction",
36
+ "preview",
37
+ "reportPath",
38
+ "transcriptPath"
39
+ ];
40
+ var RUN_FIELDS = new Set(RUN_FIELD_NAMES);
41
+ var UPDATE_FIELDS = new Set([...RUN_FIELDS].filter((field) => field !== "id" && field !== "sessionId" && field !== "source"));
42
+ function registry() {
43
+ const key2 = Symbol.for(EXTERNAL_RUN_REGISTRY_KEY);
44
+ const target = globalThis;
45
+ const existing = target[key2];
46
+ if (existing === void 0) {
47
+ const created = { version: EXTERNAL_RUN_REGISTRY_VERSION, runs: /* @__PURE__ */ new Map() };
48
+ target[key2] = created;
49
+ return created;
50
+ }
51
+ if (!existing || typeof existing !== "object" || Array.isArray(existing)) throw new Error(`Malformed external-run registry at Symbol.for("${EXTERNAL_RUN_REGISTRY_KEY}").`);
52
+ const candidate = existing;
53
+ if (candidate.version !== EXTERNAL_RUN_REGISTRY_VERSION || !(candidate.runs instanceof Map)) throw new Error(`Unsupported external-run registry at Symbol.for("${EXTERNAL_RUN_REGISTRY_KEY}").`);
54
+ return candidate;
55
+ }
56
+ function trustedRecords(current) {
57
+ const cached = trustedRecordsByRegistry.get(current);
58
+ if (cached) return cached;
59
+ const records = /* @__PURE__ */ new Map();
60
+ trustedRecordsByRegistry.set(current, records);
61
+ return records;
62
+ }
63
+ function inputObject(value, field, allowed) {
64
+ if (!value || typeof value !== "object" || Array.isArray(value)) throw new Error(`${field} must be an object.`);
65
+ const input = value;
66
+ const unknown = Object.keys(input).filter((key2) => !allowed.has(key2));
67
+ if (unknown.length) throw new Error(`${field} has unknown fields: ${unknown.join(", ")}.`);
68
+ return input;
69
+ }
70
+ function identity(value, field, maxLength = EXTERNAL_RUN_LIMITS.maxIdentityLength) {
71
+ if (typeof value !== "string" || value.length === 0 || value.trim() !== value || value.includes("\0")) throw new Error(`${field} must be a non-empty trimmed string without NUL characters.`);
72
+ if (value.length > maxLength) throw new Error(`${field} must be at most ${maxLength} characters.`);
73
+ if (/[\t\n\p{Zl}\p{Zp}]/u.test(value) || safeTerminalText(value) !== value) throw new Error(`${field} must contain only display-safe text.`);
74
+ return value;
75
+ }
76
+ function displayText(value, field, maxLength, required = false) {
77
+ if (value === void 0 && !required) return void 0;
78
+ if (typeof value !== "string" || value.length === 0) throw new Error(`${field} must be a non-empty string.`);
79
+ const safe = sanitizeDisplayText(value.slice(0, Math.max(maxLength * 4, maxLength)));
80
+ if (!safe) throw new Error(`${field} must contain displayable text.`);
81
+ return truncateDisplayText(safe, maxLength);
82
+ }
83
+ function timestamp(value, field, required = false) {
84
+ if (value === void 0 && !required) return void 0;
85
+ if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 0 || value > 864e13) throw new Error(`${field} must be a non-negative safe timestamp.`);
86
+ return value;
87
+ }
88
+ function state(value, field) {
89
+ if (value === "queued" || value === "running" || value === "completed" || value === "failed" || value === "stopped") return value;
90
+ throw new Error(`${field} is invalid.`);
91
+ }
92
+ function validateRun(value) {
93
+ const run = inputObject(value, "External run", RUN_FIELDS);
94
+ const updatedAt = timestamp(run.updatedAt, "External run updatedAt");
95
+ const endedAt = timestamp(run.endedAt, "External run endedAt");
96
+ const currentAction = displayText(run.currentAction, "External run currentAction", EXTERNAL_RUN_LIMITS.maxTextLength);
97
+ const preview = displayText(run.preview, "External run preview", EXTERNAL_RUN_LIMITS.maxPreviewLength);
98
+ const reportPath = displayText(run.reportPath, "External run reportPath", EXTERNAL_RUN_LIMITS.maxPathLength);
99
+ const transcriptPath = displayText(run.transcriptPath, "External run transcriptPath", EXTERNAL_RUN_LIMITS.maxPathLength);
100
+ return {
101
+ id: identity(run.id, "External run id"),
102
+ sessionId: identity(run.sessionId, "External run sessionId", EXTERNAL_RUN_LIMITS.maxSessionIdLength),
103
+ source: displayText(run.source, "External run source", EXTERNAL_RUN_LIMITS.maxTextLength, true),
104
+ label: displayText(run.label, "External run label", EXTERNAL_RUN_LIMITS.maxTextLength, true),
105
+ state: state(run.state, "External run state"),
106
+ startedAt: timestamp(run.startedAt, "External run startedAt", true),
107
+ ...updatedAt !== void 0 ? { updatedAt } : {},
108
+ ...endedAt !== void 0 ? { endedAt } : {},
109
+ ...currentAction ? { currentAction } : {},
110
+ ...preview ? { preview } : {},
111
+ ...reportPath ? { reportPath } : {},
112
+ ...transcriptPath ? { transcriptPath } : {}
113
+ };
114
+ }
115
+ function key(sessionId, id) {
116
+ return `${sessionId}\0${id}`;
117
+ }
118
+ function clone(run) {
119
+ return { ...run };
120
+ }
121
+ function trustedRecord(value, normalized) {
122
+ const candidate = value;
123
+ return {
124
+ value,
125
+ normalized,
126
+ keys: Object.keys(candidate),
127
+ values: RUN_FIELD_NAMES.map((field) => candidate[field])
128
+ };
129
+ }
130
+ function trustedRecordValue(value, record) {
131
+ if (!record || record.value !== value || !value || typeof value !== "object") return void 0;
132
+ try {
133
+ const candidate = value;
134
+ const keys = Object.keys(candidate);
135
+ if (keys.length !== record.keys.length || keys.some((key2, index) => key2 !== record.keys[index])) return void 0;
136
+ for (const [index, field] of RUN_FIELD_NAMES.entries()) {
137
+ if (candidate[field] !== record.values[index]) return void 0;
138
+ }
139
+ return record.normalized;
140
+ } catch {
141
+ return void 0;
142
+ }
143
+ }
144
+ function rememberTrustedRecord(current, cacheKey, value, normalized) {
145
+ trustedRecords(current).set(cacheKey, trustedRecord(value, normalized));
146
+ }
147
+ function normalizeCachedRecord(current, cacheKey, value) {
148
+ const run = validateRun(value);
149
+ rememberTrustedRecord(current, cacheKey, value, run);
150
+ return run;
151
+ }
152
+ function registerExternalRun(input) {
153
+ const run = validateRun(input);
154
+ const current = registry();
155
+ const runKey = key(run.sessionId, run.id);
156
+ if (current.runs.has(runKey)) throw new Error(`External run '${run.id}' is already registered for session '${run.sessionId}'.`);
157
+ if (current.runs.size >= EXTERNAL_RUN_LIMITS.maxCachedRuns) throw new Error(`External-run registry supports at most ${EXTERNAL_RUN_LIMITS.maxCachedRuns} cached runs.`);
158
+ current.runs.set(runKey, run);
159
+ rememberTrustedRecord(current, runKey, run, run);
160
+ return clone(run);
161
+ }
162
+ function updateExternalRun(sessionId, id, update) {
163
+ const safeSessionId = identity(sessionId, "External run sessionId", EXTERNAL_RUN_LIMITS.maxSessionIdLength);
164
+ const safeId = identity(id, "External run id");
165
+ const patch = inputObject(update, "External run update", UPDATE_FIELDS);
166
+ const current = registry();
167
+ const runKey = key(safeSessionId, safeId);
168
+ const previous = current.runs.get(runKey);
169
+ if (!previous) throw new Error(`External run '${safeId}' is not registered for session '${safeSessionId}'.`);
170
+ const next = validateRun({ ...previous, ...patch });
171
+ current.runs.set(runKey, next);
172
+ rememberTrustedRecord(current, runKey, next, next);
173
+ return clone(next);
174
+ }
175
+ function unregisterExternalRun(sessionId, id) {
176
+ const current = registry();
177
+ const runKey = key(identity(sessionId, "External run sessionId", EXTERNAL_RUN_LIMITS.maxSessionIdLength), identity(id, "External run id"));
178
+ const deleted = current.runs.delete(runKey);
179
+ if (deleted) trustedRecords(current).delete(runKey);
180
+ return deleted;
181
+ }
182
+ function snapshotBytes(runs) {
183
+ return Buffer.byteLength(JSON.stringify(runs), "utf8");
184
+ }
185
+ function getErrorMessage(error) {
186
+ return error instanceof Error ? error.message : String(error);
187
+ }
188
+ function snapshotExternalRuns(sessionId, options = {}) {
189
+ const safeSessionId = identity(sessionId, "External-run snapshot sessionId", EXTERNAL_RUN_LIMITS.maxSessionIdLength);
190
+ const current = registry();
191
+ const trusted = trustedRecords(current);
192
+ const sessionPrefix = `${safeSessionId}\0`;
193
+ const runs = [];
194
+ for (const [cacheKey, value] of current.runs.entries()) {
195
+ if (typeof cacheKey !== "string" || !cacheKey.startsWith(sessionPrefix)) continue;
196
+ try {
197
+ const run = trustedRecordValue(value, trusted.get(cacheKey)) ?? normalizeCachedRecord(current, cacheKey, value);
198
+ if (run.sessionId === safeSessionId) runs.push(run);
199
+ } catch (error) {
200
+ const message = `Malformed cached external run '${previewDisplayText(cacheKey.slice(sessionPrefix.length), EXTERNAL_RUN_LIMITS.maxIdentityLength)}': ${getErrorMessage(error)}`;
201
+ if (!options.ignoreMalformed) throw new Error(message, { cause: error instanceof Error ? error : void 0 });
202
+ current.runs.delete(cacheKey);
203
+ trusted.delete(cacheKey);
204
+ options.onMalformedRecord?.(message);
205
+ }
206
+ }
207
+ runs.sort((left, right) => {
208
+ const leftActive = left.state === "queued" || left.state === "running";
209
+ const rightActive = right.state === "queued" || right.state === "running";
210
+ if (leftActive !== rightActive) return leftActive ? -1 : 1;
211
+ return (right.updatedAt ?? right.endedAt ?? right.startedAt) - (left.updatedAt ?? left.endedAt ?? left.startedAt) || left.id.localeCompare(right.id);
212
+ });
213
+ const snapshot = runs.slice(0, EXTERNAL_RUN_LIMITS.maxSnapshotRuns).map(clone);
214
+ while (snapshot.length > 0 && snapshotBytes(snapshot) > EXTERNAL_RUN_LIMITS.maxSerializedBytes) snapshot.pop();
215
+ return snapshot;
216
+ }
217
+ var listExternalRuns = snapshotExternalRuns;
218
+
219
+ export {
220
+ EXTERNAL_RUN_REGISTRY_VERSION,
221
+ EXTERNAL_RUN_REGISTRY_KEY,
222
+ EXTERNAL_RUN_LIMITS,
223
+ registerExternalRun,
224
+ updateExternalRun,
225
+ unregisterExternalRun,
226
+ snapshotExternalRuns,
227
+ listExternalRuns
228
+ };