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.
- package/dist/resources/extensions/gsd/bootstrap/system-context.js +46 -12
- package/dist/resources/extensions/gsd/preferences.js +9 -1
- package/dist/resources/extensions/gsd/state.js +19 -2
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +16 -16
- 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 +2 -2
- package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.html +1 -1
- package/dist/web/standalone/.next/server/app/index.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app-paths-manifest.json +16 -16
- package/dist/web/standalone/.next/server/pages/404.html +1 -1
- package/dist/web/standalone/.next/server/pages/500.html +2 -2
- package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
- package/package.json +1 -1
- package/src/resources/extensions/gsd/bootstrap/system-context.ts +48 -11
- package/src/resources/extensions/gsd/preferences.ts +11 -1
- package/src/resources/extensions/gsd/state.ts +19 -1
- package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +33 -0
- package/src/resources/extensions/gsd/tests/knowledge.test.ts +89 -0
- package/src/resources/extensions/gsd/tests/preferences.test.ts +27 -0
- /package/dist/web/standalone/.next/static/{-zps1Q9mQmioAKLcQiCr8 → JyimLR2pZuvKEzv26gI3w}/_buildManifest.js +0 -0
- /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
|
+
});
|
|
File without changes
|
|
File without changes
|