@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.
- package/CHANGELOG.md +17 -8600
- package/dist/types/cli/update-cli.d.ts +3 -0
- package/dist/types/config/settings-schema.d.ts +20 -0
- package/dist/types/defaults/gjc-defaults.d.ts +19 -6
- package/dist/types/modes/components/settings-selector.d.ts +4 -0
- package/dist/types/modes/controllers/selector-controller.d.ts +1 -0
- package/dist/types/modes/interactive-mode.d.ts +1 -0
- package/dist/types/modes/theme/defaults/index.d.ts +126 -0
- package/dist/types/modes/theme/theme.d.ts +5 -0
- package/dist/types/modes/types.d.ts +1 -0
- package/package.json +7 -7
- package/src/cli/update-cli.ts +67 -16
- package/src/config/settings-schema.ts +22 -0
- package/src/defaults/gjc/skills/deep-interview/SKILL.md +39 -4
- package/src/defaults/gjc/skills/deep-interview/auto-answer-uncertain.md +37 -0
- package/src/defaults/gjc/skills/deep-interview/auto-research-greenfield.md +42 -0
- package/src/defaults/gjc/skills/ultragoal/SKILL.md +9 -6
- package/src/defaults/gjc-defaults.ts +68 -16
- package/src/gjc-runtime/deep-interview-runtime.ts +44 -0
- package/src/gjc-runtime/state-runtime.ts +3 -2
- package/src/goals/tools/goal-tool.ts +5 -1
- package/src/internal-urls/docs-index.generated.ts +4 -2
- package/src/memories/index.ts +5 -4
- package/src/modes/components/settings-selector.ts +25 -14
- package/src/modes/controllers/command-controller.ts +1 -1
- package/src/modes/controllers/selector-controller.ts +67 -0
- package/src/modes/interactive-mode.ts +14 -1
- package/src/modes/theme/defaults/blue-crab.json +126 -0
- package/src/modes/theme/defaults/index.ts +2 -0
- package/src/modes/theme/theme.ts +40 -1
- package/src/modes/types.ts +1 -0
- package/src/prompts/memories/unavailable.md +9 -0
- package/src/sdk.ts +4 -0
- 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
|
|
15
|
-
kind:
|
|
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
|
|
26
|
-
kind:
|
|
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 */
|
|
@@ -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.
|
|
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.
|
|
52
|
-
"@gajae-code/agent-core": "0.2.
|
|
53
|
-
"@gajae-code/ai": "0.2.
|
|
54
|
-
"@gajae-code/natives": "0.2.
|
|
55
|
-
"@gajae-code/tui": "0.2.
|
|
56
|
-
"@gajae-code/utils": "0.2.
|
|
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",
|
package/src/cli/update-cli.ts
CHANGED
|
@@ -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
|
|
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
|
|
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(
|
|
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,
|
|
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>
|