@gajae-code/coding-agent 0.11.2 → 0.11.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 +34 -0
- package/dist/types/cli/launch-disposition.d.ts +23 -0
- package/dist/types/cli/worktree-cli.d.ts +8 -25
- package/dist/types/commands/gc.d.ts +4 -0
- package/dist/types/commands/worktree.d.ts +7 -32
- package/dist/types/config/settings-schema.d.ts +85 -10
- package/dist/types/gjc-runtime/gc-runtime.d.ts +9 -0
- package/dist/types/gjc-runtime/state-argv.d.ts +38 -0
- package/dist/types/main.d.ts +1 -0
- package/dist/types/modes/components/custom-editor.d.ts +8 -3
- package/dist/types/modes/components/tool-transcript-format.d.ts +19 -0
- package/dist/types/modes/controllers/input-controller.d.ts +8 -2
- package/dist/types/modes/prompt-action-autocomplete.d.ts +4 -0
- package/dist/types/sdk/broker/broker.d.ts +1 -0
- package/dist/types/sdk/broker/discovery.d.ts +10 -0
- package/dist/types/sdk/broker/ensure.d.ts +24 -1
- package/dist/types/sdk/broker/internal.d.ts +3 -0
- package/dist/types/sdk/broker/session-index.d.ts +12 -0
- package/dist/types/sdk/broker/state-version.d.ts +2 -1
- package/dist/types/sdk/bus/index.d.ts +2 -0
- package/dist/types/sdk/session.d.ts +2 -0
- package/dist/types/tools/ask.d.ts +39 -12
- package/dist/types/tools/browser/screenshot-format.d.ts +8 -0
- package/dist/types/tools/browser/tab-protocol.d.ts +11 -0
- package/dist/types/tools/browser/tab-supervisor.d.ts +1 -1
- package/dist/types/tools/browser/tab-worker-path-resolver.d.ts +2 -0
- package/dist/types/tools/browser/tab-worker-smoke.d.ts +16 -0
- package/dist/types/tools/path-utils.d.ts +9 -14
- package/dist/types/tools/read.d.ts +2 -0
- package/dist/types/tools/render-utils.d.ts +1 -8
- package/dist/types/tools/resource-gc.d.ts +14 -0
- package/dist/types/tools/subagent.d.ts +1 -0
- package/dist/types/utils/file-mentions.d.ts +3 -3
- package/dist/types/utils/image-loading.d.ts +23 -0
- package/dist/types/utils/image-resize.d.ts +2 -0
- package/dist/types/utils/pasted-image-loading.d.ts +39 -0
- package/dist/types/utils/pasted-image-path.d.ts +21 -19
- package/dist/types/web/scrapers/html-to-markdown.d.ts +5 -0
- package/dist/types/web/scrapers/types.d.ts +1 -5
- package/package.json +24 -8
- package/scripts/run-threat-model-check.ts +60 -0
- package/src/cli/launch-disposition.ts +42 -0
- package/src/cli/worktree-cli.ts +9 -287
- package/src/cli.ts +10 -9
- package/src/commands/gc.ts +11 -1
- package/src/commands/sdk.ts +3 -2
- package/src/commands/worktree.ts +10 -53
- package/src/config/model-profiles.ts +15 -15
- package/src/config/settings-schema.ts +55 -10
- package/src/eval/js/shared/runtime.ts +1 -1
- package/src/gjc-runtime/gc-render.ts +19 -1
- package/src/gjc-runtime/gc-runtime.ts +68 -3
- package/src/gjc-runtime/state-argv.ts +292 -0
- package/src/gjc-runtime/state-runtime.ts +51 -212
- package/src/main.ts +99 -22
- package/src/modes/components/custom-editor.ts +103 -32
- package/src/modes/components/custom-provider-wizard.ts +26 -1
- package/src/modes/components/session-observer-overlay.ts +10 -23
- package/src/modes/components/tool-transcript-format.ts +72 -0
- package/src/modes/components/transcript-viewer-overlay.ts +42 -2
- package/src/modes/controllers/input-controller.ts +98 -37
- package/src/modes/controllers/selector-controller.ts +1 -1
- package/src/modes/interactive-mode.ts +13 -2
- package/src/modes/prompt-action-autocomplete.ts +7 -0
- package/src/sdk/broker/broker.ts +139 -32
- package/src/sdk/broker/discovery.ts +125 -0
- package/src/sdk/broker/ensure.ts +103 -19
- package/src/sdk/broker/internal.ts +10 -0
- package/src/sdk/broker/session-index.ts +228 -15
- package/src/sdk/broker/state-version.ts +5 -2
- package/src/sdk/bus/index.ts +4 -1
- package/src/sdk/bus/telegram-daemon.ts +50 -10
- package/src/sdk/host/host.ts +13 -1
- package/src/sdk/session.ts +4 -1
- package/src/session/internal/managed-session-scope.ts +15 -1
- package/src/tools/ask.ts +216 -41
- package/src/tools/bash-allowed-prefixes.ts +79 -29
- package/src/tools/browser/launch.ts +3 -1
- package/src/tools/browser/readable.ts +1 -1
- package/src/tools/browser/screenshot-format.ts +34 -0
- package/src/tools/browser/tab-protocol.ts +3 -0
- package/src/tools/browser/tab-supervisor.ts +125 -122
- package/src/tools/browser/tab-worker-entry.ts +33 -14
- package/src/tools/browser/tab-worker-path-resolver.ts +67 -0
- package/src/tools/browser/tab-worker-smoke.ts +87 -0
- package/src/tools/browser/tab-worker.ts +7 -5
- package/src/tools/output-meta.ts +6 -2
- package/src/tools/path-utils.ts +42 -35
- package/src/tools/read.ts +189 -64
- package/src/tools/render-utils.ts +1 -27
- package/src/tools/resource-gc.ts +123 -34
- package/src/tools/subagent.ts +43 -2
- package/src/utils/file-mentions.ts +4 -4
- package/src/utils/image-loading.ts +85 -34
- package/src/utils/image-resize.ts +16 -9
- package/src/utils/pasted-image-loading.ts +514 -0
- package/src/utils/pasted-image-path.ts +223 -98
- package/src/web/scrapers/html-to-markdown.ts +68 -0
- package/src/web/scrapers/readthedocs.ts +1 -1
- package/src/web/scrapers/types.ts +1 -68
- package/src/web/search/providers/openai-compatible.ts +76 -23
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
* - Questions may time out and auto-select the recommended option (configurable, disabled in plan mode)
|
|
16
16
|
*/
|
|
17
17
|
import type { AgentTool, AgentToolContext, AgentToolResult, AgentToolUpdateCallback } from "@gajae-code/agent-core";
|
|
18
|
+
import type { RawArgumentValidationResult } from "@gajae-code/ai/types";
|
|
18
19
|
import { type Component } from "@gajae-code/tui";
|
|
19
20
|
import * as z from "zod/v4";
|
|
20
21
|
import type { RenderResultOptions } from "../extensibility/custom-tools/types";
|
|
@@ -29,13 +30,19 @@ export declare const askSchema: z.ZodObject<{
|
|
|
29
30
|
}, z.core.$strip>>;
|
|
30
31
|
multi: z.ZodOptional<z.ZodBoolean>;
|
|
31
32
|
recommended: z.ZodOptional<z.ZodNumber>;
|
|
32
|
-
deepInterview: z.ZodOptional<z.ZodObject<{
|
|
33
|
+
deepInterview: z.ZodOptional<z.ZodUnion<readonly [z.ZodObject<{
|
|
33
34
|
round_id: z.ZodOptional<z.ZodString>;
|
|
34
35
|
round: z.ZodNumber;
|
|
35
36
|
component: z.ZodString;
|
|
36
37
|
dimension: z.ZodString;
|
|
37
38
|
ambiguity: z.ZodNumber;
|
|
38
|
-
|
|
39
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
40
|
+
round_id: z.ZodOptional<z.ZodString>;
|
|
41
|
+
ambiguity: z.ZodNumber;
|
|
42
|
+
round: z.ZodLiteral<0>;
|
|
43
|
+
component: z.ZodLiteral<"review-topology">;
|
|
44
|
+
dimension: z.ZodLiteral<"topology">;
|
|
45
|
+
intent_contract: z.ZodObject<{
|
|
39
46
|
items: z.ZodArray<z.ZodObject<{
|
|
40
47
|
id: z.ZodString;
|
|
41
48
|
category: z.ZodEnum<{
|
|
@@ -47,8 +54,14 @@ export declare const askSchema: z.ZodObject<{
|
|
|
47
54
|
statement: z.ZodString;
|
|
48
55
|
}, z.core.$strict>>;
|
|
49
56
|
confirmation_options: z.ZodArray<z.ZodString>;
|
|
50
|
-
}, z.core.$strict
|
|
51
|
-
|
|
57
|
+
}, z.core.$strict>;
|
|
58
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
59
|
+
round_id: z.ZodOptional<z.ZodString>;
|
|
60
|
+
component: z.ZodString;
|
|
61
|
+
dimension: z.ZodString;
|
|
62
|
+
ambiguity: z.ZodNumber;
|
|
63
|
+
round: z.ZodNumber;
|
|
64
|
+
intent_review: z.ZodObject<{
|
|
52
65
|
observed_items: z.ZodArray<z.ZodObject<{
|
|
53
66
|
id: z.ZodString;
|
|
54
67
|
category: z.ZodEnum<{
|
|
@@ -65,8 +78,8 @@ export declare const askSchema: z.ZodObject<{
|
|
|
65
78
|
rationale: z.ZodString;
|
|
66
79
|
}, z.core.$strict>>;
|
|
67
80
|
approval_options: z.ZodArray<z.ZodString>;
|
|
68
|
-
}, z.core.$strict
|
|
69
|
-
}, z.core.$strict>>;
|
|
81
|
+
}, z.core.$strict>;
|
|
82
|
+
}, z.core.$strict>]>>;
|
|
70
83
|
workflowGate: z.ZodOptional<z.ZodObject<{
|
|
71
84
|
stage: z.ZodEnum<{
|
|
72
85
|
"deep-interview": "deep-interview";
|
|
@@ -82,6 +95,7 @@ export declare const askSchema: z.ZodObject<{
|
|
|
82
95
|
}, z.core.$strip>>;
|
|
83
96
|
}, z.core.$strip>;
|
|
84
97
|
export type AskToolInput = z.infer<typeof askSchema>;
|
|
98
|
+
declare function recoverRoundZeroIntentContract(arguments_: Record<string, unknown>): RawArgumentValidationResult;
|
|
85
99
|
/** Result for a single question */
|
|
86
100
|
export interface QuestionResult {
|
|
87
101
|
id: string;
|
|
@@ -149,13 +163,19 @@ export declare class AskTool implements AgentTool<typeof askSchema, AskToolDetai
|
|
|
149
163
|
}, z.core.$strip>>;
|
|
150
164
|
multi: z.ZodOptional<z.ZodBoolean>;
|
|
151
165
|
recommended: z.ZodOptional<z.ZodNumber>;
|
|
152
|
-
deepInterview: z.ZodOptional<z.ZodObject<{
|
|
166
|
+
deepInterview: z.ZodOptional<z.ZodUnion<readonly [z.ZodObject<{
|
|
153
167
|
round_id: z.ZodOptional<z.ZodString>;
|
|
154
168
|
round: z.ZodNumber;
|
|
155
169
|
component: z.ZodString;
|
|
156
170
|
dimension: z.ZodString;
|
|
157
171
|
ambiguity: z.ZodNumber;
|
|
158
|
-
|
|
172
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
173
|
+
round_id: z.ZodOptional<z.ZodString>;
|
|
174
|
+
ambiguity: z.ZodNumber;
|
|
175
|
+
round: z.ZodLiteral<0>;
|
|
176
|
+
component: z.ZodLiteral<"review-topology">;
|
|
177
|
+
dimension: z.ZodLiteral<"topology">;
|
|
178
|
+
intent_contract: z.ZodObject<{
|
|
159
179
|
items: z.ZodArray<z.ZodObject<{
|
|
160
180
|
id: z.ZodString;
|
|
161
181
|
category: z.ZodEnum<{
|
|
@@ -167,8 +187,14 @@ export declare class AskTool implements AgentTool<typeof askSchema, AskToolDetai
|
|
|
167
187
|
statement: z.ZodString;
|
|
168
188
|
}, z.core.$strict>>;
|
|
169
189
|
confirmation_options: z.ZodArray<z.ZodString>;
|
|
170
|
-
}, z.core.$strict
|
|
171
|
-
|
|
190
|
+
}, z.core.$strict>;
|
|
191
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
192
|
+
round_id: z.ZodOptional<z.ZodString>;
|
|
193
|
+
component: z.ZodString;
|
|
194
|
+
dimension: z.ZodString;
|
|
195
|
+
ambiguity: z.ZodNumber;
|
|
196
|
+
round: z.ZodNumber;
|
|
197
|
+
intent_review: z.ZodObject<{
|
|
172
198
|
observed_items: z.ZodArray<z.ZodObject<{
|
|
173
199
|
id: z.ZodString;
|
|
174
200
|
category: z.ZodEnum<{
|
|
@@ -185,8 +211,8 @@ export declare class AskTool implements AgentTool<typeof askSchema, AskToolDetai
|
|
|
185
211
|
rationale: z.ZodString;
|
|
186
212
|
}, z.core.$strict>>;
|
|
187
213
|
approval_options: z.ZodArray<z.ZodString>;
|
|
188
|
-
}, z.core.$strict
|
|
189
|
-
}, z.core.$strict>>;
|
|
214
|
+
}, z.core.$strict>;
|
|
215
|
+
}, z.core.$strict>]>>;
|
|
190
216
|
workflowGate: z.ZodOptional<z.ZodObject<{
|
|
191
217
|
stage: z.ZodEnum<{
|
|
192
218
|
"deep-interview": "deep-interview";
|
|
@@ -201,6 +227,7 @@ export declare class AskTool implements AgentTool<typeof askSchema, AskToolDetai
|
|
|
201
227
|
}, z.core.$strip>>;
|
|
202
228
|
}, z.core.$strip>>;
|
|
203
229
|
}, z.core.$strip>;
|
|
230
|
+
readonly rawArgumentValidation: typeof recoverRoundZeroIntentContract;
|
|
204
231
|
readonly strict = true;
|
|
205
232
|
readonly loadMode = "discoverable";
|
|
206
233
|
constructor(session: ToolSession);
|
|
@@ -70,6 +70,10 @@ export type ToolReply = {
|
|
|
70
70
|
error: RunErrorPayload;
|
|
71
71
|
};
|
|
72
72
|
export type WorkerInbound = {
|
|
73
|
+
type: "bootstrap";
|
|
74
|
+
version: 1;
|
|
75
|
+
mode: "native-free";
|
|
76
|
+
} | {
|
|
73
77
|
type: "init";
|
|
74
78
|
payload: WorkerInitPayload;
|
|
75
79
|
} | {
|
|
@@ -112,6 +116,13 @@ export interface RunErrorPayload {
|
|
|
112
116
|
isAbort: boolean;
|
|
113
117
|
}
|
|
114
118
|
export type WorkerOutbound = {
|
|
119
|
+
type: "bootstrap-ready";
|
|
120
|
+
version: 1;
|
|
121
|
+
mode: "native-free";
|
|
122
|
+
} | {
|
|
123
|
+
type: "bootstrap-failed";
|
|
124
|
+
error: string;
|
|
125
|
+
} | {
|
|
115
126
|
type: "ready";
|
|
116
127
|
info: ReadyInfo;
|
|
117
128
|
} | {
|
|
@@ -5,8 +5,8 @@ interface WorkerHandle {
|
|
|
5
5
|
send(msg: WorkerInbound, transferList?: Transferable[]): void;
|
|
6
6
|
onMessage(handler: (msg: WorkerOutbound) => void): () => void;
|
|
7
7
|
onError(handler: (error: Error) => void): () => void;
|
|
8
|
+
onClose(handler: () => void): () => void;
|
|
8
9
|
terminate(): Promise<void>;
|
|
9
|
-
readonly mode: "worker" | "inline";
|
|
10
10
|
}
|
|
11
11
|
export type DialogPolicy = "accept" | "dismiss";
|
|
12
12
|
export interface PendingRun {
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { WorkerInbound } from "./tab-protocol";
|
|
2
|
+
interface SmokeWorkerHandle {
|
|
3
|
+
postMessage(message: WorkerInbound): void;
|
|
4
|
+
addEventListener(type: string, listener: EventListener): void;
|
|
5
|
+
removeEventListener(type: string, listener: EventListener): void;
|
|
6
|
+
terminate(): void;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Starts the real tab worker entry without connecting to a browser, then proves
|
|
10
|
+
* its bootstrap and shutdown protocol. The compiled branch deliberately keeps
|
|
11
|
+
* a static literal for Bun's --compile worker discovery.
|
|
12
|
+
*/
|
|
13
|
+
export declare function smokeTestTabWorker(timeoutMs?: number): Promise<void>;
|
|
14
|
+
/** Test-only: verify the smoke handshake against a controlled worker transport. */
|
|
15
|
+
export declare function smokeTestTabWorkerWithWorkerForTest(worker: SmokeWorkerHandle, timeoutMs: number): Promise<void>;
|
|
16
|
+
export {};
|
|
@@ -7,21 +7,16 @@ export declare function splitPathAndSel(rawPath: string): {
|
|
|
7
7
|
/**
|
|
8
8
|
* Variant of {@link splitPathAndSel} for internal URLs (`scheme://...`).
|
|
9
9
|
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
* This function iteratively peels selector-shaped chunks (well-formed plus
|
|
18
|
-
* common malformed shapes like `:-N`) so the rest of the read tool can pass a
|
|
19
|
-
* clean URL to the protocol handler and surface selector errors via parseSel
|
|
20
|
-
* instead of as misleading "host invalid" errors from the handler.
|
|
21
|
-
*
|
|
22
|
-
* Falls back to the input unchanged when nothing matches.
|
|
10
|
+
* Artifact authorities are generated identifiers, so their complete tail is
|
|
11
|
+
* unambiguously a selector and malformed selectors can be rejected before
|
|
12
|
+
* resolving the artifact. Other resources may legitimately use colons in
|
|
13
|
+
* their identities, so they only lose strict, recognized selector suffixes.
|
|
14
|
+
* Skill authorities additionally use the active registry to distinguish a
|
|
15
|
+
* skill name from its selector without making path-utils depend on skills.
|
|
23
16
|
*/
|
|
24
|
-
export declare function splitInternalUrlSel(rawPath: string
|
|
17
|
+
export declare function splitInternalUrlSel(rawPath: string, options?: {
|
|
18
|
+
activeSkillNames?: readonly string[];
|
|
19
|
+
}): {
|
|
25
20
|
path: string;
|
|
26
21
|
sel?: string;
|
|
27
22
|
};
|
|
@@ -27,6 +27,8 @@ export interface ReadToolDetails {
|
|
|
27
27
|
method?: string;
|
|
28
28
|
notes?: string[];
|
|
29
29
|
meta?: OutputMeta;
|
|
30
|
+
/** Whether this explicit content read may be spilled by output metadata. */
|
|
31
|
+
spillEligible?: boolean;
|
|
30
32
|
/** Raw text + start line for user-visible TUI rendering, set when content is text-like.
|
|
31
33
|
* Mirrors the same lines the model receives but without hashline/line-number prefixes,
|
|
32
34
|
* so the TUI can render the file content with its own gutter without re-parsing the formatted text. */
|
|
@@ -8,9 +8,9 @@ import type { ToolCallContext } from "@gajae-code/agent-core";
|
|
|
8
8
|
import type { Ellipsis } from "@gajae-code/natives";
|
|
9
9
|
import type { Component } from "@gajae-code/tui";
|
|
10
10
|
import type { Theme } from "../modes/theme/theme";
|
|
11
|
-
import { type ResizedImage } from "../utils/image-resize";
|
|
12
11
|
export { Ellipsis } from "@gajae-code/natives";
|
|
13
12
|
export { replaceTabs, truncateToWidth, wrapTextWithAnsi } from "@gajae-code/tui";
|
|
13
|
+
export { formatScreenshot } from "./browser/screenshot-format";
|
|
14
14
|
/** Resolve inline image dimension caps from settings and viewport. */
|
|
15
15
|
export declare function resolveImageOptions(): {
|
|
16
16
|
maxWidthCells: number;
|
|
@@ -107,13 +107,6 @@ export declare function truncateDiffByHunk(diffText: string, maxHunks: number, m
|
|
|
107
107
|
};
|
|
108
108
|
export declare function shortenPath(filePath: string, homeDir?: string): string;
|
|
109
109
|
export declare function formatToolWorkingDirectory(workdir: string | undefined, projectDir: string): string | undefined;
|
|
110
|
-
export declare function formatScreenshot(opts: {
|
|
111
|
-
saveFullRes: boolean;
|
|
112
|
-
savedMimeType: string;
|
|
113
|
-
savedByteLength: number;
|
|
114
|
-
dest: string;
|
|
115
|
-
resized: ResizedImage;
|
|
116
|
-
}): string[];
|
|
117
110
|
export declare function wrapBrackets(text: string, theme: Theme): string;
|
|
118
111
|
export declare const PARSE_ERRORS_LIMIT = 20;
|
|
119
112
|
export declare function dedupeParseErrors(errors: string[] | undefined): string[];
|
|
@@ -44,11 +44,25 @@ export interface ResourceGcRegistration {
|
|
|
44
44
|
export declare function registerResourceGcSession(reg: ResourceGcRegistration): () => void;
|
|
45
45
|
export declare function sweepOnce(d?: ResourceGcDeps): Promise<void>;
|
|
46
46
|
export declare function __setResourceGcDepsForTest(overrides: Partial<ResourceGcDeps>): void;
|
|
47
|
+
export declare function __setResourceGcSchedulerNowForTest(now: () => number): void;
|
|
47
48
|
export declare function __runResourceGcTickForTest(): Promise<void>;
|
|
49
|
+
export declare function __runResourceGcTimerCallbackForTest(owner: {
|
|
50
|
+
generation: number;
|
|
51
|
+
token: number;
|
|
52
|
+
}, deadline: number): Promise<void>;
|
|
48
53
|
export declare function __getResourceGcStateForTest(): {
|
|
49
54
|
timerActive: boolean;
|
|
50
55
|
sessionCount: number;
|
|
51
56
|
rssWarningActive: boolean;
|
|
52
57
|
inProgress: boolean;
|
|
58
|
+
generation: number;
|
|
59
|
+
pendingDeadline: number | null;
|
|
60
|
+
pendingOwner: {
|
|
61
|
+
generation: number;
|
|
62
|
+
token: number;
|
|
63
|
+
} | null;
|
|
64
|
+
deferredDeadline: number | null;
|
|
65
|
+
deferredGeneration: number | null;
|
|
66
|
+
activeGeneration: number | null;
|
|
53
67
|
};
|
|
54
68
|
export declare function __resetResourceGcForTest(): void;
|
|
@@ -98,6 +98,7 @@ export declare class SubagentTool implements AgentTool<typeof subagentSchema, Su
|
|
|
98
98
|
constructor(session: ToolSession);
|
|
99
99
|
execute(_toolCallId: string, params: SubagentParams, signal?: AbortSignal, onUpdate?: AgentToolUpdateCallback<SubagentToolDetails>, _context?: AgentToolContext): Promise<AgentToolResult<SubagentToolDetails>>;
|
|
100
100
|
}
|
|
101
|
+
export declare function capCodePointsAndBytes(text: string, maxCodePoints: number, maxBytes: number): string;
|
|
101
102
|
/**
|
|
102
103
|
* Canonical, value-based rendered-state signature for the `subagent` await panel.
|
|
103
104
|
*
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import type { AgentMessage } from "@gajae-code/agent-core";
|
|
2
2
|
/**
|
|
3
|
-
* Default inline cap for auto-read file mentions,
|
|
4
|
-
*
|
|
5
|
-
*
|
|
3
|
+
* Default inline cap for auto-read file mentions, aligned with the read-tool's
|
|
4
|
+
* 10 KiB bare-read receipt so an incidental `@path` mention injects a bounded
|
|
5
|
+
* snippet. Overridable per call.
|
|
6
6
|
*/
|
|
7
7
|
export declare const DEFAULT_FILE_MENTION_INLINE_BYTES: number;
|
|
8
8
|
/** Extract all @filepath mentions from text */
|
|
@@ -8,6 +8,24 @@ export interface LoadImageInputOptions {
|
|
|
8
8
|
maxBytes?: number;
|
|
9
9
|
resolvedPath?: string;
|
|
10
10
|
detectedMimeType?: string;
|
|
11
|
+
signal?: AbortSignal;
|
|
12
|
+
}
|
|
13
|
+
export interface LoadImageInputBytesOptions {
|
|
14
|
+
inputBuffer: Buffer;
|
|
15
|
+
resolvedPath: string;
|
|
16
|
+
mimeType: string;
|
|
17
|
+
autoResize: boolean;
|
|
18
|
+
maxBytes?: number;
|
|
19
|
+
maxOutputBytes?: number;
|
|
20
|
+
signal?: AbortSignal;
|
|
21
|
+
}
|
|
22
|
+
export interface TransformedImageInput {
|
|
23
|
+
resolvedPath: string;
|
|
24
|
+
mimeType: string;
|
|
25
|
+
buffer: Uint8Array;
|
|
26
|
+
textNote: string;
|
|
27
|
+
dimensionNote?: string;
|
|
28
|
+
bytes: number;
|
|
11
29
|
}
|
|
12
30
|
export interface LoadedImageInput {
|
|
13
31
|
resolvedPath: string;
|
|
@@ -23,4 +41,9 @@ export declare class ImageInputTooLargeError extends Error {
|
|
|
23
41
|
constructor(bytes: number, maxBytes: number);
|
|
24
42
|
}
|
|
25
43
|
export declare function ensureSupportedImageInput(image: ImageContent): Promise<ImageContent | null>;
|
|
44
|
+
/** Transform trusted source bytes without materializing a base64 payload. */
|
|
45
|
+
export declare function transformImageInputBytes(options: LoadImageInputBytesOptions): Promise<TransformedImageInput>;
|
|
46
|
+
export declare function materializeImageInput(transformed: TransformedImageInput): LoadedImageInput;
|
|
47
|
+
/** Build a model image payload from bytes already read through a trusted descriptor. */
|
|
48
|
+
export declare function loadImageInputBytes(options: LoadImageInputBytesOptions): Promise<LoadedImageInput>;
|
|
26
49
|
export declare function loadImageInput(options: LoadImageInputOptions): Promise<LoadedImageInput | null>;
|
|
@@ -16,6 +16,7 @@ export interface ResizedImage {
|
|
|
16
16
|
wasResized: boolean;
|
|
17
17
|
get data(): string;
|
|
18
18
|
}
|
|
19
|
+
export declare const DEFAULT_IMAGE_RESIZE_MAX_BYTES: number;
|
|
19
20
|
/**
|
|
20
21
|
* Resize and recompress an image to fit within the specified max dimensions and file size.
|
|
21
22
|
*
|
|
@@ -31,6 +32,7 @@ export interface ResizedImage {
|
|
|
31
32
|
* Backed by `Bun.Image`: a chainable native pipeline that runs decode/transform/encode
|
|
32
33
|
* off the JS thread when the terminal (`.bytes()`) is awaited.
|
|
33
34
|
*/
|
|
35
|
+
export declare function resizeImageBuffer(inputBuffer: Buffer, inputMimeType: string, options?: ImageResizeOptions): Promise<ResizedImage>;
|
|
34
36
|
export declare function resizeImage(img: ImageContent, options?: ImageResizeOptions): Promise<ResizedImage>;
|
|
35
37
|
/**
|
|
36
38
|
* Format a dimension note for resized images.
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { ImageContent } from "@gajae-code/ai";
|
|
2
|
+
import { type LoadedImageInput, transformImageInputBytes } from "./image-loading";
|
|
3
|
+
export declare const MAX_PASTED_IMAGE_SOURCE_BYTES: number;
|
|
4
|
+
export declare const MAX_PASTED_IMAGE_OUTPUT_BYTES: number;
|
|
5
|
+
export declare const MAX_PASTED_IMAGE_DIMENSION = 20000;
|
|
6
|
+
export declare const MAX_PASTED_IMAGE_PIXELS = 40000000;
|
|
7
|
+
export declare const MAX_PASTED_IMAGE_DECODED_BYTES: number;
|
|
8
|
+
export type PastedImageBatchErrorCode = "too-many" | "unsafe-path" | "unsupported-image" | "source-aggregate-too-large" | "output-aggregate-too-large" | "dimensions-too-large";
|
|
9
|
+
export declare class PastedImageBatchError extends Error {
|
|
10
|
+
readonly code: PastedImageBatchErrorCode;
|
|
11
|
+
readonly imagePath?: string | undefined;
|
|
12
|
+
constructor(code: PastedImageBatchErrorCode, message: string, imagePath?: string | undefined);
|
|
13
|
+
}
|
|
14
|
+
export interface LoadedPastedImageBatch {
|
|
15
|
+
images: ImageContent[];
|
|
16
|
+
loadedInputs: LoadedImageInput[];
|
|
17
|
+
sourcePaths: string[];
|
|
18
|
+
}
|
|
19
|
+
export interface PastedImageLoadingDependencies {
|
|
20
|
+
/** Synchronization hook used to exercise pathname swaps after descriptor open. */
|
|
21
|
+
afterDescriptorOpen?: (imagePath: string, index: number) => Promise<void> | void;
|
|
22
|
+
beforeDescriptorRead?: (imagePath: string, index: number) => Promise<void> | void;
|
|
23
|
+
transformImageBytes?: typeof transformImageInputBytes;
|
|
24
|
+
}
|
|
25
|
+
export type PastedImageSourcePolicy = "confirmed" | "automatic-temp";
|
|
26
|
+
export interface LoadPastedImageBatchOptions {
|
|
27
|
+
paths: readonly string[];
|
|
28
|
+
autoResize: boolean;
|
|
29
|
+
signal: AbortSignal;
|
|
30
|
+
sourcePolicy?: PastedImageSourcePolicy;
|
|
31
|
+
maxImageBytes?: number;
|
|
32
|
+
maxSourceBytes?: number;
|
|
33
|
+
maxOutputBytes?: number;
|
|
34
|
+
maxDimension?: number;
|
|
35
|
+
maxPixels?: number;
|
|
36
|
+
maxDecodedBytes?: number;
|
|
37
|
+
dependencies?: PastedImageLoadingDependencies;
|
|
38
|
+
}
|
|
39
|
+
export declare function loadPastedImageBatch(options: LoadPastedImageBatchOptions): Promise<LoadedPastedImageBatch>;
|
|
@@ -1,9 +1,8 @@
|
|
|
1
|
+
export declare const MAX_PASTED_IMAGE_COUNT = 16;
|
|
2
|
+
export declare const MAX_PASTED_IMAGE_PASTE_CHARACTERS: number;
|
|
3
|
+
export declare const MAX_PASTED_IMAGE_PATH_CHARACTERS: number;
|
|
1
4
|
export interface DecodePastedPathOptions {
|
|
2
|
-
/**
|
|
3
|
-
* Platform whose path semantics apply when decoding (shell unescaping,
|
|
4
|
-
* `file://` drive letters / UNC hosts). Defaults to `process.platform`;
|
|
5
|
-
* injectable so tests can pin the win32 contract from any host.
|
|
6
|
-
*/
|
|
5
|
+
/** Platform whose path and shell semantics apply. Defaults to `process.platform`. */
|
|
7
6
|
platform?: NodeJS.Platform;
|
|
8
7
|
/** Home directory for `~/` expansion. Defaults to `os.homedir()`. */
|
|
9
8
|
homedir?: string;
|
|
@@ -12,21 +11,24 @@ export interface ResolvePastedImagePathOptions extends DecodePastedPathOptions {
|
|
|
12
11
|
/** Base directory for relative paths. Defaults to `process.cwd()`. */
|
|
13
12
|
cwd?: string;
|
|
14
13
|
}
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
*/
|
|
14
|
+
export type PastedImagePathParseResult = {
|
|
15
|
+
kind: "paths";
|
|
16
|
+
paths: string[];
|
|
17
|
+
requiresConfirmation: boolean;
|
|
18
|
+
} | {
|
|
19
|
+
kind: "too-many";
|
|
20
|
+
maxCandidates: number;
|
|
21
|
+
};
|
|
22
|
+
/** Decode one pasted path candidate without filesystem access. */
|
|
24
23
|
export declare function decodePastedPathCandidate(text: string, options?: DecodePastedPathOptions): string | undefined;
|
|
24
|
+
/** Tokenize a bounded complete path list without filesystem access. */
|
|
25
|
+
export declare function decodePastedPathCandidates(text: string, options?: DecodePastedPathOptions, maxCandidates?: number): string[] | undefined;
|
|
26
|
+
/** Resolve one recognized clipboard-temp image path lexically, before any filesystem access. */
|
|
27
|
+
export declare function resolvePastedImagePath(text: string, options?: ResolvePastedImagePathOptions): string | undefined;
|
|
25
28
|
/**
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
* users attach them explicitly with `@path/to/image.png`.
|
|
29
|
+
* Parse a complete image path paste without filesystem access. A single path
|
|
30
|
+
* keeps the clipboard-temp-only policy; multi-path saved-image pastes require
|
|
31
|
+
* explicit confirmation before any path is opened.
|
|
30
32
|
*/
|
|
31
|
-
export declare function
|
|
33
|
+
export declare function parsePastedImagePaths(text: string, options?: ResolvePastedImagePathOptions): PastedImagePathParseResult | undefined;
|
|
32
34
|
export declare function formatPastedImageReference(placeholder: string, imagePath: string): string;
|
|
@@ -44,11 +44,7 @@ export interface LoadPageResult {
|
|
|
44
44
|
* Fetch a page with timeout and size limit
|
|
45
45
|
*/
|
|
46
46
|
export declare function loadPage(url: string, options?: LoadPageOptions): Promise<LoadPageResult>;
|
|
47
|
-
|
|
48
|
-
* Convert HTML to markdown using Turndown with GFM support.
|
|
49
|
-
* Strips script/style tags before conversion.
|
|
50
|
-
*/
|
|
51
|
-
export declare function htmlToBasicMarkdown(html: string): Promise<string>;
|
|
47
|
+
export { htmlToBasicMarkdown } from "./html-to-markdown";
|
|
52
48
|
/**
|
|
53
49
|
* Build a RenderResult from markdown content. Calls finalizeOutput internally.
|
|
54
50
|
*/
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"type": "module",
|
|
3
3
|
"name": "@gajae-code/coding-agent",
|
|
4
|
-
"version": "0.11.
|
|
4
|
+
"version": "0.11.4",
|
|
5
5
|
"description": "Gajae Code CLI with read, bash, edit, write tools and session management",
|
|
6
6
|
"homepage": "https://gajae-code.com",
|
|
7
7
|
"author": "Yeachan-Heo and Gajae Code Contributors",
|
|
@@ -53,13 +53,13 @@
|
|
|
53
53
|
"@agentclientprotocol/sdk": "1.2.1",
|
|
54
54
|
"@babel/parser": "^7.29.3",
|
|
55
55
|
"@mozilla/readability": "^0.6.0",
|
|
56
|
-
"@gajae-code/stats": "0.11.
|
|
57
|
-
"@gajae-code/agent-core": "0.11.
|
|
58
|
-
"@gajae-code/ai": "0.11.
|
|
59
|
-
"@gajae-code/bridge-client": "0.11.
|
|
60
|
-
"@gajae-code/natives": "0.11.
|
|
61
|
-
"@gajae-code/tui": "0.11.
|
|
62
|
-
"@gajae-code/utils": "0.11.
|
|
56
|
+
"@gajae-code/stats": "0.11.4",
|
|
57
|
+
"@gajae-code/agent-core": "0.11.4",
|
|
58
|
+
"@gajae-code/ai": "0.11.4",
|
|
59
|
+
"@gajae-code/bridge-client": "0.11.4",
|
|
60
|
+
"@gajae-code/natives": "0.11.4",
|
|
61
|
+
"@gajae-code/tui": "0.11.4",
|
|
62
|
+
"@gajae-code/utils": "0.11.4",
|
|
63
63
|
"@puppeteer/browsers": "^2.13.0",
|
|
64
64
|
"@types/turndown": "5.0.6",
|
|
65
65
|
"@xterm/headless": "^6.0.0",
|
|
@@ -171,6 +171,14 @@
|
|
|
171
171
|
"types": "./dist/types/capability/*.d.ts",
|
|
172
172
|
"import": "./src/capability/*.ts"
|
|
173
173
|
},
|
|
174
|
+
"./cli/worktree-cli": {
|
|
175
|
+
"types": "./dist/types/cli/worktree-cli.d.ts",
|
|
176
|
+
"import": "./src/cli/worktree-cli.ts"
|
|
177
|
+
},
|
|
178
|
+
"./cli/worktree-cli.js": {
|
|
179
|
+
"types": "./dist/types/cli/worktree-cli.d.ts",
|
|
180
|
+
"import": "./src/cli/worktree-cli.ts"
|
|
181
|
+
},
|
|
174
182
|
"./cli/*": {
|
|
175
183
|
"types": "./dist/types/cli/*.d.ts",
|
|
176
184
|
"import": "./src/cli/*.ts"
|
|
@@ -187,6 +195,14 @@
|
|
|
187
195
|
"./commands/ultraqa": null,
|
|
188
196
|
"./commands/ultrawork": null,
|
|
189
197
|
"./commands/performance-goal": null,
|
|
198
|
+
"./commands/worktree": {
|
|
199
|
+
"types": "./dist/types/commands/worktree.d.ts",
|
|
200
|
+
"import": "./src/commands/worktree.ts"
|
|
201
|
+
},
|
|
202
|
+
"./commands/worktree.js": {
|
|
203
|
+
"types": "./dist/types/commands/worktree.d.ts",
|
|
204
|
+
"import": "./src/commands/worktree.ts"
|
|
205
|
+
},
|
|
190
206
|
"./commands/*": {
|
|
191
207
|
"types": "./dist/types/commands/*.d.ts",
|
|
192
208
|
"import": "./src/commands/*.ts"
|
|
@@ -14,6 +14,61 @@ function assert(condition: unknown, message: string): asserts condition {
|
|
|
14
14
|
if (!condition) throw new Error(message);
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
+
async function sourceFiles(root: string): Promise<string[]> {
|
|
18
|
+
const files: string[] = [];
|
|
19
|
+
for (const entry of await fs.readdir(root, { withFileTypes: true })) {
|
|
20
|
+
const file = path.join(root, entry.name);
|
|
21
|
+
if (entry.isDirectory()) files.push(...(await sourceFiles(file)));
|
|
22
|
+
else if (/\.(?:ts|tsx|js|mjs|cjs)$/.test(entry.name)) files.push(file);
|
|
23
|
+
}
|
|
24
|
+
return files;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function hasDiscoverySignalAuthority(source: string): boolean {
|
|
28
|
+
return /(?:process\.)?kill\s*\(\s*(?:discovery|brokerDiscovery|record)\.pid\s*,\s*["']SIG(?:TERM|KILL)["']/m.test(
|
|
29
|
+
source,
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
async function assertNoDiscoverySignalAuthority(): Promise<void> {
|
|
34
|
+
const roots = [path.resolve(import.meta.dir, "../src/sdk"), path.resolve(import.meta.dir, "../test")];
|
|
35
|
+
const offenders: string[] = [];
|
|
36
|
+
for (const root of roots) {
|
|
37
|
+
for (const file of await sourceFiles(root)) {
|
|
38
|
+
if (hasDiscoverySignalAuthority(await fs.readFile(file, "utf8")))
|
|
39
|
+
offenders.push(path.relative(process.cwd(), file));
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
assert(offenders.length === 0, `Discovery-derived TERM/KILL authority remains in: ${offenders.join(", ")}`);
|
|
43
|
+
assert(
|
|
44
|
+
hasDiscoverySignalAuthority('process.kill(discovery.pid, "SIGTERM")'),
|
|
45
|
+
"Synthetic forbidden discovery signal was not detected",
|
|
46
|
+
);
|
|
47
|
+
assert(
|
|
48
|
+
!hasDiscoverySignalAuthority("process.kill(discovery.pid, 0)"),
|
|
49
|
+
"PID-zero observation was escalated to signal authority",
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
async function assertFixtureControlsStayTestOnly(): Promise<void> {
|
|
54
|
+
const productionRoot = path.resolve(import.meta.dir, "../src");
|
|
55
|
+
const offenders: string[] = [];
|
|
56
|
+
for (const file of await sourceFiles(productionRoot)) {
|
|
57
|
+
const source = await fs.readFile(file, "utf8");
|
|
58
|
+
if (/\b(?:GSF1|SSH1)\b/.test(source)) offenders.push(path.relative(process.cwd(), file));
|
|
59
|
+
}
|
|
60
|
+
assert(
|
|
61
|
+
offenders.length === 0,
|
|
62
|
+
`Fixture control frames are reachable from production source: ${offenders.join(", ")}`,
|
|
63
|
+
);
|
|
64
|
+
const ensureSource = await fs.readFile(path.resolve(import.meta.dir, "../src/sdk/broker/ensure.ts"), "utf8");
|
|
65
|
+
assert(
|
|
66
|
+
ensureSource.includes("startFixtureBrokerCommandWithLeaseForTest"),
|
|
67
|
+
"Dedicated fixture launch boundary is missing its explicit ForTest label",
|
|
68
|
+
);
|
|
69
|
+
assert(!/GJC_.*(?:GSF1|SSH1|SELF_REAP)/.test(ensureSource), "Production environment can select fixture controls");
|
|
70
|
+
}
|
|
71
|
+
|
|
17
72
|
async function rejectedWebSocket(url: string): Promise<void> {
|
|
18
73
|
const ws = new WebSocket(url);
|
|
19
74
|
await new Promise<void>((resolve, reject) => {
|
|
@@ -132,6 +187,11 @@ async function main(): Promise<void> {
|
|
|
132
187
|
assert(!discovery.url.includes("0.0.0.0"), "non-loopback broker URL exists");
|
|
133
188
|
await rejectedWebSocket(`${discovery.url}/?token=wrong-token`);
|
|
134
189
|
},
|
|
190
|
+
"broker-discovery-derived-signal-authority-forbidden": assertNoDiscoverySignalAuthority,
|
|
191
|
+
"broker-pid-zero-observation-allowed": async () => {
|
|
192
|
+
assert(!hasDiscoverySignalAuthority("process.kill(discovery.pid, 0)"), "PID-zero observation was rejected");
|
|
193
|
+
},
|
|
194
|
+
"broker-fixture-control-nonproduction-reachability": assertFixtureControlsStayTestOnly,
|
|
135
195
|
};
|
|
136
196
|
for (const check of manifest.checks) {
|
|
137
197
|
try {
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
export type LaunchMode = "text" | "json" | "acp";
|
|
2
|
+
|
|
3
|
+
export interface LaunchDisposition {
|
|
4
|
+
autoPrint: boolean;
|
|
5
|
+
isInteractive: boolean;
|
|
6
|
+
/** Set when an interactive launch is impossible (non-TTY stdin, nothing to run). */
|
|
7
|
+
nonInteractiveError?: string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Decides between interactive, auto-print, and fail-fast launches.
|
|
12
|
+
*
|
|
13
|
+
* A non-TTY stdin means the TUI can never receive input, so an interactive
|
|
14
|
+
* launch would execute the initial prompt and then block in the event loop
|
|
15
|
+
* forever. Prepared command-line input degrades to print mode; without any
|
|
16
|
+
* input to run we fail fast instead of hanging. Explicit `--print` and
|
|
17
|
+
* `--mode` launches are left untouched.
|
|
18
|
+
*/
|
|
19
|
+
export function resolveLaunchDisposition(args: {
|
|
20
|
+
stdinIsTTY: boolean | undefined;
|
|
21
|
+
pipedInput: string | undefined;
|
|
22
|
+
hasPreparedInput: boolean;
|
|
23
|
+
print: boolean;
|
|
24
|
+
mode: LaunchMode | undefined;
|
|
25
|
+
}): LaunchDisposition {
|
|
26
|
+
const explicitNonInteractive = args.print || args.mode !== undefined;
|
|
27
|
+
const hasPreparedInput = args.pipedInput !== undefined || args.hasPreparedInput;
|
|
28
|
+
const hasNonTtyStdin = args.stdinIsTTY !== true;
|
|
29
|
+
const autoPrint = !explicitNonInteractive && hasNonTtyStdin && hasPreparedInput;
|
|
30
|
+
const isInteractive = !explicitNonInteractive && !autoPrint;
|
|
31
|
+
|
|
32
|
+
if (isInteractive && args.stdinIsTTY !== true) {
|
|
33
|
+
return {
|
|
34
|
+
autoPrint: false,
|
|
35
|
+
isInteractive: false,
|
|
36
|
+
nonInteractiveError:
|
|
37
|
+
"stdin is not a TTY and no prompt or prepared input was provided; use -p/--print (or pass a prompt or @file) for non-interactive runs.",
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return { autoPrint, isInteractive };
|
|
42
|
+
}
|