gsd-pi 2.44.0-dev.848dd4c → 2.44.0-dev.a5271fc

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 (43) hide show
  1. package/dist/resources/extensions/gsd/bootstrap/system-context.js +46 -12
  2. package/dist/resources/extensions/gsd/preferences.js +9 -1
  3. package/dist/resources/extensions/gsd/state.js +19 -2
  4. package/dist/web/standalone/.next/BUILD_ID +1 -1
  5. package/dist/web/standalone/.next/app-path-routes-manifest.json +16 -16
  6. package/dist/web/standalone/.next/build-manifest.json +2 -2
  7. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  8. package/dist/web/standalone/.next/server/app/_global-error.html +2 -2
  9. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  10. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  11. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  12. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  13. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  14. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  15. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  16. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  17. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  18. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  19. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  20. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  21. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  22. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  23. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  24. package/dist/web/standalone/.next/server/app/index.html +1 -1
  25. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  26. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  27. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  28. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  29. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  30. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  31. package/dist/web/standalone/.next/server/app-paths-manifest.json +16 -16
  32. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  33. package/dist/web/standalone/.next/server/pages/500.html +2 -2
  34. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  35. package/package.json +1 -1
  36. package/src/resources/extensions/gsd/bootstrap/system-context.ts +48 -11
  37. package/src/resources/extensions/gsd/preferences.ts +11 -1
  38. package/src/resources/extensions/gsd/state.ts +19 -1
  39. package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +33 -0
  40. package/src/resources/extensions/gsd/tests/knowledge.test.ts +89 -0
  41. package/src/resources/extensions/gsd/tests/preferences.test.ts +27 -0
  42. /package/dist/web/standalone/.next/static/{-zps1Q9mQmioAKLcQiCr8 → JyimLR2pZuvKEzv26gI3w}/_buildManifest.js +0 -0
  43. /package/dist/web/standalone/.next/static/{-zps1Q9mQmioAKLcQiCr8 → JyimLR2pZuvKEzv26gI3w}/_ssgManifest.js +0 -0
@@ -6,6 +6,7 @@
6
6
  * - resolveGsdRootFile resolves KNOWLEDGE paths correctly
7
7
  * - inlineGsdRootFile works with the KNOWLEDGE key
8
8
  * - before_agent_start hook includes/omits knowledge block appropriately
9
+ * - loadKnowledgeBlock merges global and project knowledge correctly
9
10
  */
10
11
 
11
12
  import test from 'node:test';
@@ -16,6 +17,7 @@ import { tmpdir } from 'node:os';
16
17
  import { GSD_ROOT_FILES, resolveGsdRootFile } from '../paths.ts';
17
18
  import { inlineGsdRootFile } from '../auto-prompts.ts';
18
19
  import { appendKnowledge } from '../files.ts';
20
+ import { loadKnowledgeBlock } from '../bootstrap/system-context.ts';
19
21
 
20
22
  // ─── KNOWLEDGE is registered in GSD_ROOT_FILES ─────────────────────────────
21
23
 
@@ -159,3 +161,90 @@ test('knowledge: appendKnowledge handles lesson type', async () => {
159
161
 
160
162
  rmSync(tmp, { recursive: true, force: true });
161
163
  });
164
+
165
+ // ─── loadKnowledgeBlock — global + project merge ────────────────────────────
166
+
167
+ test('loadKnowledgeBlock: returns empty block when neither file exists', () => {
168
+ const tmp = realpathSync(mkdtempSync(join(tmpdir(), 'gsd-kb-')));
169
+ const gsdHome = join(tmp, 'home');
170
+ const cwd = join(tmp, 'project');
171
+ mkdirSync(join(cwd, '.gsd'), { recursive: true });
172
+ mkdirSync(join(gsdHome, 'agent'), { recursive: true });
173
+
174
+ const result = loadKnowledgeBlock(gsdHome, cwd);
175
+ assert.strictEqual(result.block, '');
176
+ assert.strictEqual(result.globalSizeKb, 0);
177
+
178
+ rmSync(tmp, { recursive: true, force: true });
179
+ });
180
+
181
+ test('loadKnowledgeBlock: uses project knowledge alone when no global file', () => {
182
+ const tmp = realpathSync(mkdtempSync(join(tmpdir(), 'gsd-kb-')));
183
+ const gsdHome = join(tmp, 'home');
184
+ const cwd = join(tmp, 'project');
185
+ mkdirSync(join(cwd, '.gsd'), { recursive: true });
186
+ mkdirSync(join(gsdHome, 'agent'), { recursive: true });
187
+ writeFileSync(join(cwd, '.gsd', 'KNOWLEDGE.md'), 'K001: Use real DB');
188
+
189
+ const result = loadKnowledgeBlock(gsdHome, cwd);
190
+ assert.ok(result.block.includes('[KNOWLEDGE — Rules, patterns, and lessons learned]'));
191
+ assert.ok(result.block.includes('## Project Knowledge'));
192
+ assert.ok(result.block.includes('K001: Use real DB'));
193
+ assert.ok(!result.block.includes('## Global Knowledge'));
194
+ assert.strictEqual(result.globalSizeKb, 0);
195
+
196
+ rmSync(tmp, { recursive: true, force: true });
197
+ });
198
+
199
+ test('loadKnowledgeBlock: uses global knowledge alone when no project file', () => {
200
+ const tmp = realpathSync(mkdtempSync(join(tmpdir(), 'gsd-kb-')));
201
+ const gsdHome = join(tmp, 'home');
202
+ const cwd = join(tmp, 'project');
203
+ mkdirSync(join(cwd, '.gsd'), { recursive: true });
204
+ mkdirSync(join(gsdHome, 'agent'), { recursive: true });
205
+ writeFileSync(join(gsdHome, 'agent', 'KNOWLEDGE.md'), 'G001: Respond in English');
206
+
207
+ const result = loadKnowledgeBlock(gsdHome, cwd);
208
+ assert.ok(result.block.includes('[KNOWLEDGE — Rules, patterns, and lessons learned]'));
209
+ assert.ok(result.block.includes('## Global Knowledge'));
210
+ assert.ok(result.block.includes('G001: Respond in English'));
211
+ assert.ok(!result.block.includes('## Project Knowledge'));
212
+ assert.ok(result.globalSizeKb > 0);
213
+
214
+ rmSync(tmp, { recursive: true, force: true });
215
+ });
216
+
217
+ test('loadKnowledgeBlock: merges global before project when both exist', () => {
218
+ const tmp = realpathSync(mkdtempSync(join(tmpdir(), 'gsd-kb-')));
219
+ const gsdHome = join(tmp, 'home');
220
+ const cwd = join(tmp, 'project');
221
+ mkdirSync(join(cwd, '.gsd'), { recursive: true });
222
+ mkdirSync(join(gsdHome, 'agent'), { recursive: true });
223
+ writeFileSync(join(gsdHome, 'agent', 'KNOWLEDGE.md'), 'G001: Global rule');
224
+ writeFileSync(join(cwd, '.gsd', 'KNOWLEDGE.md'), 'K001: Project rule');
225
+
226
+ const result = loadKnowledgeBlock(gsdHome, cwd);
227
+ assert.ok(result.block.includes('## Global Knowledge'));
228
+ assert.ok(result.block.includes('## Project Knowledge'));
229
+ assert.ok(result.block.includes('G001: Global rule'));
230
+ assert.ok(result.block.includes('K001: Project rule'));
231
+ // Global section appears before project section
232
+ assert.ok(result.block.indexOf('## Global Knowledge') < result.block.indexOf('## Project Knowledge'));
233
+
234
+ rmSync(tmp, { recursive: true, force: true });
235
+ });
236
+
237
+ test('loadKnowledgeBlock: reports globalSizeKb above 4KB threshold', () => {
238
+ const tmp = realpathSync(mkdtempSync(join(tmpdir(), 'gsd-kb-')));
239
+ const gsdHome = join(tmp, 'home');
240
+ const cwd = join(tmp, 'project');
241
+ mkdirSync(join(cwd, '.gsd'), { recursive: true });
242
+ mkdirSync(join(gsdHome, 'agent'), { recursive: true });
243
+ // Write > 4KB of content
244
+ writeFileSync(join(gsdHome, 'agent', 'KNOWLEDGE.md'), 'x'.repeat(5000));
245
+
246
+ const result = loadKnowledgeBlock(gsdHome, cwd);
247
+ assert.ok(result.globalSizeKb > 4, `expected > 4KB, got ${result.globalSizeKb}`);
248
+
249
+ rmSync(tmp, { recursive: true, force: true });
250
+ });
@@ -15,6 +15,7 @@ import {
15
15
  applyModeDefaults,
16
16
  getIsolationMode,
17
17
  parsePreferencesMarkdown,
18
+ _resetParseWarningFlag,
18
19
  } from "../preferences.ts";
19
20
  import type { GSDPreferences, GSDModelConfigV2, GSDPhaseModelConfig } from "../preferences.ts";
20
21
 
@@ -352,3 +353,29 @@ test("handles empty models config", () => {
352
353
  assert.notEqual(prefs, null);
353
354
  assert.equal(prefs!.models, undefined);
354
355
  });
356
+
357
+ // ── Warn-once for unrecognized format (#2373) ────────────────────────────────
358
+
359
+ test("unrecognized format warning is emitted at most once (#2373)", () => {
360
+ const warnings: string[] = [];
361
+ const origWarn = console.warn;
362
+ console.warn = (...args: unknown[]) => warnings.push(args.join(" "));
363
+ try {
364
+ // Reset internal warned flag so the test starts clean
365
+ _resetParseWarningFlag();
366
+
367
+ const unrecognized = "This is just plain text with no frontmatter or headings.";
368
+
369
+ // Call multiple times — simulates repeated preference loads
370
+ parsePreferencesMarkdown(unrecognized);
371
+ parsePreferencesMarkdown(unrecognized);
372
+ parsePreferencesMarkdown(unrecognized);
373
+
374
+ const relevant = warnings.filter(w => w.includes("unrecognized format"));
375
+ assert.equal(relevant.length, 1, `expected exactly 1 warning, got ${relevant.length}: ${JSON.stringify(relevant)}`);
376
+ } finally {
377
+ console.warn = origWarn;
378
+ // Reset so other tests aren't affected by the flag state
379
+ _resetParseWarningFlag();
380
+ }
381
+ });