@opengsd/gsd-pi 1.0.2-dev.235ebf3 → 1.0.2-dev.2c204d3
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 +63 -12
- package/dist/resource-loader.d.ts +7 -0
- package/dist/resource-loader.js +42 -9
- package/dist/resources/.managed-resources-content-hash +1 -1
- package/dist/resources/extensions/context7/index.js +12 -2
- package/dist/resources/extensions/gsd/auto/loop.js +19 -0
- package/dist/resources/extensions/gsd/auto/phases.js +1 -1
- package/dist/resources/extensions/gsd/auto/session.js +3 -0
- package/dist/resources/extensions/gsd/auto-start.js +232 -49
- package/dist/resources/extensions/gsd/auto-worktree.js +2 -54
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +4 -3
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +17 -15
- package/dist/resources/extensions/gsd/closeout-recovery.js +7 -1
- package/dist/resources/extensions/gsd/commands/handlers/auto.js +9 -1
- package/dist/resources/extensions/gsd/commands-handlers.js +3 -0
- package/dist/resources/extensions/gsd/git-conflict-state.js +26 -1
- package/dist/resources/extensions/gsd/tools/complete-task.js +9 -0
- package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +40 -1
- package/dist/resources/extensions/gsd/worktree-lifecycle.js +24 -3
- package/dist/resources/extensions/gsd/worktree-post-create-hook.js +117 -0
- package/dist/resources/extensions/search-the-web/native-search.js +57 -8
- package/dist/resources/shared/package-manager-detection.js +36 -0
- package/dist/update-check.d.ts +6 -2
- package/dist/update-check.js +7 -3
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +7 -7
- 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/api/boot/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/events/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/shutdown/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/update/route.js +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 +7 -7
- package/dist/web/standalone/.next/server/chunks/1834.js +1 -1
- package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
- 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/dist/web/standalone/node_modules/node-pty/build/Makefile +1 -1
- package/dist/web/standalone/package.json +0 -1
- package/dist/worktree-cli.d.ts +0 -2
- package/dist/worktree-cli.js +21 -9
- package/package.json +5 -2
- package/packages/cloud-mcp-gateway/bin/gsd-cloud-mcp-gateway.js +14 -0
- package/packages/cloud-mcp-gateway/package.json +4 -3
- package/packages/contracts/package.json +1 -1
- package/packages/daemon/package.json +4 -4
- package/packages/gsd-agent-core/package.json +5 -5
- package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.js +3 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/transcript-design.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/transcript-design.js +0 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/transcript-design.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-class-constants.d.ts +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-class-constants.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-class-constants.js +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-class-constants.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode.js +2 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/packages/gsd-agent-modes/package.json +7 -7
- package/packages/mcp-server/bin/gsd-mcp-server.js +14 -0
- package/packages/mcp-server/dist/workflow-tools.js +1 -1
- package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
- package/packages/mcp-server/package.json +5 -4
- package/packages/native/package.json +1 -1
- package/packages/pi-agent-core/dist/agent-loop.js +13 -13
- package/packages/pi-agent-core/dist/agent-loop.js.map +1 -1
- package/packages/pi-agent-core/package.json +1 -1
- package/packages/pi-ai/bin/pi-ai.js +14 -0
- package/packages/pi-ai/dist/models.generated.d.ts +40 -17
- package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
- package/packages/pi-ai/dist/models.generated.js +49 -30
- package/packages/pi-ai/dist/models.generated.js.map +1 -1
- package/packages/pi-ai/dist/providers/anthropic.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/anthropic.js +50 -0
- package/packages/pi-ai/dist/providers/anthropic.js.map +1 -1
- package/packages/pi-ai/dist/types.d.ts +2 -0
- package/packages/pi-ai/dist/types.d.ts.map +1 -1
- package/packages/pi-ai/dist/types.js.map +1 -1
- package/packages/pi-ai/package.json +3 -2
- package/packages/pi-coding-agent/dist/core/tools/read.d.ts +2 -2
- package/packages/pi-coding-agent/dist/core/tools/read.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/read.js +5 -3
- package/packages/pi-coding-agent/dist/core/tools/read.js.map +1 -1
- package/packages/pi-coding-agent/package.json +8 -8
- package/packages/pi-tui/package.json +1 -1
- package/packages/rpc-client/package.json +2 -2
- package/pkg/package.json +1 -1
- package/scripts/install/deps.js +10 -0
- package/scripts/install/detect-existing.js +17 -3
- package/scripts/install/npm-global.js +103 -33
- package/scripts/install.js +1 -0
- package/src/resources/extensions/context7/index.ts +15 -2
- package/src/resources/extensions/gsd/auto/loop.ts +22 -0
- package/src/resources/extensions/gsd/auto/phases.ts +1 -1
- package/src/resources/extensions/gsd/auto/session.ts +3 -0
- package/src/resources/extensions/gsd/auto-start.ts +307 -56
- package/src/resources/extensions/gsd/auto-worktree.ts +2 -56
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +4 -3
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +22 -15
- package/src/resources/extensions/gsd/closeout-recovery.ts +6 -1
- package/src/resources/extensions/gsd/commands/handlers/auto.ts +9 -1
- package/src/resources/extensions/gsd/commands-handlers.ts +2 -0
- package/src/resources/extensions/gsd/git-conflict-state.ts +25 -1
- package/src/resources/extensions/gsd/tests/auto-start-orphan-bootstrap.test.ts +436 -0
- package/src/resources/extensions/gsd/tests/closeout-recovery.test.ts +15 -0
- package/src/resources/extensions/gsd/tests/commands-dispatcher-workspace-git.test.ts +15 -2
- package/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts +64 -0
- package/src/resources/extensions/gsd/tests/orphaned-worktree-audit.test.ts +70 -10
- package/src/resources/extensions/gsd/tests/start-auto-detached.test.ts +13 -2
- package/src/resources/extensions/gsd/tests/tool-param-optionality.test.ts +24 -1
- package/src/resources/extensions/gsd/tests/workflow-mcp-auto-prep.test.ts +60 -0
- package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +54 -0
- package/src/resources/extensions/gsd/tests/workspace-git-preflight.test.ts +16 -1
- package/src/resources/extensions/gsd/tests/worktree-lifecycle.test.ts +28 -0
- package/src/resources/extensions/gsd/tests/worktree-post-create-hook.test.ts +141 -1
- package/src/resources/extensions/gsd/tests/zombie-gsd-state.test.ts +45 -1
- package/src/resources/extensions/gsd/tools/complete-task.ts +9 -0
- package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +56 -4
- package/src/resources/extensions/gsd/worktree-lifecycle.ts +37 -2
- package/src/resources/extensions/gsd/worktree-post-create-hook.ts +127 -0
- package/src/resources/extensions/search-the-web/native-search.ts +60 -8
- package/src/resources/shared/package-manager-detection.ts +39 -0
- package/dist/tsconfig.extensions.tsbuildinfo +0 -1
- /package/dist/web/standalone/.next/static/{-P554bKh56nzavKUmvFM2 → mijI90BL1BdUcMUnhC0HU}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{-P554bKh56nzavKUmvFM2 → mijI90BL1BdUcMUnhC0HU}/_ssgManifest.js +0 -0
|
@@ -17,6 +17,7 @@ import { isAutoActive, checkRemoteAutoSession } from "./auto.js";
|
|
|
17
17
|
import { getAutoWorktreePath } from "./auto-worktree.js";
|
|
18
18
|
import { currentDirectoryRoot, projectRoot } from "./commands/context.js";
|
|
19
19
|
import { loadPrompt } from "./prompt-loader.js";
|
|
20
|
+
import { isPnpmInstall } from "../../shared/package-manager-detection.js";
|
|
20
21
|
import { buildDoctorHealIssuePayload, buildDoctorHealSummary, buildWorkflowDispatchContent, } from "./workflow-protocol.js";
|
|
21
22
|
import { restoreGsdWorkflowTools, scopeGsdWorkflowToolsForDispatch, } from "./bootstrap/register-hooks.js";
|
|
22
23
|
const UPDATE_REGISTRY_URL = "https://registry.npmjs.org/@opengsd%2fgsd-pi/latest";
|
|
@@ -42,6 +43,8 @@ function isBunInstall(argv1 = process.argv[1]) {
|
|
|
42
43
|
function resolveInstallCommand(pkg) {
|
|
43
44
|
if (isBunInstall())
|
|
44
45
|
return `bun add -g ${pkg}`;
|
|
46
|
+
if (isPnpmInstall())
|
|
47
|
+
return `pnpm add -g ${pkg}`;
|
|
45
48
|
return `npm install -g ${pkg}`;
|
|
46
49
|
}
|
|
47
50
|
async function fetchLatestVersionForCommand() {
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// File Purpose: Detect and reconcile unresolved Git conflict state before automation runs.
|
|
3
3
|
import { spawnSync } from "node:child_process";
|
|
4
4
|
import { existsSync } from "node:fs";
|
|
5
|
-
import { join } from "node:path";
|
|
5
|
+
import { dirname, join, resolve } from "node:path";
|
|
6
6
|
import { autoResolveSafeConflictPaths } from "./git-conflict-resolve.js";
|
|
7
7
|
import { GIT_NO_PROMPT_ENV } from "./git-constants.js";
|
|
8
8
|
import { abortAndReset } from "./git-self-heal.js";
|
|
@@ -10,6 +10,23 @@ import { logWarning } from "./workflow-logger.js";
|
|
|
10
10
|
function splitZeroDelimited(output) {
|
|
11
11
|
return output.split("\0").filter(Boolean);
|
|
12
12
|
}
|
|
13
|
+
function hasGitMarker(basePath) {
|
|
14
|
+
try {
|
|
15
|
+
let dir = resolve(basePath);
|
|
16
|
+
for (let i = 0; i < 30; i++) {
|
|
17
|
+
if (existsSync(join(dir, ".git")))
|
|
18
|
+
return true;
|
|
19
|
+
const parent = dirname(dir);
|
|
20
|
+
if (parent === dir)
|
|
21
|
+
break;
|
|
22
|
+
dir = parent;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
// Fall through to the git probes, which will report unknown on failure.
|
|
27
|
+
}
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
13
30
|
export function listUnmergedGitPaths(basePath) {
|
|
14
31
|
try {
|
|
15
32
|
const output = spawnSync("git", ["diff", "--name-only", "--diff-filter=U", "-z"], {
|
|
@@ -57,6 +74,14 @@ export function listMergeStateBlockers(basePath) {
|
|
|
57
74
|
return MERGE_STATE_MARKERS.filter((marker) => existsSync(join(gitDir, marker)));
|
|
58
75
|
}
|
|
59
76
|
export function probeGitConflictState(basePath) {
|
|
77
|
+
if (!hasGitMarker(basePath)) {
|
|
78
|
+
return {
|
|
79
|
+
status: "clean",
|
|
80
|
+
unmerged: [],
|
|
81
|
+
checkFailures: [],
|
|
82
|
+
mergeStateBlockers: [],
|
|
83
|
+
};
|
|
84
|
+
}
|
|
60
85
|
const unmerged = listUnmergedGitPaths(basePath);
|
|
61
86
|
if (unmerged === null) {
|
|
62
87
|
return {
|
|
@@ -116,6 +116,15 @@ export async function handleCompleteTask(params, basePath) {
|
|
|
116
116
|
if (!params.milestoneId || typeof params.milestoneId !== "string" || params.milestoneId.trim() === "") {
|
|
117
117
|
return { error: "milestoneId is required and must be a non-empty string" };
|
|
118
118
|
}
|
|
119
|
+
if (!params.oneLiner || typeof params.oneLiner !== "string" || params.oneLiner.trim() === "") {
|
|
120
|
+
return { error: "oneLiner is required and must be a non-empty string" };
|
|
121
|
+
}
|
|
122
|
+
if (!params.narrative || typeof params.narrative !== "string" || params.narrative.trim() === "") {
|
|
123
|
+
return { error: "narrative is required and must be a non-empty string" };
|
|
124
|
+
}
|
|
125
|
+
if (!params.verification || typeof params.verification !== "string" || params.verification.trim() === "") {
|
|
126
|
+
return { error: "verification is required and must be a non-empty string" };
|
|
127
|
+
}
|
|
119
128
|
const artifactBasePath = resolveCanonicalMilestoneRoot(basePath, params.milestoneId);
|
|
120
129
|
// ── Ownership check (opt-in: only enforced when claim file exists) ──────
|
|
121
130
|
const ownershipErr = checkOwnership(artifactBasePath, taskUnitKey(params.milestoneId, params.sliceId, params.taskId), params.actorName);
|
|
@@ -238,6 +238,24 @@ export async function executeSummarySave(params, basePath = process.cwd()) {
|
|
|
238
238
|
};
|
|
239
239
|
}
|
|
240
240
|
}
|
|
241
|
+
function normalizeVerificationEvidence(evidence) {
|
|
242
|
+
return (evidence ?? []).map((entry) => typeof entry === "string"
|
|
243
|
+
? { command: entry, exitCode: -1, verdict: "unknown (coerced from string)", durationMs: 0 }
|
|
244
|
+
: entry);
|
|
245
|
+
}
|
|
246
|
+
function deriveVerificationSummary(evidence) {
|
|
247
|
+
if (evidence.length === 0)
|
|
248
|
+
return null;
|
|
249
|
+
const rendered = evidence.slice(0, 3).map((entry) => {
|
|
250
|
+
const command = entry.command.trim() || "(unspecified command)";
|
|
251
|
+
const verdict = entry.verdict.trim() || "recorded";
|
|
252
|
+
return `\`${command}\` exited ${entry.exitCode} (${verdict})`;
|
|
253
|
+
});
|
|
254
|
+
const suffix = evidence.length > rendered.length
|
|
255
|
+
? `; ${evidence.length - rendered.length} more check(s) recorded`
|
|
256
|
+
: "";
|
|
257
|
+
return `Verification evidence recorded: ${rendered.join("; ")}${suffix}.`;
|
|
258
|
+
}
|
|
241
259
|
export async function executeTaskComplete(params, basePath = process.cwd()) {
|
|
242
260
|
const dbAvailable = await ensureDbOpen(basePath);
|
|
243
261
|
if (!dbAvailable) {
|
|
@@ -249,7 +267,28 @@ export async function executeTaskComplete(params, basePath = process.cwd()) {
|
|
|
249
267
|
}
|
|
250
268
|
try {
|
|
251
269
|
const coerced = { ...params };
|
|
252
|
-
|
|
270
|
+
const verificationEvidence = normalizeVerificationEvidence(params.verificationEvidence);
|
|
271
|
+
coerced.verificationEvidence = verificationEvidence;
|
|
272
|
+
const verification = typeof params.verification === "string" ? params.verification.trim() : "";
|
|
273
|
+
if (verification.length === 0) {
|
|
274
|
+
const derived = deriveVerificationSummary(verificationEvidence);
|
|
275
|
+
if (derived) {
|
|
276
|
+
coerced.verification = derived;
|
|
277
|
+
}
|
|
278
|
+
else if (params.blockerDiscovered === true) {
|
|
279
|
+
coerced.verification = "Not run: blocker discovered before verification.";
|
|
280
|
+
}
|
|
281
|
+
else {
|
|
282
|
+
return {
|
|
283
|
+
content: [{
|
|
284
|
+
type: "text",
|
|
285
|
+
text: "Error completing task: verification is required unless verificationEvidence is provided or blockerDiscovered is true.",
|
|
286
|
+
}],
|
|
287
|
+
details: { operation: "complete_task", error: "verification_required" },
|
|
288
|
+
isError: true,
|
|
289
|
+
};
|
|
290
|
+
}
|
|
291
|
+
}
|
|
253
292
|
const result = await handleCompleteTask(coerced, basePath);
|
|
254
293
|
if ("error" in result) {
|
|
255
294
|
return {
|
|
@@ -203,7 +203,7 @@ function validateMilestoneId(milestoneId) {
|
|
|
203
203
|
* - emits worktree-created telemetry on successful entry
|
|
204
204
|
* - notifies the caller via `ctx.notify` for every user-visible outcome
|
|
205
205
|
*/
|
|
206
|
-
export function _enterMilestoneCore(s, deps, milestoneId, ctx) {
|
|
206
|
+
export function _enterMilestoneCore(s, deps, milestoneId, ctx, opts = {}) {
|
|
207
207
|
if (!isValidMilestoneId(milestoneId)) {
|
|
208
208
|
debugLog("WorktreeLifecycle", {
|
|
209
209
|
action: "enterMilestone",
|
|
@@ -305,7 +305,7 @@ export function _enterMilestoneCore(s, deps, milestoneId, ctx) {
|
|
|
305
305
|
// Handles the case where originalBasePath is falsy and basePath is itself
|
|
306
306
|
// a worktree path — prevents double-nested worktree paths (#3729).
|
|
307
307
|
const basePath = resolveWorktreeProjectRoot(s.basePath, s.originalBasePath);
|
|
308
|
-
const mode = getIsolationMode(basePath);
|
|
308
|
+
const mode = opts.modeOverride ?? getIsolationMode(basePath);
|
|
309
309
|
if (s.isolationDegraded) {
|
|
310
310
|
if (mode === "worktree") {
|
|
311
311
|
try {
|
|
@@ -841,7 +841,8 @@ export function mergeMilestoneStandalone(deps, mctx) {
|
|
|
841
841
|
pushed: false,
|
|
842
842
|
};
|
|
843
843
|
}
|
|
844
|
-
const mode =
|
|
844
|
+
const mode = mctx.isolationModeOverride ??
|
|
845
|
+
getIsolationMode(originalBasePath || worktreeBasePath);
|
|
845
846
|
debugLog("WorktreeLifecycle", {
|
|
846
847
|
action: "mergeAndExit",
|
|
847
848
|
milestoneId,
|
|
@@ -1137,6 +1138,7 @@ export class WorktreeLifecycle {
|
|
|
1137
1138
|
originalBasePath: this.s.originalBasePath,
|
|
1138
1139
|
worktreeBasePath: this.s.basePath,
|
|
1139
1140
|
milestoneId,
|
|
1141
|
+
isolationModeOverride: this.s.strandedRecoveryIsolationMode ?? undefined,
|
|
1140
1142
|
isolationDegraded: this.s.isolationDegraded,
|
|
1141
1143
|
notify: ctx.notify,
|
|
1142
1144
|
});
|
|
@@ -1223,6 +1225,7 @@ export class WorktreeLifecycle {
|
|
|
1223
1225
|
// Rebuild GitService after merge (branch HEAD changed)
|
|
1224
1226
|
rebuildGitService(this.s, this.deps);
|
|
1225
1227
|
}
|
|
1228
|
+
this.s.strandedRecoveryIsolationMode = null;
|
|
1226
1229
|
return result;
|
|
1227
1230
|
}
|
|
1228
1231
|
// ── Removed: _mergeWorktreeMode / _mergeBranchMode bodies ────────────
|
|
@@ -1345,6 +1348,24 @@ export class WorktreeLifecycle {
|
|
|
1345
1348
|
resumeFromPausedSession(base, persistedWorktreePath) {
|
|
1346
1349
|
this.s.basePath = resolvePausedResumeBasePath(base, persistedWorktreePath);
|
|
1347
1350
|
}
|
|
1351
|
+
/**
|
|
1352
|
+
* Adopt in-progress stranded work during bootstrap.
|
|
1353
|
+
*
|
|
1354
|
+
* Unlike completed-orphan recovery, this does not merge, delete, or commit.
|
|
1355
|
+
* It only moves the live session onto the branch/worktree proven by the
|
|
1356
|
+
* audit evidence, while preserving that mode for the eventual merge.
|
|
1357
|
+
*/
|
|
1358
|
+
adoptStrandedMilestone(milestoneId, base, ctx, opts) {
|
|
1359
|
+
this.adoptSessionRoot(base);
|
|
1360
|
+
this.s.strandedRecoveryIsolationMode = opts.mode;
|
|
1361
|
+
const result = _enterMilestoneCore(this.s, this.deps, milestoneId, ctx, {
|
|
1362
|
+
modeOverride: opts.mode,
|
|
1363
|
+
});
|
|
1364
|
+
if (!result.ok) {
|
|
1365
|
+
this.s.strandedRecoveryIsolationMode = null;
|
|
1366
|
+
}
|
|
1367
|
+
return result;
|
|
1368
|
+
}
|
|
1348
1369
|
/**
|
|
1349
1370
|
* Adopt an orphan worktree for a bootstrap-time merge (ADR-016 phase 2 / B4,
|
|
1350
1371
|
* issue #5622).
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
// Project/App: gsd-pi
|
|
2
|
+
// File Purpose: Lightweight worktree post-create hook runner.
|
|
3
|
+
import { execFileSync } from "node:child_process";
|
|
4
|
+
import { existsSync, readFileSync, realpathSync } from "node:fs";
|
|
5
|
+
import { homedir } from "node:os";
|
|
6
|
+
import { isAbsolute, join } from "node:path";
|
|
7
|
+
import { parse as parseYaml } from "yaml";
|
|
8
|
+
import { gsdHome } from "./gsd-home.js";
|
|
9
|
+
import { gsdRoot } from "./paths.js";
|
|
10
|
+
function readPreferencesObject(path) {
|
|
11
|
+
if (!existsSync(path))
|
|
12
|
+
return null;
|
|
13
|
+
const content = readFileSync(path, "utf-8");
|
|
14
|
+
try {
|
|
15
|
+
const startMarker = content.startsWith("---\r\n") ? "---\r\n" : "---\n";
|
|
16
|
+
if (content.startsWith(startMarker)) {
|
|
17
|
+
const searchStart = startMarker.length;
|
|
18
|
+
const endIdx = content.indexOf("\n---", searchStart);
|
|
19
|
+
if (endIdx === -1)
|
|
20
|
+
return null;
|
|
21
|
+
const parsed = parseYaml(content.slice(searchStart, endIdx).replace(/\r/g, ""));
|
|
22
|
+
return parsed && typeof parsed === "object" && !Array.isArray(parsed)
|
|
23
|
+
? parsed
|
|
24
|
+
: null;
|
|
25
|
+
}
|
|
26
|
+
const gitLines = [];
|
|
27
|
+
let inGitSection = false;
|
|
28
|
+
for (const rawLine of content.split("\n")) {
|
|
29
|
+
const line = rawLine.replace(/\r$/, "");
|
|
30
|
+
const heading = line.match(/^##\s+(.+)$/);
|
|
31
|
+
if (heading) {
|
|
32
|
+
inGitSection = heading[1].trim().toLowerCase().replace(/\s+/g, "_") === "git";
|
|
33
|
+
continue;
|
|
34
|
+
}
|
|
35
|
+
if (inGitSection && line.trim() && !line.trimStart().startsWith("#")) {
|
|
36
|
+
gitLines.push(line.replace(/^\s*-\s*/, ""));
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
if (gitLines.length === 0)
|
|
40
|
+
return null;
|
|
41
|
+
const parsed = parseYaml(gitLines.join("\n"));
|
|
42
|
+
return parsed && typeof parsed === "object" && !Array.isArray(parsed)
|
|
43
|
+
? { git: parsed }
|
|
44
|
+
: null;
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
function extractHookPath(preferences) {
|
|
51
|
+
const git = preferences?.git;
|
|
52
|
+
if (!git || typeof git !== "object" || Array.isArray(git))
|
|
53
|
+
return null;
|
|
54
|
+
const hookPath = git.worktree_post_create;
|
|
55
|
+
return typeof hookPath === "string" && hookPath.trim() ? hookPath : null;
|
|
56
|
+
}
|
|
57
|
+
function resolveConfiguredHookPath(sourceDir) {
|
|
58
|
+
const paths = [
|
|
59
|
+
join(homedir(), ".pi", "agent", "gsd-preferences.md"),
|
|
60
|
+
join(gsdHome(), "preferences.md"),
|
|
61
|
+
join(gsdHome(), "PREFERENCES.md"),
|
|
62
|
+
join(gsdRoot(sourceDir), "preferences.md"),
|
|
63
|
+
join(gsdRoot(sourceDir), "PREFERENCES.md"),
|
|
64
|
+
];
|
|
65
|
+
let hookPath = null;
|
|
66
|
+
for (const path of paths) {
|
|
67
|
+
hookPath = extractHookPath(readPreferencesObject(path)) ?? hookPath;
|
|
68
|
+
}
|
|
69
|
+
return hookPath;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Run the user-configured post-create hook script after worktree creation.
|
|
73
|
+
* The script receives SOURCE_DIR and WORKTREE_DIR as environment variables.
|
|
74
|
+
* Failure is non-fatal -- returns the error message or null on success.
|
|
75
|
+
*
|
|
76
|
+
* Reads git.worktree_post_create from effective global/project preferences
|
|
77
|
+
* unless hookPath is provided directly.
|
|
78
|
+
*/
|
|
79
|
+
export function runWorktreePostCreateHook(sourceDir, worktreeDir, hookPath) {
|
|
80
|
+
if (hookPath === undefined) {
|
|
81
|
+
hookPath = resolveConfiguredHookPath(sourceDir) ?? undefined;
|
|
82
|
+
}
|
|
83
|
+
if (!hookPath)
|
|
84
|
+
return null;
|
|
85
|
+
let resolved = isAbsolute(hookPath) ? hookPath : join(sourceDir, hookPath);
|
|
86
|
+
if (!existsSync(resolved)) {
|
|
87
|
+
return `Worktree post-create hook not found: ${resolved}`;
|
|
88
|
+
}
|
|
89
|
+
if (process.platform === "win32") {
|
|
90
|
+
try {
|
|
91
|
+
resolved = realpathSync.native(resolved);
|
|
92
|
+
}
|
|
93
|
+
catch {
|
|
94
|
+
// Keep the original path; the exec error below will include the failure.
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
try {
|
|
98
|
+
const needsShell = process.platform === "win32" && /\.(bat|cmd)$/i.test(resolved);
|
|
99
|
+
execFileSync(resolved, [], {
|
|
100
|
+
cwd: worktreeDir,
|
|
101
|
+
env: {
|
|
102
|
+
...process.env,
|
|
103
|
+
SOURCE_DIR: sourceDir,
|
|
104
|
+
WORKTREE_DIR: worktreeDir,
|
|
105
|
+
},
|
|
106
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
107
|
+
encoding: "utf-8",
|
|
108
|
+
timeout: 30_000,
|
|
109
|
+
shell: needsShell,
|
|
110
|
+
});
|
|
111
|
+
return null;
|
|
112
|
+
}
|
|
113
|
+
catch (err) {
|
|
114
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
115
|
+
return `Worktree post-create hook failed: ${msg}`;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
@@ -12,6 +12,45 @@ export const BRAVE_TOOL_NAMES = ["search-the-web", "search_and_read"];
|
|
|
12
12
|
export const CUSTOM_SEARCH_TOOL_NAMES = ["search-the-web", "search_and_read", "google_search"];
|
|
13
13
|
/** Thinking block types that require signature validation by the API */
|
|
14
14
|
const THINKING_TYPES = new Set(["thinking", "redacted_thinking"]);
|
|
15
|
+
const NATIVE_SERVER_TOOL_USE_TYPES = new Set([
|
|
16
|
+
"server_tool_use",
|
|
17
|
+
"serverToolUse",
|
|
18
|
+
]);
|
|
19
|
+
const NATIVE_WEB_SEARCH_RESULT_TYPES = new Set([
|
|
20
|
+
"web_search_tool_result",
|
|
21
|
+
"webSearchResult",
|
|
22
|
+
]);
|
|
23
|
+
function nativeServerToolId(block) {
|
|
24
|
+
if (!NATIVE_SERVER_TOOL_USE_TYPES.has(block?.type))
|
|
25
|
+
return undefined;
|
|
26
|
+
return typeof block.id === "string" ? block.id : undefined;
|
|
27
|
+
}
|
|
28
|
+
function nativeWebSearchResultId(block) {
|
|
29
|
+
if (!NATIVE_WEB_SEARCH_RESULT_TYPES.has(block?.type))
|
|
30
|
+
return undefined;
|
|
31
|
+
const id = block.type === "webSearchResult" ? block.toolUseId : block.tool_use_id;
|
|
32
|
+
return typeof id === "string" ? id : undefined;
|
|
33
|
+
}
|
|
34
|
+
function hasCompleteNativeServerToolReplay(content) {
|
|
35
|
+
const pendingToolUseIds = new Set();
|
|
36
|
+
let sawNativeServerToolUse = false;
|
|
37
|
+
for (const block of content) {
|
|
38
|
+
const toolUseId = nativeServerToolId(block);
|
|
39
|
+
if (toolUseId !== undefined) {
|
|
40
|
+
if (pendingToolUseIds.has(toolUseId))
|
|
41
|
+
return false;
|
|
42
|
+
sawNativeServerToolUse = true;
|
|
43
|
+
pendingToolUseIds.add(toolUseId);
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
const resultId = nativeWebSearchResultId(block);
|
|
47
|
+
if (resultId !== undefined) {
|
|
48
|
+
if (!pendingToolUseIds.delete(resultId))
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return sawNativeServerToolUse && pendingToolUseIds.size === 0;
|
|
53
|
+
}
|
|
15
54
|
/**
|
|
16
55
|
* Providers whose Anthropic-Messages endpoint is known to accept the native
|
|
17
56
|
* `web_search_20250305` server tool. Anthropic-shaped transports NOT in this
|
|
@@ -30,6 +69,10 @@ const NATIVE_WEB_SEARCH_PROVIDERS = new Set([
|
|
|
30
69
|
"anthropic-vertex",
|
|
31
70
|
"vercel-ai-gateway",
|
|
32
71
|
]);
|
|
72
|
+
function looksLikeAnthropicModelName(modelName) {
|
|
73
|
+
const normalized = modelName.trim().toLowerCase();
|
|
74
|
+
return normalized.startsWith("claude-") || normalized.startsWith("anthropic/claude-");
|
|
75
|
+
}
|
|
33
76
|
/**
|
|
34
77
|
* True when the model is an Anthropic-shaped transport AND the provider is
|
|
35
78
|
* known to accept the native `web_search_20250305` tool. Gate both on api
|
|
@@ -74,11 +117,10 @@ export function preferBraveSearch() {
|
|
|
74
117
|
* those blocks. The Anthropic API detects the modification and rejects the
|
|
75
118
|
* request with "thinking blocks cannot be modified."
|
|
76
119
|
*
|
|
77
|
-
* Fix: Remove thinking blocks from
|
|
78
|
-
*
|
|
79
|
-
*
|
|
80
|
-
*
|
|
81
|
-
* current turn regardless.
|
|
120
|
+
* Fix: Remove thinking blocks only from assistant messages that do not carry
|
|
121
|
+
* native server-tool blocks. Complete native server-tool histories can be
|
|
122
|
+
* replayed as-is; stripping thinking from those messages is itself a latest
|
|
123
|
+
* assistant message modification.
|
|
82
124
|
*/
|
|
83
125
|
export function stripThinkingFromHistory(messages) {
|
|
84
126
|
for (const msg of messages) {
|
|
@@ -87,6 +129,9 @@ export function stripThinkingFromHistory(messages) {
|
|
|
87
129
|
const content = msg.content;
|
|
88
130
|
if (!Array.isArray(content))
|
|
89
131
|
continue;
|
|
132
|
+
if (hasCompleteNativeServerToolReplay(content)) {
|
|
133
|
+
continue;
|
|
134
|
+
}
|
|
90
135
|
msg.content = content.filter((block) => !THINKING_TYPES.has(block?.type));
|
|
91
136
|
}
|
|
92
137
|
}
|
|
@@ -152,6 +197,8 @@ export function registerNativeSearchHooks(pi) {
|
|
|
152
197
|
// The model name heuristic is needed for session restores where
|
|
153
198
|
// modelsAreEqual suppresses model_select AND the SDK doesn't pass model.
|
|
154
199
|
const eventModel = event.model;
|
|
200
|
+
const payloadModelName = typeof payload.model === "string" ? payload.model : "";
|
|
201
|
+
const payloadLooksAnthropic = payloadModelName ? looksLikeAnthropicModelName(payloadModelName) : undefined;
|
|
155
202
|
let isAnthropic;
|
|
156
203
|
if (eventModel?.api || eventModel?.provider) {
|
|
157
204
|
// Preferred path: gate on api shape + provider allowlist. Both fields
|
|
@@ -161,13 +208,15 @@ export function registerNativeSearchHooks(pi) {
|
|
|
161
208
|
isAnthropic = supportsNativeWebSearch(eventModel);
|
|
162
209
|
}
|
|
163
210
|
else if (modelSelectFired) {
|
|
164
|
-
|
|
211
|
+
// The model_select flag can be stale if the next request omits event.model
|
|
212
|
+
// after a provider switch. A concrete non-Claude payload must win so an
|
|
213
|
+
// Anthropic-only tool never leaks into OpenAI Responses requests.
|
|
214
|
+
isAnthropic = isAnthropicProvider && payloadLooksAnthropic !== false;
|
|
165
215
|
}
|
|
166
216
|
else {
|
|
167
217
|
// Last resort: session-restore paths where the SDK doesn't pass model.
|
|
168
218
|
// The model-name prefix is best-effort and assumes direct Anthropic.
|
|
169
|
-
|
|
170
|
-
isAnthropic = modelName.startsWith("claude-");
|
|
219
|
+
isAnthropic = payloadLooksAnthropic === true;
|
|
171
220
|
}
|
|
172
221
|
if (!isAnthropic)
|
|
173
222
|
return;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { homedir } from 'node:os';
|
|
2
|
+
import { join, resolve as resolvePath, sep } from 'node:path';
|
|
3
|
+
function hasPnpmPath(value) {
|
|
4
|
+
if (!value)
|
|
5
|
+
return false;
|
|
6
|
+
const normalized = value.replace(/\\/g, '/').toLowerCase();
|
|
7
|
+
return (normalized.includes('/.pnpm/') ||
|
|
8
|
+
normalized.endsWith('/pnpm') ||
|
|
9
|
+
normalized.endsWith('/pnpm.cjs') ||
|
|
10
|
+
normalized.endsWith('/pnpm.js'));
|
|
11
|
+
}
|
|
12
|
+
function pathStartsWith(pathValue, dir) {
|
|
13
|
+
if (!pathValue)
|
|
14
|
+
return false;
|
|
15
|
+
const resolvedPath = resolvePath(pathValue);
|
|
16
|
+
const resolvedDir = resolvePath(dir);
|
|
17
|
+
return resolvedPath === resolvedDir || resolvedPath.startsWith(resolvedDir + sep);
|
|
18
|
+
}
|
|
19
|
+
// Shared by update-check.ts and gsd command handlers. The JS installer keeps a
|
|
20
|
+
// parallel copy because it runs before TypeScript output exists.
|
|
21
|
+
export function isPnpmInstall(argv1 = process.argv[1], env = process.env) {
|
|
22
|
+
if (env.npm_config_user_agent?.startsWith('pnpm/'))
|
|
23
|
+
return true;
|
|
24
|
+
if (hasPnpmPath(env.npm_execpath))
|
|
25
|
+
return true;
|
|
26
|
+
if (hasPnpmPath(argv1))
|
|
27
|
+
return true;
|
|
28
|
+
if (!argv1)
|
|
29
|
+
return false;
|
|
30
|
+
const pnpmBinDirs = [];
|
|
31
|
+
if (env.PNPM_HOME)
|
|
32
|
+
pnpmBinDirs.push(env.PNPM_HOME);
|
|
33
|
+
pnpmBinDirs.push(join(homedir(), 'Library', 'pnpm'));
|
|
34
|
+
pnpmBinDirs.push(join(homedir(), '.local', 'share', 'pnpm'));
|
|
35
|
+
return pnpmBinDirs.some((dir) => pathStartsWith(argv1, dir) || pathStartsWith(env.npm_execpath, dir));
|
|
36
|
+
}
|
package/dist/update-check.d.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { isPnpmInstall } from './resources/shared/package-manager-detection.js';
|
|
2
|
+
export { isPnpmInstall };
|
|
1
3
|
interface UpdateCheckCache {
|
|
2
4
|
lastCheck: number;
|
|
3
5
|
latestVersion: string;
|
|
@@ -22,7 +24,10 @@ export declare function fetchLatestVersionFromRegistry(registryUrl?: string, fet
|
|
|
22
24
|
* (PR #4147) misses this path. Inspect the unresolved invocation path instead.
|
|
23
25
|
*/
|
|
24
26
|
export declare function isBunInstall(argv1?: string | undefined): boolean;
|
|
25
|
-
export declare function resolveInstallCommand(pkg: string
|
|
27
|
+
export declare function resolveInstallCommand(pkg: string, options?: {
|
|
28
|
+
argv1?: string;
|
|
29
|
+
env?: NodeJS.ProcessEnv;
|
|
30
|
+
}): string;
|
|
26
31
|
export interface UpdateCheckOptions {
|
|
27
32
|
currentVersion?: string;
|
|
28
33
|
cachePath?: string;
|
|
@@ -45,4 +50,3 @@ export declare function checkForUpdates(options?: UpdateCheckOptions): Promise<v
|
|
|
45
50
|
* Returns true if an update was performed, false otherwise.
|
|
46
51
|
*/
|
|
47
52
|
export declare function checkAndPromptForUpdates(options?: UpdateCheckOptions): Promise<boolean>;
|
|
48
|
-
export {};
|
package/dist/update-check.js
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { existsSync, readFileSync, writeFileSync, mkdirSync } from 'node:fs';
|
|
2
|
+
import { execSync } from 'node:child_process';
|
|
2
3
|
import { dirname, join, resolve as resolvePath, sep } from 'node:path';
|
|
3
4
|
import { homedir } from 'node:os';
|
|
4
5
|
import chalk from 'chalk';
|
|
5
6
|
import { appRoot } from './app-paths.js';
|
|
6
|
-
import {
|
|
7
|
+
import { isPnpmInstall } from './resources/shared/package-manager-detection.js';
|
|
8
|
+
export { isPnpmInstall };
|
|
7
9
|
const CACHE_FILE = join(appRoot, '.update-check');
|
|
8
10
|
const NPM_PACKAGE_NAME = '@opengsd/gsd-pi';
|
|
9
11
|
const CHECK_INTERVAL_MS = 24 * 60 * 60 * 1000; // 24 hours
|
|
@@ -91,9 +93,11 @@ export function isBunInstall(argv1 = process.argv[1]) {
|
|
|
91
93
|
const resolved = resolvePath(argv1);
|
|
92
94
|
return bunBinDirs.some((dir) => resolved.startsWith(resolvePath(dir) + sep));
|
|
93
95
|
}
|
|
94
|
-
export function resolveInstallCommand(pkg) {
|
|
95
|
-
if (isBunInstall())
|
|
96
|
+
export function resolveInstallCommand(pkg, options = {}) {
|
|
97
|
+
if (isBunInstall(options.argv1))
|
|
96
98
|
return `bun add -g ${pkg}`;
|
|
99
|
+
if (isPnpmInstall(options.argv1, options.env))
|
|
100
|
+
return `pnpm add -g ${pkg}`;
|
|
97
101
|
return `npm install -g ${pkg}`;
|
|
98
102
|
}
|
|
99
103
|
function printUpdateBanner(current, latest) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
mijI90BL1BdUcMUnhC0HU
|
|
@@ -1,27 +1,27 @@
|
|
|
1
1
|
{
|
|
2
2
|
"/_not-found/page": "/_not-found",
|
|
3
3
|
"/_global-error/page": "/_global-error",
|
|
4
|
-
"/api/bridge-terminal/resize/route": "/api/bridge-terminal/resize",
|
|
5
4
|
"/api/boot/route": "/api/boot",
|
|
5
|
+
"/api/bridge-terminal/input/route": "/api/bridge-terminal/input",
|
|
6
|
+
"/api/bridge-terminal/resize/route": "/api/bridge-terminal/resize",
|
|
6
7
|
"/api/bridge-terminal/stream/route": "/api/bridge-terminal/stream",
|
|
8
|
+
"/api/browse-directories/route": "/api/browse-directories",
|
|
9
|
+
"/api/cleanup/route": "/api/cleanup",
|
|
7
10
|
"/api/captures/route": "/api/captures",
|
|
8
11
|
"/api/dev-mode/route": "/api/dev-mode",
|
|
9
|
-
"/api/cleanup/route": "/api/cleanup",
|
|
10
|
-
"/api/browse-directories/route": "/api/browse-directories",
|
|
11
|
-
"/api/bridge-terminal/input/route": "/api/bridge-terminal/input",
|
|
12
12
|
"/api/doctor/route": "/api/doctor",
|
|
13
13
|
"/api/export-data/route": "/api/export-data",
|
|
14
|
-
"/api/experimental/route": "/api/experimental",
|
|
15
14
|
"/api/forensics/route": "/api/forensics",
|
|
16
15
|
"/api/git/route": "/api/git",
|
|
16
|
+
"/api/experimental/route": "/api/experimental",
|
|
17
17
|
"/api/history/route": "/api/history",
|
|
18
18
|
"/api/hooks/route": "/api/hooks",
|
|
19
19
|
"/api/inspect/route": "/api/inspect",
|
|
20
20
|
"/api/knowledge/route": "/api/knowledge",
|
|
21
21
|
"/api/live-state/route": "/api/live-state",
|
|
22
|
-
"/api/files/route": "/api/files",
|
|
23
22
|
"/api/mcp-connections/route": "/api/mcp-connections",
|
|
24
23
|
"/api/notifications/route": "/api/notifications",
|
|
24
|
+
"/api/files/route": "/api/files",
|
|
25
25
|
"/api/onboarding/route": "/api/onboarding",
|
|
26
26
|
"/api/preferences/route": "/api/preferences",
|
|
27
27
|
"/api/recovery/route": "/api/recovery",
|
|
@@ -29,8 +29,8 @@
|
|
|
29
29
|
"/api/session/browser/route": "/api/session/browser",
|
|
30
30
|
"/api/session/command/route": "/api/session/command",
|
|
31
31
|
"/api/session/events/route": "/api/session/events",
|
|
32
|
-
"/api/settings-data/route": "/api/settings-data",
|
|
33
32
|
"/api/session/manage/route": "/api/session/manage",
|
|
33
|
+
"/api/settings-data/route": "/api/settings-data",
|
|
34
34
|
"/api/shutdown/route": "/api/shutdown",
|
|
35
35
|
"/api/skill-health/route": "/api/skill-health",
|
|
36
36
|
"/api/remote-questions/route": "/api/remote-questions",
|
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
],
|
|
5
5
|
"devFiles": [],
|
|
6
6
|
"lowPriorityFiles": [
|
|
7
|
-
"static
|
|
8
|
-
"static
|
|
7
|
+
"static/mijI90BL1BdUcMUnhC0HU/_buildManifest.js",
|
|
8
|
+
"static/mijI90BL1BdUcMUnhC0HU/_ssgManifest.js"
|
|
9
9
|
],
|
|
10
10
|
"rootMainFiles": [
|
|
11
11
|
"static/chunks/webpack-41a6d3c17ba63b62.js",
|
|
@@ -78,8 +78,8 @@
|
|
|
78
78
|
"dynamicRoutes": {},
|
|
79
79
|
"notFoundRoutes": [],
|
|
80
80
|
"preview": {
|
|
81
|
-
"previewModeId": "
|
|
82
|
-
"previewModeSigningKey": "
|
|
83
|
-
"previewModeEncryptionKey": "
|
|
81
|
+
"previewModeId": "b0c8967ff02bb3be0998b3c2be0d6bec",
|
|
82
|
+
"previewModeSigningKey": "6e4615d1d87113363594bc054198319a74821f3b9e5242aad52e96e18261e56c",
|
|
83
|
+
"previewModeEncryptionKey": "5658cf050af19d64a3d3d918a64d88f5d24b6eaaec39c243ab405d032f435c0b"
|
|
84
84
|
}
|
|
85
85
|
}
|