gsd-pi 2.38.0-dev.96dc7fb → 2.38.0-dev.98b44dc
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/README.md +15 -11
- package/dist/app-paths.js +1 -1
- package/dist/extension-registry.js +2 -2
- package/dist/remote-questions-config.js +2 -2
- package/dist/resource-loader.js +34 -1
- package/dist/resources/extensions/browser-tools/index.js +3 -1
- package/dist/resources/extensions/browser-tools/tools/verify.js +97 -0
- package/dist/resources/extensions/env-utils.js +29 -0
- package/dist/resources/extensions/get-secrets-from-user.js +5 -24
- package/dist/resources/extensions/github-sync/cli.js +284 -0
- package/dist/resources/extensions/github-sync/index.js +73 -0
- package/dist/resources/extensions/github-sync/mapping.js +67 -0
- package/dist/resources/extensions/github-sync/sync.js +424 -0
- package/dist/resources/extensions/github-sync/templates.js +118 -0
- package/dist/resources/extensions/github-sync/types.js +7 -0
- package/dist/resources/extensions/gsd/auto/session.js +6 -23
- package/dist/resources/extensions/gsd/auto-dispatch.js +8 -9
- package/dist/resources/extensions/gsd/auto-loop.js +636 -594
- package/dist/resources/extensions/gsd/auto-post-unit.js +99 -70
- package/dist/resources/extensions/gsd/auto-prompts.js +202 -48
- package/dist/resources/extensions/gsd/auto-start.js +7 -1
- package/dist/resources/extensions/gsd/auto-worktree-sync.js +2 -1
- package/dist/resources/extensions/gsd/auto-worktree.js +3 -3
- package/dist/resources/extensions/gsd/auto.js +143 -96
- package/dist/resources/extensions/gsd/commands-extensions.js +3 -2
- package/dist/resources/extensions/gsd/commands-prefs-wizard.js +1 -1
- package/dist/resources/extensions/gsd/commands.js +4 -2
- package/dist/resources/extensions/gsd/context-budget.js +2 -10
- package/dist/resources/extensions/gsd/detection.js +1 -2
- package/dist/resources/extensions/gsd/docs/preferences-reference.md +0 -2
- package/dist/resources/extensions/gsd/doctor-providers.js +30 -11
- package/dist/resources/extensions/gsd/doctor.js +20 -1
- package/dist/resources/extensions/gsd/exit-command.js +2 -1
- package/dist/resources/extensions/gsd/export.js +1 -1
- package/dist/resources/extensions/gsd/files.js +48 -9
- package/dist/resources/extensions/gsd/forensics.js +1 -1
- package/dist/resources/extensions/gsd/git-service.js +30 -12
- package/dist/resources/extensions/gsd/gitignore.js +16 -3
- package/dist/resources/extensions/gsd/guided-flow.js +149 -38
- package/dist/resources/extensions/gsd/health-widget-core.js +32 -70
- package/dist/resources/extensions/gsd/health-widget.js +3 -86
- package/dist/resources/extensions/gsd/index.js +24 -20
- package/dist/resources/extensions/gsd/migrate/parsers.js +1 -1
- package/dist/resources/extensions/gsd/migrate-external.js +18 -1
- package/dist/resources/extensions/gsd/native-git-bridge.js +37 -0
- package/dist/resources/extensions/gsd/paths.js +3 -0
- package/dist/resources/extensions/gsd/preferences-models.js +0 -12
- package/dist/resources/extensions/gsd/preferences-types.js +1 -1
- package/dist/resources/extensions/gsd/preferences-validation.js +59 -11
- package/dist/resources/extensions/gsd/preferences.js +22 -11
- package/dist/resources/extensions/gsd/prompt-loader.js +6 -2
- package/dist/resources/extensions/gsd/prompts/complete-milestone.md +1 -1
- package/dist/resources/extensions/gsd/prompts/complete-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/discuss.md +11 -14
- package/dist/resources/extensions/gsd/prompts/execute-task.md +5 -3
- package/dist/resources/extensions/gsd/prompts/guided-complete-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/guided-discuss-milestone.md +11 -12
- package/dist/resources/extensions/gsd/prompts/guided-discuss-slice.md +8 -10
- package/dist/resources/extensions/gsd/prompts/guided-execute-task.md +1 -1
- package/dist/resources/extensions/gsd/prompts/guided-plan-milestone.md +1 -1
- package/dist/resources/extensions/gsd/prompts/guided-plan-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/guided-research-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/guided-resume-task.md +1 -1
- package/dist/resources/extensions/gsd/prompts/plan-milestone.md +1 -1
- package/dist/resources/extensions/gsd/prompts/plan-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/queue.md +4 -8
- package/dist/resources/extensions/gsd/prompts/reactive-execute.md +11 -8
- package/dist/resources/extensions/gsd/prompts/reassess-roadmap.md +1 -1
- package/dist/resources/extensions/gsd/prompts/research-milestone.md +1 -1
- package/dist/resources/extensions/gsd/prompts/research-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/run-uat.md +28 -11
- package/dist/resources/extensions/gsd/prompts/workflow-start.md +2 -2
- package/dist/resources/extensions/gsd/repo-identity.js +21 -4
- package/dist/resources/extensions/gsd/resource-version.js +2 -1
- package/dist/resources/extensions/gsd/roadmap-mutations.js +24 -0
- package/dist/resources/extensions/gsd/state.js +42 -23
- package/dist/resources/extensions/gsd/templates/runtime.md +21 -0
- package/dist/resources/extensions/gsd/templates/task-plan.md +3 -0
- package/dist/resources/extensions/gsd/visualizer-data.js +1 -1
- package/dist/resources/extensions/mcp-client/index.js +14 -1
- package/dist/resources/extensions/remote-questions/status.js +4 -1
- package/dist/resources/extensions/remote-questions/store.js +4 -1
- package/dist/resources/extensions/search-the-web/provider.js +2 -1
- package/dist/resources/extensions/shared/frontmatter.js +1 -1
- package/dist/resources/extensions/subagent/isolation.js +2 -1
- package/dist/resources/extensions/ttsr/rule-loader.js +2 -1
- package/package.json +1 -1
- package/packages/pi-ai/dist/utils/oauth/anthropic.js +2 -2
- package/packages/pi-ai/dist/utils/oauth/anthropic.js.map +1 -1
- package/packages/pi-ai/src/utils/oauth/anthropic.ts +2 -2
- package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/loader.js +205 -7
- package/packages/pi-coding-agent/dist/core/extensions/loader.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/skills.d.ts +1 -0
- package/packages/pi-coding-agent/dist/core/skills.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/skills.js +6 -1
- package/packages/pi-coding-agent/dist/core/skills.js.map +1 -1
- package/packages/pi-coding-agent/dist/index.d.ts +1 -1
- package/packages/pi-coding-agent/dist/index.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/index.js +1 -1
- package/packages/pi-coding-agent/dist/index.js.map +1 -1
- package/packages/pi-coding-agent/src/core/extensions/loader.ts +223 -7
- package/packages/pi-coding-agent/src/core/skills.ts +9 -1
- package/packages/pi-coding-agent/src/index.ts +1 -0
- package/src/resources/extensions/browser-tools/index.ts +3 -0
- package/src/resources/extensions/browser-tools/tools/verify.ts +117 -0
- package/src/resources/extensions/env-utils.ts +31 -0
- package/src/resources/extensions/get-secrets-from-user.ts +5 -24
- package/src/resources/extensions/github-sync/cli.ts +364 -0
- package/src/resources/extensions/github-sync/index.ts +93 -0
- package/src/resources/extensions/github-sync/mapping.ts +81 -0
- package/src/resources/extensions/github-sync/sync.ts +556 -0
- package/src/resources/extensions/github-sync/templates.ts +183 -0
- package/src/resources/extensions/github-sync/tests/cli.test.ts +20 -0
- package/src/resources/extensions/github-sync/tests/commit-linking.test.ts +39 -0
- package/src/resources/extensions/github-sync/tests/mapping.test.ts +104 -0
- package/src/resources/extensions/github-sync/tests/templates.test.ts +110 -0
- package/src/resources/extensions/github-sync/types.ts +47 -0
- package/src/resources/extensions/gsd/auto/session.ts +7 -25
- package/src/resources/extensions/gsd/auto-dispatch.ts +7 -9
- package/src/resources/extensions/gsd/auto-loop.ts +526 -545
- package/src/resources/extensions/gsd/auto-post-unit.ts +80 -44
- package/src/resources/extensions/gsd/auto-prompts.ts +247 -50
- package/src/resources/extensions/gsd/auto-start.ts +11 -1
- package/src/resources/extensions/gsd/auto-worktree-sync.ts +3 -1
- package/src/resources/extensions/gsd/auto-worktree.ts +3 -3
- package/src/resources/extensions/gsd/auto.ts +139 -101
- package/src/resources/extensions/gsd/commands-extensions.ts +4 -2
- package/src/resources/extensions/gsd/commands-prefs-wizard.ts +1 -1
- package/src/resources/extensions/gsd/commands.ts +5 -3
- package/src/resources/extensions/gsd/context-budget.ts +2 -12
- package/src/resources/extensions/gsd/detection.ts +2 -2
- package/src/resources/extensions/gsd/docs/preferences-reference.md +0 -2
- package/src/resources/extensions/gsd/doctor-providers.ts +30 -9
- package/src/resources/extensions/gsd/doctor.ts +22 -1
- package/src/resources/extensions/gsd/exit-command.ts +2 -2
- package/src/resources/extensions/gsd/export.ts +1 -1
- package/src/resources/extensions/gsd/files.ts +51 -11
- package/src/resources/extensions/gsd/forensics.ts +1 -1
- package/src/resources/extensions/gsd/git-service.ts +44 -10
- package/src/resources/extensions/gsd/gitignore.ts +17 -3
- package/src/resources/extensions/gsd/guided-flow.ts +177 -44
- package/src/resources/extensions/gsd/health-widget-core.ts +28 -80
- package/src/resources/extensions/gsd/health-widget.ts +3 -89
- package/src/resources/extensions/gsd/index.ts +24 -17
- package/src/resources/extensions/gsd/migrate/parsers.ts +1 -1
- package/src/resources/extensions/gsd/migrate-external.ts +18 -1
- package/src/resources/extensions/gsd/native-git-bridge.ts +37 -0
- package/src/resources/extensions/gsd/paths.ts +4 -0
- package/src/resources/extensions/gsd/preferences-models.ts +0 -12
- package/src/resources/extensions/gsd/preferences-types.ts +4 -4
- package/src/resources/extensions/gsd/preferences-validation.ts +51 -11
- package/src/resources/extensions/gsd/preferences.ts +25 -11
- package/src/resources/extensions/gsd/prompt-loader.ts +7 -2
- package/src/resources/extensions/gsd/prompts/complete-milestone.md +1 -1
- package/src/resources/extensions/gsd/prompts/complete-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/discuss.md +11 -14
- package/src/resources/extensions/gsd/prompts/execute-task.md +5 -3
- package/src/resources/extensions/gsd/prompts/guided-complete-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/guided-discuss-milestone.md +11 -12
- package/src/resources/extensions/gsd/prompts/guided-discuss-slice.md +8 -10
- package/src/resources/extensions/gsd/prompts/guided-execute-task.md +1 -1
- package/src/resources/extensions/gsd/prompts/guided-plan-milestone.md +1 -1
- package/src/resources/extensions/gsd/prompts/guided-plan-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/guided-research-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/guided-resume-task.md +1 -1
- package/src/resources/extensions/gsd/prompts/plan-milestone.md +1 -1
- package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/queue.md +4 -8
- package/src/resources/extensions/gsd/prompts/reactive-execute.md +11 -8
- package/src/resources/extensions/gsd/prompts/reassess-roadmap.md +1 -1
- package/src/resources/extensions/gsd/prompts/research-milestone.md +1 -1
- package/src/resources/extensions/gsd/prompts/research-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/run-uat.md +28 -11
- package/src/resources/extensions/gsd/prompts/workflow-start.md +2 -2
- package/src/resources/extensions/gsd/repo-identity.ts +23 -4
- package/src/resources/extensions/gsd/resource-version.ts +3 -1
- package/src/resources/extensions/gsd/roadmap-mutations.ts +29 -0
- package/src/resources/extensions/gsd/state.ts +39 -21
- package/src/resources/extensions/gsd/templates/runtime.md +21 -0
- package/src/resources/extensions/gsd/templates/task-plan.md +3 -0
- package/src/resources/extensions/gsd/tests/agent-end-retry.test.ts +21 -18
- package/src/resources/extensions/gsd/tests/auto-loop.test.ts +122 -68
- package/src/resources/extensions/gsd/tests/auto-worktree-milestone-merge.test.ts +4 -3
- package/src/resources/extensions/gsd/tests/derive-state.test.ts +43 -0
- package/src/resources/extensions/gsd/tests/doctor-providers.test.ts +86 -3
- package/src/resources/extensions/gsd/tests/gitignore-tracked-gsd.test.ts +50 -0
- package/src/resources/extensions/gsd/tests/health-widget.test.ts +16 -54
- package/src/resources/extensions/gsd/tests/parsers.test.ts +131 -14
- package/src/resources/extensions/gsd/tests/plan-slice-prompt.test.ts +209 -0
- package/src/resources/extensions/gsd/tests/preferences.test.ts +2 -7
- package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +59 -0
- package/src/resources/extensions/gsd/tests/repo-identity-worktree.test.ts +21 -1
- package/src/resources/extensions/gsd/tests/run-uat.test.ts +16 -4
- package/src/resources/extensions/gsd/tests/skill-activation.test.ts +140 -0
- package/src/resources/extensions/gsd/types.ts +18 -1
- package/src/resources/extensions/gsd/verification-evidence.ts +16 -0
- package/src/resources/extensions/gsd/visualizer-data.ts +1 -1
- package/src/resources/extensions/mcp-client/index.ts +17 -1
- package/src/resources/extensions/remote-questions/status.ts +5 -1
- package/src/resources/extensions/remote-questions/store.ts +5 -1
- package/src/resources/extensions/search-the-web/provider.ts +2 -1
- package/src/resources/extensions/shared/frontmatter.ts +1 -1
- package/src/resources/extensions/subagent/isolation.ts +3 -1
- package/src/resources/extensions/ttsr/rule-loader.ts +3 -1
- package/dist/resources/extensions/gsd/prompt-compressor.js +0 -393
- package/dist/resources/extensions/gsd/semantic-chunker.js +0 -254
- package/dist/resources/extensions/gsd/summary-distiller.js +0 -212
- package/src/resources/extensions/gsd/prompt-compressor.ts +0 -508
- package/src/resources/extensions/gsd/semantic-chunker.ts +0 -336
- package/src/resources/extensions/gsd/summary-distiller.ts +0 -258
- package/src/resources/extensions/gsd/tests/context-compression.test.ts +0 -193
- package/src/resources/extensions/gsd/tests/prompt-compressor.test.ts +0 -529
- package/src/resources/extensions/gsd/tests/semantic-chunker.test.ts +0 -426
- package/src/resources/extensions/gsd/tests/summary-distiller.test.ts +0 -323
- package/src/resources/extensions/gsd/tests/token-optimization-benchmark.test.ts +0 -1272
- package/src/resources/extensions/gsd/tests/token-optimization-prefs.test.ts +0 -164
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// Pure TypeScript, zero Pi dependencies.
|
|
4
4
|
import { parseRoadmap, parsePlan, parseSummary, loadFile, parseRequirementCounts, parseContextDependsOn, } from './files.js';
|
|
5
5
|
import { resolveMilestoneFile, resolveSlicePath, resolveSliceFile, resolveTaskFile, resolveTasksDir, resolveGsdRootFile, gsdRoot, } from './paths.js';
|
|
6
|
-
import { findMilestoneIds } from './
|
|
6
|
+
import { findMilestoneIds } from './milestone-ids.js';
|
|
7
7
|
import { nativeBatchParseGsdFiles } from './native-parser-bridge.js';
|
|
8
8
|
import { join, resolve } from 'path';
|
|
9
9
|
import { existsSync, readdirSync } from 'node:fs';
|
|
@@ -82,8 +82,13 @@ export async function getActiveMilestoneId(basePath) {
|
|
|
82
82
|
// A draft milestone is still "active" — this function only determines which milestone is current.
|
|
83
83
|
}
|
|
84
84
|
const roadmap = parseRoadmap(content);
|
|
85
|
-
if (!isMilestoneComplete(roadmap))
|
|
86
|
-
|
|
85
|
+
if (!isMilestoneComplete(roadmap)) {
|
|
86
|
+
// Summary is the terminal artifact — if it exists, the milestone is
|
|
87
|
+
// complete even when roadmap checkboxes weren't ticked (#864).
|
|
88
|
+
const summaryFile = resolveMilestoneFile(basePath, mid, "SUMMARY");
|
|
89
|
+
if (!summaryFile)
|
|
90
|
+
return mid;
|
|
91
|
+
}
|
|
87
92
|
}
|
|
88
93
|
return null;
|
|
89
94
|
}
|
|
@@ -202,8 +207,14 @@ async function _deriveStateImpl(basePath) {
|
|
|
202
207
|
}
|
|
203
208
|
const rmap = parseRoadmap(rc);
|
|
204
209
|
roadmapCache.set(mid, rmap);
|
|
205
|
-
if (!isMilestoneComplete(rmap))
|
|
210
|
+
if (!isMilestoneComplete(rmap)) {
|
|
211
|
+
// Summary is the terminal artifact — if it exists, the milestone is
|
|
212
|
+
// complete even when roadmap checkboxes weren't ticked (#864).
|
|
213
|
+
const sf = resolveMilestoneFile(basePath, mid, "SUMMARY");
|
|
214
|
+
if (sf)
|
|
215
|
+
completeMilestoneIds.add(mid);
|
|
206
216
|
continue;
|
|
217
|
+
}
|
|
207
218
|
const sf = resolveMilestoneFile(basePath, mid, "SUMMARY");
|
|
208
219
|
if (sf)
|
|
209
220
|
completeMilestoneIds.add(mid);
|
|
@@ -303,29 +314,37 @@ async function _deriveStateImpl(basePath) {
|
|
|
303
314
|
registry.push({ id: mid, title, status: 'complete' });
|
|
304
315
|
}
|
|
305
316
|
}
|
|
306
|
-
else
|
|
307
|
-
//
|
|
308
|
-
|
|
309
|
-
const
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
//
|
|
317
|
+
else {
|
|
318
|
+
// Roadmap slices not all checked — but if a summary exists, the milestone
|
|
319
|
+
// is still complete. The summary is the terminal artifact (#864).
|
|
320
|
+
const summaryFile = resolveMilestoneFile(basePath, mid, "SUMMARY");
|
|
321
|
+
if (summaryFile) {
|
|
322
|
+
registry.push({ id: mid, title, status: 'complete' });
|
|
323
|
+
}
|
|
324
|
+
else if (!activeMilestoneFound) {
|
|
325
|
+
// Check milestone-level dependencies before promoting to active
|
|
326
|
+
const contextFile = resolveMilestoneFile(basePath, mid, "CONTEXT");
|
|
327
|
+
const contextContent = contextFile ? await cachedLoadFile(contextFile) : null;
|
|
328
|
+
const deps = parseContextDependsOn(contextContent);
|
|
329
|
+
const depsUnmet = deps.some(dep => !completeMilestoneIds.has(dep));
|
|
330
|
+
if (depsUnmet) {
|
|
331
|
+
registry.push({ id: mid, title, status: 'pending', dependsOn: deps });
|
|
332
|
+
// Do NOT set activeMilestoneFound — let the loop continue to the next milestone
|
|
333
|
+
}
|
|
334
|
+
else {
|
|
335
|
+
activeMilestone = { id: mid, title };
|
|
336
|
+
activeRoadmap = roadmap;
|
|
337
|
+
activeMilestoneFound = true;
|
|
338
|
+
registry.push({ id: mid, title, status: 'active', ...(deps.length > 0 ? { dependsOn: deps } : {}) });
|
|
339
|
+
}
|
|
315
340
|
}
|
|
316
341
|
else {
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
registry.push({ id: mid, title, status: '
|
|
342
|
+
const contextFile2 = resolveMilestoneFile(basePath, mid, "CONTEXT");
|
|
343
|
+
const contextContent2 = contextFile2 ? await cachedLoadFile(contextFile2) : null;
|
|
344
|
+
const deps2 = parseContextDependsOn(contextContent2);
|
|
345
|
+
registry.push({ id: mid, title, status: 'pending', ...(deps2.length > 0 ? { dependsOn: deps2 } : {}) });
|
|
321
346
|
}
|
|
322
347
|
}
|
|
323
|
-
else {
|
|
324
|
-
const contextFile2 = resolveMilestoneFile(basePath, mid, "CONTEXT");
|
|
325
|
-
const contextContent2 = contextFile2 ? await cachedLoadFile(contextFile2) : null;
|
|
326
|
-
const deps2 = parseContextDependsOn(contextContent2);
|
|
327
|
-
registry.push({ id: mid, title, status: 'pending', ...(deps2.length > 0 ? { dependsOn: deps2 } : {}) });
|
|
328
|
-
}
|
|
329
348
|
}
|
|
330
349
|
const milestoneProgress = {
|
|
331
350
|
done: registry.filter(entry => entry.status === 'complete').length,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# Runtime Context
|
|
2
|
+
|
|
3
|
+
## Stack
|
|
4
|
+
- **Language:** (e.g., TypeScript, Python, Go)
|
|
5
|
+
- **Framework:** (e.g., Next.js, FastAPI, Gin)
|
|
6
|
+
- **Build:** (e.g., npm run build, cargo build)
|
|
7
|
+
- **Test:** (e.g., npm run test, pytest)
|
|
8
|
+
- **Lint:** (e.g., npm run lint, ruff check)
|
|
9
|
+
|
|
10
|
+
## Environment
|
|
11
|
+
- **Node version:** (e.g., 20.x)
|
|
12
|
+
- **Package manager:** (e.g., npm, pnpm, yarn)
|
|
13
|
+
- **Required env vars:** (list any needed for local dev)
|
|
14
|
+
|
|
15
|
+
## Dev Server
|
|
16
|
+
- **Start command:** (e.g., npm run dev)
|
|
17
|
+
- **Default port:** (e.g., 3000)
|
|
18
|
+
- **Health check:** (e.g., curl http://localhost:3000/health)
|
|
19
|
+
|
|
20
|
+
## Notes
|
|
21
|
+
(Any runtime-specific context the executor needs to know)
|
|
@@ -3,6 +3,9 @@
|
|
|
3
3
|
# Tasks with 10+ estimated steps or 12+ estimated files trigger a warning to consider splitting.
|
|
4
4
|
estimated_steps: {{estimatedSteps}}
|
|
5
5
|
estimated_files: {{estimatedFiles}}
|
|
6
|
+
# Installed skills the planner expects the executor to load before coding.
|
|
7
|
+
skills_used:
|
|
8
|
+
- {{skillName}}
|
|
6
9
|
---
|
|
7
10
|
|
|
8
11
|
# {{taskId}}: {{taskTitle}}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { existsSync, readFileSync, statSync } from 'node:fs';
|
|
3
3
|
import { deriveState } from './state.js';
|
|
4
4
|
import { parseRoadmap, parsePlan, parseSummary, loadFile } from './files.js';
|
|
5
|
-
import { findMilestoneIds } from './
|
|
5
|
+
import { findMilestoneIds } from './milestone-ids.js';
|
|
6
6
|
import { resolveMilestoneFile, resolveSliceFile, resolveGsdRootFile } from './paths.js';
|
|
7
7
|
import { getLedger, getProjectTotals, aggregateByPhase, aggregateBySlice, aggregateByModel, aggregateByTier, formatTierSavings, loadLedgerFromDisk, } from './metrics.js';
|
|
8
8
|
import { loadAllCaptures, countPendingCaptures } from './captures.js';
|
|
@@ -76,6 +76,19 @@ function readConfigs() {
|
|
|
76
76
|
function getServerConfig(name) {
|
|
77
77
|
return readConfigs().find((s) => s.name === name);
|
|
78
78
|
}
|
|
79
|
+
/** Resolve ${VAR} references in env values against process.env. */
|
|
80
|
+
function resolveEnv(env) {
|
|
81
|
+
const resolved = {};
|
|
82
|
+
for (const [key, value] of Object.entries(env)) {
|
|
83
|
+
if (typeof value === "string") {
|
|
84
|
+
resolved[key] = value.replace(/\$\{([^}]+)\}/g, (_match, varName) => process.env[varName] ?? "");
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
resolved[key] = value;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
return resolved;
|
|
91
|
+
}
|
|
79
92
|
async function getOrConnect(name, signal) {
|
|
80
93
|
const existing = connections.get(name);
|
|
81
94
|
if (existing)
|
|
@@ -89,7 +102,7 @@ async function getOrConnect(name, signal) {
|
|
|
89
102
|
transport = new StdioClientTransport({
|
|
90
103
|
command: config.command,
|
|
91
104
|
args: config.args,
|
|
92
|
-
env: config.env ? { ...process.env, ...config.env } : undefined,
|
|
105
|
+
env: config.env ? { ...process.env, ...resolveEnv(config.env) } : undefined,
|
|
93
106
|
cwd: config.cwd,
|
|
94
107
|
stderr: "pipe",
|
|
95
108
|
});
|
|
@@ -5,8 +5,11 @@ import { existsSync, readdirSync } from "node:fs";
|
|
|
5
5
|
import { join } from "node:path";
|
|
6
6
|
import { homedir } from "node:os";
|
|
7
7
|
import { readPromptRecord } from "./store.js";
|
|
8
|
+
function getGsdHome() {
|
|
9
|
+
return process.env.GSD_HOME || join(homedir(), ".gsd");
|
|
10
|
+
}
|
|
8
11
|
export function getLatestPromptSummary() {
|
|
9
|
-
const runtimeDir = join(
|
|
12
|
+
const runtimeDir = join(getGsdHome(), "runtime", "remote-questions");
|
|
10
13
|
if (!existsSync(runtimeDir))
|
|
11
14
|
return null;
|
|
12
15
|
const files = readdirSync(runtimeDir).filter((f) => f.endsWith(".json"));
|
|
@@ -4,8 +4,11 @@
|
|
|
4
4
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
5
5
|
import { join } from "node:path";
|
|
6
6
|
import { homedir } from "node:os";
|
|
7
|
+
function getGsdHome() {
|
|
8
|
+
return process.env.GSD_HOME || join(homedir(), ".gsd");
|
|
9
|
+
}
|
|
7
10
|
function runtimeDir() {
|
|
8
|
-
return join(
|
|
11
|
+
return join(getGsdHome(), "runtime", "remote-questions");
|
|
9
12
|
}
|
|
10
13
|
function recordPath(id) {
|
|
11
14
|
return join(runtimeDir(), `${id}.json`);
|
|
@@ -15,7 +15,8 @@ import { resolveSearchProviderFromPreferences } from '../gsd/preferences.js';
|
|
|
15
15
|
// Compute authFilePath locally instead of importing from app-paths.ts,
|
|
16
16
|
// because extensions are copied to ~/.gsd/agent/extensions/ at runtime
|
|
17
17
|
// where the relative import '../../../app-paths.ts' doesn't resolve.
|
|
18
|
-
const
|
|
18
|
+
const gsdHome = process.env.GSD_HOME || join(homedir(), '.gsd');
|
|
19
|
+
const authFilePath = join(gsdHome, 'agent', 'auth.json');
|
|
19
20
|
const VALID_PREFERENCES = new Set(['tavily', 'brave', 'ollama', 'auto']);
|
|
20
21
|
const PREFERENCE_KEY = 'search_provider';
|
|
21
22
|
/** Returns the Tavily API key from the environment, or empty string if not set. */
|
|
@@ -45,7 +45,7 @@ export function parseFrontmatterMap(lines) {
|
|
|
45
45
|
continue;
|
|
46
46
|
}
|
|
47
47
|
// Array item (2-space indent)
|
|
48
|
-
const arrayMatch = line.match(/^ - (.*)$/);
|
|
48
|
+
const arrayMatch = line.match(/^ - ?(.*)$/);
|
|
49
49
|
if (arrayMatch && currentKey) {
|
|
50
50
|
// If there's a pending nested object, push it
|
|
51
51
|
if (currentObj && Object.keys(currentObj).length > 0) {
|
|
@@ -17,8 +17,9 @@ const execFile = promisify(execFileCb);
|
|
|
17
17
|
function encodeCwd(cwd) {
|
|
18
18
|
return cwd.replace(/\//g, "--");
|
|
19
19
|
}
|
|
20
|
+
const gsdHome = process.env.GSD_HOME || path.join(os.homedir(), ".gsd");
|
|
20
21
|
function getIsolationBaseDir(cwd, taskId) {
|
|
21
|
-
return path.join(
|
|
22
|
+
return path.join(gsdHome, "wt", encodeCwd(cwd), taskId);
|
|
22
23
|
}
|
|
23
24
|
// Track active isolation dirs for cleanup on exit
|
|
24
25
|
const activeIsolations = new Set();
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
import { readdirSync, readFileSync, existsSync } from "node:fs";
|
|
9
9
|
import { join, basename } from "node:path";
|
|
10
10
|
import { homedir } from "node:os";
|
|
11
|
+
const gsdHome = process.env.GSD_HOME || join(homedir(), ".gsd");
|
|
11
12
|
import { splitFrontmatter, parseFrontmatterMap } from "../shared/frontmatter.js";
|
|
12
13
|
function parseRuleFile(filePath) {
|
|
13
14
|
let content;
|
|
@@ -56,7 +57,7 @@ function scanDir(dir) {
|
|
|
56
57
|
* Project rules override global rules with the same name.
|
|
57
58
|
*/
|
|
58
59
|
export function loadRules(cwd) {
|
|
59
|
-
const globalDir = join(
|
|
60
|
+
const globalDir = join(gsdHome, "agent", "rules");
|
|
60
61
|
const projectDir = join(cwd, ".gsd", "rules");
|
|
61
62
|
const globalRules = scanDir(globalDir);
|
|
62
63
|
const projectRules = scanDir(projectDir);
|
package/package.json
CHANGED
|
@@ -5,8 +5,8 @@ import { generatePKCE } from "./pkce.js";
|
|
|
5
5
|
const decode = (s) => atob(s);
|
|
6
6
|
const CLIENT_ID = decode("OWQxYzI1MGEtZTYxYi00NGQ5LTg4ZWQtNTk0NGQxOTYyZjVl");
|
|
7
7
|
const AUTHORIZE_URL = "https://claude.ai/oauth/authorize";
|
|
8
|
-
const TOKEN_URL = "https://
|
|
9
|
-
const REDIRECT_URI = "https://
|
|
8
|
+
const TOKEN_URL = "https://platform.claude.com/v1/oauth/token";
|
|
9
|
+
const REDIRECT_URI = "https://platform.claude.com/oauth/code/callback";
|
|
10
10
|
const SCOPES = "org:create_api_key user:profile user:inference";
|
|
11
11
|
/**
|
|
12
12
|
* Login with Anthropic OAuth (device code flow)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"anthropic.js","sourceRoot":"","sources":["../../../src/utils/oauth/anthropic.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAGzC,MAAM,MAAM,GAAG,CAAC,CAAS,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AACtC,MAAM,SAAS,GAAG,MAAM,CAAC,kDAAkD,CAAC,CAAC;AAC7E,MAAM,aAAa,GAAG,mCAAmC,CAAC;AAC1D,MAAM,SAAS,GAAG,
|
|
1
|
+
{"version":3,"file":"anthropic.js","sourceRoot":"","sources":["../../../src/utils/oauth/anthropic.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Anthropic OAuth flow (Claude Pro/Max)\n */\n\nimport { generatePKCE } from \"./pkce.js\";\nimport type { OAuthCredentials, OAuthLoginCallbacks, OAuthProviderInterface } from \"./types.js\";\n\nconst decode = (s: string) => atob(s);\nconst CLIENT_ID = decode(\"OWQxYzI1MGEtZTYxYi00NGQ5LTg4ZWQtNTk0NGQxOTYyZjVl\");\nconst AUTHORIZE_URL = \"https://claude.ai/oauth/authorize\";\nconst TOKEN_URL = \"https://platform.claude.com/v1/oauth/token\";\nconst REDIRECT_URI = \"https://platform.claude.com/oauth/code/callback\";\nconst SCOPES = \"org:create_api_key user:profile user:inference\";\n\n/**\n * Login with Anthropic OAuth (device code flow)\n *\n * @param onAuthUrl - Callback to handle the authorization URL (e.g., open browser)\n * @param onPromptCode - Callback to prompt user for the authorization code\n */\nexport async function loginAnthropic(\n\tonAuthUrl: (url: string) => void,\n\tonPromptCode: () => Promise<string>,\n): Promise<OAuthCredentials> {\n\tconst { verifier, challenge } = await generatePKCE();\n\n\t// Build authorization URL\n\tconst authParams = new URLSearchParams({\n\t\tcode: \"true\",\n\t\tclient_id: CLIENT_ID,\n\t\tresponse_type: \"code\",\n\t\tredirect_uri: REDIRECT_URI,\n\t\tscope: SCOPES,\n\t\tcode_challenge: challenge,\n\t\tcode_challenge_method: \"S256\",\n\t\tstate: verifier,\n\t});\n\n\tconst authUrl = `${AUTHORIZE_URL}?${authParams.toString()}`;\n\n\t// Notify caller with URL to open\n\tonAuthUrl(authUrl);\n\n\t// Wait for user to paste authorization code (format: code#state)\n\tconst authCode = await onPromptCode();\n\tconst splits = authCode.split(\"#\");\n\tconst code = splits[0];\n\tconst state = splits[1];\n\n\t// Exchange code for tokens\n\tconst tokenResponse = await fetch(TOKEN_URL, {\n\t\tmethod: \"POST\",\n\t\theaders: {\n\t\t\t\"Content-Type\": \"application/json\",\n\t\t},\n\t\tbody: JSON.stringify({\n\t\t\tgrant_type: \"authorization_code\",\n\t\t\tclient_id: CLIENT_ID,\n\t\t\tcode: code,\n\t\t\tstate: state,\n\t\t\tredirect_uri: REDIRECT_URI,\n\t\t\tcode_verifier: verifier,\n\t\t}),\n\t\tsignal: AbortSignal.timeout(30_000),\n\t});\n\n\tif (!tokenResponse.ok) {\n\t\tconst error = await tokenResponse.text();\n\t\tthrow new Error(`Token exchange failed: ${error}`);\n\t}\n\n\tconst tokenData = (await tokenResponse.json()) as {\n\t\taccess_token: string;\n\t\trefresh_token: string;\n\t\texpires_in: number;\n\t};\n\n\t// Calculate expiry time (current time + expires_in seconds - 5 min buffer)\n\tconst expiresAt = Date.now() + tokenData.expires_in * 1000 - 5 * 60 * 1000;\n\n\t// Save credentials\n\treturn {\n\t\trefresh: tokenData.refresh_token,\n\t\taccess: tokenData.access_token,\n\t\texpires: expiresAt,\n\t};\n}\n\n/**\n * Refresh Anthropic OAuth token\n */\nexport async function refreshAnthropicToken(refreshToken: string): Promise<OAuthCredentials> {\n\tconst response = await fetch(TOKEN_URL, {\n\t\tmethod: \"POST\",\n\t\theaders: { \"Content-Type\": \"application/json\" },\n\t\tbody: JSON.stringify({\n\t\t\tgrant_type: \"refresh_token\",\n\t\t\tclient_id: CLIENT_ID,\n\t\t\trefresh_token: refreshToken,\n\t\t}),\n\t\tsignal: AbortSignal.timeout(30_000),\n\t});\n\n\tif (!response.ok) {\n\t\tconst error = await response.text();\n\t\tthrow new Error(`Anthropic token refresh failed: ${error}`);\n\t}\n\n\tconst data = (await response.json()) as {\n\t\taccess_token: string;\n\t\trefresh_token: string;\n\t\texpires_in: number;\n\t};\n\n\treturn {\n\t\trefresh: data.refresh_token,\n\t\taccess: data.access_token,\n\t\texpires: Date.now() + data.expires_in * 1000 - 5 * 60 * 1000,\n\t};\n}\n\nexport const anthropicOAuthProvider: OAuthProviderInterface = {\n\tid: \"anthropic\",\n\tname: \"Anthropic (Claude Pro/Max)\",\n\n\tasync login(callbacks: OAuthLoginCallbacks): Promise<OAuthCredentials> {\n\t\treturn loginAnthropic(\n\t\t\t(url) => callbacks.onAuth({ url }),\n\t\t\t() => callbacks.onPrompt({ message: \"Paste the authorization code:\" }),\n\t\t);\n\t},\n\n\tasync refreshToken(credentials: OAuthCredentials): Promise<OAuthCredentials> {\n\t\treturn refreshAnthropicToken(credentials.refresh);\n\t},\n\n\tgetApiKey(credentials: OAuthCredentials): string {\n\t\treturn credentials.access;\n\t},\n};\n"]}
|
|
@@ -8,8 +8,8 @@ import type { OAuthCredentials, OAuthLoginCallbacks, OAuthProviderInterface } fr
|
|
|
8
8
|
const decode = (s: string) => atob(s);
|
|
9
9
|
const CLIENT_ID = decode("OWQxYzI1MGEtZTYxYi00NGQ5LTg4ZWQtNTk0NGQxOTYyZjVl");
|
|
10
10
|
const AUTHORIZE_URL = "https://claude.ai/oauth/authorize";
|
|
11
|
-
const TOKEN_URL = "https://
|
|
12
|
-
const REDIRECT_URI = "https://
|
|
11
|
+
const TOKEN_URL = "https://platform.claude.com/v1/oauth/token";
|
|
12
|
+
const REDIRECT_URI = "https://platform.claude.com/oauth/code/callback";
|
|
13
13
|
const SCOPES = "org:create_api_key user:profile user:inference";
|
|
14
14
|
|
|
15
15
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../../src/core/extensions/loader.ts"],"names":[],"mappings":"AAAA;;;;GAIG;
|
|
1
|
+
{"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../../src/core/extensions/loader.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AA+BH,OAAO,EAAkB,KAAK,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAIhE,OAAO,EAAE,gBAAgB,EAAE,YAAY,EAAE,0BAA0B,EAAE,MAAM,oBAAoB,CAAC;AAChG,OAAO,KAAK,EACX,SAAS,EAET,gBAAgB,EAChB,gBAAgB,EAChB,oBAAoB,EAKpB,MAAM,YAAY,CAAC;AAsTpB,wBAAsB,qBAAqB,CAAC,CAAC,GAAG,OAAO,EAAE,eAAe,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,CAI/G;AA6BD;;;GAGG;AACH,wBAAgB,sBAAsB,IAAI,gBAAgB,CAmCzD;AAkMD;;GAEG;AACH,wBAAsB,wBAAwB,CAC7C,OAAO,EAAE,gBAAgB,EACzB,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE,gBAAgB,EACzB,aAAa,SAAa,GACxB,OAAO,CAAC,SAAS,CAAC,CAKpB;AAED;;;;;GAKG;AACH,wBAAsB,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,QAAQ,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAyBrH;AAmHD;;GAEG;AACH,wBAAsB,yBAAyB,CAC9C,eAAe,EAAE,MAAM,EAAE,EACzB,GAAG,EAAE,MAAM,EACX,QAAQ,GAAE,MAAsB,EAChC,QAAQ,CAAC,EAAE,QAAQ,GACjB,OAAO,CAAC,oBAAoB,CAAC,CAoD/B"}
|
|
@@ -21,6 +21,12 @@ import * as _bundledYaml from "yaml";
|
|
|
21
21
|
import * as _bundledMcpClient from "@modelcontextprotocol/sdk/client";
|
|
22
22
|
import * as _bundledMcpStdio from "@modelcontextprotocol/sdk/client/stdio.js";
|
|
23
23
|
import * as _bundledMcpStreamableHttp from "@modelcontextprotocol/sdk/client/streamableHttp.js";
|
|
24
|
+
import * as _bundledMcpSse from "@modelcontextprotocol/sdk/client/sse.js";
|
|
25
|
+
import * as _bundledMcpServer from "@modelcontextprotocol/sdk/server";
|
|
26
|
+
import * as _bundledMcpServerStdio from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
27
|
+
import * as _bundledMcpServerSse from "@modelcontextprotocol/sdk/server/sse.js";
|
|
28
|
+
import * as _bundledMcpServerStreamableHttp from "@modelcontextprotocol/sdk/server/streamableHttp.js";
|
|
29
|
+
import * as _bundledMcpTypes from "@modelcontextprotocol/sdk/types.js";
|
|
24
30
|
import { getAgentDir, isBunBinary } from "../../config.js";
|
|
25
31
|
// NOTE: This import works because loader.ts exports are NOT re-exported from index.ts,
|
|
26
32
|
// avoiding a circular dependency. Extensions can import from @gsd/pi-coding-agent.
|
|
@@ -29,8 +35,11 @@ import { createEventBus } from "../event-bus.js";
|
|
|
29
35
|
import { execCommand } from "../exec.js";
|
|
30
36
|
import { getUntrustedExtensionPaths } from "./project-trust.js";
|
|
31
37
|
export { isProjectTrusted, trustProject, getUntrustedExtensionPaths } from "./project-trust.js";
|
|
32
|
-
/**
|
|
33
|
-
|
|
38
|
+
/**
|
|
39
|
+
* Statically imported modules for Bun binary virtualModules.
|
|
40
|
+
* Maps specifier -> module object for subpaths that must be available in compiled binaries.
|
|
41
|
+
*/
|
|
42
|
+
const STATIC_BUNDLED_MODULES = {
|
|
34
43
|
"@sinclair/typebox": _bundledTypebox,
|
|
35
44
|
"@gsd/pi-agent-core": _bundledPiAgentCore,
|
|
36
45
|
"@gsd/pi-tui": _bundledPiTui,
|
|
@@ -43,6 +52,17 @@ const VIRTUAL_MODULES = {
|
|
|
43
52
|
"@modelcontextprotocol/sdk/client/stdio.js": _bundledMcpStdio,
|
|
44
53
|
"@modelcontextprotocol/sdk/client/streamableHttp": _bundledMcpStreamableHttp,
|
|
45
54
|
"@modelcontextprotocol/sdk/client/streamableHttp.js": _bundledMcpStreamableHttp,
|
|
55
|
+
"@modelcontextprotocol/sdk/client/sse": _bundledMcpSse,
|
|
56
|
+
"@modelcontextprotocol/sdk/client/sse.js": _bundledMcpSse,
|
|
57
|
+
"@modelcontextprotocol/sdk/server": _bundledMcpServer,
|
|
58
|
+
"@modelcontextprotocol/sdk/server/stdio": _bundledMcpServerStdio,
|
|
59
|
+
"@modelcontextprotocol/sdk/server/stdio.js": _bundledMcpServerStdio,
|
|
60
|
+
"@modelcontextprotocol/sdk/server/sse": _bundledMcpServerSse,
|
|
61
|
+
"@modelcontextprotocol/sdk/server/sse.js": _bundledMcpServerSse,
|
|
62
|
+
"@modelcontextprotocol/sdk/server/streamableHttp": _bundledMcpServerStreamableHttp,
|
|
63
|
+
"@modelcontextprotocol/sdk/server/streamableHttp.js": _bundledMcpServerStreamableHttp,
|
|
64
|
+
"@modelcontextprotocol/sdk/types": _bundledMcpTypes,
|
|
65
|
+
"@modelcontextprotocol/sdk/types.js": _bundledMcpTypes,
|
|
46
66
|
// Aliases for external PI ecosystem packages that import from the original scope
|
|
47
67
|
"@mariozechner/pi-agent-core": _bundledPiAgentCore,
|
|
48
68
|
"@mariozechner/pi-tui": _bundledPiTui,
|
|
@@ -50,8 +70,180 @@ const VIRTUAL_MODULES = {
|
|
|
50
70
|
"@mariozechner/pi-ai/oauth": _bundledPiAiOauth,
|
|
51
71
|
"@mariozechner/pi-coding-agent": _bundledPiCodingAgent,
|
|
52
72
|
};
|
|
73
|
+
/** Modules available to extensions via virtualModules (for compiled Bun binary) */
|
|
74
|
+
const VIRTUAL_MODULES = { ...STATIC_BUNDLED_MODULES };
|
|
53
75
|
const require = createRequire(import.meta.url);
|
|
54
76
|
const EXTENSION_TIMING_ENABLED = process.env.GSD_STARTUP_TIMING === "1" || process.env.PI_TIMING === "1";
|
|
77
|
+
/**
|
|
78
|
+
* Bundled npm packages whose subpath exports should be auto-resolved for extensions.
|
|
79
|
+
* Each package listed here will have its `exports` field read from package.json,
|
|
80
|
+
* and all subpath exports will be registered as jiti aliases (Node.js mode) so that
|
|
81
|
+
* extensions can import any standard subpath without hitting jiti's CJS double-resolve bug.
|
|
82
|
+
*/
|
|
83
|
+
const BUNDLED_PACKAGES_WITH_EXPORTS = [
|
|
84
|
+
"@modelcontextprotocol/sdk",
|
|
85
|
+
"yaml",
|
|
86
|
+
];
|
|
87
|
+
/**
|
|
88
|
+
* Read a package's `exports` field and return alias entries mapping
|
|
89
|
+
* specifiers (e.g. `@modelcontextprotocol/sdk/server`) to resolved file paths.
|
|
90
|
+
*
|
|
91
|
+
* Handles:
|
|
92
|
+
* - Explicit subpath exports: `./client` -> `@pkg/client`
|
|
93
|
+
* - Wildcard exports (`./*`): scans the package's dist directory for actual files
|
|
94
|
+
* - Both `.js`-suffixed and bare specifiers for each subpath
|
|
95
|
+
*/
|
|
96
|
+
function resolveSubpathExports(packageName) {
|
|
97
|
+
const aliases = {};
|
|
98
|
+
let packageJsonPath;
|
|
99
|
+
try {
|
|
100
|
+
// Resolve the package's root directory via its package.json
|
|
101
|
+
packageJsonPath = require.resolve(`${packageName}/package.json`);
|
|
102
|
+
}
|
|
103
|
+
catch {
|
|
104
|
+
// Package doesn't allow importing package.json via exports — find it manually
|
|
105
|
+
try {
|
|
106
|
+
const anyEntry = require.resolve(packageName);
|
|
107
|
+
// Walk up from the resolved entry to find package.json
|
|
108
|
+
let dir = path.dirname(anyEntry);
|
|
109
|
+
while (dir !== path.dirname(dir)) {
|
|
110
|
+
const candidate = path.join(dir, "package.json");
|
|
111
|
+
if (fs.existsSync(candidate)) {
|
|
112
|
+
try {
|
|
113
|
+
const pkg = JSON.parse(fs.readFileSync(candidate, "utf-8"));
|
|
114
|
+
if (pkg.name === packageName) {
|
|
115
|
+
packageJsonPath = candidate;
|
|
116
|
+
break;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
catch {
|
|
120
|
+
// not valid JSON, keep walking
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
dir = path.dirname(dir);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
catch {
|
|
127
|
+
return aliases;
|
|
128
|
+
}
|
|
129
|
+
if (!packageJsonPath)
|
|
130
|
+
return aliases;
|
|
131
|
+
}
|
|
132
|
+
let pkg;
|
|
133
|
+
try {
|
|
134
|
+
pkg = JSON.parse(fs.readFileSync(packageJsonPath, "utf-8"));
|
|
135
|
+
}
|
|
136
|
+
catch {
|
|
137
|
+
return aliases;
|
|
138
|
+
}
|
|
139
|
+
const exports = pkg.exports;
|
|
140
|
+
if (!exports || typeof exports !== "object")
|
|
141
|
+
return aliases;
|
|
142
|
+
const packageDir = path.dirname(packageJsonPath);
|
|
143
|
+
for (const [subpath, target] of Object.entries(exports)) {
|
|
144
|
+
if (subpath === ".")
|
|
145
|
+
continue; // Root export handled by static imports
|
|
146
|
+
// Handle wildcard exports like "./*"
|
|
147
|
+
if (subpath.includes("*")) {
|
|
148
|
+
resolveWildcardExports(packageName, packageDir, subpath, target, aliases);
|
|
149
|
+
continue;
|
|
150
|
+
}
|
|
151
|
+
// Explicit subpath: "./client" -> "@pkg/client"
|
|
152
|
+
const specifier = `${packageName}/${subpath.replace(/^\.\//, "")}`;
|
|
153
|
+
try {
|
|
154
|
+
const resolved = require.resolve(specifier);
|
|
155
|
+
aliases[specifier] = resolved;
|
|
156
|
+
// Add .js-suffixed variant if the specifier doesn't already end in .js
|
|
157
|
+
if (!specifier.endsWith(".js")) {
|
|
158
|
+
const jsSpecifier = `${specifier}.js`;
|
|
159
|
+
try {
|
|
160
|
+
const jsResolved = require.resolve(jsSpecifier);
|
|
161
|
+
aliases[jsSpecifier] = jsResolved;
|
|
162
|
+
}
|
|
163
|
+
catch {
|
|
164
|
+
// .js variant doesn't resolve — that's fine
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
// Add bare variant (without .js) if it ends in .js
|
|
168
|
+
if (specifier.endsWith(".js")) {
|
|
169
|
+
const bareSpecifier = specifier.slice(0, -3);
|
|
170
|
+
try {
|
|
171
|
+
const bareResolved = require.resolve(bareSpecifier);
|
|
172
|
+
aliases[bareSpecifier] = bareResolved;
|
|
173
|
+
}
|
|
174
|
+
catch {
|
|
175
|
+
// bare variant doesn't resolve — that's fine
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
catch {
|
|
180
|
+
// Subpath doesn't resolve — skip it
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
return aliases;
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Resolve wildcard export patterns (e.g. `./*`) by scanning the package's
|
|
187
|
+
* file structure to find all matching files and generate alias entries.
|
|
188
|
+
*/
|
|
189
|
+
function resolveWildcardExports(packageName, packageDir, subpathPattern, target, aliases) {
|
|
190
|
+
// Extract the target directory pattern from the export target
|
|
191
|
+
// e.g. { "require": "./dist/cjs/*" } -> "dist/cjs"
|
|
192
|
+
let targetDir = null;
|
|
193
|
+
if (typeof target === "string") {
|
|
194
|
+
targetDir = target.replace(/\/\*$/, "").replace(/^\.\//, "");
|
|
195
|
+
}
|
|
196
|
+
else if (target && typeof target === "object") {
|
|
197
|
+
const targetObj = target;
|
|
198
|
+
// Prefer "require" for CJS compatibility with jiti, fall back to "import"
|
|
199
|
+
const resolved = targetObj.require ?? targetObj.import ?? targetObj.default;
|
|
200
|
+
if (typeof resolved === "string") {
|
|
201
|
+
targetDir = resolved.replace(/\/\*$/, "").replace(/^\.\//, "");
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
if (!targetDir)
|
|
205
|
+
return;
|
|
206
|
+
const fullTargetDir = path.join(packageDir, targetDir);
|
|
207
|
+
if (!fs.existsSync(fullTargetDir))
|
|
208
|
+
return;
|
|
209
|
+
// Scan for .js files and generate specifiers
|
|
210
|
+
const subpathPrefix = subpathPattern.replace(/\/?\*$/, "").replace(/^\.\//, "");
|
|
211
|
+
scanDirForExports(packageName, fullTargetDir, subpathPrefix, aliases);
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* Recursively scan a directory for .js files and register them as aliases.
|
|
215
|
+
*/
|
|
216
|
+
function scanDirForExports(packageName, dir, relativePath, aliases) {
|
|
217
|
+
let entries;
|
|
218
|
+
try {
|
|
219
|
+
entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
220
|
+
}
|
|
221
|
+
catch {
|
|
222
|
+
return;
|
|
223
|
+
}
|
|
224
|
+
for (const entry of entries) {
|
|
225
|
+
const entryRelative = relativePath ? `${relativePath}/${entry.name}` : entry.name;
|
|
226
|
+
if (entry.isDirectory()) {
|
|
227
|
+
// Skip examples/test directories — extensions don't need them
|
|
228
|
+
if (entry.name === "examples" || entry.name === "__tests__" || entry.name === "test")
|
|
229
|
+
continue;
|
|
230
|
+
scanDirForExports(packageName, path.join(dir, entry.name), entryRelative, aliases);
|
|
231
|
+
}
|
|
232
|
+
else if (entry.name.endsWith(".js") && !entry.name.endsWith(".d.js")) {
|
|
233
|
+
const filePath = path.join(dir, entry.name);
|
|
234
|
+
const specifier = `${packageName}/${entryRelative}`;
|
|
235
|
+
// Only add if not already covered by an explicit export
|
|
236
|
+
if (!(specifier in aliases)) {
|
|
237
|
+
aliases[specifier] = filePath;
|
|
238
|
+
}
|
|
239
|
+
// Also add bare (no .js) variant
|
|
240
|
+
const bareSpecifier = specifier.replace(/\.js$/, "");
|
|
241
|
+
if (!(bareSpecifier in aliases)) {
|
|
242
|
+
aliases[bareSpecifier] = filePath;
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
}
|
|
55
247
|
function logExtensionTiming(extensionPath, ms, outcome) {
|
|
56
248
|
if (!EXTENSION_TIMING_ENABLED)
|
|
57
249
|
return;
|
|
@@ -79,7 +271,18 @@ function getAliases() {
|
|
|
79
271
|
}
|
|
80
272
|
return fileURLToPath(import.meta.resolve(specifier));
|
|
81
273
|
};
|
|
274
|
+
// Auto-discover subpath exports from bundled npm packages.
|
|
275
|
+
// This ensures extensions can import any standard subpath (e.g. @modelcontextprotocol/sdk/server)
|
|
276
|
+
// without hitting jiti's CJS double-resolve bug.
|
|
277
|
+
const autoDiscovered = {};
|
|
278
|
+
for (const packageName of BUNDLED_PACKAGES_WITH_EXPORTS) {
|
|
279
|
+
const subpathAliases = resolveSubpathExports(packageName);
|
|
280
|
+
Object.assign(autoDiscovered, subpathAliases);
|
|
281
|
+
}
|
|
82
282
|
_aliases = {
|
|
283
|
+
// Auto-discovered subpath exports (lowest priority — overridden by manual entries below)
|
|
284
|
+
...autoDiscovered,
|
|
285
|
+
// Manual entries for workspace packages and packages needing special resolution
|
|
83
286
|
"@gsd/pi-coding-agent": packageIndex,
|
|
84
287
|
"@gsd/pi-agent-core": resolveWorkspaceOrImport("agent/dist/index.js", "@gsd/pi-agent-core"),
|
|
85
288
|
"@gsd/pi-tui": resolveWorkspaceOrImport("tui/dist/index.js", "@gsd/pi-tui"),
|
|
@@ -87,11 +290,6 @@ function getAliases() {
|
|
|
87
290
|
"@gsd/pi-ai/oauth": resolveWorkspaceOrImport("ai/dist/oauth.js", "@gsd/pi-ai/oauth"),
|
|
88
291
|
"@sinclair/typebox": typeboxRoot,
|
|
89
292
|
"yaml": yamlRoot,
|
|
90
|
-
"@modelcontextprotocol/sdk/client": require.resolve("@modelcontextprotocol/sdk/client"),
|
|
91
|
-
"@modelcontextprotocol/sdk/client/stdio": require.resolve("@modelcontextprotocol/sdk/client/stdio.js"),
|
|
92
|
-
"@modelcontextprotocol/sdk/client/stdio.js": require.resolve("@modelcontextprotocol/sdk/client/stdio.js"),
|
|
93
|
-
"@modelcontextprotocol/sdk/client/streamableHttp": require.resolve("@modelcontextprotocol/sdk/client/streamableHttp.js"),
|
|
94
|
-
"@modelcontextprotocol/sdk/client/streamableHttp.js": require.resolve("@modelcontextprotocol/sdk/client/streamableHttp.js"),
|
|
95
293
|
// Aliases for external PI ecosystem packages that import from the original scope
|
|
96
294
|
"@mariozechner/pi-coding-agent": packageIndex,
|
|
97
295
|
"@mariozechner/pi-agent-core": resolveWorkspaceOrImport("agent/dist/index.js", "@gsd/pi-agent-core"),
|