@gajae-code/coding-agent 0.2.3 → 0.2.4

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 (34) hide show
  1. package/CHANGELOG.md +17 -8600
  2. package/dist/types/cli/update-cli.d.ts +3 -0
  3. package/dist/types/config/settings-schema.d.ts +20 -0
  4. package/dist/types/defaults/gjc-defaults.d.ts +19 -6
  5. package/dist/types/modes/components/settings-selector.d.ts +4 -0
  6. package/dist/types/modes/controllers/selector-controller.d.ts +1 -0
  7. package/dist/types/modes/interactive-mode.d.ts +1 -0
  8. package/dist/types/modes/theme/defaults/index.d.ts +126 -0
  9. package/dist/types/modes/theme/theme.d.ts +5 -0
  10. package/dist/types/modes/types.d.ts +1 -0
  11. package/package.json +7 -7
  12. package/src/cli/update-cli.ts +67 -16
  13. package/src/config/settings-schema.ts +22 -0
  14. package/src/defaults/gjc/skills/deep-interview/SKILL.md +39 -4
  15. package/src/defaults/gjc/skills/deep-interview/auto-answer-uncertain.md +37 -0
  16. package/src/defaults/gjc/skills/deep-interview/auto-research-greenfield.md +42 -0
  17. package/src/defaults/gjc/skills/ultragoal/SKILL.md +9 -6
  18. package/src/defaults/gjc-defaults.ts +68 -16
  19. package/src/gjc-runtime/deep-interview-runtime.ts +44 -0
  20. package/src/gjc-runtime/state-runtime.ts +3 -2
  21. package/src/goals/tools/goal-tool.ts +5 -1
  22. package/src/internal-urls/docs-index.generated.ts +4 -2
  23. package/src/memories/index.ts +5 -4
  24. package/src/modes/components/settings-selector.ts +25 -14
  25. package/src/modes/controllers/command-controller.ts +1 -1
  26. package/src/modes/controllers/selector-controller.ts +67 -0
  27. package/src/modes/interactive-mode.ts +14 -1
  28. package/src/modes/theme/defaults/blue-crab.json +126 -0
  29. package/src/modes/theme/defaults/index.ts +2 -0
  30. package/src/modes/theme/theme.ts +40 -1
  31. package/src/modes/types.ts +1 -0
  32. package/src/prompts/memories/unavailable.md +9 -0
  33. package/src/sdk.ts +4 -0
  34. package/src/slash-commands/builtin-registry.ts +11 -1
@@ -21,6 +21,9 @@ export declare function parseUpdateArgs(args: string[]): {
21
21
  check: boolean;
22
22
  } | undefined;
23
23
  export declare function resolveUpdateMethodForTest(ompPath: string, bunBinDir: string | undefined): "bun" | "binary";
24
+ export declare function formatBinaryDownloadFailureMessageForTest(binaryName: string, url: string, status: string | number, platform?: NodeJS.Platform): string;
25
+ export declare function buildReleaseBinaryUrlForTest(version: string, platform?: NodeJS.Platform, arch?: string): string;
26
+ export declare function formatManualUpdateInstructionsForTest(platform?: NodeJS.Platform): string;
24
27
  /**
25
28
  * Atomically replace the installed binary and roll back if version verification fails.
26
29
  */
@@ -982,6 +982,24 @@ export declare const SETTINGS_SCHEMA: {
982
982
  readonly description: "Maximum wait between retries, in ms. When the provider asks us to wait longer than this and no credential or model fallback succeeds, the request fails fast instead of sleeping (e.g. 3-hour Anthropic rate-limit windows).";
983
983
  };
984
984
  };
985
+ readonly "retry.requestMaxRetries": {
986
+ readonly type: "number";
987
+ readonly default: 5;
988
+ readonly ui: {
989
+ readonly tab: "model";
990
+ readonly label: "Provider Request Retries";
991
+ readonly description: "Maximum provider request retries before a stream is established. Counts retries, not the first attempt. Set to 0 to disable provider request retries.";
992
+ };
993
+ };
994
+ readonly "retry.streamMaxRetries": {
995
+ readonly type: "number";
996
+ readonly default: 5;
997
+ readonly ui: {
998
+ readonly tab: "model";
999
+ readonly label: "Provider Stream Retries";
1000
+ readonly description: "Maximum provider stream replay retries for replay-safe transient stream failures. Counts retries, not the first attempt. Set to 0 to disable provider stream retries.";
1001
+ };
1002
+ };
985
1003
  readonly "retry.fallbackChains": {
986
1004
  readonly type: "record";
987
1005
  readonly default: Record<string, string[]>;
@@ -3240,6 +3258,8 @@ export interface RetrySettings {
3240
3258
  maxRetries: number;
3241
3259
  baseDelayMs: number;
3242
3260
  maxDelayMs: number;
3261
+ requestMaxRetries: number;
3262
+ streamMaxRetries: number;
3243
3263
  }
3244
3264
  export interface MemoriesSettings {
3245
3265
  enabled: boolean;
@@ -1,6 +1,6 @@
1
1
  export declare const DEFAULT_GJC_DEFINITION_NAMES: readonly ["deep-interview", "ralplan", "team", "ultragoal"];
2
2
  export type DefaultGjcDefinitionName = (typeof DEFAULT_GJC_DEFINITION_NAMES)[number];
3
- export type DefaultGjcDefinitionKind = "skill";
3
+ export type DefaultGjcDefinitionKind = "skill" | "skill-fragment";
4
4
  export type EmbeddedDefaultGjcSkill = {
5
5
  name: DefaultGjcDefinitionName;
6
6
  description: string;
@@ -11,23 +11,35 @@ export type EmbeddedDefaultGjcSkill = {
11
11
  content: string;
12
12
  };
13
13
  export type DefaultGjcInstallStatus = "different" | "matching" | "missing" | "skipped" | "written";
14
- export interface DefaultGjcDefinition {
15
- kind: DefaultGjcDefinitionKind;
14
+ export interface DefaultGjcSkillDefinition {
15
+ kind: "skill";
16
16
  name: DefaultGjcDefinitionName;
17
17
  relativePath: string;
18
18
  content: string;
19
19
  }
20
+ export interface DefaultGjcSkillFragmentDefinition {
21
+ kind: "skill-fragment";
22
+ parentSkillName: DefaultGjcDefinitionName;
23
+ relativePath: string;
24
+ content: string;
25
+ }
26
+ export type DefaultGjcDefinition = DefaultGjcSkillDefinition | DefaultGjcSkillFragmentDefinition;
20
27
  export interface InstallDefaultGjcDefinitionsOptions {
21
28
  check?: boolean;
22
29
  force?: boolean;
23
30
  targetRoot?: string;
24
31
  }
25
- export interface DefaultGjcDefinitionInstallFile {
26
- kind: DefaultGjcDefinitionKind;
32
+ export type DefaultGjcDefinitionInstallFile = {
33
+ kind: "skill";
27
34
  name: DefaultGjcDefinitionName;
28
35
  path: string;
29
36
  status: DefaultGjcInstallStatus;
30
- }
37
+ } | {
38
+ kind: "skill-fragment";
39
+ parentSkillName: DefaultGjcDefinitionName;
40
+ path: string;
41
+ status: DefaultGjcInstallStatus;
42
+ };
31
43
  export interface DefaultGjcDefinitionInstallResult {
32
44
  targetRoot: string;
33
45
  total: number;
@@ -40,5 +52,6 @@ export interface DefaultGjcDefinitionInstallResult {
40
52
  }
41
53
  export declare function getDefaultGjcDefinitions(): readonly DefaultGjcDefinition[];
42
54
  export declare function getDefaultGjcAgentDefinitions(): readonly DefaultGjcDefinition[];
55
+ export declare function getEmbeddedDefaultGjcSkillFragments(parentSkillName: DefaultGjcDefinitionName): DefaultGjcSkillFragmentDefinition[];
43
56
  export declare function getEmbeddedDefaultGjcSkills(): EmbeddedDefaultGjcSkill[];
44
57
  export declare function installDefaultGjcDefinitions(options?: InstallDefaultGjcDefinitionsOptions): Promise<DefaultGjcDefinitionInstallResult>;
@@ -29,6 +29,10 @@ export interface StatusLinePreviewSettings {
29
29
  export interface SettingsCallbacks {
30
30
  /** Called when any setting value changes */
31
31
  onChange: (path: SettingPath, newValue: unknown) => void;
32
+ /** Called for theme preview while browsing theme settings */
33
+ onThemePreview?: (theme: string) => void | Promise<void>;
34
+ /** Called to restore the rendered theme when theme settings preview is cancelled */
35
+ onThemePreviewCancel?: (theme: string) => void | Promise<void>;
32
36
  /** Called for status line preview while configuring */
33
37
  onStatusLinePreview?: (settings: StatusLinePreviewSettings) => void;
34
38
  /** Get current rendered status line for inline preview */
@@ -15,6 +15,7 @@ export declare class SelectorController {
15
15
  }): void;
16
16
  showProviderOnboarding(): void;
17
17
  showSettingsSelector(): void;
18
+ showThemeSelector(): void;
18
19
  showHistorySearch(): void;
19
20
  /**
20
21
  * Show the Extension Control Center dashboard.
@@ -200,6 +200,7 @@ export declare class InteractiveMode implements InteractiveModeContext {
200
200
  executeCompaction(customInstructionsOrOptions?: string | CompactOptions, isAuto?: boolean): Promise<CompactionOutcome>;
201
201
  openInBrowser(urlOrPath: string): void;
202
202
  showSettingsSelector(): void;
203
+ showThemeSelector(): void;
203
204
  showHistorySearch(): void;
204
205
  showExtensionsDashboard(): void;
205
206
  showAgentsDashboard(): void;
@@ -467,6 +467,132 @@ export declare const defaultThemes: {
467
467
  "infoBg": string;
468
468
  };
469
469
  };
470
+ "blue-crab": {
471
+ $schema: string;
472
+ name: string;
473
+ vars: {
474
+ "cyan": string;
475
+ "blue": string;
476
+ "green": string;
477
+ "red": string;
478
+ "yellow": string;
479
+ "gray": string;
480
+ "dimGray": string;
481
+ "darkGray": string;
482
+ "accent": string;
483
+ "selectedBg": string;
484
+ "userMsgBg": string;
485
+ "toolPendingBg": string;
486
+ "toolSuccessBg": string;
487
+ "toolErrorBg": string;
488
+ "customMsgBg": string;
489
+ "abyss": string;
490
+ "deepNavy": string;
491
+ "crabShell": string;
492
+ "claw": string;
493
+ "ocean": string;
494
+ "azure": string;
495
+ "seafoam": string;
496
+ "kelp": string;
497
+ "sand": string;
498
+ "coral": string;
499
+ "ink": string;
500
+ "mantle": string;
501
+ "surface": string;
502
+ "surfaceBright": string;
503
+ "foam": string;
504
+ "mutedShell": string;
505
+ "dimShell": string;
506
+ "brandBlue": string;
507
+ "shell": string;
508
+ "dangerRed": string;
509
+ "warningAmber": string;
510
+ "diffRemovalRed": string;
511
+ };
512
+ colors: {
513
+ "accent": string;
514
+ "border": string;
515
+ "borderAccent": string;
516
+ "borderMuted": string;
517
+ "success": string;
518
+ "error": string;
519
+ "warning": string;
520
+ "muted": string;
521
+ "dim": string;
522
+ "text": string;
523
+ "thinkingText": string;
524
+ "selectedBg": string;
525
+ "userMessageBg": string;
526
+ "userMessageText": string;
527
+ "customMessageBg": string;
528
+ "customMessageText": string;
529
+ "customMessageLabel": string;
530
+ "toolPendingBg": string;
531
+ "toolSuccessBg": string;
532
+ "toolErrorBg": string;
533
+ "toolTitle": string;
534
+ "toolOutput": string;
535
+ "mdHeading": string;
536
+ "mdLink": string;
537
+ "mdLinkUrl": string;
538
+ "mdCode": string;
539
+ "mdCodeBlock": string;
540
+ "mdCodeBlockBorder": string;
541
+ "mdQuote": string;
542
+ "mdQuoteBorder": string;
543
+ "mdHr": string;
544
+ "mdListBullet": string;
545
+ "toolDiffAdded": string;
546
+ "toolDiffRemoved": string;
547
+ "toolDiffContext": string;
548
+ "link": string;
549
+ "syntaxComment": string;
550
+ "syntaxKeyword": string;
551
+ "syntaxFunction": string;
552
+ "syntaxVariable": string;
553
+ "syntaxString": string;
554
+ "syntaxNumber": string;
555
+ "syntaxType": string;
556
+ "syntaxOperator": string;
557
+ "syntaxPunctuation": string;
558
+ "thinkingOff": string;
559
+ "thinkingMinimal": string;
560
+ "thinkingLow": string;
561
+ "thinkingMedium": string;
562
+ "thinkingHigh": string;
563
+ "thinkingXhigh": string;
564
+ "bashMode": string;
565
+ "statusLineBg": string;
566
+ "statusLineSep": string;
567
+ "statusLineModel": string;
568
+ "statusLinePath": string;
569
+ "statusLineGitClean": string;
570
+ "statusLineGitDirty": string;
571
+ "statusLineContext": string;
572
+ "statusLineSpend": string;
573
+ "statusLineStaged": string;
574
+ "statusLineDirty": string;
575
+ "statusLineUntracked": string;
576
+ "statusLineOutput": string;
577
+ "statusLineCost": string;
578
+ "statusLineSubagents": string;
579
+ "pythonMode": string;
580
+ };
581
+ export: {
582
+ "pageBg": string;
583
+ "cardBg": string;
584
+ "infoBg": string;
585
+ };
586
+ symbols: {
587
+ "preset": string;
588
+ "overrides": {
589
+ "icon.pi": string;
590
+ "icon.agents": string;
591
+ "status.running": string;
592
+ "md.bullet": string;
593
+ };
594
+ };
595
+ };
470
596
  "dark-abyss": {
471
597
  $schema: string;
472
598
  name: string;
@@ -186,6 +186,7 @@ export interface ThemeInfo {
186
186
  }
187
187
  export declare function getAvailableThemesWithPaths(): Promise<ThemeInfo[]>;
188
188
  export declare function getThemeByName(name: string): Promise<Theme | undefined>;
189
+ export declare function getDetectedThemeSettingsPath(): "theme.dark" | "theme.light";
189
190
  export declare var theme: Theme;
190
191
  /** Get the name of the currently active theme. */
191
192
  export declare function getCurrentThemeName(): string | undefined;
@@ -198,6 +199,10 @@ export declare function previewTheme(name: string): Promise<{
198
199
  success: boolean;
199
200
  error?: string;
200
201
  }>;
202
+ export declare function restoreThemePreview(name: string): Promise<{
203
+ success: boolean;
204
+ error?: string;
205
+ }>;
201
206
  /**
202
207
  * Enable auto-detection mode, switching to the appropriate dark/light theme.
203
208
  */
@@ -208,6 +208,7 @@ export interface InteractiveModeContext {
208
208
  openInBrowser(urlOrPath: string): void;
209
209
  refreshSlashCommandState(cwd?: string): Promise<void>;
210
210
  showSettingsSelector(): void;
211
+ showThemeSelector(): void;
211
212
  showHistorySearch(): void;
212
213
  showExtensionsDashboard(): void;
213
214
  showAgentsDashboard(): void;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "type": "module",
3
3
  "name": "@gajae-code/coding-agent",
4
- "version": "0.2.3",
4
+ "version": "0.2.4",
5
5
  "description": "Gajae Code CLI with read, bash, edit, write tools and session management",
6
6
  "homepage": "https://gaebal-gajae.dev",
7
7
  "author": "Yeachan-Heo",
@@ -48,12 +48,12 @@
48
48
  "@agentclientprotocol/sdk": "0.21.0",
49
49
  "@babel/parser": "^7.29.3",
50
50
  "@mozilla/readability": "^0.6.0",
51
- "@gajae-code/stats": "0.2.3",
52
- "@gajae-code/agent-core": "0.2.3",
53
- "@gajae-code/ai": "0.2.3",
54
- "@gajae-code/natives": "0.2.3",
55
- "@gajae-code/tui": "0.2.3",
56
- "@gajae-code/utils": "0.2.3",
51
+ "@gajae-code/stats": "0.2.4",
52
+ "@gajae-code/agent-core": "0.2.4",
53
+ "@gajae-code/ai": "0.2.4",
54
+ "@gajae-code/natives": "0.2.4",
55
+ "@gajae-code/tui": "0.2.4",
56
+ "@gajae-code/utils": "0.2.4",
57
57
  "@puppeteer/browsers": "^2.13.0",
58
58
  "@types/turndown": "5.0.6",
59
59
  "@xterm/headless": "^6.0.0",
@@ -12,7 +12,7 @@ import { $ } from "bun";
12
12
  import chalk from "chalk";
13
13
  import { theme } from "../modes/theme/theme";
14
14
 
15
- const REPO = "can1357/gajae-code";
15
+ const RELEASE_REPO = "Yeachan-Heo/gajae-code";
16
16
  const PACKAGE = "@gajae-code/coding-agent";
17
17
 
18
18
  interface ReleaseInfo {
@@ -122,7 +122,7 @@ async function resolveUpdateTarget(): Promise<UpdateTarget> {
122
122
 
123
123
  if (bunBinDir) return { method: "bun" };
124
124
 
125
- throw new Error(`Could not resolve ${APP_NAME} binary path in PATH`);
125
+ throw new Error(formatUnsupportedTargetMessage(`Could not resolve ${APP_NAME} binary path in PATH`));
126
126
  }
127
127
 
128
128
  /**
@@ -166,10 +166,7 @@ function compareVersions(a: string, b: string): number {
166
166
  /**
167
167
  * Get the appropriate binary name for this platform.
168
168
  */
169
- function getBinaryName(): string {
170
- const platform = process.platform;
171
- const arch = process.arch;
172
-
169
+ function getBinaryName(platform: NodeJS.Platform = process.platform, arch: string = process.arch): string {
173
170
  let os: string;
174
171
  switch (platform) {
175
172
  case "linux":
@@ -182,7 +179,7 @@ function getBinaryName(): string {
182
179
  os = "windows";
183
180
  break;
184
181
  default:
185
- throw new Error(`Unsupported platform: ${platform}`);
182
+ throw new Error(formatUnsupportedTargetMessage(`Unsupported platform: ${platform}`));
186
183
  }
187
184
 
188
185
  let archName: string;
@@ -194,7 +191,7 @@ function getBinaryName(): string {
194
191
  archName = "arm64";
195
192
  break;
196
193
  default:
197
- throw new Error(`Unsupported architecture: ${arch}`);
194
+ throw new Error(formatUnsupportedTargetMessage(`Unsupported architecture: ${arch}`));
198
195
  }
199
196
 
200
197
  if (os === "windows") {
@@ -233,6 +230,65 @@ function printVerifiedVersion(expectedVersion: string): void {
233
230
  console.log(chalk.green(`\n${theme.status.success} Updated to ${expectedVersion}`));
234
231
  }
235
232
 
233
+ function formatBinaryInstallInstruction(platform: NodeJS.Platform = process.platform): string {
234
+ if (platform === "win32") {
235
+ return `For a supported binary install, reinstall with PowerShell: irm https://raw.githubusercontent.com/${RELEASE_REPO}/main/scripts/install.ps1 | iex`;
236
+ }
237
+ return `For a supported binary install, reinstall with: curl -fsSL https://raw.githubusercontent.com/${RELEASE_REPO}/main/scripts/install.sh | sh -s -- --binary`;
238
+ }
239
+
240
+ function formatManualUpdateInstructions(platform: NodeJS.Platform = process.platform): string {
241
+ return [
242
+ `If ${APP_NAME} was installed with Bun, run: bun install -g ${PACKAGE}@latest`,
243
+ `If ${APP_NAME} was installed with npm, pnpm, or another package manager, update it with that same manager.`,
244
+ formatBinaryInstallInstruction(platform),
245
+ ].join("\n");
246
+ }
247
+
248
+ function formatUnsupportedTargetMessage(reason: string, platform: NodeJS.Platform = process.platform): string {
249
+ return `${reason}.\n${formatManualUpdateInstructions(platform)}`;
250
+ }
251
+
252
+ function buildReleaseBinaryUrl(
253
+ version: string,
254
+ platform: NodeJS.Platform = process.platform,
255
+ arch: string = process.arch,
256
+ ): string {
257
+ const binaryName = getBinaryName(platform, arch);
258
+ const tag = `v${version}`;
259
+ return `https://github.com/${RELEASE_REPO}/releases/download/${tag}/${binaryName}`;
260
+ }
261
+
262
+ function formatBinaryDownloadFailureMessage(
263
+ binaryName: string,
264
+ url: string,
265
+ status: string | number,
266
+ platform: NodeJS.Platform = process.platform,
267
+ ): string {
268
+ return `Download failed for ${binaryName} from ${url}: ${status}.\n${formatManualUpdateInstructions(platform)}`;
269
+ }
270
+
271
+ export function formatBinaryDownloadFailureMessageForTest(
272
+ binaryName: string,
273
+ url: string,
274
+ status: string | number,
275
+ platform: NodeJS.Platform = process.platform,
276
+ ): string {
277
+ return formatBinaryDownloadFailureMessage(binaryName, url, status, platform);
278
+ }
279
+
280
+ export function buildReleaseBinaryUrlForTest(
281
+ version: string,
282
+ platform: NodeJS.Platform = process.platform,
283
+ arch: string = process.arch,
284
+ ): string {
285
+ return buildReleaseBinaryUrl(version, platform, arch);
286
+ }
287
+
288
+ export function formatManualUpdateInstructionsForTest(platform: NodeJS.Platform = process.platform): string {
289
+ return formatManualUpdateInstructions(platform);
290
+ }
291
+
236
292
  function formatVerificationFailure(result: InstalledVersionVerification, expectedVersion: string): string {
237
293
  if (result.actual) {
238
294
  return `${APP_NAME} at ${result.path} still reports ${result.actual} (expected ${expectedVersion})`;
@@ -250,11 +306,7 @@ async function printVerification(expectedVersion: string): Promise<void> {
250
306
  return;
251
307
  }
252
308
  console.log(chalk.yellow(`\nWarning: ${formatVerificationFailure(result, expectedVersion)}`));
253
- console.log(
254
- chalk.yellow(
255
- `You may need to reinstall: curl -fsSL https://raw.githubusercontent.com/can1357/gajae-code/main/scripts/install.sh | sh`,
256
- ),
257
- );
309
+ console.log(chalk.yellow(formatManualUpdateInstructions()));
258
310
  }
259
311
 
260
312
  async function unlinkIfExists(filePath: string): Promise<void> {
@@ -314,8 +366,7 @@ async function updateViaBun(expectedVersion: string): Promise<void> {
314
366
  */
315
367
  async function updateViaBinaryAt(targetPath: string, expectedVersion: string): Promise<void> {
316
368
  const binaryName = getBinaryName();
317
- const tag = `v${expectedVersion}`;
318
- const url = `https://github.com/${REPO}/releases/download/${tag}/${binaryName}`;
369
+ const url = buildReleaseBinaryUrl(expectedVersion);
319
370
 
320
371
  const tempPath = `${targetPath}.new`;
321
372
  const backupPath = `${targetPath}.bak`;
@@ -323,7 +374,7 @@ async function updateViaBinaryAt(targetPath: string, expectedVersion: string): P
323
374
 
324
375
  const response = await fetch(url, { redirect: "follow" });
325
376
  if (!response.ok || !response.body) {
326
- throw new Error(`Download failed: ${response.statusText}`);
377
+ throw new Error(formatBinaryDownloadFailureMessage(binaryName, url, response.statusText || response.status));
327
378
  }
328
379
  const fileStream = fs.createWriteStream(tempPath, { mode: 0o755 });
329
380
  await pipeline(response.body, fileStream);
@@ -843,6 +843,26 @@ export const SETTINGS_SCHEMA = {
843
843
  "Maximum wait between retries, in ms. When the provider asks us to wait longer than this and no credential or model fallback succeeds, the request fails fast instead of sleeping (e.g. 3-hour Anthropic rate-limit windows).",
844
844
  },
845
845
  },
846
+ "retry.requestMaxRetries": {
847
+ type: "number",
848
+ default: 5,
849
+ ui: {
850
+ tab: "model",
851
+ label: "Provider Request Retries",
852
+ description:
853
+ "Maximum provider request retries before a stream is established. Counts retries, not the first attempt. Set to 0 to disable provider request retries.",
854
+ },
855
+ },
856
+ "retry.streamMaxRetries": {
857
+ type: "number",
858
+ default: 5,
859
+ ui: {
860
+ tab: "model",
861
+ label: "Provider Stream Retries",
862
+ description:
863
+ "Maximum provider stream replay retries for replay-safe transient stream failures. Counts retries, not the first attempt. Set to 0 to disable provider stream retries.",
864
+ },
865
+ },
846
866
  "retry.fallbackChains": { type: "record", default: {} as Record<string, string[]> },
847
867
  "retry.fallbackRevertPolicy": {
848
868
  type: "enum",
@@ -2833,6 +2853,8 @@ export interface RetrySettings {
2833
2853
  maxRetries: number;
2834
2854
  baseDelayMs: number;
2835
2855
  maxDelayMs: number;
2856
+ requestMaxRetries: number;
2857
+ streamMaxRetries: number;
2836
2858
  }
2837
2859
 
2838
2860
  export interface MemoriesSettings {
@@ -39,6 +39,7 @@ Inspired by the [Ouroboros project](https://github.com/Q00/ouroboros) which demo
39
39
 
40
40
  <Execution_Policy>
41
41
  - Ask ONE question at a time -- never batch multiple questions
42
+ - Preserve the user/session language for every user-facing announcement, topology confirmation, option label, and interview question when state includes `language.instruction`; for example Korean initial ideas must receive Korean deep-interview questions unless the user explicitly requests another language
42
43
  - Target the WEAKEST clarity dimension with each question
43
44
  - Before Round 1 ambiguity scoring, run a one-time Round 0 topology enumeration gate that confirms the top-level component list and locks it into state
44
45
  - Make weakest-dimension targeting explicit every round: name the weakest dimension, state its score/gap, and explain why the next question is aimed there
@@ -54,6 +55,15 @@ Inspired by the [Ouroboros project](https://github.com/Q00/ouroboros) which demo
54
55
  - Challenge agents activate at specific round thresholds to shift perspective
55
56
  </Execution_Policy>
56
57
 
58
+ <Internal_Auto_Mode_Protocol>
59
+ - `auto-research-greenfield.md` and `auto-answer-uncertain.md` are internal prompt fragments loaded on demand with bundle metadata `kind: "skill-fragment"`; they are not public skills, are never slash-command/discoverable, and must not be registered through any `skill://` route.
60
+ - Load fragments only for the specific hook that needs them, with forked inherited context kept read-only and prompt-budgeted; summarize active interview context before spawning the architect if the payload is large.
61
+ - Auto-mode architects are read-only: no code edits, no `.gjc/` mutation, no workflow chaining, no formatters, and no execution delegation.
62
+ - Validate every fragment response before using it: required sections must be present, candidates/answer must match the requested shape, rationale must cite available context, confidence must be explicit, and insufficient-context fallbacks must be honored.
63
+ - If architect spawn, fragment loading, or response validation fails, continue the normal manual interview path silently and record an internal audit note in state by incrementing `architect_failures`; do not expose tool noise to the user unless it changes the next user-facing question.
64
+ - Track `auto_researched_rounds`, `auto_answered_rounds`, and `architect_failures` in state and final spec metadata.
65
+ </Internal_Auto_Mode_Protocol>
66
+
57
67
 
58
68
 
59
69
  <Steps>
@@ -83,6 +93,7 @@ Deep Interview threshold: <resolvedThresholdPercent> (source: <resolvedThreshold
83
93
  - Substitute `<resolvedThreshold>`, `<resolvedThresholdPercent>`, and `<resolvedThresholdSource>` throughout the remaining instructions before continuing.
84
94
  - Include `threshold_source` in the first `gjc state write` payload and preserve it on later state updates; do not edit `.gjc/state` files directly unless an explicit force override is active.
85
95
  - Include both threshold and source in the final spec metadata.
96
+ - Read any `language` object from active deep-interview state and carry `language.instruction` forward mechanically. If absent, infer the user/session language from `{{ARGUMENTS}}` only when it is obvious. Do not surprise a Korean session with English questions.
86
97
 
87
98
  ## Phase 1: Initialize
88
99
 
@@ -133,7 +144,10 @@ Deep Interview threshold: <resolvedThresholdPercent> (source: <resolvedThreshold
133
144
  "last_targeted_component_id": null
134
145
  },
135
146
  "challenge_modes_used": [],
136
- "ontology_snapshots": []
147
+ "ontology_snapshots": [],
148
+ "auto_researched_rounds": [],
149
+ "auto_answered_rounds": [],
150
+ "architect_failures": 0
137
151
  }
138
152
  }
139
153
  ```
@@ -170,7 +184,7 @@ I'm reading this as {N} top-level component(s):
170
184
  Is that topology right? Should any component be added, removed, merged, split, or explicitly deferred?
171
185
  ```
172
186
 
173
- Options should include contextually relevant choices such as **Looks right**, **Add/remove/merge components**, **Defer one or more components**, plus free-text. This is the only pre-scoring question and preserves the one-question-per-round rule.
187
+ Options should include contextually relevant choices such as **Looks right**, **Add/remove/merge components**, **Defer one or more components**, plus free-text, translated/localized according to `language.instruction` when present. This is the only pre-scoring question and preserves the one-question-per-round rule.
174
188
 
175
189
  3. **Lock topology into state** after the answer. Store a normalized component list and confirmation timestamp:
176
190
 
@@ -246,9 +260,15 @@ If any prompt input is too large, summarize it first and then continue from the
246
260
  | Context Clarity (brownfield) | "How does this fit?" | "I found JWT auth middleware in `src/auth/` (pattern: passport + JWT). Should this feature extend that path or intentionally diverge from it?" |
247
261
  | Scope-fuzzy / ontology stress | "What IS the core thing here?" | "You have named Tasks, Projects, and Workspaces across the last rounds. Which one is the core entity, and which are supporting views or containers?" |
248
262
 
263
+ ### Step 2a′: Auto-Research Greenfield Questions
264
+
265
+ When the next question is for a greenfield interview and is tagged `research: true`, load `auto-research-greenfield.md` as an internal `kind: "skill-fragment"` prompt for a fork-context architect before Step 2b. Pass only the tagged question, locked topology summary, prompt-safe initial idea, trimmed prior decisions/gaps, and relevant constraints. The architect must return 2-3 ranked candidates with rationale, confidence, and fallback notes. Validate the shape before use; if valid, incorporate the candidates as concise answer options or context for the single user-facing question and append the round number to `auto_researched_rounds`. If invalid or unavailable, fall back silently to the normal generated question and increment `architect_failures`.
266
+
267
+ Auto-research must never add a public skill entrypoint, never be slash-command/discoverable, never register a `skill://` handler, and never alter the one-question-per-round rule.
268
+
249
269
  ### Step 2b: Ask the Question
250
270
 
251
- Use the `ask` tool with the generated question. Present it clearly with the current ambiguity context:
271
+ Use the `ask` tool with the generated question. Before rendering the prompt/options, apply `language.instruction` from state when present so the entire user-facing question remains in the preserved session language. Present it clearly with the current ambiguity context:
252
272
 
253
273
  ```
254
274
  Round {n} | Component: {target_component_name} | Targeting: {weakest_dimension} | Why now: {one_sentence_targeting_rationale} | Ambiguity: {score}%
@@ -258,10 +278,18 @@ Round {n} | Component: {target_component_name} | Targeting: {weakest_dimension}
258
278
 
259
279
  Options should include contextually relevant choices plus free-text.
260
280
 
281
+ ### Step 2b′: Auto-Answer Opted-Out Questions
282
+
283
+ After the `ask` tool resolves and before ambiguity scoring, if the user opts out of answering the current question or explicitly asks the agent to decide, load `auto-answer-uncertain.md` as an internal `kind: "skill-fragment"` prompt for a fork-context architect. Pass the opted-out question, prompt-safe transcript summary, locked topology, current scores/gaps, and any auto-research candidates used for the round. The architect must return exactly one decisive answer with rationale, confidence, and explicit uncertainty. Validate the response shape before using it; if valid, record it as the tentative answer for scoring, append the round number to `auto_answered_rounds`, and mark the transcript answer as architect-assisted.
284
+
285
+ Auto-answer has a clarity cap: unless the architect confidence is `high` and uncertainty is negligible, no dimension score improved solely by the auto-answer may exceed `0.85`. If the auto-answer would make ambiguity cross the resolved threshold, ask the user for threshold-crossing confirmation before Phase 4: present the tentative assumption and require explicit confirmation, revision, or continued questioning. On architect failure or invalid response, continue with the user's opt-out as an unresolved gap, increment `architect_failures`, and do not block the interview.
286
+
261
287
  ### Step 2c: Score Ambiguity
262
288
 
263
289
  After receiving the user's answer, score clarity across all dimensions.
264
290
 
291
+ If the round used an auto-answer, include the architect answer, rationale, confidence, and uncertainty in the scoring prompt. Apply the Step 2b′ clarity cap mechanically before calculating ambiguity, and treat any low-confidence or insufficient-context auto-answer as an unresolved gap rather than user-confirmed truth.
292
+
265
293
  **Scoring prompt** (use opus model, temperature 0.1 for consistency):
266
294
 
267
295
  ```
@@ -355,7 +383,7 @@ Round {n} complete.
355
383
 
356
384
  ### Step 2e: Update State
357
385
 
358
- Update interview state with the new round, global scores, per-component `topology.components[].clarity_scores`, `topology.components[].weakest_dimension`, ontology snapshot, and `topology.last_targeted_component_id` via `gjc state write`; never patch `.gjc/state` directly unless an explicit force override is active.
386
+ Update interview state with the new round, global scores, per-component `topology.components[].clarity_scores`, `topology.components[].weakest_dimension`, ontology snapshot, `topology.last_targeted_component_id`, `auto_researched_rounds`, `auto_answered_rounds`, and `architect_failures` via `gjc state write`; never patch `.gjc/state` directly unless an explicit force override is active.
359
387
 
360
388
  ### Step 2f: Check Soft Limits
361
389
 
@@ -408,6 +436,9 @@ Spec structure:
408
436
  - Threshold Source: <resolvedThresholdSource>
409
437
  - Initial Context Summarized: {yes|no}
410
438
  - Status: {PASSED | BELOW_THRESHOLD_EARLY_EXIT}
439
+ - Auto-Researched Rounds: {auto_researched_rounds}
440
+ - Auto-Answered Rounds: {auto_answered_rounds}
441
+ - Architect Failures: {architect_failures}
411
442
 
412
443
  ## Clarity Breakdown
413
444
  | Dimension | Score | Weight | Weighted |
@@ -569,6 +600,8 @@ Skipping any stage is possible but reduces quality assurance:
569
600
  - Use the GJC workflow CLI to save the final spec at `.gjc/specs/deep-interview-{slug}.md` exactly; do not use `write`, `edit`, or `ast_edit` directly on `.gjc/` paths without force override.
570
601
  - Use public GJC workflow entrypoints to bridge to ralplan/team only after explicit execution approval — never implement directly
571
602
  - Challenge agent modes are prompt injections, not separate agent spawns
603
+ - Use internal fragment auto-modes only at their documented hooks: `auto-research-greenfield.md` between Step 2a and 2b for greenfield `research: true` questions, and `auto-answer-uncertain.md` as Step 2b′ after `ask` resolves and before scoring.
604
+ - Fragment auto-modes are loaded on demand as `kind: "skill-fragment"`; they are not public workflow skills, not slash-command/discoverable, and not `skill://` registrations.
572
605
  </Tool_Usage>
573
606
 
574
607
  <Examples>
@@ -703,6 +736,8 @@ Why bad: 45% ambiguity means nearly half the requirements are unclear. The mathe
703
736
  - [ ] Multi-component interviews rotate targeting across active components when N > 1
704
737
  - [ ] Spec includes Topology section with confirmed active components and user-confirmed deferrals
705
738
  - [ ] Spec includes Ontology (Key Entities) table and Ontology Convergence section
739
+ - [ ] Internal auto-mode fragments, when used, were loaded only on demand as non-public `kind: "skill-fragment"` prompts; responses were validated, failures incremented `architect_failures`, and final metadata includes `auto_researched_rounds`, `auto_answered_rounds`, and `architect_failures`
740
+ - [ ] Auto-answer threshold crossing, if any, received explicit user confirmation before spec crystallization
706
741
  </Final_Checklist>
707
742
 
708
743
  <Advanced>