gsd-pi 2.75.0-dev.2203010a0 → 2.75.0-dev.a44b82572
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/dist/onboarding.d.ts +5 -1
- package/dist/onboarding.js +5 -3
- package/dist/resources/extensions/gsd/auto-model-selection.js +1 -1
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +23 -19
- package/dist/resources/extensions/gsd/bootstrap/memory-tools.js +128 -0
- package/dist/resources/extensions/gsd/bootstrap/register-extension.js +2 -0
- package/dist/resources/extensions/gsd/bootstrap/system-context.js +17 -4
- package/dist/resources/extensions/gsd/commands/handlers/onboarding.js +52 -68
- package/dist/resources/extensions/gsd/commands/handlers/ops.js +5 -0
- package/dist/resources/extensions/gsd/commands-memory.js +462 -0
- package/dist/resources/extensions/gsd/gsd-db.js +237 -4
- package/dist/resources/extensions/gsd/memory-embeddings.js +219 -0
- package/dist/resources/extensions/gsd/memory-extractor.js +78 -27
- package/dist/resources/extensions/gsd/memory-ingest.js +218 -0
- package/dist/resources/extensions/gsd/memory-relations.js +189 -0
- package/dist/resources/extensions/gsd/memory-source-store.js +113 -0
- package/dist/resources/extensions/gsd/memory-store.js +299 -6
- package/dist/resources/extensions/gsd/model-router.js +9 -5
- package/dist/resources/extensions/gsd/notification-overlay.js +7 -22
- package/dist/resources/extensions/gsd/tools/memory-tools.js +306 -0
- package/dist/resources/extensions/gsd/tools/skip-slice.js +78 -0
- package/dist/tsconfig.extensions.tsbuildinfo +1 -1
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +17 -17
- package/dist/web/standalone/.next/build-manifest.json +2 -2
- package/dist/web/standalone/.next/prerender-manifest.json +3 -3
- package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.html +1 -1
- package/dist/web/standalone/.next/server/app/index.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app-paths-manifest.json +17 -17
- package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
- package/dist/web/standalone/.next/server/middleware-manifest.json +5 -5
- package/dist/web/standalone/.next/server/pages/404.html +1 -1
- package/dist/web/standalone/.next/server/pages/500.html +1 -1
- package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
- package/package.json +1 -1
- package/packages/mcp-server/dist/server.d.ts.map +1 -1
- package/packages/mcp-server/dist/server.js +12 -10
- package/packages/mcp-server/dist/server.js.map +1 -1
- package/packages/mcp-server/dist/session-manager.d.ts.map +1 -1
- package/packages/mcp-server/dist/session-manager.js +8 -1
- package/packages/mcp-server/dist/session-manager.js.map +1 -1
- package/packages/mcp-server/dist/workflow-tools.d.ts +1 -0
- package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
- package/packages/mcp-server/dist/workflow-tools.js +113 -14
- package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
- package/packages/mcp-server/src/mcp-server.test.ts +40 -4
- package/packages/mcp-server/src/server.ts +12 -10
- package/packages/mcp-server/src/session-manager.ts +10 -3
- package/packages/mcp-server/src/workflow-tools.test.ts +91 -1
- package/packages/mcp-server/src/workflow-tools.ts +128 -18
- package/packages/mcp-server/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-coding-agent/dist/cli/args.d.ts +6 -0
- package/packages/pi-coding-agent/dist/cli/args.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/cli/args.js +14 -4
- package/packages/pi-coding-agent/dist/cli/args.js.map +1 -1
- package/packages/pi-coding-agent/dist/cli/args.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/cli/args.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/cli/args.test.js +38 -0
- package/packages/pi-coding-agent/dist/cli/args.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/sdk.d.ts +10 -0
- package/packages/pi-coding-agent/dist/core/sdk.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/sdk.js +7 -1
- package/packages/pi-coding-agent/dist/core/sdk.js.map +1 -1
- package/packages/pi-coding-agent/dist/main.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/main.js +3 -0
- package/packages/pi-coding-agent/dist/main.js.map +1 -1
- package/packages/pi-coding-agent/src/cli/args.test.ts +44 -0
- package/packages/pi-coding-agent/src/cli/args.ts +21 -6
- package/packages/pi-coding-agent/src/core/sdk.ts +17 -1
- package/packages/pi-coding-agent/src/main.ts +4 -0
- package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
- package/src/resources/extensions/gsd/auto-model-selection.ts +1 -1
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +24 -20
- package/src/resources/extensions/gsd/bootstrap/memory-tools.ts +158 -0
- package/src/resources/extensions/gsd/bootstrap/register-extension.ts +2 -0
- package/src/resources/extensions/gsd/bootstrap/system-context.ts +20 -4
- package/src/resources/extensions/gsd/commands/handlers/onboarding.ts +65 -98
- package/src/resources/extensions/gsd/commands/handlers/ops.ts +5 -0
- package/src/resources/extensions/gsd/commands-memory.ts +551 -0
- package/src/resources/extensions/gsd/gsd-db.ts +273 -4
- package/src/resources/extensions/gsd/memory-embeddings.ts +235 -0
- package/src/resources/extensions/gsd/memory-extractor.ts +100 -34
- package/src/resources/extensions/gsd/memory-ingest.ts +286 -0
- package/src/resources/extensions/gsd/memory-relations.ts +240 -0
- package/src/resources/extensions/gsd/memory-source-store.ts +138 -0
- package/src/resources/extensions/gsd/memory-store.ts +351 -7
- package/src/resources/extensions/gsd/model-router.ts +10 -5
- package/src/resources/extensions/gsd/notification-overlay.ts +9 -19
- package/src/resources/extensions/gsd/tests/auto-model-selection.test.ts +12 -0
- package/src/resources/extensions/gsd/tests/complete-slice.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/complete-task.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/escalation.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/gsd-db.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/md-importer.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/memory-embeddings.test.ts +213 -0
- package/src/resources/extensions/gsd/tests/memory-ingest.test.ts +153 -0
- package/src/resources/extensions/gsd/tests/memory-maintenance.test.ts +107 -0
- package/src/resources/extensions/gsd/tests/memory-relations.test.ts +175 -0
- package/src/resources/extensions/gsd/tests/memory-store.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/memory-tools.test.ts +295 -0
- package/src/resources/extensions/gsd/tests/model-router.test.ts +50 -0
- package/src/resources/extensions/gsd/tests/notification-overlay.test.ts +56 -37
- package/src/resources/extensions/gsd/tests/skip-slice-cascades-tasks.test.ts +125 -0
- package/src/resources/extensions/gsd/tools/memory-tools.ts +380 -0
- package/src/resources/extensions/gsd/tools/skip-slice.ts +133 -0
- package/src/resources/extensions/gsd/workflow-logger.ts +3 -1
- /package/dist/web/standalone/.next/static/{8FZqxNe9FxQDmsbRzR8tA → iBwPQUj73sn8jxegTo320}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{8FZqxNe9FxQDmsbRzR8tA → iBwPQUj73sn8jxegTo320}/_ssgManifest.js +0 -0
package/dist/onboarding.d.ts
CHANGED
|
@@ -20,6 +20,10 @@ type PicoModule = {
|
|
|
20
20
|
red: (s: string) => string;
|
|
21
21
|
reset: (s: string) => string;
|
|
22
22
|
};
|
|
23
|
+
interface RunOnboardingOptions {
|
|
24
|
+
/** Show logo + intro banner. Disable when onboarding is launched inside an active TUI session. */
|
|
25
|
+
showIntro?: boolean;
|
|
26
|
+
}
|
|
23
27
|
/**
|
|
24
28
|
* Determine if the onboarding wizard should run.
|
|
25
29
|
*
|
|
@@ -46,7 +50,7 @@ export declare function shouldRunOnboarding(authStorage: AuthStorage, settingsDe
|
|
|
46
50
|
* All steps are skippable. All errors are recoverable.
|
|
47
51
|
* Writes status to stderr during execution.
|
|
48
52
|
*/
|
|
49
|
-
export declare function runOnboarding(authStorage: AuthStorage): Promise<void>;
|
|
53
|
+
export declare function runOnboarding(authStorage: AuthStorage, opts?: RunOnboardingOptions): Promise<void>;
|
|
50
54
|
export declare function runLlmStep(p: ClackModule, pc: PicoModule, authStorage: AuthStorage): Promise<boolean>;
|
|
51
55
|
export declare function runWebSearchStep(p: ClackModule, pc: PicoModule, authStorage: AuthStorage, isAnthropicAuth: boolean): Promise<string | null>;
|
|
52
56
|
export declare function runToolKeysStep(p: ClackModule, pc: PicoModule, authStorage: AuthStorage): Promise<number>;
|
package/dist/onboarding.js
CHANGED
|
@@ -194,7 +194,7 @@ export function shouldRunOnboarding(authStorage, settingsDefaultProvider) {
|
|
|
194
194
|
* All steps are skippable. All errors are recoverable.
|
|
195
195
|
* Writes status to stderr during execution.
|
|
196
196
|
*/
|
|
197
|
-
export async function runOnboarding(authStorage) {
|
|
197
|
+
export async function runOnboarding(authStorage, opts = {}) {
|
|
198
198
|
let p;
|
|
199
199
|
let pc;
|
|
200
200
|
try {
|
|
@@ -207,8 +207,10 @@ export async function runOnboarding(authStorage) {
|
|
|
207
207
|
return;
|
|
208
208
|
}
|
|
209
209
|
// ── Intro ─────────────────────────────────────────────────────────────────
|
|
210
|
-
|
|
211
|
-
|
|
210
|
+
if (opts.showIntro !== false) {
|
|
211
|
+
process.stderr.write(renderLogo(pc.cyan));
|
|
212
|
+
p.intro(pc.bold('Welcome to GSD — let\'s get you set up'));
|
|
213
|
+
}
|
|
212
214
|
const completedSteps = [];
|
|
213
215
|
// ── LLM Provider Selection ────────────────────────────────────────────────
|
|
214
216
|
const llmResult = await runStep(p, 'LLM setup failed', () => runLlmStep(p, pc, authStorage), {
|
|
@@ -150,7 +150,7 @@ sessionModelOverride) {
|
|
|
150
150
|
const shouldClassify = !isHook || routingConfig.hooks !== false;
|
|
151
151
|
if (shouldClassify) {
|
|
152
152
|
let classification = classifyUnitComplexity(unitType, unitId, basePath, budgetPct, taskMetadataForPolicy);
|
|
153
|
-
const availableModelIds = routingEligibleModels.map(m => m.id);
|
|
153
|
+
const availableModelIds = routingEligibleModels.map(m => `${m.provider}/${m.id}`);
|
|
154
154
|
// Escalate tier on retry when escalate_on_failure is enabled (default: true)
|
|
155
155
|
if (retryContext?.isRetry &&
|
|
156
156
|
retryContext.previousTier &&
|
|
@@ -708,28 +708,23 @@ export function registerDbTools(pi) {
|
|
|
708
708
|
};
|
|
709
709
|
}
|
|
710
710
|
try {
|
|
711
|
-
const {
|
|
711
|
+
const { handleSkipSlice } = await import("../tools/skip-slice.js");
|
|
712
712
|
const { invalidateStateCache } = await import("../state.js");
|
|
713
|
-
const
|
|
714
|
-
|
|
713
|
+
const result = handleSkipSlice({
|
|
714
|
+
milestoneId: params.milestoneId,
|
|
715
|
+
sliceId: params.sliceId,
|
|
716
|
+
reason: params.reason,
|
|
717
|
+
});
|
|
718
|
+
if (result.error) {
|
|
715
719
|
return {
|
|
716
|
-
content: [{ type: "text", text: `Error:
|
|
717
|
-
details: {
|
|
720
|
+
content: [{ type: "text", text: `Error: ${result.error}` }],
|
|
721
|
+
details: {
|
|
722
|
+
operation: "skip_slice",
|
|
723
|
+
error: result.error,
|
|
724
|
+
errorCode: result.errorCode ?? "skip_failed",
|
|
725
|
+
},
|
|
718
726
|
};
|
|
719
727
|
}
|
|
720
|
-
if (slice.status === "complete" || slice.status === "done") {
|
|
721
|
-
return {
|
|
722
|
-
content: [{ type: "text", text: `Error: Slice ${params.sliceId} is already complete — cannot skip.` }],
|
|
723
|
-
details: { operation: "skip_slice", error: "already_complete" },
|
|
724
|
-
};
|
|
725
|
-
}
|
|
726
|
-
if (slice.status === "skipped") {
|
|
727
|
-
return {
|
|
728
|
-
content: [{ type: "text", text: `Slice ${params.sliceId} is already skipped.` }],
|
|
729
|
-
details: { operation: "skip_slice", sliceId: params.sliceId, milestoneId: params.milestoneId },
|
|
730
|
-
};
|
|
731
|
-
}
|
|
732
|
-
updateSliceStatus(params.milestoneId, params.sliceId, "skipped");
|
|
733
728
|
invalidateStateCache();
|
|
734
729
|
// Rebuild STATE.md so it reflects the skip immediately (#3477).
|
|
735
730
|
// Without this, /gsd auto reads stale STATE.md and resumes the skipped slice.
|
|
@@ -741,13 +736,20 @@ export function registerDbTools(pi) {
|
|
|
741
736
|
catch (err) {
|
|
742
737
|
logError("tool", `skip_slice rebuildState failed: ${err.message}`, { tool: "gsd_skip_slice" });
|
|
743
738
|
}
|
|
739
|
+
const suffix = result.wasAlreadySkipped
|
|
740
|
+
? result.tasksSkipped > 0
|
|
741
|
+
? ` (already skipped; cascaded ${result.tasksSkipped} leftover task(s) to skipped).`
|
|
742
|
+
: " (already skipped; no pending tasks to cascade)."
|
|
743
|
+
: ` Cascaded ${result.tasksSkipped} task(s) to skipped. Auto-mode will advance past this slice.`;
|
|
744
744
|
return {
|
|
745
|
-
content: [{ type: "text", text: `Skipped slice ${params.sliceId} (${params.milestoneId}). Reason: ${params.reason ?? "User-directed skip"}
|
|
745
|
+
content: [{ type: "text", text: `Skipped slice ${params.sliceId} (${params.milestoneId}). Reason: ${params.reason ?? "User-directed skip"}.${suffix}` }],
|
|
746
746
|
details: {
|
|
747
747
|
operation: "skip_slice",
|
|
748
748
|
sliceId: params.sliceId,
|
|
749
749
|
milestoneId: params.milestoneId,
|
|
750
750
|
reason: params.reason,
|
|
751
|
+
tasksSkipped: result.tasksSkipped,
|
|
752
|
+
wasAlreadySkipped: result.wasAlreadySkipped,
|
|
751
753
|
},
|
|
752
754
|
};
|
|
753
755
|
}
|
|
@@ -764,12 +766,14 @@ export function registerDbTools(pi) {
|
|
|
764
766
|
name: "gsd_skip_slice",
|
|
765
767
|
label: "Skip Slice",
|
|
766
768
|
description: "Mark a slice as skipped so auto-mode advances past it without executing. " +
|
|
769
|
+
"Non-closed tasks within the slice are cascaded to skipped so milestone completion is not blocked by leftover pending tasks (#4375). " +
|
|
767
770
|
"The slice data is preserved for reference. The state machine treats skipped slices like completed ones for dependency satisfaction.",
|
|
768
771
|
promptSnippet: "Skip a GSD slice (mark as skipped, auto-mode will advance past it)",
|
|
769
772
|
promptGuidelines: [
|
|
770
773
|
"Use gsd_skip_slice when a slice should be bypassed — descoped, superseded, or no longer relevant.",
|
|
771
774
|
"Cannot skip a slice that is already complete.",
|
|
772
775
|
"Skipped slices satisfy downstream dependencies just like completed slices.",
|
|
776
|
+
"All pending/active tasks in the slice are cascaded to skipped; completed tasks are never downgraded.",
|
|
773
777
|
],
|
|
774
778
|
parameters: Type.Object({
|
|
775
779
|
sliceId: Type.String({ description: "Slice ID (e.g. S02)" }),
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
// GSD2 — Memory tool registration
|
|
2
|
+
//
|
|
3
|
+
// Exposes the memory-layer tools (capture_thought, memory_query, gsd_graph)
|
|
4
|
+
// to the LLM over MCP. All three degrade gracefully when the GSD database
|
|
5
|
+
// is unavailable.
|
|
6
|
+
import { Type } from "@sinclair/typebox";
|
|
7
|
+
import { ensureDbOpen } from "./dynamic-tools.js";
|
|
8
|
+
import { executeGsdGraph, executeMemoryCapture, executeMemoryQuery, } from "../tools/memory-tools.js";
|
|
9
|
+
export function registerMemoryTools(pi) {
|
|
10
|
+
// ─── capture_thought ────────────────────────────────────────────────────
|
|
11
|
+
pi.registerTool({
|
|
12
|
+
name: "capture_thought",
|
|
13
|
+
label: "Capture Thought",
|
|
14
|
+
description: "Record a durable piece of project knowledge (decision, convention, gotcha, pattern, " +
|
|
15
|
+
"preference, or environment detail) into the GSD memory store. Use sparingly — one memory " +
|
|
16
|
+
"per genuinely reusable insight, not per task.",
|
|
17
|
+
promptSnippet: "Capture a durable project insight into the GSD memory store (categories: architecture, convention, gotcha, pattern, preference, environment)",
|
|
18
|
+
promptGuidelines: [
|
|
19
|
+
"Use capture_thought for insights that will remain useful across future sessions.",
|
|
20
|
+
"Do NOT capture one-off bug fixes, temporary state, secrets, or task-specific details.",
|
|
21
|
+
"Keep content to 1–3 sentences.",
|
|
22
|
+
"Set confidence: 0.6 tentative, 0.8 solid, 0.95 well-confirmed (default 0.8).",
|
|
23
|
+
],
|
|
24
|
+
parameters: Type.Object({
|
|
25
|
+
category: Type.Union([
|
|
26
|
+
Type.Literal("architecture"),
|
|
27
|
+
Type.Literal("convention"),
|
|
28
|
+
Type.Literal("gotcha"),
|
|
29
|
+
Type.Literal("preference"),
|
|
30
|
+
Type.Literal("environment"),
|
|
31
|
+
Type.Literal("pattern"),
|
|
32
|
+
], { description: "Memory category" }),
|
|
33
|
+
content: Type.String({ description: "The memory text (1–3 sentences, no secrets)" }),
|
|
34
|
+
confidence: Type.Optional(Type.Number({ description: "0.1–0.99, default 0.8", minimum: 0.1, maximum: 0.99 })),
|
|
35
|
+
tags: Type.Optional(Type.Array(Type.String(), { description: "Free-form tags (reserved for future use)" })),
|
|
36
|
+
scope: Type.Optional(Type.String({ description: "Scope name (reserved for future use; defaults to project)" })),
|
|
37
|
+
}),
|
|
38
|
+
async execute(_toolCallId, params, _signal, _onUpdate, _ctx) {
|
|
39
|
+
const ok = await ensureDbOpen();
|
|
40
|
+
if (!ok) {
|
|
41
|
+
return {
|
|
42
|
+
content: [{ type: "text", text: "Error: GSD database is not available. Cannot capture memory." }],
|
|
43
|
+
details: { operation: "memory_capture", error: "db_unavailable" },
|
|
44
|
+
isError: true,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
return executeMemoryCapture(params);
|
|
48
|
+
},
|
|
49
|
+
});
|
|
50
|
+
// ─── memory_query ───────────────────────────────────────────────────────
|
|
51
|
+
pi.registerTool({
|
|
52
|
+
name: "memory_query",
|
|
53
|
+
label: "Query Memory",
|
|
54
|
+
description: "Search the GSD memory store for relevant memories. Phase 1 uses keyword matching ranked " +
|
|
55
|
+
"by confidence and reinforcement; future phases add semantic (embedding) retrieval.",
|
|
56
|
+
promptSnippet: "Search the GSD memory store by keyword; returns ranked memories with id, category, and content",
|
|
57
|
+
promptGuidelines: [
|
|
58
|
+
"Use memory_query when you need durable project context that may not be in the current prompt.",
|
|
59
|
+
"Provide a short keyword-style query — not a full question.",
|
|
60
|
+
"Use category to narrow results to gotchas, conventions, architecture notes, etc.",
|
|
61
|
+
],
|
|
62
|
+
parameters: Type.Object({
|
|
63
|
+
query: Type.String({ description: "Keyword query (2+ char terms)" }),
|
|
64
|
+
k: Type.Optional(Type.Number({ description: "Max results (default 10, max 50)", minimum: 1, maximum: 50 })),
|
|
65
|
+
category: Type.Optional(Type.Union([
|
|
66
|
+
Type.Literal("architecture"),
|
|
67
|
+
Type.Literal("convention"),
|
|
68
|
+
Type.Literal("gotcha"),
|
|
69
|
+
Type.Literal("preference"),
|
|
70
|
+
Type.Literal("environment"),
|
|
71
|
+
Type.Literal("pattern"),
|
|
72
|
+
], { description: "Restrict results to a single category" })),
|
|
73
|
+
scope: Type.Optional(Type.String({ description: "Only include memories with this scope (e.g. 'project', 'global')" })),
|
|
74
|
+
tag: Type.Optional(Type.String({ description: "Only include memories tagged with this value" })),
|
|
75
|
+
include_superseded: Type.Optional(Type.Boolean({ description: "Include superseded memories (default false)" })),
|
|
76
|
+
reinforce_hits: Type.Optional(Type.Boolean({ description: "Increment hit_count on returned memories (default false)" })),
|
|
77
|
+
}),
|
|
78
|
+
async execute(_toolCallId, params, _signal, _onUpdate, _ctx) {
|
|
79
|
+
const ok = await ensureDbOpen();
|
|
80
|
+
if (!ok) {
|
|
81
|
+
return {
|
|
82
|
+
content: [{ type: "text", text: "Error: GSD database is not available. Cannot query memory." }],
|
|
83
|
+
details: { operation: "memory_query", error: "db_unavailable" },
|
|
84
|
+
isError: true,
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
return executeMemoryQuery(params);
|
|
88
|
+
},
|
|
89
|
+
});
|
|
90
|
+
// ─── gsd_graph ──────────────────────────────────────────────────────────
|
|
91
|
+
pi.registerTool({
|
|
92
|
+
name: "gsd_graph",
|
|
93
|
+
label: "GSD Knowledge Graph",
|
|
94
|
+
description: "Inspect the relationship graph between memories. mode=query walks supersedes edges from a " +
|
|
95
|
+
"given memoryId; mode=build is a placeholder that future phases will use to rebuild graph " +
|
|
96
|
+
"edges from milestone LEARNINGS artifacts.",
|
|
97
|
+
promptSnippet: "Query the memory relationship graph or trigger a rebuild",
|
|
98
|
+
promptGuidelines: [
|
|
99
|
+
"Use mode=query with a memoryId when you want to see how a memory relates to others.",
|
|
100
|
+
"Phase 1 only exposes supersedes edges; additional relation types arrive in later phases.",
|
|
101
|
+
],
|
|
102
|
+
parameters: Type.Object({
|
|
103
|
+
mode: Type.Union([Type.Literal("build"), Type.Literal("query")], {
|
|
104
|
+
description: "build = recompute graph (placeholder), query = inspect edges",
|
|
105
|
+
}),
|
|
106
|
+
memoryId: Type.Optional(Type.String({ description: "Memory ID (required when mode=query)" })),
|
|
107
|
+
depth: Type.Optional(Type.Number({ description: "Hops to traverse (0–5, default 1)", minimum: 0, maximum: 5 })),
|
|
108
|
+
rel: Type.Optional(Type.Union([
|
|
109
|
+
Type.Literal("related_to"),
|
|
110
|
+
Type.Literal("depends_on"),
|
|
111
|
+
Type.Literal("contradicts"),
|
|
112
|
+
Type.Literal("elaborates"),
|
|
113
|
+
Type.Literal("supersedes"),
|
|
114
|
+
], { description: "Only include edges with this relation type" })),
|
|
115
|
+
}),
|
|
116
|
+
async execute(_toolCallId, params, _signal, _onUpdate, _ctx) {
|
|
117
|
+
const ok = await ensureDbOpen();
|
|
118
|
+
if (!ok) {
|
|
119
|
+
return {
|
|
120
|
+
content: [{ type: "text", text: "Error: GSD database is not available." }],
|
|
121
|
+
details: { operation: "gsd_graph", error: "db_unavailable" },
|
|
122
|
+
isError: true,
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
return executeGsdGraph(params);
|
|
126
|
+
},
|
|
127
|
+
});
|
|
128
|
+
}
|
|
@@ -5,6 +5,7 @@ import { loadEcosystemExtensions } from "../ecosystem/loader.js";
|
|
|
5
5
|
import { registerDbTools } from "./db-tools.js";
|
|
6
6
|
import { registerDynamicTools } from "./dynamic-tools.js";
|
|
7
7
|
import { registerJournalTools } from "./journal-tools.js";
|
|
8
|
+
import { registerMemoryTools } from "./memory-tools.js";
|
|
8
9
|
import { registerQueryTools } from "./query-tools.js";
|
|
9
10
|
import { registerHooks } from "./register-hooks.js";
|
|
10
11
|
import { registerShortcuts } from "./register-shortcuts.js";
|
|
@@ -74,6 +75,7 @@ export function registerGsdExtension(pi) {
|
|
|
74
75
|
["db-tools", () => registerDbTools(pi)],
|
|
75
76
|
["journal-tools", () => registerJournalTools(pi)],
|
|
76
77
|
["query-tools", () => registerQueryTools(pi)],
|
|
78
|
+
["memory-tools", () => registerMemoryTools(pi)],
|
|
77
79
|
["shortcuts", () => registerShortcuts(pi)],
|
|
78
80
|
["hooks", () => registerHooks(pi, ecosystemHandlers)],
|
|
79
81
|
["ecosystem", () => {
|
|
@@ -89,10 +89,23 @@ export async function buildBeforeAgentStartResult(event, ctx) {
|
|
|
89
89
|
}
|
|
90
90
|
let memoryBlock = "";
|
|
91
91
|
try {
|
|
92
|
-
const { formatMemoriesForPrompt, getActiveMemoriesRanked } = await import("../memory-store.js");
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
92
|
+
const { formatMemoriesForPrompt, getActiveMemoriesRanked, queryMemoriesRanked } = await import("../memory-store.js");
|
|
93
|
+
// Always-on "critical" set — small, stable memories that belong in every
|
|
94
|
+
// turn (gotchas, environment, conventions). Ranked by the existing score.
|
|
95
|
+
const CRITICAL_CATEGORIES = new Set(["gotcha", "environment", "convention"]);
|
|
96
|
+
const allRanked = getActiveMemoriesRanked(60);
|
|
97
|
+
const critical = allRanked.filter((m) => CRITICAL_CATEGORIES.has(m.category)).slice(0, 5);
|
|
98
|
+
const criticalIds = new Set(critical.map((m) => m.id));
|
|
99
|
+
// Prompt-relevance set — hybrid FTS5 + (future) semantic retrieval.
|
|
100
|
+
let relevant = [];
|
|
101
|
+
const userPrompt = (event.prompt ?? "").trim();
|
|
102
|
+
if (userPrompt) {
|
|
103
|
+
const hits = queryMemoriesRanked({ query: userPrompt, k: 10 });
|
|
104
|
+
relevant = hits.map((h) => h.memory).filter((m) => !criticalIds.has(m.id));
|
|
105
|
+
}
|
|
106
|
+
const merged = [...critical, ...relevant];
|
|
107
|
+
if (merged.length > 0) {
|
|
108
|
+
const formatted = formatMemoriesForPrompt(merged, 2000);
|
|
96
109
|
if (formatted) {
|
|
97
110
|
memoryBlock = `\n\n${formatted}`;
|
|
98
111
|
}
|
|
@@ -1,31 +1,26 @@
|
|
|
1
|
-
// GSD — /gsd onboarding command handler (re-entry
|
|
1
|
+
// GSD — /gsd onboarding command handler (re-entry hub)
|
|
2
2
|
//
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
3
|
+
// The first-run wizard in src/onboarding.ts uses @clack/prompts and takes over
|
|
4
|
+
// raw stdin. Running it from inside the pi-coding-agent TUI wedges the TUI
|
|
5
|
+
// (clack leaves stdin paused + cooked, pi-tui's data handler then receives no
|
|
6
|
+
// keypresses). So re-entry cannot replay the clack wizard — instead it routes
|
|
7
|
+
// to a setup hub built from ctx.ui.select, which the TUI owns.
|
|
8
|
+
//
|
|
9
|
+
// Clack-only steps (llm/search/remote/tool-keys via the first-run wizard) are
|
|
10
|
+
// surfaced as notifications pointing the user at the canonical per-step
|
|
11
|
+
// commands (/login, /gsd keys, /gsd remote) that are already ctx.ui-safe.
|
|
12
|
+
import { ONBOARDING_STEPS, isValidStepId, } from "../../setup-catalog.js";
|
|
10
13
|
import { isOnboardingComplete, readOnboardingRecord, resetOnboarding, } from "../../onboarding-state.js";
|
|
11
|
-
// Inline auth path (mirrors src/app-paths.ts) — keep this module rootDir-clean
|
|
12
|
-
// for the resources tsconfig. Importing from src/ pulls files outside
|
|
13
|
-
// src/resources and breaks the build.
|
|
14
|
-
const AUTH_FILE_PATH = join(process.env.GSD_CODING_AGENT_DIR ||
|
|
15
|
-
join(process.env.GSD_HOME || join(homedir(), ".gsd"), "agent"), "auth.json");
|
|
16
|
-
async function loadFirstRunWizard() {
|
|
17
|
-
const specifier = "../../../../../onboarding.js";
|
|
18
|
-
return (await import(/* @vite-ignore */ specifier));
|
|
19
|
-
}
|
|
20
14
|
function parseArgs(raw) {
|
|
21
15
|
const tokens = raw.split(/\s+/).filter(Boolean);
|
|
22
|
-
const out = {
|
|
16
|
+
const out = { reset: false, step: null, stepValid: null };
|
|
23
17
|
for (let i = 0; i < tokens.length; i++) {
|
|
24
18
|
const t = tokens[i];
|
|
25
|
-
if (t === "--
|
|
26
|
-
out.resume = true;
|
|
27
|
-
else if (t === "--reset" || t === "reset")
|
|
19
|
+
if (t === "--reset" || t === "reset")
|
|
28
20
|
out.reset = true;
|
|
21
|
+
else if (t === "--resume" || t === "resume") {
|
|
22
|
+
// Re-entry no longer replays the wizard; --resume collapses into the hub.
|
|
23
|
+
}
|
|
29
24
|
else if (t === "--step" || t === "step") {
|
|
30
25
|
const next = tokens[i + 1];
|
|
31
26
|
if (next) {
|
|
@@ -42,46 +37,26 @@ function parseArgs(raw) {
|
|
|
42
37
|
}
|
|
43
38
|
return out;
|
|
44
39
|
}
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
// full sequence with skip prompts. We still mark completion at the end and
|
|
52
|
-
// record the resume hint for next time. This keeps the wizard linear and
|
|
53
|
-
// simple; per-step jump support comes via --step.
|
|
54
|
-
if (fromStep) {
|
|
55
|
-
ctx.ui.notify(`Resuming from step: ${fromStep}. The wizard runs all remaining steps; press skip on any you've already configured.`, "info");
|
|
56
|
-
}
|
|
57
|
-
const { runOnboarding } = await loadFirstRunWizard();
|
|
58
|
-
await runOnboarding(authStorage);
|
|
59
|
-
}
|
|
60
|
-
async function runSingleStep(ctx, stepId) {
|
|
61
|
-
const authStorage = await getAuthStorage();
|
|
62
|
-
const ob = await loadFirstRunWizard();
|
|
63
|
-
// Lazy-load clack + chalk via the same path the wizard uses
|
|
64
|
-
const p = await import("@clack/prompts");
|
|
65
|
-
const { default: chalk } = await import("chalk");
|
|
66
|
-
const pc = {
|
|
67
|
-
cyan: chalk.cyan, green: chalk.green, yellow: chalk.yellow,
|
|
68
|
-
dim: chalk.dim, bold: chalk.bold, red: chalk.red, reset: chalk.reset,
|
|
69
|
-
};
|
|
40
|
+
// ─── Per-step routing ────────────────────────────────────────────────────────
|
|
41
|
+
//
|
|
42
|
+
// Clack-based steps are surfaced as notifications — running them inline from
|
|
43
|
+
// the TUI would wedge stdin (see header comment). Everything else routes to an
|
|
44
|
+
// existing ctx.ui-safe handler.
|
|
45
|
+
async function runStep(ctx, stepId) {
|
|
70
46
|
switch (stepId) {
|
|
71
47
|
case "llm":
|
|
72
|
-
|
|
48
|
+
ctx.ui.notify("LLM provider setup: run /login to sign in via OAuth, or /gsd keys add to paste an API key.", "info");
|
|
73
49
|
return;
|
|
74
50
|
case "search":
|
|
75
|
-
|
|
51
|
+
ctx.ui.notify("Web search setup: run /gsd keys add and pick a search provider (brave, tavily, etc.).", "info");
|
|
76
52
|
return;
|
|
77
53
|
case "remote":
|
|
78
|
-
|
|
54
|
+
ctx.ui.notify("Remote questions setup: run /gsd remote to configure Discord / Slack / Telegram notifications.", "info");
|
|
79
55
|
return;
|
|
80
56
|
case "tool-keys":
|
|
81
|
-
|
|
57
|
+
ctx.ui.notify("Tool keys setup: run /gsd keys add to save API keys for Context7, Jina, Groq voice, etc.", "info");
|
|
82
58
|
return;
|
|
83
59
|
case "model": {
|
|
84
|
-
// Delegate to /gsd model picker
|
|
85
60
|
const { handleCoreCommand } = await import("./core.js");
|
|
86
61
|
await handleCoreCommand("model", ctx);
|
|
87
62
|
return;
|
|
@@ -94,7 +69,6 @@ async function runSingleStep(ctx, stepId) {
|
|
|
94
69
|
return;
|
|
95
70
|
}
|
|
96
71
|
case "doctor": {
|
|
97
|
-
// Best-effort: surface provider doctor results inline
|
|
98
72
|
try {
|
|
99
73
|
const { runProviderDoctor } = await import("../../doctor-providers.js");
|
|
100
74
|
if (typeof runProviderDoctor === "function") {
|
|
@@ -106,10 +80,9 @@ async function runSingleStep(ctx, stepId) {
|
|
|
106
80
|
ctx.ui.notify("Run /gsd doctor to validate your setup.", "info");
|
|
107
81
|
return;
|
|
108
82
|
}
|
|
109
|
-
case "skills":
|
|
110
|
-
ctx.ui.notify("Skill install runs
|
|
83
|
+
case "skills":
|
|
84
|
+
ctx.ui.notify("Skill install runs during /gsd init. Use /gsd init or /skill manage.", "info");
|
|
111
85
|
return;
|
|
112
|
-
}
|
|
113
86
|
case "project": {
|
|
114
87
|
const { handleCoreCommand } = await import("./core.js");
|
|
115
88
|
await handleCoreCommand("init", ctx);
|
|
@@ -117,6 +90,25 @@ async function runSingleStep(ctx, stepId) {
|
|
|
117
90
|
}
|
|
118
91
|
}
|
|
119
92
|
}
|
|
93
|
+
// ─── Setup hub ───────────────────────────────────────────────────────────────
|
|
94
|
+
async function renderSetupHub(ctx) {
|
|
95
|
+
const record = readOnboardingRecord();
|
|
96
|
+
const completed = new Set(record.completedSteps);
|
|
97
|
+
const skipped = new Set(record.skippedSteps);
|
|
98
|
+
const labels = ONBOARDING_STEPS.map(step => {
|
|
99
|
+
const mark = completed.has(step.id) ? "✓" : skipped.has(step.id) ? "↷" : "○";
|
|
100
|
+
const req = step.required ? " (required)" : "";
|
|
101
|
+
return `${mark} ${step.label}${req} — ${step.hint}`;
|
|
102
|
+
});
|
|
103
|
+
const labelToStep = new Map(labels.map((label, i) => [label, ONBOARDING_STEPS[i].id]));
|
|
104
|
+
const choice = await ctx.ui.select("GSD Setup — pick a step to configure", labels);
|
|
105
|
+
if (typeof choice !== "string")
|
|
106
|
+
return;
|
|
107
|
+
const stepId = labelToStep.get(choice);
|
|
108
|
+
if (!stepId)
|
|
109
|
+
return;
|
|
110
|
+
await runStep(ctx, stepId);
|
|
111
|
+
}
|
|
120
112
|
function renderStatus() {
|
|
121
113
|
const r = readOnboardingRecord();
|
|
122
114
|
const lines = ["GSD Onboarding\n"];
|
|
@@ -149,27 +141,19 @@ export async function handleOnboarding(rawArgs, ctx) {
|
|
|
149
141
|
ctx.ui.notify(`Unknown step "${args.step}". Valid: ${validIds}`, "warning");
|
|
150
142
|
return;
|
|
151
143
|
}
|
|
152
|
-
await
|
|
144
|
+
await runStep(ctx, args.step);
|
|
153
145
|
return;
|
|
154
146
|
}
|
|
155
147
|
if (args.reset) {
|
|
156
148
|
resetOnboarding();
|
|
157
|
-
ctx.ui.notify("Onboarding
|
|
158
|
-
await
|
|
149
|
+
ctx.ui.notify("Onboarding state cleared. API keys/credentials are unchanged — manage them with /gsd keys. Restart GSD to re-run the first-run wizard, or pick a step below.", "info");
|
|
150
|
+
await renderSetupHub(ctx);
|
|
159
151
|
return;
|
|
160
152
|
}
|
|
161
|
-
|
|
162
|
-
const r = readOnboardingRecord();
|
|
163
|
-
const next = nearestResumeStep(r.lastResumePoint, r.completedSteps);
|
|
164
|
-
await runWholeWizard(ctx, next);
|
|
165
|
-
return;
|
|
166
|
-
}
|
|
167
|
-
// No flags. If already complete, show status + offer choice.
|
|
153
|
+
// No flags (or --resume). Show status if complete, then open the hub.
|
|
168
154
|
if (isOnboardingComplete()) {
|
|
169
155
|
ctx.ui.notify(renderStatus(), "info");
|
|
170
|
-
ctx.ui.notify("Onboarding already complete. Use /gsd onboarding --reset to start over, or --step <name> to redo one section.", "info");
|
|
171
|
-
return;
|
|
172
156
|
}
|
|
173
|
-
await
|
|
157
|
+
await renderSetupHub(ctx);
|
|
174
158
|
}
|
|
175
159
|
export { renderStatus as renderOnboardingStatus };
|
|
@@ -248,6 +248,11 @@ Examples:
|
|
|
248
248
|
await handleExtractLearnings(trimmed.replace(/^extract-learnings\s*/, "").trim(), ctx, pi);
|
|
249
249
|
return true;
|
|
250
250
|
}
|
|
251
|
+
if (trimmed === "memory" || trimmed.startsWith("memory ") || trimmed === "memory help") {
|
|
252
|
+
const { handleMemory } = await import("../../commands-memory.js");
|
|
253
|
+
await handleMemory(trimmed.replace(/^memory\s*/, "").trim(), ctx, pi);
|
|
254
|
+
return true;
|
|
255
|
+
}
|
|
251
256
|
if (trimmed === "scan" || trimmed.startsWith("scan ")) {
|
|
252
257
|
const { handleScan } = await import("../../commands-scan.js");
|
|
253
258
|
// \s* (not \s+) is intentional: handles both /gsd scan (no args) and /gsd scan --focus X
|