pi-crew 0.5.1 → 0.5.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/README.md +1 -1
  3. package/docs/actions-reference.md +87 -0
  4. package/docs/commands-reference.md +5 -0
  5. package/docs/pi-crew-bugs.md +6 -0
  6. package/index.ts +1 -1
  7. package/package.json +18 -16
  8. package/src/benchmark/benchmark-runner.ts +245 -0
  9. package/src/benchmark/feedback-loop.ts +66 -0
  10. package/src/extension/async-notifier.ts +1 -1
  11. package/src/extension/autonomous-policy.ts +1 -1
  12. package/src/extension/cross-extension-rpc.ts +1 -1
  13. package/src/extension/plan-orchestrate.ts +322 -0
  14. package/src/extension/register.ts +31 -41
  15. package/src/extension/registration/command-utils.ts +1 -1
  16. package/src/extension/registration/commands.ts +1 -1
  17. package/src/extension/registration/compaction-guard.ts +1 -1
  18. package/src/extension/registration/subagent-helpers.ts +1 -1
  19. package/src/extension/registration/subagent-tools.ts +1 -1
  20. package/src/extension/registration/team-tool.ts +1 -1
  21. package/src/extension/registration/viewers.ts +1 -1
  22. package/src/extension/session-summary.ts +1 -1
  23. package/src/extension/team-manager-command.ts +1 -1
  24. package/src/extension/team-tool/context.ts +1 -1
  25. package/src/extension/team-tool/handle-schedule.ts +183 -0
  26. package/src/extension/team-tool/orchestrate.ts +102 -0
  27. package/src/extension/team-tool/run.ts +215 -28
  28. package/src/extension/team-tool.ts +10 -0
  29. package/src/extension/tool-result.ts +1 -1
  30. package/src/i18n.ts +1 -1
  31. package/src/observability/event-to-metric.ts +1 -1
  32. package/src/prompt/prompt-runtime.ts +1 -1
  33. package/src/runtime/background-runner.ts +27 -5
  34. package/src/runtime/crash-recovery.ts +1 -1
  35. package/src/runtime/crew-hooks.ts +240 -0
  36. package/src/runtime/custom-tools/irc-tool.ts +1 -1
  37. package/src/runtime/custom-tools/submit-result-tool.ts +1 -1
  38. package/src/runtime/diagnostic-export.ts +38 -2
  39. package/src/runtime/foreground-watchdog.ts +1 -1
  40. package/src/runtime/live-session-runtime.ts +1 -1
  41. package/src/runtime/mcp-proxy.ts +1 -1
  42. package/src/runtime/pi-spawn.ts +20 -4
  43. package/src/runtime/process-status.ts +15 -2
  44. package/src/runtime/runtime-resolver.ts +1 -1
  45. package/src/runtime/session-resources.ts +1 -1
  46. package/src/runtime/task-runner.ts +31 -1
  47. package/src/runtime/team-runner.ts +6 -0
  48. package/src/schema/team-tool-schema.ts +24 -1
  49. package/src/state/crew-init.ts +56 -38
  50. package/src/state/decision-ledger.ts +295 -0
  51. package/src/state/hook-instinct-bridge.ts +90 -0
  52. package/src/state/hook-integrations.ts +51 -0
  53. package/src/state/instinct-store.ts +249 -0
  54. package/src/state/run-metrics.ts +135 -0
  55. package/src/state/tiered-eval.ts +471 -0
  56. package/src/state/types-eval.ts +58 -0
  57. package/src/state/types.ts +3 -0
  58. package/src/tools/safe-bash-extension.ts +5 -5
  59. package/src/ui/crew-widget.ts +1 -1
  60. package/src/ui/pi-ui-compat.ts +1 -1
  61. package/src/ui/run-action-dispatcher.ts +1 -1
  62. package/src/ui/tool-render.ts +2 -2
  63. package/src/utils/project-detector.ts +160 -0
  64. package/test-bugs-all.mjs +1 -1
  65. package/skills/.gitkeep +0 -0
  66. package/skills/REFERENCE.md +0 -136
@@ -0,0 +1,322 @@
1
+ /**
2
+ * Plan Orchestrate — Decompose plan documents into agent chain commands.
3
+ *
4
+ * Parses tagged sections from markdown plan documents and builds commands
5
+ * for sequential agent chain execution based on ECC recommendations.
6
+ */
7
+
8
+ import * as fs from "node:fs";
9
+ import * as path from "node:path";
10
+
11
+ /**
12
+ * Tag → Agent chain mapping from ECC recommendations.
13
+ */
14
+ export const TAG_TO_CHAIN: Record<string, string[]> = {
15
+ design: ["planner", "architect"],
16
+ impl: ["tdd-guide", "lang-reviewer"],
17
+ security: ["security-reviewer", "lang-reviewer"],
18
+ build: ["build-error-resolver"],
19
+ test: ["test-engineer", "verifier"],
20
+ review: ["reviewer"],
21
+ } as const;
22
+
23
+ /**
24
+ * Options for plan orchestration.
25
+ */
26
+ export interface OrchestrateOptions {
27
+ /** Path to the plan markdown document. */
28
+ planPath: string;
29
+ }
30
+
31
+ /**
32
+ * A single orchestrated step parsed from a plan section.
33
+ */
34
+ export interface OrchestratedStep {
35
+ /** Unique step identifier. */
36
+ stepId: string;
37
+ /** Tag from the parsed section. */
38
+ tag: string;
39
+ /** Agent chain for this step. */
40
+ chain: string[];
41
+ /** Prompt/goal text extracted from the section. */
42
+ prompt: string;
43
+ /** Raw heading text if present. */
44
+ heading?: string;
45
+ }
46
+
47
+ /**
48
+ * Parse tagged sections from a plan markdown document.
49
+ *
50
+ * Expected format:
51
+ * ```markdown
52
+ * # Design Phase
53
+ * <!-- tag: design -->
54
+ * Design the authentication system...
55
+ *
56
+ * # Implementation
57
+ * <!-- tag: impl -->
58
+ * Implement the JWT auth...
59
+ * ```
60
+ *
61
+ * @param planPath - Path to the plan markdown document.
62
+ * @returns Array of OrchestratedStep parsed from the document.
63
+ */
64
+ export function parsePlanDocument(planPath: string): OrchestratedStep[] {
65
+ if (!fs.existsSync(planPath)) {
66
+ throw new Error(`Plan document not found: ${planPath}`);
67
+ }
68
+
69
+ const content = fs.readFileSync(planPath, "utf-8");
70
+ return parsePlanDocumentContent(content);
71
+ }
72
+
73
+ /**
74
+ * Parse tagged sections from plan content string.
75
+ * This is the core parsing logic used by both parsePlanDocument and parsePlanDocumentSimple.
76
+ */
77
+ function parsePlanDocumentContent(content: string): OrchestratedStep[] {
78
+ const steps: OrchestratedStep[] = [];
79
+
80
+ // Find all tag matches with their positions
81
+ const tagRegex = /<!--\s*tag:\s*(\w+)\s*-->/g;
82
+ const tagMatches: Array<{ tag: string; start: number; end: number }> = [];
83
+
84
+ let match: RegExpExecArray | null;
85
+ while ((match = tagRegex.exec(content)) !== null) {
86
+ tagMatches.push({
87
+ tag: match[1],
88
+ start: match.index,
89
+ end: match.index + match[0].length,
90
+ });
91
+ }
92
+
93
+ if (tagMatches.length === 0) {
94
+ return [];
95
+ }
96
+
97
+ // For each tag, extract the content before it (to get heading)
98
+ // and the content after it until either another tag or section
99
+ for (let i = 0; i < tagMatches.length; i++) {
100
+ const current = tagMatches[i];
101
+ const nextTagStart = i < tagMatches.length - 1 ? tagMatches[i + 1].start : content.length;
102
+
103
+ // Find the heading by looking back from the tag position.
104
+ // Use global regex to find ALL headings in the window, then take the LAST
105
+ // (nearest to the tag) — simple `.match()` only finds the FIRST heading.
106
+ const textBeforeTag = content.slice(
107
+ Math.max(0, current.start - 500),
108
+ current.start,
109
+ );
110
+ const headingRegex = /(^|\n)(#{1,6})\s+(.+?)(\n|$)/g;
111
+ let lastHeadingMatch: RegExpExecArray | null = null;
112
+ let hm: RegExpExecArray | null;
113
+ while ((hm = headingRegex.exec(textBeforeTag)) !== null) {
114
+ lastHeadingMatch = hm;
115
+ }
116
+ const heading = lastHeadingMatch ? lastHeadingMatch[3].trim() : undefined;
117
+
118
+ // Get content after the tag until next tag or heading
119
+ // Start from end of tag comment, skip any whitespace/newline
120
+ const afterTagContent = content.slice(current.end);
121
+
122
+ // Find the section content: capture until next heading (##) or next tag
123
+ const sectionEndMatch = afterTagContent.search(/(^|\n)(#{1,6}\s|\n<!--\s*tag:)/m);
124
+ const sectionContent =
125
+ sectionEndMatch >= 0
126
+ ? afterTagContent.slice(0, sectionEndMatch)
127
+ : afterTagContent;
128
+
129
+ // Extract prompt text - remove the tag comment lines and empty lines
130
+ const promptLines: string[] = [];
131
+ const lines = sectionContent.split("\n");
132
+ for (const line of lines) {
133
+ const trimmed = line.trim();
134
+ if (!trimmed || trimmed.startsWith("<!--")) continue;
135
+ promptLines.push(trimmed);
136
+ }
137
+
138
+ const prompt = promptLines.join("\n").trim();
139
+ if (!prompt) continue;
140
+
141
+ const chain = TAG_TO_CHAIN[current.tag] ?? [];
142
+
143
+ steps.push({
144
+ stepId: `step-${(i + 1).toString().padStart(2, "0")}-${current.tag}`,
145
+ tag: current.tag,
146
+ chain,
147
+ prompt,
148
+ heading,
149
+ });
150
+ }
151
+
152
+ return steps;
153
+ }
154
+
155
+ /**
156
+ * Alternative simpler parser for plans that use explicit tag blocks.
157
+ * Actually uses the same core logic as parsePlanDocument.
158
+ *
159
+ * @param planPath - Path to the plan markdown document.
160
+ * @returns Array of OrchestratedStep parsed from the document.
161
+ */
162
+ export function parsePlanDocumentSimple(planPath: string): OrchestratedStep[] {
163
+ if (!fs.existsSync(planPath)) {
164
+ throw new Error(`Plan document not found: ${planPath}`);
165
+ }
166
+
167
+ const content = fs.readFileSync(planPath, "utf-8");
168
+ const steps = parsePlanDocumentContent(content);
169
+
170
+ if (steps.length === 0) {
171
+ // Try implicit detection
172
+ const tag = detectImplicitTag(content);
173
+ if (tag) {
174
+ return [
175
+ {
176
+ stepId: "step-01-unknown",
177
+ tag,
178
+ chain: TAG_TO_CHAIN[tag] ?? [],
179
+ prompt: content.trim(),
180
+ },
181
+ ];
182
+ }
183
+ }
184
+
185
+ return steps;
186
+ }
187
+
188
+ /**
189
+ * Detect implicit tag from content keywords when no explicit tag is present.
190
+ */
191
+ function detectImplicitTag(content: string): string | undefined {
192
+ const lowerContent = content.toLowerCase();
193
+ // Use word-boundary regex to avoid substring false matches.
194
+ // E.g., "implementation" must NOT trigger "impl" — only the word "implement" should.
195
+ const hasWord = (word: string): boolean =>
196
+ new RegExp(`\\b${word}\\b`).test(lowerContent);
197
+
198
+ if (hasWord("design") || hasWord("architecture")) return "design";
199
+ if (hasWord("implement") || hasWord("coding")) return "impl";
200
+ if (hasWord("security") || hasWord("audit")) return "security";
201
+ if (hasWord("build") || hasWord("compile")) return "build";
202
+ if (hasWord("test") || hasWord("verify")) return "test";
203
+ if (hasWord("review") || hasWord("feedback")) return "review";
204
+ return undefined;
205
+ }
206
+
207
+ /**
208
+ * Build agent chain command strings from orchestrated steps.
209
+ *
210
+ * @param steps - Array of OrchestratedStep to convert to commands.
211
+ * @returns Array of command strings for execution.
212
+ */
213
+ export function buildAgentChain(steps: OrchestratedStep[]): string[] {
214
+ return steps.map((step) => {
215
+ const agentList = step.chain.join(",");
216
+ // Escape single quotes in the goal for shell safety
217
+ const escapedGoal = step.prompt.replace(/'/g, "'\\''");
218
+ return `team action='run' agent='${agentList}' goal='${escapedGoal}'`;
219
+ });
220
+ }
221
+
222
+ /**
223
+ * Build structured chain data (useful for programmatic use).
224
+ *
225
+ * @param steps - Array of OrchestratedStep to convert.
226
+ * @returns Array of chain objects with step data and commands.
227
+ */
228
+ export function buildChainData(
229
+ steps: OrchestratedStep[],
230
+ ): Array<{
231
+ step: OrchestratedStep;
232
+ commands: string[];
233
+ }> {
234
+ return steps.map((step) => ({
235
+ step,
236
+ commands: buildAgentChain([step]),
237
+ }));
238
+ }
239
+
240
+ /**
241
+ * Parse and return a formatted overview of the plan.
242
+ *
243
+ * @param planPath - Path to the plan markdown document.
244
+ * @returns Summary string with step count and breakdown by tag.
245
+ */
246
+ export function formatPlanOverview(planPath: string): string {
247
+ const steps = parsePlanDocument(planPath);
248
+
249
+ if (steps.length === 0) {
250
+ // Try simple parser
251
+ const simpleSteps = parsePlanDocumentSimple(planPath);
252
+ if (simpleSteps.length === 0) {
253
+ return "No tagged sections found in plan document.";
254
+ }
255
+ return formatStepsOverview(simpleSteps);
256
+ }
257
+
258
+ return formatStepsOverview(steps);
259
+ }
260
+
261
+ function formatStepsOverview(steps: OrchestratedStep[]): string {
262
+ const lines: string[] = [
263
+ `Plan Orchestration: ${steps.length} step(s)`,
264
+ "",
265
+ ];
266
+
267
+ const tagCounts: Record<string, number> = {};
268
+ for (const step of steps) {
269
+ tagCounts[step.tag] = (tagCounts[step.tag] ?? 0) + 1;
270
+ }
271
+
272
+ lines.push("Summary by tag:");
273
+ for (const [tag, count] of Object.entries(tagCounts)) {
274
+ const chain = TAG_TO_CHAIN[tag]?.join(", ") ?? "(unknown)";
275
+ lines.push(` - ${tag}: ${count} step(s) → agents: ${chain}`);
276
+ }
277
+
278
+ lines.push("", "Steps:");
279
+ for (const step of steps) {
280
+ const preview =
281
+ step.prompt.length > 60
282
+ ? step.prompt.slice(0, 60) + "..."
283
+ : step.prompt;
284
+ // Include heading if available (e.g., "Security Review" from the plan's heading)
285
+ const headingPrefix = step.heading ? `${step.heading}: ` : "";
286
+ lines.push(
287
+ ` ${step.stepId} [${step.tag}] ${step.chain.join(",")}: ${headingPrefix}${preview}`,
288
+ );
289
+ }
290
+
291
+ return lines.join("\n");
292
+ }
293
+
294
+ /**
295
+ * Main orchestration function that parses a plan and returns pre-formatted output.
296
+ */
297
+ export async function orchestratePlan(
298
+ options: OrchestrateOptions,
299
+ ): Promise<{
300
+ steps: OrchestratedStep[];
301
+ chain: string[];
302
+ overview: string;
303
+ }> {
304
+ const { planPath } = options;
305
+
306
+ // Try primary parser first
307
+ let steps = parsePlanDocument(planPath);
308
+
309
+ // Fall back to simple parser if no results
310
+ if (steps.length === 0) {
311
+ steps = parsePlanDocumentSimple(planPath);
312
+ }
313
+
314
+ if (steps.length === 0) {
315
+ throw new Error(`No tagged sections found in plan document: ${planPath}`);
316
+ }
317
+
318
+ const chain = buildAgentChain(steps);
319
+ const overview = formatPlanOverview(planPath);
320
+
321
+ return { steps, chain, overview };
322
+ }
@@ -4,8 +4,9 @@ import { fileURLToPath } from "node:url";
4
4
  import type {
5
5
  ExtensionAPI,
6
6
  ExtensionContext,
7
- } from "@mariozechner/pi-coding-agent";
7
+ } from "@earendil-works/pi-coding-agent";
8
8
  import { loadConfig } from "../config/config.ts";
9
+ import { applyCrewSettingsToConfig, loadCrewSettings, saveCrewSettings } from "../runtime/settings-store.ts";
9
10
  // 2.7: Lazy-load LiveRunSidebar — only constructed when the user actually opens
10
11
  // a live run sidebar overlay. The class pulls in transcript-viewer and other
11
12
  // heavy UI modules.
@@ -50,10 +51,6 @@ import { listLiveAgents } from "../runtime/live-agent-manager.ts";
50
51
  import { createManifestCache } from "../runtime/manifest-cache.ts";
51
52
  import { checkProcessLiveness } from "../runtime/process-status.ts";
52
53
  import { CrewScheduler } from "../runtime/scheduler.ts";
53
- import {
54
- applyCrewSettingsToConfig,
55
- loadCrewSettings,
56
- } from "../runtime/settings-store.ts";
57
54
  import { appendEvent } from "../state/event-log.ts";
58
55
  import { loadRunManifestById, updateRunStatus } from "../state/state-store.ts";
59
56
  import type { TeamRunManifest } from "../state/types.ts";
@@ -109,6 +106,7 @@ import {
109
106
  } from "./registration/subagent-helpers.ts";
110
107
  import { registerSubagentTools } from "./registration/subagent-tools.ts";
111
108
  import { registerTeamTool } from "./registration/team-tool.ts";
109
+ import { handleTeamTool } from "./team-tool.ts";
112
110
 
113
111
  let _cachedOTLPExporter: typeof OTLPExporterType | undefined;
114
112
  async function importOTLPExporter(): Promise<typeof OTLPExporterType> {
@@ -916,34 +914,6 @@ export function registerPiTeams(pi: ExtensionAPI): void {
916
914
  });
917
915
  }
918
916
  }
919
- // Always send followUp notification regardless of ownerCurrent.
920
- // The run completed — the assistant needs to know even if the
921
- // originating session generation has changed (compaction, etc.).
922
- if (runId) {
923
- const loaded = loadRunManifestById(ctx.cwd, runId);
924
- const status = loaded?.manifest.status ?? "finished";
925
- const teamName = loaded?.manifest.team ?? "unknown";
926
- const goalSummary = (loaded?.manifest.goal ?? "").slice(
927
- 0,
928
- 100,
929
- );
930
- try {
931
- pi.sendUserMessage(
932
- [
933
- `pi-crew run ${status}: ${runId} (${teamName})`,
934
- `Goal: ${goalSummary}`,
935
- status === "completed"
936
- ? "Review the run results. If the run modified source files, run tests to verify. Summarize what was done."
937
- : "The run ended with status: " +
938
- status +
939
- ". Check the run artifacts and take appropriate action.",
940
- ].join("\n"),
941
- { deliverAs: "followUp" },
942
- );
943
- } catch {
944
- /* non-critical */
945
- }
946
- }
947
917
  if (ownerCurrent && currentCtx) {
948
918
  const config = loadConfig(currentCtx.cwd).config.ui;
949
919
  updateCrewWidget(
@@ -1325,18 +1295,43 @@ export function registerPiTeams(pi: ExtensionAPI): void {
1325
1295
  applyCrewSettingsToConfig(loadedConfig.config, crewSettings);
1326
1296
 
1327
1297
  // Start scheduler with event-based executor
1298
+ // Resolve sessionId before the scheduler executor closure captures it.
1299
+ const sessionId =
1300
+ ctx.sessionManager?.getSessionId?.() ??
1301
+ (typeof ctx === "object" && ctx !== null && "sessionId" in ctx
1302
+ ? (ctx as Record<string, unknown>).sessionId
1303
+ : undefined);
1328
1304
  crewScheduler = new CrewScheduler();
1329
1305
  crewScheduler.start({
1330
1306
  emit: (event) => {
1331
1307
  if (cleanedUp) return;
1308
+ pi.events?.emit?.("crew-scheduler", event);
1332
1309
  },
1333
1310
  executor: (job) => {
1311
+ let runParams: { action: string; team: string; goal: string };
1312
+ try {
1313
+ runParams = JSON.parse(job.prompt);
1314
+ } catch {
1315
+ runParams = { action: "run", team: "default", goal: job.prompt };
1316
+ }
1317
+ if (runParams.action !== "run") return `scheduled-${job.id}-${Date.now()}`;
1318
+ setImmediate(async () => {
1319
+ try {
1320
+ await handleTeamTool(
1321
+ { action: "run", team: runParams.team, goal: runParams.goal, async: true },
1322
+ { cwd: ctx.cwd, sessionId },
1323
+ );
1324
+ } catch (err) {
1325
+ logInternalError("scheduler.execute", err);
1326
+ }
1327
+ });
1334
1328
  return `scheduled-${job.id}-${Date.now()}`;
1335
1329
  },
1336
- finalizer: (_jobId, _agentId) => {
1337
- // no-op for now; future: launch team run
1338
- },
1330
+ finalizer: () => {},
1339
1331
  });
1332
+ // Wire scheduler into handle-schedule.ts so handlers can add/list jobs.
1333
+ // Uses a global symbol so the module doesn't need a direct circular import.
1334
+ (globalThis as Record<symbol | string, unknown>)[Symbol.for("pi-crew:scheduler")] = crewScheduler;
1340
1335
  // Load scheduled jobs from settings if present
1341
1336
  if (Array.isArray((crewSettings as any).scheduledJobs)) {
1342
1337
  for (const job of (crewSettings as any).scheduledJobs) {
@@ -1351,11 +1346,6 @@ export function registerPiTeams(pi: ExtensionAPI): void {
1351
1346
  configureNotifications(ctx);
1352
1347
  configureObservability(ctx);
1353
1348
  configureDeliveryCoordinator();
1354
- const sessionId =
1355
- ctx.sessionManager?.getSessionId?.() ??
1356
- (typeof ctx === "object" && ctx !== null && "sessionId" in ctx
1357
- ? (ctx as Record<string, unknown>).sessionId
1358
- : undefined);
1359
1349
  if (typeof sessionId === "string" && sessionId)
1360
1350
  deliveryCoordinator?.activate(sessionId);
1361
1351
  tryRegisterSessionCleanup(pi, () => {
@@ -1,4 +1,4 @@
1
- import type { ExtensionCommandContext } from "@mariozechner/pi-coding-agent";
1
+ import type { ExtensionCommandContext } from "@earendil-works/pi-coding-agent";
2
2
  import type { TeamToolParamsValue } from "../../schema/team-tool-schema.ts";
3
3
 
4
4
  export function parseRunArgs(args: string): TeamToolParamsValue {
@@ -1,4 +1,4 @@
1
- import type { ExtensionAPI, ExtensionCommandContext, ExtensionContext } from "@mariozechner/pi-coding-agent";
1
+ import type { ExtensionAPI, ExtensionCommandContext, ExtensionContext } from "@earendil-works/pi-coding-agent";
2
2
  import { loadConfig } from "../../config/config.ts";
3
3
  // Lazy-loaded: team-tool.ts pulls in entire runtime chain (1.4s+).
4
4
  import type { handleTeamTool as HandleTeamToolFn } from "../team-tool.ts";
@@ -1,4 +1,4 @@
1
- import type { ExtensionAPI, ExtensionContext } from "@mariozechner/pi-coding-agent";
1
+ import type { ExtensionAPI, ExtensionContext } from "@earendil-works/pi-coding-agent";
2
2
  import { listRecentRuns } from "../run-index.ts";
3
3
  import type { ArtifactDescriptor, TeamRunManifest } from "../../state/types.ts";
4
4
 
@@ -1,5 +1,5 @@
1
1
  import * as fs from "node:fs";
2
- import type { ExtensionAPI, ExtensionCommandContext, ExtensionContext } from "@mariozechner/pi-coding-agent";
2
+ import type { ExtensionAPI, ExtensionCommandContext, ExtensionContext } from "@earendil-works/pi-coding-agent";
3
3
  import { loadRunManifestById } from "../../state/state-store.ts";
4
4
  import { savePersistedSubagentRecord, type SubagentRecord, type SubagentSpawnOptions } from "../../subagents/manager.ts";
5
5
  import { resolveRealContainedPath } from "../../utils/safe-paths.ts";
@@ -1,4 +1,4 @@
1
- import type { ExtensionAPI, ToolDefinition } from "@mariozechner/pi-coding-agent";
1
+ import type { ExtensionAPI, ToolDefinition } from "@earendil-works/pi-coding-agent";
2
2
  import { Type } from "@sinclair/typebox";
3
3
  import type { TeamToolParamsValue } from "../../schema/team-tool-schema.ts";
4
4
  // Lazy-loaded: team-tool.ts pulls in entire runtime chain.
@@ -1,5 +1,5 @@
1
1
  import * as fs from "node:fs";
2
- import type { ExtensionAPI, ExtensionContext, ToolDefinition } from "@mariozechner/pi-coding-agent";
2
+ import type { ExtensionAPI, ExtensionContext, ToolDefinition } from "@earendil-works/pi-coding-agent";
3
3
  import { loadConfig } from "../../config/config.ts";
4
4
  import { TeamToolParams, type TeamToolParamsValue } from "../../schema/team-tool-schema.ts";
5
5
  import type { CrewWidgetState } from "../../ui/crew-widget.ts";
@@ -1,4 +1,4 @@
1
- import type { ExtensionCommandContext } from "@mariozechner/pi-coding-agent";
1
+ import type { ExtensionCommandContext } from "@earendil-works/pi-coding-agent";
2
2
  import { loadRunManifestById } from "../../state/state-store.ts";
3
3
  import { readCrewAgents } from "../../runtime/crew-agent-records.ts";
4
4
  import { loadConfig } from "../../config/config.ts";
@@ -1,4 +1,4 @@
1
- import type { ExtensionContext } from "@mariozechner/pi-coding-agent";
1
+ import type { ExtensionContext } from "@earendil-works/pi-coding-agent";
2
2
  import { isDisplayActiveRun } from "../runtime/process-status.ts";
3
3
  import { listRuns } from "./run-index.ts";
4
4
  import { readCrewAgents } from "../runtime/crew-agent-records.ts";
@@ -1,4 +1,4 @@
1
- import type { ExtensionCommandContext } from "@mariozechner/pi-coding-agent";
1
+ import type { ExtensionCommandContext } from "@earendil-works/pi-coding-agent";
2
2
  import { listRuns } from "./run-index.ts";
3
3
  // Lazy-loaded: team-tool.ts pulls in entire runtime chain.
4
4
  import type { handleTeamTool as HandleTeamToolFn } from "./team-tool.ts";
@@ -1,4 +1,4 @@
1
- import type { ExtensionContext } from "@mariozechner/pi-coding-agent";
1
+ import type { ExtensionContext } from "@earendil-works/pi-coding-agent";
2
2
  import type { PiTeamsConfig } from "../../config/config.ts";
3
3
  import type { MetricRegistry } from "../../observability/metric-registry.ts";
4
4
  import type { TeamToolDetails } from "../team-tool-types.ts";