@di-code/coding-agent 0.1.2 → 0.1.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/README.md +499 -143
- package/dist/cli.d.ts +1 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +15 -0
- package/dist/cli.js.map +1 -1
- package/dist/core/clipboard-image.d.ts +13 -0
- package/dist/core/clipboard-image.d.ts.map +1 -0
- package/dist/core/clipboard-image.js +99 -0
- package/dist/core/clipboard-image.js.map +1 -0
- package/dist/core/context-builder.d.ts.map +1 -1
- package/dist/core/context-builder.js +6 -2
- package/dist/core/context-builder.js.map +1 -1
- package/dist/core/image-input.d.ts +13 -0
- package/dist/core/image-input.d.ts.map +1 -0
- package/dist/core/image-input.js +147 -0
- package/dist/core/image-input.js.map +1 -0
- package/dist/core/session/session-storage.d.ts.map +1 -1
- package/dist/core/session/session-storage.js +1 -0
- package/dist/core/session/session-storage.js.map +1 -1
- package/dist/core/session.d.ts +19 -2
- package/dist/core/session.d.ts.map +1 -1
- package/dist/core/session.js +101 -4
- package/dist/core/session.js.map +1 -1
- package/dist/core/tools/bash.d.ts +2 -2
- package/dist/core/tools/bash.d.ts.map +1 -1
- package/dist/core/tools/bash.js.map +1 -1
- package/dist/core/tools/edit-diff.d.ts +25 -0
- package/dist/core/tools/edit-diff.d.ts.map +1 -0
- package/dist/core/tools/edit-diff.js +136 -0
- package/dist/core/tools/edit-diff.js.map +1 -0
- package/dist/core/tools/edit.d.ts +13 -4
- package/dist/core/tools/edit.d.ts.map +1 -1
- package/dist/core/tools/edit.js +64 -30
- package/dist/core/tools/edit.js.map +1 -1
- package/dist/core/tools/read.d.ts +2 -2
- package/dist/core/tools/read.d.ts.map +1 -1
- package/dist/core/tools/read.js.map +1 -1
- package/dist/core/tools/write.d.ts +2 -2
- package/dist/core/tools/write.d.ts.map +1 -1
- package/dist/core/tools/write.js.map +1 -1
- package/dist/entry.js +9 -2
- package/dist/entry.js.map +1 -1
- package/dist/main.d.ts +3 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +42 -8
- package/dist/main.js.map +1 -1
- package/dist/modes/interactive-components.d.ts +3 -0
- package/dist/modes/interactive-components.d.ts.map +1 -1
- package/dist/modes/interactive-components.js +76 -25
- package/dist/modes/interactive-components.js.map +1 -1
- package/dist/modes/interactive-diff.d.ts +8 -0
- package/dist/modes/interactive-diff.d.ts.map +1 -0
- package/dist/modes/interactive-diff.js +78 -0
- package/dist/modes/interactive-diff.js.map +1 -0
- package/dist/modes/interactive-layout.d.ts +6 -1
- package/dist/modes/interactive-layout.d.ts.map +1 -1
- package/dist/modes/interactive-layout.js +21 -1
- package/dist/modes/interactive-layout.js.map +1 -1
- package/dist/modes/interactive-state.d.ts +17 -2
- package/dist/modes/interactive-state.d.ts.map +1 -1
- package/dist/modes/interactive-state.js +103 -3
- package/dist/modes/interactive-state.js.map +1 -1
- package/dist/modes/interactive.d.ts +18 -0
- package/dist/modes/interactive.d.ts.map +1 -1
- package/dist/modes/interactive.js +289 -24
- package/dist/modes/interactive.js.map +1 -1
- package/dist/provider-onboarding.d.ts +8 -1
- package/dist/provider-onboarding.d.ts.map +1 -1
- package/dist/provider-onboarding.js +53 -23
- package/dist/provider-onboarding.js.map +1 -1
- package/dist/rpc-entry.js +1 -1
- package/dist/rpc-entry.js.map +1 -1
- package/dist/startup.d.ts +11 -3
- package/dist/startup.d.ts.map +1 -1
- package/dist/startup.js +240 -84
- package/dist/startup.js.map +1 -1
- package/dist/utils/syntax-highlight.d.ts +2 -0
- package/dist/utils/syntax-highlight.d.ts.map +1 -0
- package/dist/utils/syntax-highlight.js +55 -0
- package/dist/utils/syntax-highlight.js.map +1 -0
- package/package.json +9 -4
package/dist/cli.d.ts
CHANGED
package/dist/cli.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,UAAU,GAAG,OAAO,GAAG,MAAM,GAAG,aAAa,CAAC;AAE1D,MAAM,MAAM,UAAU,GACnB;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAChB;IAAE,IAAI,EAAE,SAAS,CAAA;CAAE,GACnB;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,MAAM,EAAE,SAAS,GAAG,MAAM,GAAG,QAAQ,GAAG,SAAS,GAAG,QAAQ,GAAG,QAAQ,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,GAC9G;IACA,IAAI,EAAE,KAAK,CAAC;IACZ,IAAI,EAAE,UAAU,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,eAAe,CAAC,EAAE,IAAI,CAAC;IACvB,QAAQ,CAAC,EAAE,IAAI,CAAC;IAChB,cAAc,CAAC,EAAE,IAAI,CAAC;IACtB,UAAU,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC/B,YAAY,CAAC,EAAE,OAAO,CAAC;CACtB,CAAC;AAEL,qBAAa,aAAc,SAAQ,KAAK;gBAC3B,OAAO,EAAE,MAAM;CAI3B;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,UAAU,
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,UAAU,GAAG,OAAO,GAAG,MAAM,GAAG,aAAa,CAAC;AAE1D,MAAM,MAAM,UAAU,GACnB;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAChB;IAAE,IAAI,EAAE,SAAS,CAAA;CAAE,GACnB;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,MAAM,EAAE,SAAS,GAAG,MAAM,GAAG,QAAQ,GAAG,SAAS,GAAG,QAAQ,GAAG,QAAQ,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,GAC9G;IACA,IAAI,EAAE,KAAK,CAAC;IACZ,IAAI,EAAE,UAAU,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,eAAe,CAAC,EAAE,IAAI,CAAC;IACvB,UAAU,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC/B,QAAQ,CAAC,EAAE,IAAI,CAAC;IAChB,cAAc,CAAC,EAAE,IAAI,CAAC;IACtB,UAAU,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC/B,YAAY,CAAC,EAAE,OAAO,CAAC;CACtB,CAAC;AAEL,qBAAa,aAAc,SAAQ,KAAK;gBAC3B,OAAO,EAAE,MAAM;CAI3B;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,UAAU,CAkJhE;AAqBD,MAAM,WAAW,eAAe;IAC/B,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,GAAG,CAAC,OAAO,EAAE,OAAO,CAAC,UAAU,EAAE;QAAE,IAAI,EAAE,KAAK,CAAA;KAAE,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACpE,MAAM,CAAC,CAAC,OAAO,EAAE,OAAO,CAAC,UAAU,EAAE;QAAE,IAAI,EAAE,QAAQ,CAAA;KAAE,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAC3E,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CACzB;AAED,wBAAsB,MAAM,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,EAAE,YAAY,EAAE,eAAe,GAAG,OAAO,CAAC,MAAM,CAAC,CAyBpG"}
|
package/dist/cli.js
CHANGED
|
@@ -37,6 +37,7 @@ export function parseCliArgs(args) {
|
|
|
37
37
|
let noContextFiles = false;
|
|
38
38
|
let projectTrust;
|
|
39
39
|
const skillPaths = [];
|
|
40
|
+
const imagePaths = [];
|
|
40
41
|
const promptParts = [];
|
|
41
42
|
for (let index = 0; index < args.length; index++) {
|
|
42
43
|
const argument = args[index];
|
|
@@ -77,6 +78,15 @@ export function parseCliArgs(args) {
|
|
|
77
78
|
index++;
|
|
78
79
|
continue;
|
|
79
80
|
}
|
|
81
|
+
if (argument === "--image") {
|
|
82
|
+
const value = args[index + 1];
|
|
83
|
+
if (value === undefined || value.trim().length === 0) {
|
|
84
|
+
throw new CliUsageError("Option --image requires a non-empty value.");
|
|
85
|
+
}
|
|
86
|
+
imagePaths.push(value);
|
|
87
|
+
index++;
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
80
90
|
if (argument === "--mode") {
|
|
81
91
|
const value = args[index + 1];
|
|
82
92
|
if (value === undefined) {
|
|
@@ -114,6 +124,9 @@ export function parseCliArgs(args) {
|
|
|
114
124
|
if (continueSession && sessionPath !== undefined) {
|
|
115
125
|
throw new CliUsageError("Cannot combine --continue with --session.");
|
|
116
126
|
}
|
|
127
|
+
if (mode === "interactive" && imagePaths.length > 0) {
|
|
128
|
+
throw new CliUsageError("--image is not available in interactive mode.");
|
|
129
|
+
}
|
|
117
130
|
if (promptParts.length === 0 && mode !== "interactive") {
|
|
118
131
|
throw new CliUsageError("A prompt is required.");
|
|
119
132
|
}
|
|
@@ -126,6 +139,7 @@ export function parseCliArgs(args) {
|
|
|
126
139
|
...(noSkills ? { noSkills: true } : {}),
|
|
127
140
|
...(noContextFiles ? { noContextFiles: true } : {}),
|
|
128
141
|
...(skillPaths.length > 0 ? { skillPaths } : {}),
|
|
142
|
+
...(imagePaths.length > 0 ? { imagePaths } : {}),
|
|
129
143
|
...(projectTrust === undefined ? {} : { projectTrust }),
|
|
130
144
|
};
|
|
131
145
|
}
|
|
@@ -137,6 +151,7 @@ Options:
|
|
|
137
151
|
--interactive Start interactive terminal mode
|
|
138
152
|
--continue, -c Continue the most recently modified session
|
|
139
153
|
--session <path> Create or resume a JSONL session (relative to the work root)
|
|
154
|
+
--image <path> Attach a local PNG, JPEG, WebP, or GIF image (repeatable)
|
|
140
155
|
--skill <path> Add a SKILL.md file or skill directory (repeatable)
|
|
141
156
|
--no-skills Disable all Skill loading
|
|
142
157
|
--no-context-files Disable AGENTS.md discovery and loading
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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","sourcesContent":["export type OutputMode = \"print\" | \"json\" | \"interactive\";\n\nexport type CliCommand =\n\t| { kind: \"help\" }\n\t| { kind: \"version\" }\n\t| { kind: \"plugin\"; action: \"install\" | \"list\" | \"enable\" | \"disable\" | \"update\" | \"remove\"; argument?: string }\n\t| {\n\t\t\tkind: \"run\";\n\t\t\tmode: OutputMode;\n\t\t\tprompt: string;\n\t\t\tsessionPath?: string;\n\t\t\tcontinueSession?: true;\n\t\t\tnoSkills?: true;\n\t\t\tnoContextFiles?: true;\n\t\t\tskillPaths?: readonly string[];\n\t\t\tprojectTrust?: boolean;\n\t };\n\nexport class CliUsageError extends Error {\n\tconstructor(message: string) {\n\t\tsuper(message);\n\t\tthis.name = \"CliUsageError\";\n\t}\n}\n\nexport function parseCliArgs(args: readonly string[]): CliCommand {\n\tif (args[0] === \"plugin\") {\n\t\tconst action = args[1];\n\t\tif (\n\t\t\taction !== \"install\" &&\n\t\t\taction !== \"list\" &&\n\t\t\taction !== \"enable\" &&\n\t\t\taction !== \"disable\" &&\n\t\t\taction !== \"update\" &&\n\t\t\taction !== \"remove\"\n\t\t)\n\t\t\tthrow new CliUsageError(\"Plugin command must be install, list, enable, disable, update, or remove.\");\n\t\tconst argument = args[2];\n\t\tif (\n\t\t\targs.length > 3 ||\n\t\t\t(action !== \"list\" && (argument === undefined || argument.trim() === \"\")) ||\n\t\t\t(action === \"list\" && argument !== undefined)\n\t\t)\n\t\t\tthrow new CliUsageError(\"Plugin command has invalid arguments.\");\n\t\treturn { kind: \"plugin\", action, ...(argument ? { argument } : {}) };\n\t}\n\tconst staticOption = args.find((argument) => [\"-h\", \"--help\", \"-v\", \"--version\"].includes(argument));\n\tif (staticOption !== undefined) {\n\t\tconst kind = staticOption === \"-h\" || staticOption === \"--help\" ? \"help\" : \"version\";\n\t\tif (args.length !== 1) {\n\t\t\tthrow new CliUsageError(`--${kind} must be used on its own.`);\n\t\t}\n\t\treturn { kind };\n\t}\n\n\tlet mode: OutputMode = \"print\";\n\tlet printAlias = false;\n\tlet sessionPath: string | undefined;\n\tlet continueSession = false;\n\tlet noSkills = false;\n\tlet noContextFiles = false;\n\tlet projectTrust: boolean | undefined;\n\tconst skillPaths: string[] = [];\n\tconst promptParts: string[] = [];\n\n\tfor (let index = 0; index < args.length; index++) {\n\t\tconst argument = args[index];\n\t\tif (argument === \"-p\" || argument === \"--print\") {\n\t\t\tprintAlias = true;\n\t\t\tcontinue;\n\t\t}\n\t\tif (argument === \"--interactive\") {\n\t\t\tmode = \"interactive\";\n\t\t\tcontinue;\n\t\t}\n\t\tif (argument === \"-c\" || argument === \"--continue\") {\n\t\t\tcontinueSession = true;\n\t\t\tcontinue;\n\t\t}\n\t\tif (argument === \"--no-skills\") {\n\t\t\tnoSkills = true;\n\t\t\tcontinue;\n\t\t}\n\t\tif (argument === \"--no-context-files\") {\n\t\t\tnoContextFiles = true;\n\t\t\tcontinue;\n\t\t}\n\t\tif (argument === \"--trust-project\" || argument === \"--untrust-project\") {\n\t\t\tconst nextTrust = argument === \"--trust-project\";\n\t\t\tif (projectTrust !== undefined && projectTrust !== nextTrust) {\n\t\t\t\tthrow new CliUsageError(\"Cannot combine --trust-project with --untrust-project.\");\n\t\t\t}\n\t\t\tprojectTrust = nextTrust;\n\t\t\tcontinue;\n\t\t}\n\t\tif (argument === \"--skill\") {\n\t\t\tconst value = args[index + 1];\n\t\t\tif (value === undefined || value.trim().length === 0) {\n\t\t\t\tthrow new CliUsageError(\"Option --skill requires a non-empty value.\");\n\t\t\t}\n\t\t\tskillPaths.push(value);\n\t\t\tindex++;\n\t\t\tcontinue;\n\t\t}\n\t\tif (argument === \"--mode\") {\n\t\t\tconst value = args[index + 1];\n\t\t\tif (value === undefined) {\n\t\t\t\tthrow new CliUsageError(\"Option --mode requires a value.\");\n\t\t\t}\n\t\t\tif (value !== \"print\" && value !== \"json\" && value !== \"interactive\") {\n\t\t\t\tthrow new CliUsageError(`Unsupported mode \"${value}\". Expected print, json, or interactive.`);\n\t\t\t}\n\t\t\tmode = value;\n\t\t\tindex++;\n\t\t\tcontinue;\n\t\t}\n\t\tif (argument === \"--session\") {\n\t\t\tconst value = args[index + 1];\n\t\t\tif (value === undefined) {\n\t\t\t\tthrow new CliUsageError(\"Option --session requires a value.\");\n\t\t\t}\n\t\t\tif (value.trim().length === 0) {\n\t\t\t\tthrow new CliUsageError(\"Option --session requires a non-empty value.\");\n\t\t\t}\n\t\t\tsessionPath = value;\n\t\t\tindex++;\n\t\t\tcontinue;\n\t\t}\n\t\tif (argument?.startsWith(\"-\")) {\n\t\t\tthrow new CliUsageError(`Unknown option \"${argument}\".`);\n\t\t}\n\t\tif (argument !== undefined) {\n\t\t\tpromptParts.push(argument);\n\t\t}\n\t}\n\n\tif (printAlias && mode !== \"print\") {\n\t\tthrow new CliUsageError(`Cannot combine --print with --mode ${mode}.`);\n\t}\n\tif (continueSession && sessionPath !== undefined) {\n\t\tthrow new CliUsageError(\"Cannot combine --continue with --session.\");\n\t}\n\tif (promptParts.length === 0 && mode !== \"interactive\") {\n\t\tthrow new CliUsageError(\"A prompt is required.\");\n\t}\n\n\treturn {\n\t\tkind: \"run\",\n\t\tmode,\n\t\tprompt: promptParts.join(\" \"),\n\t\t...(sessionPath ? { sessionPath } : {}),\n\t\t...(continueSession ? { continueSession: true as const } : {}),\n\t\t...(noSkills ? { noSkills: true as const } : {}),\n\t\t...(noContextFiles ? { noContextFiles: true as const } : {}),\n\t\t...(skillPaths.length > 0 ? { skillPaths } : {}),\n\t\t...(projectTrust === undefined ? {} : { projectTrust }),\n\t};\n}\n\nconst HELP_TEXT = `Usage: di-code [options] <prompt>\n\nOptions:\n -p, --print Print only the final assistant text (default)\n --mode <mode> Output mode: print, json, or interactive\n --interactive Start interactive terminal mode\n --continue, -c Continue the most recently modified session\n --session <path> Create or resume a JSONL session (relative to the work root)\n --skill <path> Add a SKILL.md file or skill directory (repeatable)\n --no-skills Disable all Skill loading\n --no-context-files Disable AGENTS.md discovery and loading\n --trust-project Persist trust for project-local Skill discovery\n --untrust-project Persist denial for project-local Skill discovery\n plugin <action> Install, list, enable, disable, update, or remove a plugin\n -h, --help Show help\n -v, --version Show version\n`;\n\nexport interface CliDependencies {\n\tstdout(text: string): void;\n\tstderr(text: string): void;\n\trun(command: Extract<CliCommand, { kind: \"run\" }>): Promise<number>;\n\tplugin?(command: Extract<CliCommand, { kind: \"plugin\" }>): Promise<number>;\n\treadonly version: string;\n}\n\nexport async function runCli(args: readonly string[], dependencies: CliDependencies): Promise<number> {\n\tlet command: CliCommand;\n\ttry {\n\t\tcommand = parseCliArgs(args);\n\t} catch (cause) {\n\t\tif (cause instanceof CliUsageError) {\n\t\t\tdependencies.stderr(`${cause.message}\\n`);\n\t\t\treturn 1;\n\t\t}\n\t\tthrow cause;\n\t}\n\n\tswitch (command.kind) {\n\t\tcase \"help\":\n\t\t\tdependencies.stdout(HELP_TEXT);\n\t\t\treturn 0;\n\t\tcase \"plugin\":\n\t\t\tif (!dependencies.plugin) throw new Error(\"Plugin command handler is unavailable.\");\n\t\t\treturn dependencies.plugin(command);\n\t\tcase \"version\":\n\t\t\tdependencies.stdout(`${dependencies.version}\\n`);\n\t\t\treturn 0;\n\t\tcase \"run\":\n\t\t\treturn dependencies.run(command);\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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","sourcesContent":["export type OutputMode = \"print\" | \"json\" | \"interactive\";\n\nexport type CliCommand =\n\t| { kind: \"help\" }\n\t| { kind: \"version\" }\n\t| { kind: \"plugin\"; action: \"install\" | \"list\" | \"enable\" | \"disable\" | \"update\" | \"remove\"; argument?: string }\n\t| {\n\t\t\tkind: \"run\";\n\t\t\tmode: OutputMode;\n\t\t\tprompt: string;\n\t\t\tsessionPath?: string;\n\t\t\tcontinueSession?: true;\n\t\t\timagePaths?: readonly string[];\n\t\t\tnoSkills?: true;\n\t\t\tnoContextFiles?: true;\n\t\t\tskillPaths?: readonly string[];\n\t\t\tprojectTrust?: boolean;\n\t };\n\nexport class CliUsageError extends Error {\n\tconstructor(message: string) {\n\t\tsuper(message);\n\t\tthis.name = \"CliUsageError\";\n\t}\n}\n\nexport function parseCliArgs(args: readonly string[]): CliCommand {\n\tif (args[0] === \"plugin\") {\n\t\tconst action = args[1];\n\t\tif (\n\t\t\taction !== \"install\" &&\n\t\t\taction !== \"list\" &&\n\t\t\taction !== \"enable\" &&\n\t\t\taction !== \"disable\" &&\n\t\t\taction !== \"update\" &&\n\t\t\taction !== \"remove\"\n\t\t)\n\t\t\tthrow new CliUsageError(\"Plugin command must be install, list, enable, disable, update, or remove.\");\n\t\tconst argument = args[2];\n\t\tif (\n\t\t\targs.length > 3 ||\n\t\t\t(action !== \"list\" && (argument === undefined || argument.trim() === \"\")) ||\n\t\t\t(action === \"list\" && argument !== undefined)\n\t\t)\n\t\t\tthrow new CliUsageError(\"Plugin command has invalid arguments.\");\n\t\treturn { kind: \"plugin\", action, ...(argument ? { argument } : {}) };\n\t}\n\tconst staticOption = args.find((argument) => [\"-h\", \"--help\", \"-v\", \"--version\"].includes(argument));\n\tif (staticOption !== undefined) {\n\t\tconst kind = staticOption === \"-h\" || staticOption === \"--help\" ? \"help\" : \"version\";\n\t\tif (args.length !== 1) {\n\t\t\tthrow new CliUsageError(`--${kind} must be used on its own.`);\n\t\t}\n\t\treturn { kind };\n\t}\n\n\tlet mode: OutputMode = \"print\";\n\tlet printAlias = false;\n\tlet sessionPath: string | undefined;\n\tlet continueSession = false;\n\tlet noSkills = false;\n\tlet noContextFiles = false;\n\tlet projectTrust: boolean | undefined;\n\tconst skillPaths: string[] = [];\n\tconst imagePaths: string[] = [];\n\tconst promptParts: string[] = [];\n\n\tfor (let index = 0; index < args.length; index++) {\n\t\tconst argument = args[index];\n\t\tif (argument === \"-p\" || argument === \"--print\") {\n\t\t\tprintAlias = true;\n\t\t\tcontinue;\n\t\t}\n\t\tif (argument === \"--interactive\") {\n\t\t\tmode = \"interactive\";\n\t\t\tcontinue;\n\t\t}\n\t\tif (argument === \"-c\" || argument === \"--continue\") {\n\t\t\tcontinueSession = true;\n\t\t\tcontinue;\n\t\t}\n\t\tif (argument === \"--no-skills\") {\n\t\t\tnoSkills = true;\n\t\t\tcontinue;\n\t\t}\n\t\tif (argument === \"--no-context-files\") {\n\t\t\tnoContextFiles = true;\n\t\t\tcontinue;\n\t\t}\n\t\tif (argument === \"--trust-project\" || argument === \"--untrust-project\") {\n\t\t\tconst nextTrust = argument === \"--trust-project\";\n\t\t\tif (projectTrust !== undefined && projectTrust !== nextTrust) {\n\t\t\t\tthrow new CliUsageError(\"Cannot combine --trust-project with --untrust-project.\");\n\t\t\t}\n\t\t\tprojectTrust = nextTrust;\n\t\t\tcontinue;\n\t\t}\n\t\tif (argument === \"--skill\") {\n\t\t\tconst value = args[index + 1];\n\t\t\tif (value === undefined || value.trim().length === 0) {\n\t\t\t\tthrow new CliUsageError(\"Option --skill requires a non-empty value.\");\n\t\t\t}\n\t\t\tskillPaths.push(value);\n\t\t\tindex++;\n\t\t\tcontinue;\n\t\t}\n\t\tif (argument === \"--image\") {\n\t\t\tconst value = args[index + 1];\n\t\t\tif (value === undefined || value.trim().length === 0) {\n\t\t\t\tthrow new CliUsageError(\"Option --image requires a non-empty value.\");\n\t\t\t}\n\t\t\timagePaths.push(value);\n\t\t\tindex++;\n\t\t\tcontinue;\n\t\t}\n\t\tif (argument === \"--mode\") {\n\t\t\tconst value = args[index + 1];\n\t\t\tif (value === undefined) {\n\t\t\t\tthrow new CliUsageError(\"Option --mode requires a value.\");\n\t\t\t}\n\t\t\tif (value !== \"print\" && value !== \"json\" && value !== \"interactive\") {\n\t\t\t\tthrow new CliUsageError(`Unsupported mode \"${value}\". Expected print, json, or interactive.`);\n\t\t\t}\n\t\t\tmode = value;\n\t\t\tindex++;\n\t\t\tcontinue;\n\t\t}\n\t\tif (argument === \"--session\") {\n\t\t\tconst value = args[index + 1];\n\t\t\tif (value === undefined) {\n\t\t\t\tthrow new CliUsageError(\"Option --session requires a value.\");\n\t\t\t}\n\t\t\tif (value.trim().length === 0) {\n\t\t\t\tthrow new CliUsageError(\"Option --session requires a non-empty value.\");\n\t\t\t}\n\t\t\tsessionPath = value;\n\t\t\tindex++;\n\t\t\tcontinue;\n\t\t}\n\t\tif (argument?.startsWith(\"-\")) {\n\t\t\tthrow new CliUsageError(`Unknown option \"${argument}\".`);\n\t\t}\n\t\tif (argument !== undefined) {\n\t\t\tpromptParts.push(argument);\n\t\t}\n\t}\n\n\tif (printAlias && mode !== \"print\") {\n\t\tthrow new CliUsageError(`Cannot combine --print with --mode ${mode}.`);\n\t}\n\tif (continueSession && sessionPath !== undefined) {\n\t\tthrow new CliUsageError(\"Cannot combine --continue with --session.\");\n\t}\n\tif (mode === \"interactive\" && imagePaths.length > 0) {\n\t\tthrow new CliUsageError(\"--image is not available in interactive mode.\");\n\t}\n\tif (promptParts.length === 0 && mode !== \"interactive\") {\n\t\tthrow new CliUsageError(\"A prompt is required.\");\n\t}\n\n\treturn {\n\t\tkind: \"run\",\n\t\tmode,\n\t\tprompt: promptParts.join(\" \"),\n\t\t...(sessionPath ? { sessionPath } : {}),\n\t\t...(continueSession ? { continueSession: true as const } : {}),\n\t\t...(noSkills ? { noSkills: true as const } : {}),\n\t\t...(noContextFiles ? { noContextFiles: true as const } : {}),\n\t\t...(skillPaths.length > 0 ? { skillPaths } : {}),\n\t\t...(imagePaths.length > 0 ? { imagePaths } : {}),\n\t\t...(projectTrust === undefined ? {} : { projectTrust }),\n\t};\n}\n\nconst HELP_TEXT = `Usage: di-code [options] <prompt>\n\nOptions:\n -p, --print Print only the final assistant text (default)\n --mode <mode> Output mode: print, json, or interactive\n --interactive Start interactive terminal mode\n --continue, -c Continue the most recently modified session\n --session <path> Create or resume a JSONL session (relative to the work root)\n --image <path> Attach a local PNG, JPEG, WebP, or GIF image (repeatable)\n --skill <path> Add a SKILL.md file or skill directory (repeatable)\n --no-skills Disable all Skill loading\n --no-context-files Disable AGENTS.md discovery and loading\n --trust-project Persist trust for project-local Skill discovery\n --untrust-project Persist denial for project-local Skill discovery\n plugin <action> Install, list, enable, disable, update, or remove a plugin\n -h, --help Show help\n -v, --version Show version\n`;\n\nexport interface CliDependencies {\n\tstdout(text: string): void;\n\tstderr(text: string): void;\n\trun(command: Extract<CliCommand, { kind: \"run\" }>): Promise<number>;\n\tplugin?(command: Extract<CliCommand, { kind: \"plugin\" }>): Promise<number>;\n\treadonly version: string;\n}\n\nexport async function runCli(args: readonly string[], dependencies: CliDependencies): Promise<number> {\n\tlet command: CliCommand;\n\ttry {\n\t\tcommand = parseCliArgs(args);\n\t} catch (cause) {\n\t\tif (cause instanceof CliUsageError) {\n\t\t\tdependencies.stderr(`${cause.message}\\n`);\n\t\t\treturn 1;\n\t\t}\n\t\tthrow cause;\n\t}\n\n\tswitch (command.kind) {\n\t\tcase \"help\":\n\t\t\tdependencies.stdout(HELP_TEXT);\n\t\t\treturn 0;\n\t\tcase \"plugin\":\n\t\t\tif (!dependencies.plugin) throw new Error(\"Plugin command handler is unavailable.\");\n\t\t\treturn dependencies.plugin(command);\n\t\tcase \"version\":\n\t\t\tdependencies.stdout(`${dependencies.version}\\n`);\n\t\t\treturn 0;\n\t\tcase \"run\":\n\t\t\treturn dependencies.run(command);\n\t}\n}\n"]}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { ImageContent } from "@di-code/ai";
|
|
2
|
+
/** Reads a native clipboard image when the optional platform package is available. */
|
|
3
|
+
export declare function readClipboardImage(): Promise<ImageContent | null>;
|
|
4
|
+
export declare function clipboardImageDirectory(root: string): string;
|
|
5
|
+
export declare function isClipboardImagePath(path: string, directory: string): boolean;
|
|
6
|
+
/** Removes generated clipboard images that were left by an older process. */
|
|
7
|
+
export declare function cleanupStaleClipboardImages(root: string, maxAgeMs?: number): Promise<void>;
|
|
8
|
+
export declare function removeClipboardImage(path: string, directory: string): Promise<void>;
|
|
9
|
+
/** Writes one clipboard image to a temporary file, matching Pi's editor flow. */
|
|
10
|
+
export declare function writeImageContentToTempFile(image: ImageContent, directory?: string): Promise<string>;
|
|
11
|
+
/** Reads the clipboard and returns the temporary path that should be inserted into the editor. */
|
|
12
|
+
export declare function readClipboardImagePath(directory?: string): Promise<string | null>;
|
|
13
|
+
//# sourceMappingURL=clipboard-image.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"clipboard-image.d.ts","sourceRoot":"","sources":["../../src/core/clipboard-image.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAsBhD,sFAAsF;AACtF,wBAAsB,kBAAkB,IAAI,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAMvE;AAeD,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE5D;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAG7E;AAED,6EAA6E;AAC7E,wBAAsB,2BAA2B,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,SAAuB,GAAG,OAAO,CAAC,IAAI,CAAC,CAsB9G;AAED,wBAAsB,oBAAoB,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAOzF;AAED,iFAAiF;AACjF,wBAAsB,2BAA2B,CAAC,KAAK,EAAE,YAAY,EAAE,SAAS,SAAW,GAAG,OAAO,CAAC,MAAM,CAAC,CAM5G;AAED,kGAAkG;AAClG,wBAAsB,sBAAsB,CAAC,SAAS,SAAW,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAGzF"}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
import { mkdir, readdir, stat, unlink, writeFile } from "node:fs/promises";
|
|
3
|
+
import { createRequire } from "node:module";
|
|
4
|
+
import { tmpdir } from "node:os";
|
|
5
|
+
import { basename, dirname, join, resolve } from "node:path";
|
|
6
|
+
import { imageContentFromBytes } from "./image-input.js";
|
|
7
|
+
const CLIPBOARD_FILE_PREFIX = "di-code-clipboard-";
|
|
8
|
+
const CLIPBOARD_FILE_PATTERN = new RegExp(`^${CLIPBOARD_FILE_PREFIX}[0-9a-f-]+\\.(?:png|jpg|jpeg|gif|webp)$`, "i");
|
|
9
|
+
const DEFAULT_STALE_AGE_MS = 24 * 60 * 60 * 1000;
|
|
10
|
+
const require = createRequire(import.meta.url);
|
|
11
|
+
function loadClipboardModule() {
|
|
12
|
+
try {
|
|
13
|
+
return require("@mariozechner/clipboard");
|
|
14
|
+
}
|
|
15
|
+
catch {
|
|
16
|
+
return undefined;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
/** Reads a native clipboard image when the optional platform package is available. */
|
|
20
|
+
export async function readClipboardImage() {
|
|
21
|
+
const clipboard = loadClipboardModule();
|
|
22
|
+
if (!clipboard?.hasImage())
|
|
23
|
+
return null;
|
|
24
|
+
const bytes = await clipboard.getImageBinary();
|
|
25
|
+
if (bytes.length === 0)
|
|
26
|
+
return null;
|
|
27
|
+
return imageContentFromBytes(Uint8Array.from(bytes), "clipboard image");
|
|
28
|
+
}
|
|
29
|
+
function extensionForMimeType(mimeType) {
|
|
30
|
+
switch (mimeType.toLowerCase().split(";", 1)[0]) {
|
|
31
|
+
case "image/jpeg":
|
|
32
|
+
return "jpg";
|
|
33
|
+
case "image/gif":
|
|
34
|
+
return "gif";
|
|
35
|
+
case "image/webp":
|
|
36
|
+
return "webp";
|
|
37
|
+
default:
|
|
38
|
+
return "png";
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
export function clipboardImageDirectory(root) {
|
|
42
|
+
return join(root, ".di-code", "clipboard");
|
|
43
|
+
}
|
|
44
|
+
export function isClipboardImagePath(path, directory) {
|
|
45
|
+
const absolutePath = resolve(path);
|
|
46
|
+
return dirname(absolutePath) === resolve(directory) && CLIPBOARD_FILE_PATTERN.test(basename(absolutePath));
|
|
47
|
+
}
|
|
48
|
+
/** Removes generated clipboard images that were left by an older process. */
|
|
49
|
+
export async function cleanupStaleClipboardImages(root, maxAgeMs = DEFAULT_STALE_AGE_MS) {
|
|
50
|
+
const directory = clipboardImageDirectory(root);
|
|
51
|
+
let entries;
|
|
52
|
+
try {
|
|
53
|
+
entries = await readdir(directory, { withFileTypes: true });
|
|
54
|
+
}
|
|
55
|
+
catch (cause) {
|
|
56
|
+
if (cause instanceof Error && "code" in cause && cause.code === "ENOENT")
|
|
57
|
+
return;
|
|
58
|
+
throw cause;
|
|
59
|
+
}
|
|
60
|
+
const cutoff = Date.now() - maxAgeMs;
|
|
61
|
+
await Promise.all(entries
|
|
62
|
+
.filter((entry) => entry.isFile() && CLIPBOARD_FILE_PATTERN.test(entry.name))
|
|
63
|
+
.map(async (entry) => {
|
|
64
|
+
const path = join(directory, entry.name);
|
|
65
|
+
try {
|
|
66
|
+
if ((await stat(path)).mtimeMs < cutoff)
|
|
67
|
+
await unlink(path);
|
|
68
|
+
}
|
|
69
|
+
catch (cause) {
|
|
70
|
+
if (!(cause instanceof Error && "code" in cause && cause.code === "ENOENT"))
|
|
71
|
+
throw cause;
|
|
72
|
+
}
|
|
73
|
+
}));
|
|
74
|
+
}
|
|
75
|
+
export async function removeClipboardImage(path, directory) {
|
|
76
|
+
if (!isClipboardImagePath(path, directory))
|
|
77
|
+
return;
|
|
78
|
+
try {
|
|
79
|
+
await unlink(path);
|
|
80
|
+
}
|
|
81
|
+
catch (cause) {
|
|
82
|
+
if (!(cause instanceof Error && "code" in cause && cause.code === "ENOENT"))
|
|
83
|
+
throw cause;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
/** Writes one clipboard image to a temporary file, matching Pi's editor flow. */
|
|
87
|
+
export async function writeImageContentToTempFile(image, directory = tmpdir()) {
|
|
88
|
+
const extension = extensionForMimeType(image.mimeType);
|
|
89
|
+
await mkdir(directory, { recursive: true });
|
|
90
|
+
const path = join(directory, `${CLIPBOARD_FILE_PREFIX}${randomUUID()}.${extension}`);
|
|
91
|
+
await writeFile(path, Buffer.from(image.data, "base64"));
|
|
92
|
+
return path;
|
|
93
|
+
}
|
|
94
|
+
/** Reads the clipboard and returns the temporary path that should be inserted into the editor. */
|
|
95
|
+
export async function readClipboardImagePath(directory = tmpdir()) {
|
|
96
|
+
const image = await readClipboardImage();
|
|
97
|
+
return image ? writeImageContentToTempFile(image, directory) : null;
|
|
98
|
+
}
|
|
99
|
+
//# sourceMappingURL=clipboard-image.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"clipboard-image.js","sourceRoot":"","sources":["../../src/core/clipboard-image.ts"],"names":[],"mappings":"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","sourcesContent":["import { randomUUID } from \"node:crypto\";\nimport type { Dirent } from \"node:fs\";\nimport { mkdir, readdir, stat, unlink, writeFile } from \"node:fs/promises\";\nimport { createRequire } from \"node:module\";\nimport { tmpdir } from \"node:os\";\nimport { basename, dirname, join, resolve } from \"node:path\";\nimport type { ImageContent } from \"@di-code/ai\";\nimport { imageContentFromBytes } from \"./image-input.ts\";\n\ninterface ClipboardModule {\n\thasImage(): boolean;\n\tgetImageBinary(): Promise<Uint8Array | readonly number[]>;\n}\n\nconst CLIPBOARD_FILE_PREFIX = \"di-code-clipboard-\";\nconst CLIPBOARD_FILE_PATTERN = new RegExp(`^${CLIPBOARD_FILE_PREFIX}[0-9a-f-]+\\\\.(?:png|jpg|jpeg|gif|webp)$`, \"i\");\nconst DEFAULT_STALE_AGE_MS = 24 * 60 * 60 * 1000;\n\nconst require = createRequire(import.meta.url);\n\nfunction loadClipboardModule(): ClipboardModule | undefined {\n\ttry {\n\t\treturn require(\"@mariozechner/clipboard\") as ClipboardModule;\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\n/** Reads a native clipboard image when the optional platform package is available. */\nexport async function readClipboardImage(): Promise<ImageContent | null> {\n\tconst clipboard = loadClipboardModule();\n\tif (!clipboard?.hasImage()) return null;\n\tconst bytes = await clipboard.getImageBinary();\n\tif (bytes.length === 0) return null;\n\treturn imageContentFromBytes(Uint8Array.from(bytes), \"clipboard image\");\n}\n\nfunction extensionForMimeType(mimeType: string): string {\n\tswitch (mimeType.toLowerCase().split(\";\", 1)[0]) {\n\t\tcase \"image/jpeg\":\n\t\t\treturn \"jpg\";\n\t\tcase \"image/gif\":\n\t\t\treturn \"gif\";\n\t\tcase \"image/webp\":\n\t\t\treturn \"webp\";\n\t\tdefault:\n\t\t\treturn \"png\";\n\t}\n}\n\nexport function clipboardImageDirectory(root: string): string {\n\treturn join(root, \".di-code\", \"clipboard\");\n}\n\nexport function isClipboardImagePath(path: string, directory: string): boolean {\n\tconst absolutePath = resolve(path);\n\treturn dirname(absolutePath) === resolve(directory) && CLIPBOARD_FILE_PATTERN.test(basename(absolutePath));\n}\n\n/** Removes generated clipboard images that were left by an older process. */\nexport async function cleanupStaleClipboardImages(root: string, maxAgeMs = DEFAULT_STALE_AGE_MS): Promise<void> {\n\tconst directory = clipboardImageDirectory(root);\n\tlet entries: Dirent[];\n\ttry {\n\t\tentries = await readdir(directory, { withFileTypes: true });\n\t} catch (cause) {\n\t\tif (cause instanceof Error && \"code\" in cause && cause.code === \"ENOENT\") return;\n\t\tthrow cause;\n\t}\n\tconst cutoff = Date.now() - maxAgeMs;\n\tawait Promise.all(\n\t\tentries\n\t\t\t.filter((entry) => entry.isFile() && CLIPBOARD_FILE_PATTERN.test(entry.name))\n\t\t\t.map(async (entry) => {\n\t\t\t\tconst path = join(directory, entry.name);\n\t\t\t\ttry {\n\t\t\t\t\tif ((await stat(path)).mtimeMs < cutoff) await unlink(path);\n\t\t\t\t} catch (cause) {\n\t\t\t\t\tif (!(cause instanceof Error && \"code\" in cause && cause.code === \"ENOENT\")) throw cause;\n\t\t\t\t}\n\t\t\t}),\n\t);\n}\n\nexport async function removeClipboardImage(path: string, directory: string): Promise<void> {\n\tif (!isClipboardImagePath(path, directory)) return;\n\ttry {\n\t\tawait unlink(path);\n\t} catch (cause) {\n\t\tif (!(cause instanceof Error && \"code\" in cause && cause.code === \"ENOENT\")) throw cause;\n\t}\n}\n\n/** Writes one clipboard image to a temporary file, matching Pi's editor flow. */\nexport async function writeImageContentToTempFile(image: ImageContent, directory = tmpdir()): Promise<string> {\n\tconst extension = extensionForMimeType(image.mimeType);\n\tawait mkdir(directory, { recursive: true });\n\tconst path = join(directory, `${CLIPBOARD_FILE_PREFIX}${randomUUID()}.${extension}`);\n\tawait writeFile(path, Buffer.from(image.data, \"base64\"));\n\treturn path;\n}\n\n/** Reads the clipboard and returns the temporary path that should be inserted into the editor. */\nexport async function readClipboardImagePath(directory = tmpdir()): Promise<string | null> {\n\tconst image = await readClipboardImage();\n\treturn image ? writeImageContentToTempFile(image, directory) : null;\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"context-builder.d.ts","sourceRoot":"","sources":["../../src/core/context-builder.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAe,MAAM,aAAa,CAAC;AACxD,OAAO,KAAK,EAAE,YAAY,EAA4C,MAAM,oBAAoB,CAAC;AAEjG,MAAM,WAAW,mBAAmB;IACnC,QAAQ,CAAC,QAAQ,EAAE,SAAS,OAAO,EAAE,CAAC;IACtC,QAAQ,CAAC,cAAc,EAAE,SAAS,CAAC,MAAM,GAAG,IAAI,CAAC,EAAE,CAAC;CACpD;
|
|
1
|
+
{"version":3,"file":"context-builder.d.ts","sourceRoot":"","sources":["../../src/core/context-builder.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAe,MAAM,aAAa,CAAC;AACxD,OAAO,KAAK,EAAE,YAAY,EAA4C,MAAM,oBAAoB,CAAC;AAEjG,MAAM,WAAW,mBAAmB;IACnC,QAAQ,CAAC,QAAQ,EAAE,SAAS,OAAO,EAAE,CAAC;IACtC,QAAQ,CAAC,cAAc,EAAE,SAAS,CAAC,MAAM,GAAG,IAAI,CAAC,EAAE,CAAC;CACpD;AA2BD,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,SAAS,YAAY,EAAE,GAAG,mBAAmB,CAkCzF"}
|
|
@@ -13,6 +13,10 @@ function createSummaryMessage(entry) {
|
|
|
13
13
|
function messageEntries(entries) {
|
|
14
14
|
return entries.filter((entry) => entry.type === "message");
|
|
15
15
|
}
|
|
16
|
+
function contextMessageEntries(entries) {
|
|
17
|
+
return messageEntries(entries).filter((entry) => entry.message.role !== "assistant" ||
|
|
18
|
+
(entry.message.stopReason !== "error" && entry.message.stopReason !== "aborted"));
|
|
19
|
+
}
|
|
16
20
|
export function buildSessionContext(entries) {
|
|
17
21
|
const snapshot = structuredClone([...entries]);
|
|
18
22
|
let summaryIndex = -1;
|
|
@@ -23,7 +27,7 @@ export function buildSessionContext(entries) {
|
|
|
23
27
|
}
|
|
24
28
|
}
|
|
25
29
|
if (summaryIndex < 0) {
|
|
26
|
-
const messages =
|
|
30
|
+
const messages = contextMessageEntries(snapshot);
|
|
27
31
|
return {
|
|
28
32
|
messages: messages.map((entry) => entry.message),
|
|
29
33
|
sourceEntryIds: messages.map((entry) => entry.id),
|
|
@@ -37,7 +41,7 @@ export function buildSessionContext(entries) {
|
|
|
37
41
|
if (firstKeptIndex < 0) {
|
|
38
42
|
throw new Error("Summary firstKeptEntryId must reference an earlier message entry.");
|
|
39
43
|
}
|
|
40
|
-
const keptEntries =
|
|
44
|
+
const keptEntries = contextMessageEntries(snapshot.slice(firstKeptIndex));
|
|
41
45
|
return {
|
|
42
46
|
messages: [createSummaryMessage(summary), ...keptEntries.map((entry) => entry.message)],
|
|
43
47
|
sourceEntryIds: [null, ...keptEntries.map((entry) => entry.id)],
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"context-builder.js","sourceRoot":"","sources":["../../src/core/context-builder.ts"],"names":[],"mappings":"AAQA,SAAS,oBAAoB,CAAC,KAA0B;IACvD,OAAO;QACN,IAAI,EAAE,MAAM;QACZ,OAAO,EAAE;YACR;gBACC,IAAI,EAAE,MAAM;gBACZ,IAAI,EAAE,2BAA2B,KAAK,CAAC,OAAO,2BAA2B;aACzE;SACD;QACD,SAAS,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,SAAS,CAAC;KACtC,CAAC;AACH,CAAC;AAED,SAAS,cAAc,CAAC,OAAgC;IACvD,OAAO,OAAO,CAAC,MAAM,CAAC,CAAC,KAAK,EAAgC,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC;AAC1F,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,OAAgC;IACnE,MAAM,QAAQ,GAAG,eAAe,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IAC/C,IAAI,YAAY,GAAG,CAAC,CAAC,CAAC;IACtB,KAAK,IAAI,KAAK,GAAG,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,KAAK,IAAI,CAAC,EAAE,KAAK,EAAE,EAAE,CAAC;QAC3D,IAAI,QAAQ,CAAC,KAAK,CAAC,EAAE,IAAI,KAAK,SAAS,EAAE,CAAC;YACzC,YAAY,GAAG,KAAK,CAAC;YACrB,MAAM;QACP,CAAC;IACF,CAAC;IAED,IAAI,YAAY,GAAG,CAAC,EAAE,CAAC;QACtB,MAAM,QAAQ,GAAG,
|
|
1
|
+
{"version":3,"file":"context-builder.js","sourceRoot":"","sources":["../../src/core/context-builder.ts"],"names":[],"mappings":"AAQA,SAAS,oBAAoB,CAAC,KAA0B;IACvD,OAAO;QACN,IAAI,EAAE,MAAM;QACZ,OAAO,EAAE;YACR;gBACC,IAAI,EAAE,MAAM;gBACZ,IAAI,EAAE,2BAA2B,KAAK,CAAC,OAAO,2BAA2B;aACzE;SACD;QACD,SAAS,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,SAAS,CAAC;KACtC,CAAC;AACH,CAAC;AAED,SAAS,cAAc,CAAC,OAAgC;IACvD,OAAO,OAAO,CAAC,MAAM,CAAC,CAAC,KAAK,EAAgC,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC;AAC1F,CAAC;AAED,SAAS,qBAAqB,CAAC,OAAgC;IAC9D,OAAO,cAAc,CAAC,OAAO,CAAC,CAAC,MAAM,CACpC,CAAC,KAAK,EAAE,EAAE,CACT,KAAK,CAAC,OAAO,CAAC,IAAI,KAAK,WAAW;QAClC,CAAC,KAAK,CAAC,OAAO,CAAC,UAAU,KAAK,OAAO,IAAI,KAAK,CAAC,OAAO,CAAC,UAAU,KAAK,SAAS,CAAC,CACjF,CAAC;AACH,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,OAAgC;IACnE,MAAM,QAAQ,GAAG,eAAe,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IAC/C,IAAI,YAAY,GAAG,CAAC,CAAC,CAAC;IACtB,KAAK,IAAI,KAAK,GAAG,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,KAAK,IAAI,CAAC,EAAE,KAAK,EAAE,EAAE,CAAC;QAC3D,IAAI,QAAQ,CAAC,KAAK,CAAC,EAAE,IAAI,KAAK,SAAS,EAAE,CAAC;YACzC,YAAY,GAAG,KAAK,CAAC;YACrB,MAAM;QACP,CAAC;IACF,CAAC;IAED,IAAI,YAAY,GAAG,CAAC,EAAE,CAAC;QACtB,MAAM,QAAQ,GAAG,qBAAqB,CAAC,QAAQ,CAAC,CAAC;QACjD,OAAO;YACN,QAAQ,EAAE,QAAQ,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC;YAChD,cAAc,EAAE,QAAQ,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC;SACjD,CAAC;IACH,CAAC;IAED,MAAM,OAAO,GAAG,QAAQ,CAAC,YAAY,CAAC,CAAC;IACvC,IAAI,OAAO,EAAE,IAAI,KAAK,SAAS,EAAE,CAAC;QACjC,MAAM,IAAI,KAAK,CAAC,6CAA6C,CAAC,CAAC;IAChE,CAAC;IACD,MAAM,cAAc,GAAG,QAAQ,CAAC,SAAS,CACxC,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE,CAAC,KAAK,GAAG,YAAY,IAAI,KAAK,CAAC,IAAI,KAAK,SAAS,IAAI,KAAK,CAAC,EAAE,KAAK,OAAO,CAAC,gBAAgB,CAC3G,CAAC;IACF,IAAI,cAAc,GAAG,CAAC,EAAE,CAAC;QACxB,MAAM,IAAI,KAAK,CAAC,mEAAmE,CAAC,CAAC;IACtF,CAAC;IAED,MAAM,WAAW,GAAG,qBAAqB,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC,CAAC;IAC1E,OAAO;QACN,QAAQ,EAAE,CAAC,oBAAoB,CAAC,OAAO,CAAC,EAAE,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QACvF,cAAc,EAAE,CAAC,IAAI,EAAE,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;KAC/D,CAAC;AACH,CAAC","sourcesContent":["import type { Message, UserMessage } from \"@di-code/ai\";\nimport type { SessionEntry, SessionMessageEntry, SessionSummaryEntry } from \"./session/types.ts\";\n\nexport interface BuiltSessionContext {\n\treadonly messages: readonly Message[];\n\treadonly sourceEntryIds: readonly (string | null)[];\n}\n\nfunction createSummaryMessage(entry: SessionSummaryEntry): UserMessage {\n\treturn {\n\t\trole: \"user\",\n\t\tcontent: [\n\t\t\t{\n\t\t\t\ttype: \"text\",\n\t\t\t\ttext: `<conversation-summary>\\n${entry.summary}\\n</conversation-summary>`,\n\t\t\t},\n\t\t],\n\t\ttimestamp: Date.parse(entry.timestamp),\n\t};\n}\n\nfunction messageEntries(entries: readonly SessionEntry[]): SessionMessageEntry[] {\n\treturn entries.filter((entry): entry is SessionMessageEntry => entry.type === \"message\");\n}\n\nfunction contextMessageEntries(entries: readonly SessionEntry[]): SessionMessageEntry[] {\n\treturn messageEntries(entries).filter(\n\t\t(entry) =>\n\t\t\tentry.message.role !== \"assistant\" ||\n\t\t\t(entry.message.stopReason !== \"error\" && entry.message.stopReason !== \"aborted\"),\n\t);\n}\n\nexport function buildSessionContext(entries: readonly SessionEntry[]): BuiltSessionContext {\n\tconst snapshot = structuredClone([...entries]);\n\tlet summaryIndex = -1;\n\tfor (let index = snapshot.length - 1; index >= 0; index--) {\n\t\tif (snapshot[index]?.type === \"summary\") {\n\t\t\tsummaryIndex = index;\n\t\t\tbreak;\n\t\t}\n\t}\n\n\tif (summaryIndex < 0) {\n\t\tconst messages = contextMessageEntries(snapshot);\n\t\treturn {\n\t\t\tmessages: messages.map((entry) => entry.message),\n\t\t\tsourceEntryIds: messages.map((entry) => entry.id),\n\t\t};\n\t}\n\n\tconst summary = snapshot[summaryIndex];\n\tif (summary?.type !== \"summary\") {\n\t\tthrow new Error(\"Latest summary entry could not be resolved.\");\n\t}\n\tconst firstKeptIndex = snapshot.findIndex(\n\t\t(entry, index) => index < summaryIndex && entry.type === \"message\" && entry.id === summary.firstKeptEntryId,\n\t);\n\tif (firstKeptIndex < 0) {\n\t\tthrow new Error(\"Summary firstKeptEntryId must reference an earlier message entry.\");\n\t}\n\n\tconst keptEntries = contextMessageEntries(snapshot.slice(firstKeptIndex));\n\treturn {\n\t\tmessages: [createSummaryMessage(summary), ...keptEntries.map((entry) => entry.message)],\n\t\tsourceEntryIds: [null, ...keptEntries.map((entry) => entry.id)],\n\t};\n}\n"]}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { ImageContent } from "@di-code/ai";
|
|
2
|
+
export declare const MAX_IMAGE_INPUTS = 4;
|
|
3
|
+
export declare const MAX_IMAGE_INPUT_BYTES: number;
|
|
4
|
+
/** Converts already-read bytes into validated provider-neutral image content. */
|
|
5
|
+
export declare function imageContentFromBytes(data: Uint8Array, source: string): ImageContent;
|
|
6
|
+
/** Reads explicitly requested local image files into the provider-neutral user-message format. */
|
|
7
|
+
export declare function loadImageInputs(paths: readonly string[], cwd: string): Promise<ImageContent[]>;
|
|
8
|
+
/** Extracts @path references into image attachments or bounded text blocks for the model prompt. */
|
|
9
|
+
export declare function extractImageAttachments(text: string, cwd: string): Promise<{
|
|
10
|
+
text: string;
|
|
11
|
+
images: ImageContent[];
|
|
12
|
+
}>;
|
|
13
|
+
//# sourceMappingURL=image-input.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"image-input.d.ts","sourceRoot":"","sources":["../../src/core/image-input.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAIhD,eAAO,MAAM,gBAAgB,IAAI,CAAC;AAClC,eAAO,MAAM,qBAAqB,QAAkB,CAAC;AAwCrD,iFAAiF;AACjF,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,GAAG,YAAY,CAOpF;AAyDD,kGAAkG;AAClG,wBAAsB,eAAe,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,CAKpG;AAUD,oGAAoG;AACpG,wBAAsB,uBAAuB,CAC5C,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,MAAM,GACT,OAAO,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,YAAY,EAAE,CAAA;CAAE,CAAC,CA8BnD"}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import { readFile, stat } from "node:fs/promises";
|
|
2
|
+
import { basename, isAbsolute, relative, resolve } from "node:path";
|
|
3
|
+
import { resolveAllowedFilePath } from "./tools/path-boundary.js";
|
|
4
|
+
import { DEFAULT_READ_MAX_BYTES, DEFAULT_READ_MAX_LINES } from "./tools/read.js";
|
|
5
|
+
export const MAX_IMAGE_INPUTS = 4;
|
|
6
|
+
export const MAX_IMAGE_INPUT_BYTES = 5 * 1024 * 1024;
|
|
7
|
+
const IMAGE_REFERENCE = /(^|\s)@(?:"([^"\r\n]+)"|'([^'\r\n]+)'|([^\s@]+))/g;
|
|
8
|
+
function detectImageMimeType(data) {
|
|
9
|
+
if (data.length >= 8 &&
|
|
10
|
+
data[0] === 137 &&
|
|
11
|
+
data[1] === 80 &&
|
|
12
|
+
data[2] === 78 &&
|
|
13
|
+
data[3] === 71 &&
|
|
14
|
+
data[4] === 13 &&
|
|
15
|
+
data[5] === 10 &&
|
|
16
|
+
data[6] === 26 &&
|
|
17
|
+
data[7] === 10) {
|
|
18
|
+
return "image/png";
|
|
19
|
+
}
|
|
20
|
+
if (data.length >= 3 && data[0] === 255 && data[1] === 216 && data[2] === 255)
|
|
21
|
+
return "image/jpeg";
|
|
22
|
+
if (data.length >= 6 &&
|
|
23
|
+
(Buffer.from(data.subarray(0, 6)).equals(Buffer.from("GIF87a")) ||
|
|
24
|
+
Buffer.from(data.subarray(0, 6)).equals(Buffer.from("GIF89a")))) {
|
|
25
|
+
return "image/gif";
|
|
26
|
+
}
|
|
27
|
+
if (data.length >= 12 &&
|
|
28
|
+
Buffer.from(data.subarray(0, 4)).equals(Buffer.from("RIFF")) &&
|
|
29
|
+
Buffer.from(data.subarray(8, 12)).equals(Buffer.from("WEBP"))) {
|
|
30
|
+
return "image/webp";
|
|
31
|
+
}
|
|
32
|
+
return undefined;
|
|
33
|
+
}
|
|
34
|
+
function displayPath(path) {
|
|
35
|
+
return path.trim() || "<empty path>";
|
|
36
|
+
}
|
|
37
|
+
/** Converts already-read bytes into validated provider-neutral image content. */
|
|
38
|
+
export function imageContentFromBytes(data, source) {
|
|
39
|
+
if (data.byteLength > MAX_IMAGE_INPUT_BYTES) {
|
|
40
|
+
throw new Error(`Image exceeds the 5 MiB limit: ${displayPath(source)}`);
|
|
41
|
+
}
|
|
42
|
+
const mimeType = detectImageMimeType(data);
|
|
43
|
+
if (!mimeType)
|
|
44
|
+
throw new Error(`Unsupported image format: ${displayPath(source)}`);
|
|
45
|
+
return { type: "image", data: Buffer.from(data).toString("base64"), mimeType };
|
|
46
|
+
}
|
|
47
|
+
async function loadImageInput(path, cwd) {
|
|
48
|
+
if (path.trim().length === 0)
|
|
49
|
+
throw new Error("Image path must not be empty.");
|
|
50
|
+
const absolutePath = resolve(cwd, path);
|
|
51
|
+
const metadata = await stat(absolutePath);
|
|
52
|
+
if (!metadata.isFile())
|
|
53
|
+
throw new Error(`Image path is not a regular file: ${displayPath(path)}`);
|
|
54
|
+
if (metadata.size > MAX_IMAGE_INPUT_BYTES) {
|
|
55
|
+
throw new Error(`Image exceeds the 5 MiB limit: ${displayPath(path)}`);
|
|
56
|
+
}
|
|
57
|
+
const data = await readFile(absolutePath);
|
|
58
|
+
if (data.length > MAX_IMAGE_INPUT_BYTES) {
|
|
59
|
+
throw new Error(`Image exceeds the 5 MiB limit: ${displayPath(path)}`);
|
|
60
|
+
}
|
|
61
|
+
return imageContentFromBytes(data, path);
|
|
62
|
+
}
|
|
63
|
+
function containsNulByte(data) {
|
|
64
|
+
for (const byte of data)
|
|
65
|
+
if (byte === 0)
|
|
66
|
+
return true;
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
function escapeFileName(path) {
|
|
70
|
+
return path.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """);
|
|
71
|
+
}
|
|
72
|
+
function relativeAttachmentPath(path, cwd) {
|
|
73
|
+
const absolutePath = resolve(cwd, path);
|
|
74
|
+
const relativePath = relative(resolve(cwd), absolutePath).replaceAll("\\", "/");
|
|
75
|
+
return relativePath || basename(absolutePath);
|
|
76
|
+
}
|
|
77
|
+
async function loadTextAttachment(path, cwd) {
|
|
78
|
+
const absolutePath = await resolveAllowedFilePath(path, cwd);
|
|
79
|
+
const metadata = await stat(absolutePath);
|
|
80
|
+
if (!metadata.isFile())
|
|
81
|
+
throw new Error(`File attachment is not a regular file: ${displayPath(path)}`);
|
|
82
|
+
if (metadata.size > DEFAULT_READ_MAX_BYTES) {
|
|
83
|
+
throw new Error(`Text attachment exceeds the 50 KiB limit: ${displayPath(path)}`);
|
|
84
|
+
}
|
|
85
|
+
const data = await readFile(absolutePath);
|
|
86
|
+
if (data.length > DEFAULT_READ_MAX_BYTES) {
|
|
87
|
+
throw new Error(`Text attachment exceeds the 50 KiB limit: ${displayPath(path)}`);
|
|
88
|
+
}
|
|
89
|
+
if (containsNulByte(data))
|
|
90
|
+
throw new Error(`Binary files are not supported by @ attachments: ${displayPath(path)}`);
|
|
91
|
+
const normalized = data.toString("utf8").replace(/\r\n?/g, "\n");
|
|
92
|
+
const lines = normalized.split("\n");
|
|
93
|
+
const content = lines.length > DEFAULT_READ_MAX_LINES
|
|
94
|
+
? `${lines.slice(0, DEFAULT_READ_MAX_LINES).join("\n")}\n\n[File truncated after ${DEFAULT_READ_MAX_LINES} lines.]`
|
|
95
|
+
: normalized;
|
|
96
|
+
const fileName = escapeFileName(relativeAttachmentPath(path, cwd));
|
|
97
|
+
return `<file name="${fileName}">\n${content}\n</file>`;
|
|
98
|
+
}
|
|
99
|
+
/** Reads explicitly requested local image files into the provider-neutral user-message format. */
|
|
100
|
+
export async function loadImageInputs(paths, cwd) {
|
|
101
|
+
if (paths.length > MAX_IMAGE_INPUTS) {
|
|
102
|
+
throw new Error(`At most ${MAX_IMAGE_INPUTS} images can be attached to one prompt.`);
|
|
103
|
+
}
|
|
104
|
+
return Promise.all(paths.map((path) => loadImageInput(path, cwd)));
|
|
105
|
+
}
|
|
106
|
+
function isMissingFileError(cause) {
|
|
107
|
+
return cause instanceof Error && "code" in cause && cause.code === "ENOENT";
|
|
108
|
+
}
|
|
109
|
+
function isUnsupportedImageError(cause) {
|
|
110
|
+
return cause instanceof Error && cause.message.startsWith("Unsupported image format:");
|
|
111
|
+
}
|
|
112
|
+
/** Extracts @path references into image attachments or bounded text blocks for the model prompt. */
|
|
113
|
+
export async function extractImageAttachments(text, cwd) {
|
|
114
|
+
const images = [];
|
|
115
|
+
const attachments = [];
|
|
116
|
+
let result = "";
|
|
117
|
+
let cursor = 0;
|
|
118
|
+
for (const match of text.matchAll(IMAGE_REFERENCE)) {
|
|
119
|
+
const index = match.index ?? 0;
|
|
120
|
+
const leading = match[1] ?? "";
|
|
121
|
+
const path = match[2] ?? match[3] ?? match[4] ?? "";
|
|
122
|
+
result += `${text.slice(cursor, index)}${leading}`;
|
|
123
|
+
cursor = index + match[0].length;
|
|
124
|
+
try {
|
|
125
|
+
if (!isAbsolute(path))
|
|
126
|
+
await resolveAllowedFilePath(path, cwd);
|
|
127
|
+
const [image] = await loadImageInputs([path], cwd);
|
|
128
|
+
if (!image)
|
|
129
|
+
throw new Error("Image attachment was not loaded.");
|
|
130
|
+
if (images.length >= MAX_IMAGE_INPUTS) {
|
|
131
|
+
throw new Error(`At most ${MAX_IMAGE_INPUTS} images can be attached to one prompt.`);
|
|
132
|
+
}
|
|
133
|
+
images.push(image);
|
|
134
|
+
attachments.push(`[Attached image: ${basename(path)}]`);
|
|
135
|
+
}
|
|
136
|
+
catch (cause) {
|
|
137
|
+
if (isMissingFileError(cause))
|
|
138
|
+
throw new Error(`File attachment was not found: ${path}`);
|
|
139
|
+
if (!isUnsupportedImageError(cause))
|
|
140
|
+
throw cause;
|
|
141
|
+
attachments.push(await loadTextAttachment(path, cwd));
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
const prompt = `${result}${text.slice(cursor)}`.replace(/[ \t]{2,}/g, " ").trim();
|
|
145
|
+
return { text: [...attachments, prompt].filter((value) => value.length > 0).join("\n"), images };
|
|
146
|
+
}
|
|
147
|
+
//# sourceMappingURL=image-input.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"image-input.js","sourceRoot":"","sources":["../../src/core/image-input.ts"],"names":[],"mappings":"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","sourcesContent":["import { readFile, stat } from \"node:fs/promises\";\nimport { basename, isAbsolute, relative, resolve } from \"node:path\";\nimport type { ImageContent } from \"@di-code/ai\";\nimport { resolveAllowedFilePath } from \"./tools/path-boundary.ts\";\nimport { DEFAULT_READ_MAX_BYTES, DEFAULT_READ_MAX_LINES } from \"./tools/read.ts\";\n\nexport const MAX_IMAGE_INPUTS = 4;\nexport const MAX_IMAGE_INPUT_BYTES = 5 * 1024 * 1024;\n\nconst IMAGE_REFERENCE = /(^|\\s)@(?:\"([^\"\\r\\n]+)\"|'([^'\\r\\n]+)'|([^\\s@]+))/g;\n\nfunction detectImageMimeType(data: Uint8Array): ImageContent[\"mimeType\"] | undefined {\n\tif (\n\t\tdata.length >= 8 &&\n\t\tdata[0] === 137 &&\n\t\tdata[1] === 80 &&\n\t\tdata[2] === 78 &&\n\t\tdata[3] === 71 &&\n\t\tdata[4] === 13 &&\n\t\tdata[5] === 10 &&\n\t\tdata[6] === 26 &&\n\t\tdata[7] === 10\n\t) {\n\t\treturn \"image/png\";\n\t}\n\tif (data.length >= 3 && data[0] === 255 && data[1] === 216 && data[2] === 255) return \"image/jpeg\";\n\tif (\n\t\tdata.length >= 6 &&\n\t\t(Buffer.from(data.subarray(0, 6)).equals(Buffer.from(\"GIF87a\")) ||\n\t\t\tBuffer.from(data.subarray(0, 6)).equals(Buffer.from(\"GIF89a\")))\n\t) {\n\t\treturn \"image/gif\";\n\t}\n\tif (\n\t\tdata.length >= 12 &&\n\t\tBuffer.from(data.subarray(0, 4)).equals(Buffer.from(\"RIFF\")) &&\n\t\tBuffer.from(data.subarray(8, 12)).equals(Buffer.from(\"WEBP\"))\n\t) {\n\t\treturn \"image/webp\";\n\t}\n\treturn undefined;\n}\n\nfunction displayPath(path: string): string {\n\treturn path.trim() || \"<empty path>\";\n}\n\n/** Converts already-read bytes into validated provider-neutral image content. */\nexport function imageContentFromBytes(data: Uint8Array, source: string): ImageContent {\n\tif (data.byteLength > MAX_IMAGE_INPUT_BYTES) {\n\t\tthrow new Error(`Image exceeds the 5 MiB limit: ${displayPath(source)}`);\n\t}\n\tconst mimeType = detectImageMimeType(data);\n\tif (!mimeType) throw new Error(`Unsupported image format: ${displayPath(source)}`);\n\treturn { type: \"image\", data: Buffer.from(data).toString(\"base64\"), mimeType };\n}\n\nasync function loadImageInput(path: string, cwd: string): Promise<ImageContent> {\n\tif (path.trim().length === 0) throw new Error(\"Image path must not be empty.\");\n\tconst absolutePath = resolve(cwd, path);\n\tconst metadata = await stat(absolutePath);\n\tif (!metadata.isFile()) throw new Error(`Image path is not a regular file: ${displayPath(path)}`);\n\tif (metadata.size > MAX_IMAGE_INPUT_BYTES) {\n\t\tthrow new Error(`Image exceeds the 5 MiB limit: ${displayPath(path)}`);\n\t}\n\n\tconst data = await readFile(absolutePath);\n\tif (data.length > MAX_IMAGE_INPUT_BYTES) {\n\t\tthrow new Error(`Image exceeds the 5 MiB limit: ${displayPath(path)}`);\n\t}\n\treturn imageContentFromBytes(data, path);\n}\n\nfunction containsNulByte(data: Uint8Array): boolean {\n\tfor (const byte of data) if (byte === 0) return true;\n\treturn false;\n}\n\nfunction escapeFileName(path: string): string {\n\treturn path.replaceAll(\"&\", \"&\").replaceAll(\"<\", \"<\").replaceAll(\">\", \">\").replaceAll('\"', \""\");\n}\n\nfunction relativeAttachmentPath(path: string, cwd: string): string {\n\tconst absolutePath = resolve(cwd, path);\n\tconst relativePath = relative(resolve(cwd), absolutePath).replaceAll(\"\\\\\", \"/\");\n\treturn relativePath || basename(absolutePath);\n}\n\nasync function loadTextAttachment(path: string, cwd: string): Promise<string> {\n\tconst absolutePath = await resolveAllowedFilePath(path, cwd);\n\tconst metadata = await stat(absolutePath);\n\tif (!metadata.isFile()) throw new Error(`File attachment is not a regular file: ${displayPath(path)}`);\n\tif (metadata.size > DEFAULT_READ_MAX_BYTES) {\n\t\tthrow new Error(`Text attachment exceeds the 50 KiB limit: ${displayPath(path)}`);\n\t}\n\n\tconst data = await readFile(absolutePath);\n\tif (data.length > DEFAULT_READ_MAX_BYTES) {\n\t\tthrow new Error(`Text attachment exceeds the 50 KiB limit: ${displayPath(path)}`);\n\t}\n\tif (containsNulByte(data)) throw new Error(`Binary files are not supported by @ attachments: ${displayPath(path)}`);\n\n\tconst normalized = data.toString(\"utf8\").replace(/\\r\\n?/g, \"\\n\");\n\tconst lines = normalized.split(\"\\n\");\n\tconst content =\n\t\tlines.length > DEFAULT_READ_MAX_LINES\n\t\t\t? `${lines.slice(0, DEFAULT_READ_MAX_LINES).join(\"\\n\")}\\n\\n[File truncated after ${DEFAULT_READ_MAX_LINES} lines.]`\n\t\t\t: normalized;\n\tconst fileName = escapeFileName(relativeAttachmentPath(path, cwd));\n\treturn `<file name=\"${fileName}\">\\n${content}\\n</file>`;\n}\n\n/** Reads explicitly requested local image files into the provider-neutral user-message format. */\nexport async function loadImageInputs(paths: readonly string[], cwd: string): Promise<ImageContent[]> {\n\tif (paths.length > MAX_IMAGE_INPUTS) {\n\t\tthrow new Error(`At most ${MAX_IMAGE_INPUTS} images can be attached to one prompt.`);\n\t}\n\treturn Promise.all(paths.map((path) => loadImageInput(path, cwd)));\n}\n\nfunction isMissingFileError(cause: unknown): boolean {\n\treturn cause instanceof Error && \"code\" in cause && cause.code === \"ENOENT\";\n}\n\nfunction isUnsupportedImageError(cause: unknown): boolean {\n\treturn cause instanceof Error && cause.message.startsWith(\"Unsupported image format:\");\n}\n\n/** Extracts @path references into image attachments or bounded text blocks for the model prompt. */\nexport async function extractImageAttachments(\n\ttext: string,\n\tcwd: string,\n): Promise<{ text: string; images: ImageContent[] }> {\n\tconst images: ImageContent[] = [];\n\tconst attachments: string[] = [];\n\tlet result = \"\";\n\tlet cursor = 0;\n\n\tfor (const match of text.matchAll(IMAGE_REFERENCE)) {\n\t\tconst index = match.index ?? 0;\n\t\tconst leading = match[1] ?? \"\";\n\t\tconst path = match[2] ?? match[3] ?? match[4] ?? \"\";\n\t\tresult += `${text.slice(cursor, index)}${leading}`;\n\t\tcursor = index + match[0].length;\n\t\ttry {\n\t\t\tif (!isAbsolute(path)) await resolveAllowedFilePath(path, cwd);\n\t\t\tconst [image] = await loadImageInputs([path], cwd);\n\t\t\tif (!image) throw new Error(\"Image attachment was not loaded.\");\n\t\t\tif (images.length >= MAX_IMAGE_INPUTS) {\n\t\t\t\tthrow new Error(`At most ${MAX_IMAGE_INPUTS} images can be attached to one prompt.`);\n\t\t\t}\n\t\t\timages.push(image);\n\t\t\tattachments.push(`[Attached image: ${basename(path)}]`);\n\t\t} catch (cause) {\n\t\t\tif (isMissingFileError(cause)) throw new Error(`File attachment was not found: ${path}`);\n\t\t\tif (!isUnsupportedImageError(cause)) throw cause;\n\t\t\tattachments.push(await loadTextAttachment(path, cwd));\n\t\t}\n\t}\n\n\tconst prompt = `${result}${text.slice(cursor)}`.replace(/[ \\t]{2,}/g, \" \").trim();\n\treturn { text: [...attachments, prompt].filter((value) => value.length > 0).join(\"\\n\"), images };\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session-storage.d.ts","sourceRoot":"","sources":["../../../src/core/session/session-storage.ts"],"names":[],"mappings":"AAGA,OAAO,EACN,KAAK,aAAa,EAElB,KAAK,YAAY,EACjB,KAAK,aAAa,EAKlB,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"session-storage.d.ts","sourceRoot":"","sources":["../../../src/core/session/session-storage.ts"],"names":[],"mappings":"AAGA,OAAO,EACN,KAAK,aAAa,EAElB,KAAK,YAAY,EACjB,KAAK,aAAa,EAKlB,MAAM,YAAY,CAAC;AA6MpB,wBAAsB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CA+E9E;AAED,MAAM,WAAW,oBAAoB;IACpC,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IAC5B,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACzD;AAaD,wBAAsB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAiB9F;AA8CD,wBAAsB,kBAAkB,CACvC,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,YAAY,EACnB,gBAAgB,EAAE,MAAM,EACxB,OAAO,GAAE,oBAAyB,GAChC,OAAO,CAAC,IAAI,CAAC,CAkFf"}
|
|
@@ -112,6 +112,7 @@ function isMessage(value) {
|
|
|
112
112
|
isNonEmptyString(value.toolName) &&
|
|
113
113
|
Array.isArray(value.content) &&
|
|
114
114
|
value.content.every(isToolResultContent) &&
|
|
115
|
+
(value.details === undefined || isJsonValue(value.details)) &&
|
|
115
116
|
typeof value.isError === "boolean");
|
|
116
117
|
default:
|
|
117
118
|
return false;
|