gsd-pi 2.67.0-dev.4fb8afe → 2.67.0-dev.509bd95

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/commands/handlers/core.js +38 -24
  2. package/dist/resources/extensions/gsd/commands/index.js +8 -1
  3. package/dist/resources/extensions/gsd/workflow-logger.js +18 -3
  4. package/dist/web/standalone/.next/BUILD_ID +1 -1
  5. package/dist/web/standalone/.next/app-path-routes-manifest.json +13 -13
  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 +1 -1
  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 +13 -13
  32. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  33. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  34. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  35. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  36. package/package.json +1 -1
  37. package/src/resources/extensions/gsd/commands/handlers/core.ts +52 -25
  38. package/src/resources/extensions/gsd/commands/index.ts +7 -1
  39. package/src/resources/extensions/gsd/tests/core-overlay-fallback.test.ts +101 -0
  40. package/src/resources/extensions/gsd/tests/workflow-logger.test.ts +16 -0
  41. package/src/resources/extensions/gsd/workflow-logger.ts +19 -3
  42. /package/dist/web/standalone/.next/static/{IBTC_HlEpTBAa4HXMoV_A → mHJZ3Z8yGRzZ32BmQs-I7}/_buildManifest.js +0 -0
  43. /package/dist/web/standalone/.next/static/{IBTC_HlEpTBAa4HXMoV_A → mHJZ3Z8yGRzZ32BmQs-I7}/_ssgManifest.js +0 -0
@@ -74,3 +74,104 @@ test("model command resolves and persists exact provider-qualified selection", a
74
74
  assert.deepEqual(applied, selectedModel);
75
75
  assert.match(notices[0]!.message, /openai\/gpt-5\.4/);
76
76
  });
77
+
78
+ test("interactive model picker chooses provider first, then model", async () => {
79
+ const selectedModel = { provider: "openai", id: "gpt-5.4" };
80
+ let applied: typeof selectedModel | null = null;
81
+ const selects: Array<{ title: string; options: string[] }> = [];
82
+ const notices: Array<{ message: string; type?: string }> = [];
83
+
84
+ const ctx = {
85
+ hasUI: true,
86
+ model: { provider: "anthropic", id: "claude-sonnet-4-6" },
87
+ modelRegistry: {
88
+ getAvailable: () => [
89
+ { provider: "openai", id: "gpt-5.4" },
90
+ { provider: "anthropic", id: "claude-opus-4-6" },
91
+ { provider: "openai", id: "gpt-5.3-mini" },
92
+ { provider: "anthropic", id: "claude-sonnet-4-6" },
93
+ ],
94
+ },
95
+ ui: {
96
+ select: async (title: string, options: string[]) => {
97
+ selects.push({ title, options });
98
+ return selects.length === 1 ? "openai (2 models)" : "gpt-5.4";
99
+ },
100
+ notify: (message: string, type?: string) => {
101
+ notices.push({ message, type });
102
+ },
103
+ },
104
+ } as any;
105
+
106
+ const pi = {
107
+ setModel: async (model: typeof selectedModel) => {
108
+ applied = model;
109
+ return true;
110
+ },
111
+ } as any;
112
+
113
+ const handled = await handleCoreCommand("model", ctx, pi);
114
+ assert.equal(handled, true);
115
+ assert.deepEqual(selects, [
116
+ {
117
+ title: "Select session model: — choose provider:",
118
+ options: ["anthropic (2 models)", "openai (2 models)", "(cancel)"],
119
+ },
120
+ {
121
+ title: "Select session model: — openai:",
122
+ options: ["gpt-5.3-mini", "gpt-5.4", "(cancel)"],
123
+ },
124
+ ]);
125
+ assert.deepEqual(applied, selectedModel);
126
+ assert.match(notices[0]!.message, /openai\/gpt-5\.4/);
127
+ });
128
+
129
+ test("ambiguous typed model selection chooses provider first, then model", async () => {
130
+ const selectedModel = { provider: "github-copilot", id: "gpt-5" };
131
+ let applied: typeof selectedModel | null = null;
132
+ const selects: Array<{ title: string; options: string[] }> = [];
133
+ const notices: Array<{ message: string; type?: string }> = [];
134
+
135
+ const ctx = {
136
+ hasUI: true,
137
+ model: { provider: "anthropic", id: "claude-sonnet-4-6" },
138
+ modelRegistry: {
139
+ getAvailable: () => [
140
+ { provider: "openai", id: "gpt-5" },
141
+ { provider: "github-copilot", id: "gpt-5" },
142
+ { provider: "openai", id: "gpt-5-mini" },
143
+ ],
144
+ },
145
+ ui: {
146
+ select: async (title: string, options: string[]) => {
147
+ selects.push({ title, options });
148
+ return selects.length === 1 ? "github-copilot (1 model)" : "gpt-5";
149
+ },
150
+ notify: (message: string, type?: string) => {
151
+ notices.push({ message, type });
152
+ },
153
+ },
154
+ } as any;
155
+
156
+ const pi = {
157
+ setModel: async (model: typeof selectedModel) => {
158
+ applied = model;
159
+ return true;
160
+ },
161
+ } as any;
162
+
163
+ const handled = await handleCoreCommand("model gpt", ctx, pi);
164
+ assert.equal(handled, true);
165
+ assert.deepEqual(selects, [
166
+ {
167
+ title: "Multiple models match \"gpt\" — choose provider:",
168
+ options: ["github-copilot (1 model)", "openai (2 models)", "(cancel)"],
169
+ },
170
+ {
171
+ title: "Multiple models match \"gpt\" — github-copilot:",
172
+ options: ["gpt-5", "(cancel)"],
173
+ },
174
+ ]);
175
+ assert.deepEqual(applied, selectedModel);
176
+ assert.match(notices[0]!.message, /github-copilot\/gpt-5/);
177
+ });
@@ -18,6 +18,7 @@ import {
18
18
  summarizeLogs,
19
19
  formatForNotification,
20
20
  setLogBasePath,
21
+ setStderrLoggingEnabled,
21
22
  _resetLogs,
22
23
  } from "../workflow-logger.ts";
23
24
 
@@ -375,5 +376,20 @@ describe("workflow-logger", () => {
375
376
  logError("tool", "failed", { cmd: "complete_task" });
376
377
  assert.ok(written[0].includes('"cmd":"complete_task"'));
377
378
  });
379
+
380
+ test("suppresses stderr when disabled", (t) => {
381
+ const written: string[] = [];
382
+ const orig = process.stderr.write.bind(process.stderr);
383
+ const previous = setStderrLoggingEnabled(false);
384
+ // @ts-ignore — patching for test
385
+ process.stderr.write = (chunk: string) => { written.push(chunk); return true; };
386
+ t.after(() => {
387
+ process.stderr.write = orig;
388
+ setStderrLoggingEnabled(previous);
389
+ });
390
+
391
+ logWarning("engine", "hidden warning");
392
+ assert.deepEqual(written, []);
393
+ });
378
394
  });
379
395
  });
@@ -67,6 +67,7 @@ export interface LogEntry {
67
67
  const MAX_BUFFER = 100;
68
68
  let _buffer: LogEntry[] = [];
69
69
  let _auditBasePath: string | null = null;
70
+ let _stderrEnabled = true;
70
71
 
71
72
  /**
72
73
  * Set the base path for persistent audit log writes.
@@ -77,6 +78,16 @@ export function setLogBasePath(basePath: string): void {
77
78
  _auditBasePath = basePath;
78
79
  }
79
80
 
81
+ /**
82
+ * Enable or disable immediate stderr writes for workflow logs.
83
+ * Returns the previous setting so callers can restore it.
84
+ */
85
+ export function setStderrLoggingEnabled(enabled: boolean): boolean {
86
+ const previous = _stderrEnabled;
87
+ _stderrEnabled = enabled;
88
+ return previous;
89
+ }
90
+
80
91
  // ─── Public API ─────────────────────────────────────────────────────────
81
92
 
82
93
  /**
@@ -245,7 +256,7 @@ function _push(
245
256
  // Always forward to stderr so terminal watchers see it (see module header for policy)
246
257
  const prefix = severity === "error" ? "ERROR" : "WARN";
247
258
  const ctxStr = context ? ` ${JSON.stringify(context)}` : "";
248
- process.stderr.write(`[gsd:${component}] ${prefix}: ${message}${ctxStr}\n`);
259
+ _writeStderr(`[gsd:${component}] ${prefix}: ${message}${ctxStr}\n`);
249
260
 
250
261
  // Persist to notification store (both warnings and errors)
251
262
  try {
@@ -255,7 +266,7 @@ function _push(
255
266
  "workflow-logger",
256
267
  );
257
268
  } catch (notifErr) {
258
- process.stderr.write(`[gsd:workflow-logger] notification-store append failed: ${(notifErr as Error).message}\n`);
269
+ _writeStderr(`[gsd:workflow-logger] notification-store append failed: ${(notifErr as Error).message}\n`);
259
270
  }
260
271
 
261
272
  // Buffer for auto-loop to drain
@@ -275,11 +286,16 @@ function _push(
275
286
  appendFileSync(join(auditDir, "audit-log.jsonl"), JSON.stringify(sanitized) + "\n", "utf-8");
276
287
  } catch (auditErr) {
277
288
  // Best-effort — never let audit write failures bubble up
278
- process.stderr.write(`[gsd:audit] failed to persist log entry: ${(auditErr as Error).message}\n`);
289
+ _writeStderr(`[gsd:audit] failed to persist log entry: ${(auditErr as Error).message}\n`);
279
290
  }
280
291
  }
281
292
  }
282
293
 
294
+ function _writeStderr(message: string): void {
295
+ if (!_stderrEnabled) return;
296
+ process.stderr.write(message);
297
+ }
298
+
283
299
  /**
284
300
  * Sanitize a log entry before persisting to the audit JSONL file.
285
301
  * Strips potentially sensitive context (raw paths, cwd, full error text)