pi-shadow-mind 0.1.5

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 (51) hide show
  1. package/DESIGN.md +493 -0
  2. package/README.md +58 -0
  3. package/dist/config.d.ts +18 -0
  4. package/dist/config.js +132 -0
  5. package/dist/config.js.map +1 -0
  6. package/dist/entity-store.d.ts +22 -0
  7. package/dist/entity-store.js +71 -0
  8. package/dist/entity-store.js.map +1 -0
  9. package/dist/index.d.ts +2 -0
  10. package/dist/index.js +8537 -0
  11. package/dist/index.js.map +7 -0
  12. package/dist/management-tools.d.ts +4 -0
  13. package/dist/management-tools.js +130 -0
  14. package/dist/management-tools.js.map +1 -0
  15. package/dist/protocol.d.ts +5 -0
  16. package/dist/protocol.js +34 -0
  17. package/dist/protocol.js.map +1 -0
  18. package/dist/random.d.ts +2 -0
  19. package/dist/random.js +14 -0
  20. package/dist/random.js.map +1 -0
  21. package/dist/registry.d.ts +9 -0
  22. package/dist/registry.js +139 -0
  23. package/dist/registry.js.map +1 -0
  24. package/dist/report-batcher.d.ts +15 -0
  25. package/dist/report-batcher.js +49 -0
  26. package/dist/report-batcher.js.map +1 -0
  27. package/dist/runtime.d.ts +36 -0
  28. package/dist/runtime.js +274 -0
  29. package/dist/runtime.js.map +1 -0
  30. package/dist/scheduler.d.ts +10 -0
  31. package/dist/scheduler.js +46 -0
  32. package/dist/scheduler.js.map +1 -0
  33. package/dist/shadow-runner.d.ts +93 -0
  34. package/dist/shadow-runner.js +251 -0
  35. package/dist/shadow-runner.js.map +1 -0
  36. package/dist/shutdown-drain.d.ts +12 -0
  37. package/dist/shutdown-drain.js +22 -0
  38. package/dist/shutdown-drain.js.map +1 -0
  39. package/dist/summaries.d.ts +9 -0
  40. package/dist/summaries.js +56 -0
  41. package/dist/summaries.js.map +1 -0
  42. package/dist/trajectory.d.ts +7 -0
  43. package/dist/trajectory.js +33 -0
  44. package/dist/trajectory.js.map +1 -0
  45. package/dist/types.d.ts +64 -0
  46. package/dist/types.js +2 -0
  47. package/dist/types.js.map +1 -0
  48. package/dist/validation.d.ts +8 -0
  49. package/dist/validation.js +18 -0
  50. package/dist/validation.js.map +1 -0
  51. package/package.json +52 -0
@@ -0,0 +1,251 @@
1
+ import { mkdir } from "node:fs/promises";
2
+ import { fileURLToPath } from "node:url";
3
+ import { basename, dirname, join, normalize, resolve } from "node:path";
4
+ import { Type } from "typebox";
5
+ import { DefaultResourceLoader, SessionManager, SettingsManager, createAgentSession, } from "@earendil-works/pi-coding-agent";
6
+ import { DEFAULT_READ_TOOLS } from "./types.js";
7
+ /**
8
+ * Resolve the final tool allowlist for a Shadow run against the main session's
9
+ * tool registry, per the design contract:
10
+ *
11
+ * - the final set is `readOnlyTools defaults + whitelist + report_to_main`;
12
+ * - names that do not exist in the main session are dropped (ignored) and
13
+ * returned as `missing`, while the rest are provided normally;
14
+ * - the built-in `report_to_main` is always kept.
15
+ */
16
+ export function resolveShadowTools(whitelist, available, defaults = DEFAULT_READ_TOOLS) {
17
+ const builtin = new Set(["report_to_main"]);
18
+ const requested = [...new Set([...defaults, ...whitelist, ...builtin])];
19
+ const tools = [];
20
+ const missing = [];
21
+ for (const name of requested) {
22
+ (builtin.has(name) || available.has(name) ? tools : missing).push(name);
23
+ }
24
+ return { tools, missing };
25
+ }
26
+ import { buildShadowHandoff, buildShadowKickoff, buildShadowSystemPrompt } from "./protocol.js";
27
+ import { sanitizeTrajectory } from "./trajectory.js";
28
+ const SELF_PATH = normalize(resolve(fileURLToPath(import.meta.url)));
29
+ function runReason(timedOut, reported, aborted, failed = false) {
30
+ if (timedOut)
31
+ return "timeout";
32
+ if (reported)
33
+ return "report";
34
+ if (aborted)
35
+ return "aborted";
36
+ return failed ? "error" : "silent";
37
+ }
38
+ /** Unify the three run() return paths so result shape changes touch one place. */
39
+ export function buildRunResult(options) {
40
+ const { reason, error, durationMs, session, baseMessageCount, missingTools, thinkingLevel } = options;
41
+ const ownMessages = session ? session.messages.slice(baseMessageCount) : [];
42
+ const metrics = toolMetrics(ownMessages);
43
+ return {
44
+ reason,
45
+ ...(error !== undefined ? { error } : {}),
46
+ durationMs,
47
+ toolNames: session?.getActiveToolNames() ?? [],
48
+ missingTools,
49
+ ...metrics,
50
+ ...(thinkingLevel !== undefined ? { thinkingLevel } : {}),
51
+ sessionFile: session?.sessionFile,
52
+ };
53
+ }
54
+ export class ShadowRunner {
55
+ controllers = new Map();
56
+ async run(request) {
57
+ const started = Date.now();
58
+ const controller = new AbortController();
59
+ this.controllers.set(request.runId, { controller });
60
+ const state = { reported: false, timedOut: false };
61
+ let finalReason = "error";
62
+ let sessionManager;
63
+ let timeout;
64
+ let missingTools = [];
65
+ let baseMessageCount = 0;
66
+ let thinkingLevel;
67
+ try {
68
+ const model = resolveRunModel(request);
69
+ assertShadowModelAuth(model, request);
70
+ const trajectory = sanitizeTrajectory(request.messages);
71
+ assertTrajectoryFits(model, trajectory);
72
+ sessionManager = await createShadowSessionManager(request);
73
+ for (const message of trajectory)
74
+ sessionManager.appendMessage(message);
75
+ sessionManager.appendMessage(buildShadowHandoff(model));
76
+ const boot = await this.bootstrapSession(request, model, controller, state, sessionManager);
77
+ state.session = boot.session;
78
+ missingTools = boot.missingTools;
79
+ thinkingLevel = boot.thinkingLevel;
80
+ baseMessageCount = boot.session.messages.length;
81
+ this.controllers.set(request.runId, { controller, session: boot.session });
82
+ if (controller.signal.aborted) {
83
+ finalReason = "aborted";
84
+ return buildRunResult({ reason: finalReason, durationMs: Date.now() - started, session: boot.session, baseMessageCount, missingTools, thinkingLevel });
85
+ }
86
+ const timeoutMs = (request.shadow.timeoutSeconds ?? request.config.defaultShadowTimeoutSeconds) * 1000;
87
+ timeout = setTimeout(() => {
88
+ state.timedOut = true;
89
+ controller.abort();
90
+ void boot.session?.abort();
91
+ }, timeoutMs);
92
+ controller.signal.addEventListener("abort", () => void boot.session?.abort(), { once: true });
93
+ await boot.session.prompt(buildShadowKickoff(request.shadow));
94
+ await boot.session.waitForIdle();
95
+ finalReason = runReason(state.timedOut, state.reported, controller.signal.aborted);
96
+ return buildRunResult({ reason: finalReason, durationMs: Date.now() - started, session: boot.session, baseMessageCount, missingTools, thinkingLevel });
97
+ }
98
+ catch (error) {
99
+ finalReason = runReason(state.timedOut, state.reported, controller.signal.aborted, true);
100
+ return buildRunResult({ reason: finalReason, error: error instanceof Error ? error.message : String(error), durationMs: Date.now() - started, session: state.session, baseMessageCount, missingTools, thinkingLevel });
101
+ }
102
+ finally {
103
+ if (timeout)
104
+ clearTimeout(timeout);
105
+ sessionManager?.appendCustomEntry("shadow-mind-run-end", { runId: request.runId, reason: finalReason, durationMs: Date.now() - started });
106
+ state.session?.dispose();
107
+ this.controllers.delete(request.runId);
108
+ }
109
+ }
110
+ /** Build the shadow AgentSession (loader, report tool, allowlist) and validate it. */
111
+ async bootstrapSession(request, model, controller, state, sessionManager) {
112
+ const thinkingLevel = resolveRunThinkingLevel(model, request);
113
+ const settingsManager = SettingsManager.create(request.cwd, request.agentDir);
114
+ const resourceLoader = new DefaultResourceLoader({
115
+ cwd: request.cwd,
116
+ agentDir: request.agentDir,
117
+ settingsManager,
118
+ systemPrompt: buildShadowSystemPrompt(request.mainSystemPrompt, request.shadow),
119
+ // The inherited main system prompt already embeds APPEND_SYSTEM.md,
120
+ // AGENTS.md and skills; keep the loader from re-discovering them so the
121
+ // shadow context stays a strict subset (no duplication).
122
+ appendSystemPrompt: [],
123
+ agentsFilesOverride: () => ({ agentsFiles: [] }),
124
+ skillsOverride: (base) => ({ skills: [], diagnostics: base.diagnostics }),
125
+ extensionsOverride: (base) => ({
126
+ ...base,
127
+ extensions: base.extensions.filter((extension) => !isSelfExtension(extension.resolvedPath)),
128
+ }),
129
+ });
130
+ const reportTool = createReportTool((content) => {
131
+ if (state.reported || controller.signal.aborted)
132
+ return;
133
+ state.reported = true;
134
+ request.onReport({
135
+ shadowId: request.shadow.id,
136
+ shadowName: request.shadow.name,
137
+ content,
138
+ epoch: request.epoch,
139
+ runId: request.runId,
140
+ });
141
+ queueMicrotask(() => void state.session?.abort());
142
+ });
143
+ const tools = [...new Set(request.tools)];
144
+ const created = await createAgentSession({
145
+ cwd: request.cwd,
146
+ agentDir: request.agentDir,
147
+ model,
148
+ thinkingLevel,
149
+ tools,
150
+ customTools: [reportTool],
151
+ resourceLoader,
152
+ sessionManager,
153
+ settingsManager,
154
+ });
155
+ const missingTools = tools.filter((name) => !created.session.getActiveToolNames().includes(name));
156
+ return { session: created.session, missingTools, thinkingLevel };
157
+ }
158
+ abort(runId) {
159
+ this.controllers.get(runId)?.controller.abort();
160
+ }
161
+ abortAll() {
162
+ for (const { controller } of this.controllers.values())
163
+ controller.abort();
164
+ }
165
+ }
166
+ export function toolMetrics(messages) {
167
+ const stats = new Map();
168
+ for (const message of messages) {
169
+ if (message.role !== "toolResult")
170
+ continue;
171
+ const tool = message.toolName ?? "unknown";
172
+ const entry = stats.get(tool) ?? { tool, calls: 0, failures: 0 };
173
+ entry.calls += 1;
174
+ if (message.isError)
175
+ entry.failures += 1;
176
+ stats.set(tool, entry);
177
+ }
178
+ const toolStats = [...stats.values()].sort((a, b) => b.calls - a.calls);
179
+ return {
180
+ toolCalls: toolStats.reduce((sum, stat) => sum + stat.calls, 0),
181
+ toolFailures: toolStats.reduce((sum, stat) => sum + stat.failures, 0),
182
+ toolStats,
183
+ };
184
+ }
185
+ function createReportTool(onReport) {
186
+ return {
187
+ name: "report_to_main",
188
+ label: "Report to Main",
189
+ description: "Report a concrete finding or completed result to the main agent and immediately end this Shadow Mind run.",
190
+ promptSnippet: "Report a useful result to the main agent and end this run",
191
+ parameters: Type.Object({ content: Type.String({ description: "The complete report for the main agent" }) }),
192
+ async execute(_toolCallId, params) {
193
+ const content = params.content;
194
+ onReport(content);
195
+ return { content: [{ type: "text", text: "Report delivered." }], details: {}, terminate: true };
196
+ },
197
+ };
198
+ }
199
+ async function createShadowSessionManager(request) {
200
+ if (!request.shadow.debug)
201
+ return SessionManager.inMemory(request.cwd);
202
+ const directory = join(request.agentDir, "shadow-minds", "logs", request.shadow.id);
203
+ await mkdir(directory, { recursive: true });
204
+ const manager = SessionManager.create(request.cwd, directory);
205
+ manager.appendCustomEntry("shadow-mind-run", { runId: request.runId, epoch: request.epoch, shadowId: request.shadow.id });
206
+ return manager;
207
+ }
208
+ function resolveRunModel(request) {
209
+ const fullId = request.shadow.runWithModel ?? request.config.defaultShadowModel;
210
+ if (!fullId)
211
+ return request.mainModel;
212
+ const model = request.resolveModel(fullId);
213
+ if (!model)
214
+ throw new Error(`shadow model not found: ${fullId}`);
215
+ return model;
216
+ }
217
+ function assertShadowModelAuth(model, request) {
218
+ if (request.modelAuthOk && !request.modelAuthOk(model)) {
219
+ throw new Error(`shadow model ${model.provider}/${model.id} has no configured auth`);
220
+ }
221
+ }
222
+ /**
223
+ * Resolve the thinking level for this run: shadow config → plugin default →
224
+ * the main session's effective level. The first candidate the model supports
225
+ * (per its thinkingLevelMap; null marks unsupported, a missing key or map means
226
+ * provider default, i.e. supported) wins. Fails only when none are supported.
227
+ */
228
+ export function resolveRunThinkingLevel(model, request) {
229
+ const candidates = [request.shadow.thinkingLevel, request.config.defaultThinkingLevel, request.mainThinkingLevel]
230
+ .filter((level) => level !== undefined);
231
+ for (const level of candidates) {
232
+ if (model.thinkingLevelMap?.[level] !== null)
233
+ return level;
234
+ }
235
+ throw new Error(`no supported thinking level for ${model.provider}/${model.id} (tried: ${candidates.join(", ") || "none"})`);
236
+ }
237
+ function assertTrajectoryFits(model, messages) {
238
+ const chars = messages.reduce((sum, message) => sum + (JSON.stringify(message)?.length ?? 0), 0);
239
+ const estimated = Math.ceil(chars / 2);
240
+ if (estimated > model.contextWindow) {
241
+ throw new Error(`trajectory ~${estimated} tokens exceeds ${model.provider}/${model.id} context window (${model.contextWindow})`);
242
+ }
243
+ }
244
+ function isSelfExtension(candidate) {
245
+ const normalized = normalize(resolve(candidate));
246
+ if (normalized === SELF_PATH)
247
+ return true;
248
+ const sourceDirectory = normalize(resolve(dirname(SELF_PATH)));
249
+ return dirname(normalized) === sourceDirectory && (basename(normalized) === "index.ts" || basename(normalized) === "index.js");
250
+ }
251
+ //# sourceMappingURL=shadow-runner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shadow-runner.js","sourceRoot":"","sources":["../src/shadow-runner.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ export interface DrainResult {
2
+ settled: boolean;
3
+ durationMs: number;
4
+ }
5
+ export declare function waitForSettled(options: {
6
+ timeoutMs: number;
7
+ isSettled: () => boolean;
8
+ pollMs?: number;
9
+ quietMs?: number;
10
+ now?: () => number;
11
+ delay?: (ms: number) => Promise<void>;
12
+ }): Promise<DrainResult>;
@@ -0,0 +1,22 @@
1
+ export async function waitForSettled(options) {
2
+ const pollMs = options.pollMs ?? 25;
3
+ const quietMs = options.quietMs ?? 50;
4
+ const now = options.now ?? Date.now;
5
+ const delay = options.delay ?? ((ms) => new Promise((resolve) => setTimeout(resolve, ms)));
6
+ const started = now();
7
+ let settledSince;
8
+ while (now() - started < options.timeoutMs) {
9
+ if (options.isSettled()) {
10
+ settledSince ??= now();
11
+ if (now() - settledSince >= quietMs)
12
+ return { settled: true, durationMs: now() - started };
13
+ }
14
+ else {
15
+ settledSince = undefined;
16
+ }
17
+ const remaining = options.timeoutMs - (now() - started);
18
+ await delay(Math.min(pollMs, Math.max(1, remaining)));
19
+ }
20
+ return { settled: false, durationMs: now() - started };
21
+ }
22
+ //# sourceMappingURL=shutdown-drain.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shutdown-drain.js","sourceRoot":"","sources":["../src/shutdown-drain.ts"],"names":[],"mappings":"AAKA,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,OAOpC;IACC,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,EAAE,CAAC;IACpC,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,EAAE,CAAC;IACtC,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC;IACpC,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,IAAI,CAAC,CAAC,EAAU,EAAE,EAAE,CAAC,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC;IACzG,MAAM,OAAO,GAAG,GAAG,EAAE,CAAC;IACtB,IAAI,YAAgC,CAAC;IAErC,OAAO,GAAG,EAAE,GAAG,OAAO,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC;QAC3C,IAAI,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC;YACxB,YAAY,KAAK,GAAG,EAAE,CAAC;YACvB,IAAI,GAAG,EAAE,GAAG,YAAY,IAAI,OAAO;gBAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,GAAG,EAAE,GAAG,OAAO,EAAE,CAAC;QAC7F,CAAC;aAAM,CAAC;YACN,YAAY,GAAG,SAAS,CAAC;QAC3B,CAAC;QACD,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,GAAG,CAAC,GAAG,EAAE,GAAG,OAAO,CAAC,CAAC;QACxD,MAAM,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC;IACxD,CAAC;IACD,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,GAAG,EAAE,GAAG,OAAO,EAAE,CAAC;AACzD,CAAC"}
@@ -0,0 +1,9 @@
1
+ interface ToolResultLike {
2
+ toolName?: string;
3
+ content?: unknown;
4
+ isError?: boolean;
5
+ }
6
+ type Summarizer = (result: ToolResultLike) => string;
7
+ export declare function summarizeToolResult(result: ToolResultLike): string;
8
+ export declare function registerToolResultSummarizer(toolName: string, summarizer: Summarizer): void;
9
+ export {};
@@ -0,0 +1,56 @@
1
+ const summarizers = new Map([
2
+ ["read", (result) => summarizeLines(result, "read")],
3
+ ["grep", (result) => summarizeLines(result, "matches")],
4
+ ["find", (result) => summarizeLines(result, "paths")],
5
+ ["ls", (result) => summarizeLines(result, "entries")],
6
+ ]);
7
+ export function summarizeToolResult(result) {
8
+ const summary = summarizers.get(result.toolName ?? "")?.(result) ?? summarizeGeneric(result);
9
+ return result.isError ? `error · ${summary}` : summary;
10
+ }
11
+ export function registerToolResultSummarizer(toolName, summarizer) {
12
+ summarizers.set(toolName, summarizer);
13
+ }
14
+ function summarizeLines(result, noun) {
15
+ const text = textContent(result.content);
16
+ if (!text)
17
+ return `0 ${noun}`;
18
+ const lines = text.split(/\r?\n/).filter(Boolean);
19
+ const preview = compact(lines[0] ?? "");
20
+ return `${lines.length} ${noun}${preview ? ` · ${preview}` : ""}`;
21
+ }
22
+ function summarizeGeneric(result) {
23
+ return describeContent(result.content) ?? "no output";
24
+ }
25
+ function describeContent(content) {
26
+ if (Array.isArray(content)) {
27
+ const blocks = content.filter((block) => Boolean(block) && typeof block === "object");
28
+ if (!blocks.length)
29
+ return "empty result";
30
+ const counts = new Map();
31
+ for (const block of blocks) {
32
+ const type = block.type ?? "object";
33
+ counts.set(type, (counts.get(type) ?? 0) + 1);
34
+ }
35
+ return [...counts.entries()].map(([type, count]) => `${count} ${type}${count > 1 ? "s" : ""}`).join(" · ");
36
+ }
37
+ if (content === null)
38
+ return "null";
39
+ if (typeof content === "string")
40
+ return `text · ${content.length} chars`;
41
+ if (typeof content === "number" || typeof content === "boolean")
42
+ return `${typeof content} · ${String(content)}`;
43
+ if (typeof content === "object")
44
+ return `object · ${Object.keys(content).length} keys`;
45
+ return undefined;
46
+ }
47
+ function textContent(content) {
48
+ if (!Array.isArray(content))
49
+ return "";
50
+ return content.filter((part) => Boolean(part) && typeof part === "object" && part.type === "text")
51
+ .map((part) => part.text ?? "").join("\n");
52
+ }
53
+ function compact(value) {
54
+ return value.replace(/\s+/g, " ").trim();
55
+ }
56
+ //# sourceMappingURL=summaries.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"summaries.js","sourceRoot":"","sources":["../src/summaries.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ type MessageLike = {
2
+ role?: string;
3
+ content?: unknown;
4
+ [key: string]: unknown;
5
+ };
6
+ export declare function sanitizeTrajectory(messages: readonly MessageLike[]): MessageLike[];
7
+ export {};
@@ -0,0 +1,33 @@
1
+ import { summarizeToolResult } from "./summaries.js";
2
+ export function sanitizeTrajectory(messages) {
3
+ return messages.flatMap((message) => {
4
+ if (message.role === "assistant") {
5
+ const content = Array.isArray(message.content)
6
+ ? message.content.filter((block) => !isThinkingBlock(block)).map(clone)
7
+ : message.content;
8
+ return [{ ...clone(message), content }];
9
+ }
10
+ if (message.role === "toolResult") {
11
+ return [{
12
+ ...clone(message),
13
+ content: [{ type: "text", text: summarizeToolResult(message) }],
14
+ details: undefined,
15
+ usage: undefined,
16
+ }];
17
+ }
18
+ if (message.role === "custom") {
19
+ return message.customType === "shadow-report" ? [clone(message)] : [];
20
+ }
21
+ if (message.role === "user" || message.role === "compactionSummary" || message.role === "branchSummary") {
22
+ return [clone(message)];
23
+ }
24
+ return [];
25
+ });
26
+ }
27
+ function isThinkingBlock(value) {
28
+ return Boolean(value) && typeof value === "object" && value.type === "thinking";
29
+ }
30
+ function clone(value) {
31
+ return structuredClone(value);
32
+ }
33
+ //# sourceMappingURL=trajectory.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trajectory.js","sourceRoot":"","sources":["../src/trajectory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAIrD,MAAM,UAAU,kBAAkB,CAAC,QAAgC;IACjE,OAAO,QAAQ,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAClC,IAAI,OAAO,CAAC,IAAI,KAAK,WAAW,EAAE,CAAC;YACjC,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC;gBAC5C,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC;gBACvE,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC;YACpB,OAAO,CAAC,EAAE,GAAG,KAAK,CAAC,OAAO,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC;QAC1C,CAAC;QACD,IAAI,OAAO,CAAC,IAAI,KAAK,YAAY,EAAE,CAAC;YAClC,OAAO,CAAC;oBACN,GAAG,KAAK,CAAC,OAAO,CAAC;oBACjB,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,mBAAmB,CAAC,OAAO,CAAC,EAAE,CAAC;oBAC/D,OAAO,EAAE,SAAS;oBAClB,KAAK,EAAE,SAAS;iBACjB,CAAC,CAAC;QACL,CAAC;QACD,IAAI,OAAO,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YAC9B,OAAO,OAAO,CAAC,UAAU,KAAK,eAAe,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QACxE,CAAC;QACD,IAAI,OAAO,CAAC,IAAI,KAAK,MAAM,IAAI,OAAO,CAAC,IAAI,KAAK,mBAAmB,IAAI,OAAO,CAAC,IAAI,KAAK,eAAe,EAAE,CAAC;YACxG,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC;QAC1B,CAAC;QACD,OAAO,EAAE,CAAC;IACZ,CAAC,CAAC,CAAC;AACL,CAAC;AAED,SAAS,eAAe,CAAC,KAAc;IACrC,OAAO,OAAO,CAAC,KAAK,CAAC,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAK,KAA2B,CAAC,IAAI,KAAK,UAAU,CAAC;AACzG,CAAC;AAED,SAAS,KAAK,CAAI,KAAQ;IACxB,OAAO,eAAe,CAAC,KAAK,CAAC,CAAC;AAChC,CAAC"}
@@ -0,0 +1,64 @@
1
+ import type { ThinkingLevel } from "@earendil-works/pi-agent-core";
2
+ export declare const DEFAULT_READ_TOOLS: readonly ["read", "grep", "find", "ls"];
3
+ export interface ShadowConfig {
4
+ heartbeatProbability: number;
5
+ maxParallelShadows: number;
6
+ defaultShadowTimeoutSeconds: number;
7
+ headlessDrainTimeoutSeconds: number;
8
+ resultBatchWindowMs: number;
9
+ defaultShadowModel?: string;
10
+ defaultThinkingLevel: ThinkingLevel;
11
+ randomSeed?: number;
12
+ }
13
+ export interface ShadowDefinition {
14
+ id: string;
15
+ name: string;
16
+ enabled: boolean;
17
+ debug: boolean;
18
+ activationProbability: number;
19
+ activeForModels: string[];
20
+ runWithModel?: string;
21
+ thinkingLevel?: ThinkingLevel;
22
+ timeoutSeconds?: number;
23
+ tools: string[];
24
+ prompt: string;
25
+ filePath: string;
26
+ }
27
+ export interface RegistryDiagnostic {
28
+ filePath: string;
29
+ message: string;
30
+ }
31
+ export interface RegistrySnapshot {
32
+ shadows: ShadowDefinition[];
33
+ diagnostics: RegistryDiagnostic[];
34
+ }
35
+ export type RunEndReason = "report" | "silent" | "timeout" | "aborted" | "error";
36
+ export interface ShadowReport {
37
+ shadowId: string;
38
+ shadowName: string;
39
+ content: string;
40
+ epoch: number;
41
+ runId: string;
42
+ }
43
+ export interface RuntimeEvent {
44
+ at: string;
45
+ kind: string;
46
+ epoch: number;
47
+ data?: Record<string, unknown>;
48
+ }
49
+ export interface HeartbeatDecision {
50
+ heartbeatRoll: number;
51
+ activated: Array<{
52
+ shadow: ShadowDefinition;
53
+ roll: number;
54
+ }>;
55
+ candidates: Array<{
56
+ shadowId: string;
57
+ roll: number;
58
+ selected: boolean;
59
+ }>;
60
+ /** Shadow ids excluded because active_for_models did not match the main model. */
61
+ modelFiltered: string[];
62
+ /** Shadow ids excluded because the same shadow is already running. */
63
+ runningExcluded: string[];
64
+ }
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ export const DEFAULT_READ_TOOLS = ["read", "grep", "find", "ls"];
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,CAAU,CAAC"}
@@ -0,0 +1,8 @@
1
+ import type { ThinkingLevel } from "@earendil-works/pi-agent-core";
2
+ /** Canonical set of valid pi thinking levels, shared by config and registry. */
3
+ export declare const THINKING_LEVELS: ReadonlySet<ThinkingLevel>;
4
+ export declare function isFiniteNumber(value: unknown): value is number;
5
+ export declare function inRange(value: number, min: number, max: number): boolean;
6
+ export declare function isNonEmptyString(value: unknown): value is string;
7
+ export declare function isStringArray(value: unknown): value is string[];
8
+ export declare function isThinkingLevel(value: unknown): value is ThinkingLevel;
@@ -0,0 +1,18 @@
1
+ /** Canonical set of valid pi thinking levels, shared by config and registry. */
2
+ export const THINKING_LEVELS = new Set(["off", "minimal", "low", "medium", "high", "xhigh", "max"]);
3
+ export function isFiniteNumber(value) {
4
+ return typeof value === "number" && Number.isFinite(value);
5
+ }
6
+ export function inRange(value, min, max) {
7
+ return value >= min && value <= max;
8
+ }
9
+ export function isNonEmptyString(value) {
10
+ return typeof value === "string" && value.trim() !== "";
11
+ }
12
+ export function isStringArray(value) {
13
+ return Array.isArray(value) && value.every((item) => isNonEmptyString(item));
14
+ }
15
+ export function isThinkingLevel(value) {
16
+ return typeof value === "string" && THINKING_LEVELS.has(value);
17
+ }
18
+ //# sourceMappingURL=validation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validation.js","sourceRoot":"","sources":["../src/validation.ts"],"names":[],"mappings":"AAEA,gFAAgF;AAChF,MAAM,CAAC,MAAM,eAAe,GAA+B,IAAI,GAAG,CAAgB,CAAC,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,CAAC,CAAC,CAAC;AAE/I,MAAM,UAAU,cAAc,CAAC,KAAc;IAC3C,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;AAC7D,CAAC;AAED,MAAM,UAAU,OAAO,CAAC,KAAa,EAAE,GAAW,EAAE,GAAW;IAC7D,OAAO,KAAK,IAAI,GAAG,IAAI,KAAK,IAAI,GAAG,CAAC;AACtC,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,KAAc;IAC7C,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC;AAC1D,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,KAAc;IAC1C,OAAO,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC,CAAC;AAC/E,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,KAAc;IAC5C,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,eAAe,CAAC,GAAG,CAAC,KAAsB,CAAC,CAAC;AAClF,CAAC"}
package/package.json ADDED
@@ -0,0 +1,52 @@
1
+ {
2
+ "name": "pi-shadow-mind",
3
+ "version": "0.1.5",
4
+ "description": "Parallel cognitive runtime for Pi",
5
+ "type": "module",
6
+ "keywords": [
7
+ "pi-package",
8
+ "pi",
9
+ "agent",
10
+ "multi-agent"
11
+ ],
12
+ "license": "MIT",
13
+ "files": [
14
+ "dist",
15
+ "README.md",
16
+ "DESIGN.md"
17
+ ],
18
+ "pi": {
19
+ "extensions": [
20
+ "./dist/index.js"
21
+ ]
22
+ },
23
+ "scripts": {
24
+ "clean": "node -e \"require('node:fs').rmSync('dist',{recursive:true,force:true})\"",
25
+ "build": "npm run clean && tsc -p tsconfig.build.json && esbuild src/index.ts --bundle --platform=node --format=esm --target=node20 --outfile=dist/index.js --sourcemap --external:@earendil-works/* --external:typebox",
26
+ "typecheck": "tsc --noEmit",
27
+ "test": "vitest run",
28
+ "verify": "npm run typecheck && npm test",
29
+ "prepack": "npm run verify && npm run build"
30
+ },
31
+ "dependencies": {
32
+ "yaml": "^2.8.1"
33
+ },
34
+ "peerDependencies": {
35
+ "@earendil-works/pi-agent-core": "*",
36
+ "@earendil-works/pi-ai": "*",
37
+ "@earendil-works/pi-coding-agent": "*",
38
+ "@earendil-works/pi-tui": "*",
39
+ "typebox": "*"
40
+ },
41
+ "devDependencies": {
42
+ "@earendil-works/pi-agent-core": "^0.84.1",
43
+ "@earendil-works/pi-ai": "^0.84.1",
44
+ "@earendil-works/pi-coding-agent": "^0.84.1",
45
+ "@earendil-works/pi-tui": "^0.84.1",
46
+ "@types/node": "^24.0.0",
47
+ "esbuild": "^0.25.0",
48
+ "typebox": "^1.3.13",
49
+ "typescript": "^5.9.3",
50
+ "vitest": "^3.2.4"
51
+ }
52
+ }