gsd-pi 2.72.0-dev.3159350 → 2.72.0-dev.4f3264a

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (189) hide show
  1. package/dist/resources/extensions/async-jobs/await-tool.js +4 -7
  2. package/dist/resources/extensions/async-jobs/job-manager.js +3 -28
  3. package/dist/resources/extensions/claude-code-cli/stream-adapter.js +26 -27
  4. package/dist/resources/extensions/gsd/auto/loop.js +1 -84
  5. package/dist/resources/extensions/gsd/auto-observability.js +54 -0
  6. package/dist/resources/extensions/gsd/auto-post-unit.js +0 -6
  7. package/dist/resources/extensions/gsd/auto.js +19 -25
  8. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +11 -9
  9. package/dist/resources/extensions/gsd/commands-handlers.js +1 -4
  10. package/dist/resources/extensions/gsd/context-injector.js +1 -1
  11. package/dist/resources/extensions/gsd/custom-workflow-engine.js +7 -3
  12. package/dist/resources/extensions/gsd/file-watcher.js +80 -0
  13. package/dist/resources/extensions/gsd/gsd-db.js +5 -47
  14. package/dist/resources/extensions/gsd/key-manager.js +0 -2
  15. package/dist/resources/extensions/gsd/preferences-skills.js +34 -2
  16. package/dist/resources/extensions/gsd/preferences-types.js +0 -15
  17. package/dist/resources/extensions/gsd/preferences.js +3 -16
  18. package/dist/resources/extensions/gsd/prompt-loader.js +1 -4
  19. package/dist/resources/extensions/gsd/rtk-status.js +43 -0
  20. package/dist/resources/extensions/gsd/state.js +1 -21
  21. package/dist/resources/extensions/gsd/write-intercept.js +1 -10
  22. package/dist/resources/extensions/ollama/index.js +5 -4
  23. package/dist/resources/extensions/ollama/ollama-client.js +6 -35
  24. package/dist/resources/extensions/ollama/ollama-discovery.js +6 -32
  25. package/dist/web/standalone/.next/BUILD_ID +1 -1
  26. package/dist/web/standalone/.next/app-path-routes-manifest.json +11 -11
  27. package/dist/web/standalone/.next/build-manifest.json +2 -2
  28. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  29. package/dist/web/standalone/.next/server/app/_global-error/page.js +3 -3
  30. package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  31. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  32. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  33. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  34. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  35. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  36. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  37. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  38. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  39. package/dist/web/standalone/.next/server/app/_not-found/page.js +2 -2
  40. package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  41. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  42. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  43. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  44. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  45. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  46. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  47. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  48. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  49. package/dist/web/standalone/.next/server/app/api/boot/route.js +1 -1
  50. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js +1 -1
  51. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js +1 -1
  52. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js +2 -2
  53. package/dist/web/standalone/.next/server/app/api/browse-directories/route.js +1 -1
  54. package/dist/web/standalone/.next/server/app/api/captures/route.js +1 -1
  55. package/dist/web/standalone/.next/server/app/api/cleanup/route.js +1 -1
  56. package/dist/web/standalone/.next/server/app/api/dev-mode/route.js +1 -1
  57. package/dist/web/standalone/.next/server/app/api/doctor/route.js +1 -1
  58. package/dist/web/standalone/.next/server/app/api/experimental/route.js +2 -2
  59. package/dist/web/standalone/.next/server/app/api/export-data/route.js +1 -1
  60. package/dist/web/standalone/.next/server/app/api/files/route.js +1 -1
  61. package/dist/web/standalone/.next/server/app/api/forensics/route.js +1 -1
  62. package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
  63. package/dist/web/standalone/.next/server/app/api/history/route.js +1 -1
  64. package/dist/web/standalone/.next/server/app/api/hooks/route.js +1 -1
  65. package/dist/web/standalone/.next/server/app/api/inspect/route.js +1 -1
  66. package/dist/web/standalone/.next/server/app/api/knowledge/route.js +1 -1
  67. package/dist/web/standalone/.next/server/app/api/live-state/route.js +1 -1
  68. package/dist/web/standalone/.next/server/app/api/notifications/route.js +2 -2
  69. package/dist/web/standalone/.next/server/app/api/onboarding/route.js +1 -1
  70. package/dist/web/standalone/.next/server/app/api/preferences/route.js +1 -1
  71. package/dist/web/standalone/.next/server/app/api/projects/route.js +1 -1
  72. package/dist/web/standalone/.next/server/app/api/recovery/route.js +1 -1
  73. package/dist/web/standalone/.next/server/app/api/remote-questions/route.js +2 -2
  74. package/dist/web/standalone/.next/server/app/api/session/browser/route.js +1 -1
  75. package/dist/web/standalone/.next/server/app/api/session/command/route.js +1 -1
  76. package/dist/web/standalone/.next/server/app/api/session/events/route.js +2 -2
  77. package/dist/web/standalone/.next/server/app/api/session/manage/route.js +1 -1
  78. package/dist/web/standalone/.next/server/app/api/settings-data/route.js +1 -1
  79. package/dist/web/standalone/.next/server/app/api/shutdown/route.js +1 -1
  80. package/dist/web/standalone/.next/server/app/api/skill-health/route.js +1 -1
  81. package/dist/web/standalone/.next/server/app/api/steer/route.js +1 -1
  82. package/dist/web/standalone/.next/server/app/api/switch-root/route.js +1 -1
  83. package/dist/web/standalone/.next/server/app/api/terminal/input/route.js +2 -2
  84. package/dist/web/standalone/.next/server/app/api/terminal/resize/route.js +2 -2
  85. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js +2 -2
  86. package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js +3 -3
  87. package/dist/web/standalone/.next/server/app/api/terminal/upload/route.js +1 -1
  88. package/dist/web/standalone/.next/server/app/api/undo/route.js +1 -1
  89. package/dist/web/standalone/.next/server/app/api/update/route.js +1 -1
  90. package/dist/web/standalone/.next/server/app/api/visualizer/route.js +1 -1
  91. package/dist/web/standalone/.next/server/app/index.html +1 -1
  92. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  93. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  94. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  95. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  96. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  97. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  98. package/dist/web/standalone/.next/server/app/page.js +2 -2
  99. package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  100. package/dist/web/standalone/.next/server/app-paths-manifest.json +11 -11
  101. package/dist/web/standalone/.next/server/chunks/2331.js +16 -16
  102. package/dist/web/standalone/.next/server/chunks/4741.js +12 -12
  103. package/dist/web/standalone/.next/server/chunks/5822.js +2 -2
  104. package/dist/web/standalone/.next/server/chunks/63.js +8 -8
  105. package/dist/web/standalone/.next/server/chunks/6897.js +3 -3
  106. package/dist/web/standalone/.next/server/functions-config-manifest.json +9 -0
  107. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  108. package/dist/web/standalone/.next/server/middleware-manifest.json +2 -29
  109. package/dist/web/standalone/.next/server/middleware.js +12 -4
  110. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  111. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  112. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  113. package/dist/web/standalone/.next/server/webpack-runtime.js +1 -1
  114. package/package.json +1 -1
  115. package/packages/pi-ai/dist/env-api-keys.js +0 -1
  116. package/packages/pi-ai/dist/env-api-keys.js.map +1 -1
  117. package/packages/pi-ai/dist/models.custom.d.ts +0 -105
  118. package/packages/pi-ai/dist/models.custom.d.ts.map +1 -1
  119. package/packages/pi-ai/dist/models.custom.js +0 -97
  120. package/packages/pi-ai/dist/models.custom.js.map +1 -1
  121. package/packages/pi-ai/dist/models.generated.d.ts +140 -648
  122. package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
  123. package/packages/pi-ai/dist/models.generated.js +364 -861
  124. package/packages/pi-ai/dist/models.generated.js.map +1 -1
  125. package/packages/pi-ai/dist/models.test.js +0 -105
  126. package/packages/pi-ai/dist/models.test.js.map +1 -1
  127. package/packages/pi-ai/dist/types.d.ts +1 -1
  128. package/packages/pi-ai/dist/types.d.ts.map +1 -1
  129. package/packages/pi-ai/dist/types.js.map +1 -1
  130. package/packages/pi-ai/src/env-api-keys.ts +0 -1
  131. package/packages/pi-ai/src/models.custom.ts +0 -98
  132. package/packages/pi-ai/src/models.generated.ts +364 -861
  133. package/packages/pi-ai/src/models.test.ts +0 -135
  134. package/packages/pi-ai/src/types.ts +0 -1
  135. package/packages/pi-coding-agent/dist/core/model-resolver.d.ts.map +1 -1
  136. package/packages/pi-coding-agent/dist/core/model-resolver.js +0 -1
  137. package/packages/pi-coding-agent/dist/core/model-resolver.js.map +1 -1
  138. package/packages/pi-coding-agent/src/core/model-resolver.ts +0 -1
  139. package/src/resources/extensions/async-jobs/await-tool.test.ts +7 -40
  140. package/src/resources/extensions/async-jobs/await-tool.ts +4 -7
  141. package/src/resources/extensions/async-jobs/job-manager.ts +3 -33
  142. package/src/resources/extensions/claude-code-cli/stream-adapter.ts +26 -27
  143. package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +2 -20
  144. package/src/resources/extensions/gsd/auto/loop.ts +1 -89
  145. package/src/resources/extensions/gsd/auto-observability.ts +72 -0
  146. package/src/resources/extensions/gsd/auto-post-unit.ts +0 -7
  147. package/src/resources/extensions/gsd/auto.ts +20 -25
  148. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +10 -8
  149. package/src/resources/extensions/gsd/commands-handlers.ts +1 -5
  150. package/src/resources/extensions/gsd/context-injector.ts +1 -1
  151. package/src/resources/extensions/gsd/custom-workflow-engine.ts +8 -4
  152. package/src/resources/extensions/gsd/file-watcher.ts +100 -0
  153. package/src/resources/extensions/gsd/gsd-db.ts +5 -52
  154. package/src/resources/extensions/gsd/key-manager.ts +0 -2
  155. package/src/resources/extensions/gsd/preferences-skills.ts +36 -2
  156. package/src/resources/extensions/gsd/preferences-types.ts +0 -16
  157. package/src/resources/extensions/gsd/preferences.ts +6 -19
  158. package/src/resources/extensions/gsd/prompt-loader.ts +1 -6
  159. package/src/resources/extensions/gsd/rtk-status.ts +53 -0
  160. package/src/resources/extensions/gsd/state.ts +0 -20
  161. package/src/resources/extensions/gsd/tests/gsd-db.test.ts +0 -74
  162. package/src/resources/extensions/gsd/tests/key-manager.test.ts +0 -63
  163. package/src/resources/extensions/gsd/tests/preferences.test.ts +0 -53
  164. package/src/resources/extensions/gsd/write-intercept.ts +1 -10
  165. package/src/resources/extensions/ollama/index.ts +5 -4
  166. package/src/resources/extensions/ollama/ollama-client.ts +6 -35
  167. package/src/resources/extensions/ollama/ollama-discovery.ts +6 -37
  168. package/src/resources/extensions/ollama/tests/ollama-discovery.test.ts +0 -54
  169. package/dist/resources/extensions/gsd/definition-io.js +0 -15
  170. package/dist/web/standalone/.next/server/edge-runtime-webpack.js +0 -2
  171. package/packages/pi-ai/dist/models.generated.test.d.ts +0 -2
  172. package/packages/pi-ai/dist/models.generated.test.d.ts.map +0 -1
  173. package/packages/pi-ai/dist/models.generated.test.js +0 -334
  174. package/packages/pi-ai/dist/models.generated.test.js.map +0 -1
  175. package/packages/pi-ai/src/models.generated.test.ts +0 -373
  176. package/src/resources/extensions/gsd/definition-io.ts +0 -18
  177. package/src/resources/extensions/gsd/tests/auto-paused-ui-cleanup.test.ts +0 -27
  178. package/src/resources/extensions/gsd/tests/block-db-writes.test.ts +0 -63
  179. package/src/resources/extensions/gsd/tests/definition-io.test.ts +0 -57
  180. package/src/resources/extensions/gsd/tests/doctor-heal-fixable-warnings.test.ts +0 -14
  181. package/src/resources/extensions/gsd/tests/false-degraded-mode-warning.test.ts +0 -104
  182. package/src/resources/extensions/gsd/tests/memory-pressure-stuck-state.test.ts +0 -54
  183. package/src/resources/extensions/gsd/tests/post-unit-state-rebuild.test.ts +0 -34
  184. package/src/resources/extensions/gsd/tests/preferences-formatting.test.ts +0 -87
  185. package/src/resources/extensions/gsd/tests/prompt-loader-working-directory.test.ts +0 -19
  186. package/src/resources/extensions/gsd/tests/register-hooks-depth-verification.test.ts +0 -97
  187. package/src/resources/extensions/gsd/tests/stale-slice-rows.test.ts +0 -41
  188. /package/dist/web/standalone/.next/static/{eR2tLKungpmiiOyUIhqjF → vr6Pbde48w4rMUplqDdh_}/_buildManifest.js +0 -0
  189. /package/dist/web/standalone/.next/static/{eR2tLKungpmiiOyUIhqjF → vr6Pbde48w4rMUplqDdh_}/_ssgManifest.js +0 -0
@@ -121,25 +121,6 @@ function openRawDb(path) {
121
121
  return new Database(path);
122
122
  }
123
123
  const SCHEMA_VERSION = 14;
124
- function indexExists(db, name) {
125
- return !!db.prepare("SELECT 1 as present FROM sqlite_master WHERE type = 'index' AND name = ?").get(name);
126
- }
127
- function dedupeVerificationEvidenceRows(db) {
128
- db.exec(`
129
- DELETE FROM verification_evidence
130
- WHERE rowid NOT IN (
131
- SELECT MIN(rowid)
132
- FROM verification_evidence
133
- GROUP BY task_id, slice_id, milestone_id, command, verdict
134
- )
135
- `);
136
- }
137
- function ensureVerificationEvidenceDedupIndex(db) {
138
- if (indexExists(db, "idx_verification_evidence_dedup"))
139
- return;
140
- dedupeVerificationEvidenceRows(db);
141
- db.exec("CREATE UNIQUE INDEX IF NOT EXISTS idx_verification_evidence_dedup ON verification_evidence(task_id, slice_id, milestone_id, command, verdict)");
142
- }
143
124
  function initSchema(db, fileBacked) {
144
125
  if (fileBacked)
145
126
  db.exec("PRAGMA journal_mode=WAL");
@@ -377,7 +358,7 @@ function initSchema(db, fileBacked) {
377
358
  db.exec("CREATE INDEX IF NOT EXISTS idx_milestones_status ON milestones(status)");
378
359
  db.exec("CREATE INDEX IF NOT EXISTS idx_quality_gates_pending ON quality_gates(milestone_id, slice_id, status)");
379
360
  db.exec("CREATE INDEX IF NOT EXISTS idx_verification_evidence_task ON verification_evidence(milestone_id, slice_id, task_id)");
380
- ensureVerificationEvidenceDedupIndex(db);
361
+ db.exec("CREATE UNIQUE INDEX IF NOT EXISTS idx_verification_evidence_dedup ON verification_evidence(task_id, slice_id, milestone_id, command, verdict)");
381
362
  // v14 index — slice dependency lookups
382
363
  db.exec("CREATE INDEX IF NOT EXISTS idx_slice_deps_target ON slice_dependencies(milestone_id, depends_on_slice_id)");
383
364
  db.exec(`CREATE VIEW IF NOT EXISTS active_decisions AS SELECT * FROM decisions WHERE superseded_by IS NULL`);
@@ -687,7 +668,7 @@ function migrateSchema(db) {
687
668
  db.exec("CREATE INDEX IF NOT EXISTS idx_milestones_status ON milestones(status)");
688
669
  db.exec("CREATE INDEX IF NOT EXISTS idx_quality_gates_pending ON quality_gates(milestone_id, slice_id, status)");
689
670
  db.exec("CREATE INDEX IF NOT EXISTS idx_verification_evidence_task ON verification_evidence(milestone_id, slice_id, task_id)");
690
- ensureVerificationEvidenceDedupIndex(db);
671
+ db.exec("CREATE UNIQUE INDEX IF NOT EXISTS idx_verification_evidence_dedup ON verification_evidence(task_id, slice_id, milestone_id, command, verdict)");
691
672
  db.prepare("INSERT INTO schema_version (version, applied_at) VALUES (:version, :applied_at)").run({
692
673
  ":version": 13,
693
674
  ":applied_at": new Date().toISOString(),
@@ -1353,29 +1334,6 @@ export function setSliceSummaryMd(milestoneId, sliceId, summaryMd, uatMd) {
1353
1334
  currentDb.prepare(`UPDATE slices SET full_summary_md = :summary_md, full_uat_md = :uat_md WHERE milestone_id = :mid AND id = :sid`).run({ ":mid": milestoneId, ":sid": sliceId, ":summary_md": summaryMd, ":uat_md": uatMd });
1354
1335
  }
1355
1336
  function rowToTask(row) {
1356
- const parseTaskArray = (value) => {
1357
- if (Array.isArray(value)) {
1358
- return value.filter((entry) => typeof entry === "string");
1359
- }
1360
- if (typeof value !== "string")
1361
- return [];
1362
- const trimmed = value.trim();
1363
- if (!trimmed)
1364
- return [];
1365
- try {
1366
- const parsed = JSON.parse(trimmed);
1367
- if (Array.isArray(parsed)) {
1368
- return parsed.filter((entry) => typeof entry === "string");
1369
- }
1370
- if (typeof parsed === "string" && parsed.trim()) {
1371
- return [parsed.trim()];
1372
- }
1373
- }
1374
- catch {
1375
- // Older/corrupt DB rows may contain raw comma-separated paths instead of JSON arrays.
1376
- }
1377
- return trimmed.split(",").map((entry) => entry.trim()).filter(Boolean);
1378
- };
1379
1337
  return {
1380
1338
  milestone_id: row["milestone_id"],
1381
1339
  slice_id: row["slice_id"],
@@ -1395,10 +1353,10 @@ function rowToTask(row) {
1395
1353
  full_summary_md: row["full_summary_md"],
1396
1354
  description: row["description"] ?? "",
1397
1355
  estimate: row["estimate"] ?? "",
1398
- files: parseTaskArray(row["files"]),
1356
+ files: JSON.parse(row["files"] || "[]"),
1399
1357
  verify: row["verify"] ?? "",
1400
- inputs: parseTaskArray(row["inputs"]),
1401
- expected_output: parseTaskArray(row["expected_output"]),
1358
+ inputs: JSON.parse(row["inputs"] || "[]"),
1359
+ expected_output: JSON.parse(row["expected_output"] || "[]"),
1402
1360
  observability_impact: row["observability_impact"] ?? "",
1403
1361
  full_plan_md: row["full_plan_md"] ?? "",
1404
1362
  sequence: row["sequence"] ?? 0,
@@ -26,8 +26,6 @@ export const PROVIDER_REGISTRY = [
26
26
  { id: "custom-openai", label: "Custom (OpenAI-compat)", category: "llm", envVar: "CUSTOM_OPENAI_API_KEY" },
27
27
  { id: "cerebras", label: "Cerebras", category: "llm", envVar: "CEREBRAS_API_KEY" },
28
28
  { id: "azure-openai-responses", label: "Azure OpenAI", category: "llm", envVar: "AZURE_OPENAI_API_KEY" },
29
- { id: "alibaba-coding-plan", label: "Alibaba Coding Plan", category: "llm", envVar: "ALIBABA_API_KEY", dashboardUrl: "bailian.console.aliyun.com" },
30
- { id: "alibaba-dashscope", label: "Alibaba DashScope", category: "llm", envVar: "DASHSCOPE_API_KEY", dashboardUrl: "dashscope.console.aliyun.com" },
31
29
  // Tool Keys
32
30
  { id: "context7", label: "Context7 Docs", category: "tool", envVar: "CONTEXT7_API_KEY", dashboardUrl: "context7.com/dashboard" },
33
31
  { id: "jina", label: "Jina Page Extract", category: "tool", envVar: "JINA_API_KEY", dashboardUrl: "jina.ai/api" },
@@ -9,6 +9,7 @@ import { homedir } from "node:os";
9
9
  import { isAbsolute, join } from "node:path";
10
10
  import { statSync } from "node:fs";
11
11
  import { validatePreferences } from "./preferences-validation.js";
12
+ import { loadEffectiveGSDPreferences } from "./preferences.js";
12
13
  /**
13
14
  * Known skill directories, in priority order.
14
15
  * Searches both the skills.sh ecosystem directory (~/.agents/skills/) and
@@ -129,5 +130,36 @@ export function resolveAllSkillReferences(preferences, cwd) {
129
130
  }
130
131
  return { resolutions, warnings };
131
132
  }
132
- // resolveSkillDiscoveryMode and resolveSkillStalenessDays moved to
133
- // preferences.ts to break circular dependency (they need loadEffectiveGSDPreferences).
133
+ /**
134
+ * Format a skill reference for the system prompt.
135
+ * If resolved, shows the path so the agent knows exactly where to read.
136
+ * If unresolved, marks it clearly.
137
+ */
138
+ export function formatSkillRef(ref, resolutions) {
139
+ const resolution = resolutions.get(ref);
140
+ if (!resolution || resolution.method === "unresolved") {
141
+ return `${ref} (⚠ not found — check skill name or path)`;
142
+ }
143
+ // For absolute paths where SKILL.md is just appended, don't clutter the output
144
+ if (resolution.method === "absolute-path" || resolution.method === "absolute-dir") {
145
+ return ref;
146
+ }
147
+ // For bare names resolved from skill directories, show the resolved path
148
+ return `${ref} → \`${resolution.resolvedPath}\``;
149
+ }
150
+ /**
151
+ * Resolve the skill discovery mode from effective preferences.
152
+ * Defaults to "suggest" -- skills are identified during research but not installed automatically.
153
+ */
154
+ export function resolveSkillDiscoveryMode() {
155
+ const prefs = loadEffectiveGSDPreferences();
156
+ return prefs?.preferences.skill_discovery ?? "suggest";
157
+ }
158
+ /**
159
+ * Resolve the skill staleness threshold in days.
160
+ * Returns 0 if disabled, default 60 if not configured.
161
+ */
162
+ export function resolveSkillStalenessDays() {
163
+ const prefs = loadEffectiveGSDPreferences();
164
+ return prefs?.preferences.skill_staleness_days ?? 60;
165
+ }
@@ -92,18 +92,3 @@ export const KNOWN_UNIT_TYPES = [
92
92
  "discuss-milestone", "discuss-slice", "worktree-merge",
93
93
  ];
94
94
  export const SKILL_ACTIONS = new Set(["use", "prefer", "avoid"]);
95
- /**
96
- * Format a skill reference for the system prompt.
97
- * If resolved, shows the path so the agent knows exactly where to read.
98
- * If unresolved, marks it clearly.
99
- */
100
- export function formatSkillRef(ref, resolutions) {
101
- const resolution = resolutions.get(ref);
102
- if (!resolution || resolution.method === "unresolved") {
103
- return `${ref} (⚠ not found — check skill name or path)`;
104
- }
105
- if (resolution.method === "absolute-path" || resolution.method === "absolute-dir") {
106
- return ref;
107
- }
108
- return `${ref} → \`${resolution.resolvedPath}\``;
109
- }
@@ -17,23 +17,13 @@ import { parse as parseYaml } from "yaml";
17
17
  import { normalizeStringArray } from "../shared/format-utils.js";
18
18
  import { logWarning } from "./workflow-logger.js";
19
19
  import { resolveProfileDefaults as _resolveProfileDefaults } from "./preferences-models.js";
20
- import { KNOWN_PREFERENCE_KEYS, MODE_DEFAULTS, formatSkillRef, } from "./preferences-types.js";
20
+ import { KNOWN_PREFERENCE_KEYS, MODE_DEFAULTS, } from "./preferences-types.js";
21
21
  import { validatePreferences } from "./preferences-validation.js";
22
+ import { formatSkillRef } from "./preferences-skills.js";
22
23
  // ─── Re-exports: validation ─────────────────────────────────────────────────
23
24
  export { validatePreferences } from "./preferences-validation.js";
24
25
  // ─── Re-exports: skills ─────────────────────────────────────────────────────
25
- export { resolveAllSkillReferences } from "./preferences-skills.js";
26
- // These lived in preferences-skills.ts but imported loadEffectiveGSDPreferences
27
- // back from this file, creating a circular dependency. Moved here since they
28
- // are trivial wrappers over loadEffectiveGSDPreferences.
29
- export function resolveSkillDiscoveryMode() {
30
- const prefs = loadEffectiveGSDPreferences();
31
- return prefs?.preferences.skill_discovery ?? "suggest";
32
- }
33
- export function resolveSkillStalenessDays() {
34
- const prefs = loadEffectiveGSDPreferences();
35
- return prefs?.preferences.skill_staleness_days ?? 60;
36
- }
26
+ export { resolveAllSkillReferences, resolveSkillDiscoveryMode, resolveSkillStalenessDays, } from "./preferences-skills.js";
37
27
  // ─── Re-exports: models ─────────────────────────────────────────────────────
38
28
  export { resolveModelForUnit, resolveModelWithFallbacksForUnit, getNextFallbackModel, isTransientNetworkError, validateModelId, updatePreferencesModels, resolveDynamicRoutingConfig, resolveAutoSupervisorConfig, resolveProfileDefaults, resolveEffectiveProfile, resolveInlineLevel, resolveContextSelection, resolveSearchProviderFromPreferences, } from "./preferences-models.js";
39
29
  // ─── Path Constants & Getters ───────────────────────────────────────────────
@@ -314,9 +304,6 @@ function mergePreferences(base, override) {
314
304
  github: (base.github || override.github)
315
305
  ? { ...(base.github ?? {}), ...(override.github ?? {}) }
316
306
  : undefined,
317
- experimental: (base.experimental || override.experimental)
318
- ? { ...(base.experimental ?? {}), ...(override.experimental ?? {}) }
319
- : undefined,
320
307
  service_tier: override.service_tier ?? base.service_tier,
321
308
  forensics_dedup: override.forensics_dedup ?? base.forensics_dedup,
322
309
  show_token_cost: override.show_token_cost ?? base.show_token_cost,
@@ -132,13 +132,10 @@ export function loadPrompt(name, vars = {}) {
132
132
  }
133
133
  }
134
134
  for (const [key, value] of Object.entries(effectiveVars)) {
135
- const safeValue = key === "workingDirectory" && typeof value === "string"
136
- ? value.replaceAll("\\", "/")
137
- : value;
138
135
  // Use split/join instead of replaceAll to avoid JavaScript's special
139
136
  // replacement patterns ($', $`, $&) being interpreted in the value.
140
137
  // See: https://github.com/gsd-build/gsd-2/issues/2968
141
- content = content.split(`{{${key}}}`).join(safeValue);
138
+ content = content.split(`{{${key}}}`).join(value);
142
139
  }
143
140
  return content.trim();
144
141
  }
@@ -0,0 +1,43 @@
1
+ import { ensureRtkSessionBaseline, formatRtkSavingsLabel, getRtkSessionSavings, } from "../shared/rtk-session-stats.js";
2
+ import { loadEffectiveGSDPreferences } from "./preferences.js";
3
+ const STATUS_KEY = "gsd-rtk";
4
+ const REFRESH_INTERVAL_MS = 30_000;
5
+ let refreshTimer = null;
6
+ function clearTimer() {
7
+ if (refreshTimer) {
8
+ clearInterval(refreshTimer);
9
+ refreshTimer = null;
10
+ }
11
+ }
12
+ function isRtkEnabledInPrefs() {
13
+ return loadEffectiveGSDPreferences()?.preferences.experimental?.rtk === true;
14
+ }
15
+ function updateStatus(ctx) {
16
+ if (!ctx.hasUI)
17
+ return;
18
+ if (!isRtkEnabledInPrefs())
19
+ return;
20
+ const basePath = ctx.cwd;
21
+ const sessionId = ctx.sessionManager.getSessionId();
22
+ ensureRtkSessionBaseline(basePath, sessionId);
23
+ const savings = getRtkSessionSavings(basePath, sessionId);
24
+ ctx.ui.setStatus(STATUS_KEY, formatRtkSavingsLabel(savings) ?? undefined);
25
+ }
26
+ export function startRtkStatusUpdates(ctx) {
27
+ clearTimer();
28
+ if (!isRtkEnabledInPrefs()) {
29
+ // Ensure any previously set status is cleared (e.g. preference was toggled off)
30
+ ctx.ui.setStatus(STATUS_KEY, undefined);
31
+ return;
32
+ }
33
+ updateStatus(ctx);
34
+ if (!ctx.hasUI)
35
+ return;
36
+ refreshTimer = setInterval(() => {
37
+ updateStatus(ctx);
38
+ }, REFRESH_INTERVAL_MS);
39
+ }
40
+ export function stopRtkStatusUpdates(ctx) {
41
+ clearTimer();
42
+ ctx?.ui.setStatus(STATUS_KEY, undefined);
43
+ }
@@ -13,7 +13,7 @@ import { existsSync, readdirSync, readFileSync } from 'node:fs';
13
13
  import { debugCount, debugTime } from './debug-logger.js';
14
14
  import { logWarning, logError } from './workflow-logger.js';
15
15
  import { extractVerdict } from './verdict-parser.js';
16
- import { isDbAvailable, wasDbOpenAttempted, getAllMilestones, getMilestone, getMilestoneSlices, getSliceTasks, getReplanHistory, getSlice, insertMilestone, insertSlice, insertTask, updateSliceStatus, updateTaskStatus, getPendingGateCountForTurn, } from './gsd-db.js';
16
+ import { isDbAvailable, wasDbOpenAttempted, getAllMilestones, getMilestone, getMilestoneSlices, getSliceTasks, getReplanHistory, getSlice, insertMilestone, insertSlice, insertTask, updateTaskStatus, getPendingGateCountForTurn, } from './gsd-db.js';
17
17
  /**
18
18
  * A "ghost" milestone directory contains only META.json (and no substantive
19
19
  * files like CONTEXT, CONTEXT-DRAFT, ROADMAP, or SUMMARY). These appear when
@@ -286,26 +286,6 @@ function reconcileDiskToDb(basePath) {
286
286
  depends: s.depends, demo: s.demo,
287
287
  });
288
288
  }
289
- // Reconcile stale *existing* slice rows (#3599): a slice row may exist in
290
- // the DB with status "pending" even though disk artifacts (SUMMARY) prove
291
- // completion — the same class of desync that task-level reconciliation
292
- // (further below) already handles. Without this, the dependency resolver
293
- // builds doneSliceIds from stale DB rows and downstream slices stay blocked
294
- // forever with "No slice eligible".
295
- for (const dbSlice of dbSlices) {
296
- if (isStatusDone(dbSlice.status))
297
- continue;
298
- const summaryPath = resolveSliceFile(basePath, mid, dbSlice.id, "SUMMARY");
299
- if (summaryPath) {
300
- try {
301
- updateSliceStatus(mid, dbSlice.id, "complete");
302
- logWarning("reconcile", `slice ${mid}/${dbSlice.id} status reconciled from "${dbSlice.status}" to "complete" (#3599)`, { mid, sid: dbSlice.id });
303
- }
304
- catch (e) {
305
- logError("reconcile", `failed to update slice ${dbSlice.id}`, { sid: dbSlice.id, error: e.message });
306
- }
307
- }
308
- }
309
289
  }
310
290
  return allMilestones;
311
291
  }
@@ -22,9 +22,6 @@ const BLOCKED_PATTERNS = [
22
22
  /(^|[/\\])\.gsd[/\\]STATE\.md$/i,
23
23
  // Also match resolved symlink paths under ~/.gsd/projects/ (Pitfall #6)
24
24
  /(^|[/\\])\.gsd[/\\]projects[/\\][^/\\]+[/\\]STATE\.md$/i,
25
- // gsd.db and WAL/SHM files — single-writer WAL connection managed by engine (#3625)
26
- /(^|[/\\])\.gsd[/\\]gsd\.db(-wal|-shm)?$/i,
27
- /(^|[/\\])\.gsd[/\\]projects[/\\][^/\\]+[/\\]gsd\.db(-wal|-shm)?$/i,
28
25
  ];
29
26
  /**
30
27
  * Bash command patterns that target STATE.md.
@@ -41,12 +38,6 @@ const BASH_STATE_PATTERNS = [
41
38
  /\bsed\b.*-i.*STATE\.md/i,
42
39
  // dd output to STATE.md
43
40
  /\bdd\b.*of=\S*STATE\.md/i,
44
- // Direct DB access via sqlite3/sql.js/better-sqlite3 targeting gsd.db (#3625)
45
- /\b(sqlite3|sql\.js|better-sqlite3|node:sqlite)\b.*gsd\.db/i,
46
- /\bgsd\.db\b.*\b(sqlite3|sql\.js|better-sqlite3)\b/i,
47
- // Shell writes targeting gsd.db files
48
- /[>|]+\s*\S*gsd\.db/i,
49
- /\b(cp|mv|dd)\b.*gsd\.db/i,
50
41
  ];
51
42
  /**
52
43
  * Tests whether the given file path matches a blocked authoritative .gsd/ state file.
@@ -84,7 +75,7 @@ function matchesBlockedPattern(path) {
84
75
  * Error message returned when an agent attempts to directly write an authoritative .gsd/ state file.
85
76
  * Directs the agent to use engine tool calls instead.
86
77
  */
87
- export const BLOCKED_WRITE_ERROR = `Direct writes to .gsd/STATE.md and .gsd/gsd.db are blocked. Use engine tool calls instead:
78
+ export const BLOCKED_WRITE_ERROR = `Direct writes to .gsd/STATE.md are blocked. Use engine tool calls instead:
88
79
  - To complete a task: call gsd_complete_task(milestone_id, slice_id, task_id, summary)
89
80
  - To complete a slice: call gsd_complete_slice(milestone_id, slice_id, summary, uat_result)
90
81
  - To save a decision: call gsd_save_decision(scope, decision, choice, rationale)
@@ -59,12 +59,13 @@ async function probeAndRegister(pi) {
59
59
  return false;
60
60
  }
61
61
  const baseUrl = client.getOllamaHost();
62
- // Use authMode "apiKey" (#3440). Local Ollama ignores the Authorization header,
63
- // so the "ollama" fallback is harmless. For cloud endpoints (OLLAMA_HOST pointing
64
- // to ollama.com or a remote instance), OLLAMA_API_KEY is picked up here.
62
+ // Use authMode "apiKey" with a dummy key (#3440).
63
+ // authMode "none" requires a custom streamSimple handler, but Ollama uses
64
+ // the standard OpenAI-compatible streaming endpoint. Ollama ignores the
65
+ // Authorization header so the dummy key is harmless.
65
66
  pi.registerProvider("ollama", {
66
67
  authMode: "apiKey",
67
- apiKey: process.env.OLLAMA_API_KEY ?? "ollama",
68
+ apiKey: "ollama",
68
69
  baseUrl,
69
70
  api: "ollama-chat",
70
71
  streamSimple: streamOllamaChat,
@@ -15,34 +15,11 @@ export function getOllamaHost() {
15
15
  return host;
16
16
  return `http://${host}`;
17
17
  }
18
- /**
19
- * Get auth headers for Ollama API requests.
20
- * For cloud endpoints (OLLAMA_HOST pointing to ollama.com or remote instances),
21
- * OLLAMA_API_KEY is used as a Bearer token. Local Ollama ignores the header.
22
- */
23
- function getAuthHeaders() {
24
- const apiKey = process.env.OLLAMA_API_KEY;
25
- if (!apiKey)
26
- return {};
27
- return { Authorization: `Bearer ${apiKey}` };
28
- }
29
- /**
30
- * Merge auth headers into request options.
31
- */
32
- function withAuth(options = {}) {
33
- const authHeaders = getAuthHeaders();
34
- if (Object.keys(authHeaders).length === 0)
35
- return options;
36
- return {
37
- ...options,
38
- headers: { ...authHeaders, ...(options.headers || {}) },
39
- };
40
- }
41
18
  async function fetchWithTimeout(url, options = {}, timeoutMs = REQUEST_TIMEOUT_MS) {
42
19
  const controller = new AbortController();
43
20
  const timeout = setTimeout(() => controller.abort(), timeoutMs);
44
21
  try {
45
- return await fetch(url, withAuth({ ...options, signal: controller.signal }));
22
+ return await fetch(url, { ...options, signal: controller.signal });
46
23
  }
47
24
  finally {
48
25
  clearTimeout(timeout);
@@ -50,16 +27,10 @@ async function fetchWithTimeout(url, options = {}, timeoutMs = REQUEST_TIMEOUT_M
50
27
  }
51
28
  /**
52
29
  * Check if Ollama is running and reachable.
53
- * For cloud endpoints (OLLAMA_HOST pointing to ollama.com), uses /api/tags
54
- * as the probe since the root endpoint may not be available.
55
30
  */
56
31
  export async function isRunning() {
57
32
  try {
58
- const host = getOllamaHost();
59
- const isCloud = host.includes("ollama.com") || host.includes("cloud");
60
- const probeUrl = isCloud ? `${host}/api/tags` : `${host}/`;
61
- const timeout = isCloud ? REQUEST_TIMEOUT_MS : PROBE_TIMEOUT_MS;
62
- const response = await fetchWithTimeout(probeUrl, isCloud ? { method: "GET" } : {}, timeout);
33
+ const response = await fetchWithTimeout(`${getOllamaHost()}/`, {}, PROBE_TIMEOUT_MS);
63
34
  return response.ok;
64
35
  }
65
36
  catch {
@@ -121,12 +92,12 @@ export async function getRunningModels() {
121
92
  * Returns when the pull is complete.
122
93
  */
123
94
  export async function pullModel(name, onProgress, signal) {
124
- const response = await fetch(`${getOllamaHost()}/api/pull`, withAuth({
95
+ const response = await fetch(`${getOllamaHost()}/api/pull`, {
125
96
  method: "POST",
126
97
  headers: { "Content-Type": "application/json" },
127
98
  body: JSON.stringify({ name, stream: true }),
128
99
  signal,
129
- }));
100
+ });
130
101
  if (!response.ok) {
131
102
  const text = await response.text();
132
103
  throw new Error(`Ollama /api/pull returned ${response.status}: ${text}`);
@@ -143,12 +114,12 @@ export async function pullModel(name, onProgress, signal) {
143
114
  * Returns an async generator yielding each NDJSON response chunk.
144
115
  */
145
116
  export async function* chat(request, signal) {
146
- const response = await fetch(`${getOllamaHost()}/api/chat`, withAuth({
117
+ const response = await fetch(`${getOllamaHost()}/api/chat`, {
147
118
  method: "POST",
148
119
  headers: { "Content-Type": "application/json" },
149
120
  body: JSON.stringify(request),
150
121
  signal,
151
- }));
122
+ });
152
123
  if (!response.ok) {
153
124
  const text = await response.text();
154
125
  throw new Error(`Ollama /api/chat returned ${response.status}: ${text}`);
@@ -6,40 +6,14 @@
6
6
  *
7
7
  * Returns models in the format expected by pi.registerProvider().
8
8
  */
9
- import { listModels, showModel } from "./ollama-client.js";
9
+ import { listModels } from "./ollama-client.js";
10
10
  import { estimateContextFromParams, formatModelSize, getModelCapabilities, humanizeModelName, } from "./model-capabilities.js";
11
- /**
12
- * Extract context window from /api/show model_info.
13
- * Keys follow the pattern "{architecture}.context_length" (e.g. "llama.context_length").
14
- */
15
- function extractContextFromModelInfo(modelInfo) {
16
- for (const [key, value] of Object.entries(modelInfo)) {
17
- if (key.endsWith(".context_length") && typeof value === "number" && value > 0) {
18
- return value;
19
- }
20
- }
21
- return undefined;
22
- }
23
11
  const ZERO_COST = { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 };
24
- async function enrichModel(info, deps) {
12
+ function enrichModel(info) {
25
13
  const caps = getModelCapabilities(info.name);
26
14
  const parameterSize = info.details?.parameter_size ?? "";
27
- // /api/tags doesn't include context length; /api/show does via "{arch}.context_length" in model_info.
28
- let showContextWindow;
29
- if (caps.contextWindow === undefined) {
30
- try {
31
- const showData = await deps.showModel(info.name);
32
- showContextWindow = extractContextFromModelInfo(showData.model_info);
33
- }
34
- catch (err) {
35
- // non-fatal: fall through to estimate
36
- if (process.env.GSD_DEBUG)
37
- console.warn(`[ollama] /api/show failed for ${info.name}:`, err instanceof Error ? err.message : String(err));
38
- }
39
- }
40
- // Determine context window: known table > /api/show > estimate from param size > default
15
+ // Determine context window: known table > estimate from param size > default
41
16
  const contextWindow = caps.contextWindow ??
42
- showContextWindow ??
43
17
  (parameterSize ? estimateContextFromParams(parameterSize) : 8192);
44
18
  // Determine max tokens: known table > fraction of context > default
45
19
  const maxTokens = caps.maxTokens ?? Math.min(Math.floor(contextWindow / 4), 16384);
@@ -64,11 +38,11 @@ async function enrichModel(info, deps) {
64
38
  /**
65
39
  * Discover all locally available Ollama models with enriched capabilities.
66
40
  */
67
- export async function discoverModels(deps = { listModels, showModel }) {
68
- const tags = await deps.listModels();
41
+ export async function discoverModels() {
42
+ const tags = await listModels();
69
43
  if (!tags.models || tags.models.length === 0)
70
44
  return [];
71
- return Promise.all(tags.models.map((m) => enrichModel(m, deps)));
45
+ return tags.models.map(enrichModel);
72
46
  }
73
47
  /**
74
48
  * Format a discovered model for display in model list.
@@ -1 +1 @@
1
- eR2tLKungpmiiOyUIhqjF
1
+ vr6Pbde48w4rMUplqDdh_
@@ -4,43 +4,43 @@
4
4
  "/api/boot/route": "/api/boot",
5
5
  "/api/bridge-terminal/resize/route": "/api/bridge-terminal/resize",
6
6
  "/api/bridge-terminal/input/route": "/api/bridge-terminal/input",
7
- "/api/cleanup/route": "/api/cleanup",
7
+ "/api/bridge-terminal/stream/route": "/api/bridge-terminal/stream",
8
8
  "/api/dev-mode/route": "/api/dev-mode",
9
- "/api/captures/route": "/api/captures",
9
+ "/api/cleanup/route": "/api/cleanup",
10
10
  "/api/doctor/route": "/api/doctor",
11
+ "/api/captures/route": "/api/captures",
11
12
  "/api/export-data/route": "/api/export-data",
12
- "/api/browse-directories/route": "/api/browse-directories",
13
13
  "/api/forensics/route": "/api/forensics",
14
+ "/api/browse-directories/route": "/api/browse-directories",
14
15
  "/api/git/route": "/api/git",
15
16
  "/api/history/route": "/api/history",
16
17
  "/api/hooks/route": "/api/hooks",
17
- "/api/experimental/route": "/api/experimental",
18
- "/api/bridge-terminal/stream/route": "/api/bridge-terminal/stream",
19
18
  "/api/inspect/route": "/api/inspect",
20
19
  "/api/knowledge/route": "/api/knowledge",
21
- "/api/notifications/route": "/api/notifications",
20
+ "/api/experimental/route": "/api/experimental",
22
21
  "/api/live-state/route": "/api/live-state",
22
+ "/api/notifications/route": "/api/notifications",
23
23
  "/api/preferences/route": "/api/preferences",
24
24
  "/api/recovery/route": "/api/recovery",
25
25
  "/api/onboarding/route": "/api/onboarding",
26
- "/api/session/browser/route": "/api/session/browser",
27
26
  "/api/projects/route": "/api/projects",
27
+ "/api/session/browser/route": "/api/session/browser",
28
+ "/api/session/events/route": "/api/session/events",
28
29
  "/api/session/command/route": "/api/session/command",
29
- "/api/files/route": "/api/files",
30
30
  "/api/settings-data/route": "/api/settings-data",
31
+ "/api/files/route": "/api/files",
31
32
  "/api/shutdown/route": "/api/shutdown",
32
33
  "/api/session/manage/route": "/api/session/manage",
33
- "/api/session/events/route": "/api/session/events",
34
34
  "/api/skill-health/route": "/api/skill-health",
35
35
  "/api/steer/route": "/api/steer",
36
36
  "/api/terminal/input/route": "/api/terminal/input",
37
- "/api/switch-root/route": "/api/switch-root",
38
37
  "/api/terminal/resize/route": "/api/terminal/resize",
38
+ "/api/switch-root/route": "/api/switch-root",
39
39
  "/api/terminal/sessions/route": "/api/terminal/sessions",
40
40
  "/api/terminal/stream/route": "/api/terminal/stream",
41
+ "/api/undo/route": "/api/undo",
41
42
  "/api/terminal/upload/route": "/api/terminal/upload",
42
43
  "/api/visualizer/route": "/api/visualizer",
43
- "/api/undo/route": "/api/undo",
44
44
  "/api/update/route": "/api/update",
45
45
  "/api/remote-questions/route": "/api/remote-questions",
46
46
  "/page": "/"
@@ -4,8 +4,8 @@
4
4
  ],
5
5
  "devFiles": [],
6
6
  "lowPriorityFiles": [
7
- "static/eR2tLKungpmiiOyUIhqjF/_buildManifest.js",
8
- "static/eR2tLKungpmiiOyUIhqjF/_ssgManifest.js"
7
+ "static/vr6Pbde48w4rMUplqDdh_/_buildManifest.js",
8
+ "static/vr6Pbde48w4rMUplqDdh_/_ssgManifest.js"
9
9
  ],
10
10
  "rootMainFiles": [
11
11
  "static/chunks/webpack-b868033a5834586d.js",
@@ -78,8 +78,8 @@
78
78
  "dynamicRoutes": {},
79
79
  "notFoundRoutes": [],
80
80
  "preview": {
81
- "previewModeId": "e0009b46cfd8a6ddf1952a7d63518f54",
82
- "previewModeSigningKey": "875a702424fd6d785618cf58cf4d7dc7e5d9b0989bfe20c80783baca959d4675",
83
- "previewModeEncryptionKey": "0ea6a4f3808af5c115687cbea57a3a65fe5f5444ed9084d35a2d5e673d9ab47f"
81
+ "previewModeId": "056d72cb497176b59eacca17d28d85f2",
82
+ "previewModeSigningKey": "69bb7934dcb0a09b7069cfd9f5466dfaae71acefd3f1ca3f7ba908a007b77a71",
83
+ "previewModeEncryptionKey": "65843937e372e058af890aefb5c0878ad985c4b4575d4624c0491b7aa3e3b9a6"
84
84
  }
85
85
  }