@di-code/coding-agent 0.1.1 → 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (100) hide show
  1. package/README.md +489 -143
  2. package/dist/cli.d.ts +12 -0
  3. package/dist/cli.d.ts.map +1 -1
  4. package/dist/cli.js +74 -0
  5. package/dist/cli.js.map +1 -1
  6. package/dist/core/clipboard-image.d.ts +13 -0
  7. package/dist/core/clipboard-image.d.ts.map +1 -0
  8. package/dist/core/clipboard-image.js +99 -0
  9. package/dist/core/clipboard-image.js.map +1 -0
  10. package/dist/core/image-input.d.ts +13 -0
  11. package/dist/core/image-input.d.ts.map +1 -0
  12. package/dist/core/image-input.js +102 -0
  13. package/dist/core/image-input.js.map +1 -0
  14. package/dist/core/resources/index.d.ts +3 -0
  15. package/dist/core/resources/index.d.ts.map +1 -0
  16. package/dist/core/resources/index.js +2 -0
  17. package/dist/core/resources/index.js.map +1 -0
  18. package/dist/core/resources/loader.d.ts +8 -0
  19. package/dist/core/resources/loader.d.ts.map +1 -0
  20. package/dist/core/resources/loader.js +174 -0
  21. package/dist/core/resources/loader.js.map +1 -0
  22. package/dist/core/resources/skills.d.ts +10 -0
  23. package/dist/core/resources/skills.d.ts.map +1 -0
  24. package/dist/core/resources/skills.js +167 -0
  25. package/dist/core/resources/skills.js.map +1 -0
  26. package/dist/core/resources/types.d.ts +41 -0
  27. package/dist/core/resources/types.d.ts.map +1 -0
  28. package/dist/core/resources/types.js +2 -0
  29. package/dist/core/resources/types.js.map +1 -0
  30. package/dist/core/session.d.ts +10 -1
  31. package/dist/core/session.d.ts.map +1 -1
  32. package/dist/core/session.js +33 -5
  33. package/dist/core/session.js.map +1 -1
  34. package/dist/core/skill-command.d.ts +3 -0
  35. package/dist/core/skill-command.d.ts.map +1 -0
  36. package/dist/core/skill-command.js +34 -0
  37. package/dist/core/skill-command.js.map +1 -0
  38. package/dist/core/system-prompt.d.ts +6 -0
  39. package/dist/core/system-prompt.d.ts.map +1 -0
  40. package/dist/core/system-prompt.js +57 -0
  41. package/dist/core/system-prompt.js.map +1 -0
  42. package/dist/extensions/runtime.d.ts +7 -4
  43. package/dist/extensions/runtime.d.ts.map +1 -1
  44. package/dist/extensions/runtime.js +45 -10
  45. package/dist/extensions/runtime.js.map +1 -1
  46. package/dist/index.d.ts +3 -0
  47. package/dist/index.d.ts.map +1 -1
  48. package/dist/index.js +3 -0
  49. package/dist/index.js.map +1 -1
  50. package/dist/main.d.ts +1 -0
  51. package/dist/main.d.ts.map +1 -1
  52. package/dist/main.js +91 -2
  53. package/dist/main.js.map +1 -1
  54. package/dist/modes/interactive-components.d.ts +1 -0
  55. package/dist/modes/interactive-components.d.ts.map +1 -1
  56. package/dist/modes/interactive-components.js +48 -20
  57. package/dist/modes/interactive-components.js.map +1 -1
  58. package/dist/modes/interactive-layout.d.ts +2 -1
  59. package/dist/modes/interactive-layout.d.ts.map +1 -1
  60. package/dist/modes/interactive-layout.js +17 -1
  61. package/dist/modes/interactive-layout.js.map +1 -1
  62. package/dist/modes/interactive-state.d.ts +12 -2
  63. package/dist/modes/interactive-state.d.ts.map +1 -1
  64. package/dist/modes/interactive-state.js +50 -3
  65. package/dist/modes/interactive-state.js.map +1 -1
  66. package/dist/modes/interactive.d.ts +12 -0
  67. package/dist/modes/interactive.d.ts.map +1 -1
  68. package/dist/modes/interactive.js +125 -9
  69. package/dist/modes/interactive.js.map +1 -1
  70. package/dist/plugins/index.d.ts +5 -0
  71. package/dist/plugins/index.d.ts.map +1 -0
  72. package/dist/plugins/index.js +5 -0
  73. package/dist/plugins/index.js.map +1 -0
  74. package/dist/plugins/loader.d.ts +18 -0
  75. package/dist/plugins/loader.d.ts.map +1 -0
  76. package/dist/plugins/loader.js +92 -0
  77. package/dist/plugins/loader.js.map +1 -0
  78. package/dist/plugins/manager.d.ts +23 -0
  79. package/dist/plugins/manager.d.ts.map +1 -0
  80. package/dist/plugins/manager.js +152 -0
  81. package/dist/plugins/manager.js.map +1 -0
  82. package/dist/plugins/manifest.d.ts +7 -0
  83. package/dist/plugins/manifest.d.ts.map +1 -0
  84. package/dist/plugins/manifest.js +116 -0
  85. package/dist/plugins/manifest.js.map +1 -0
  86. package/dist/plugins/types.d.ts +41 -0
  87. package/dist/plugins/types.d.ts.map +1 -0
  88. package/dist/plugins/types.js +2 -0
  89. package/dist/plugins/types.js.map +1 -0
  90. package/dist/provider-onboarding.d.ts.map +1 -1
  91. package/dist/provider-onboarding.js +20 -1
  92. package/dist/provider-onboarding.js.map +1 -1
  93. package/dist/startup.d.ts.map +1 -1
  94. package/dist/startup.js +65 -16
  95. package/dist/startup.js.map +1 -1
  96. package/dist/utils/syntax-highlight.d.ts +2 -0
  97. package/dist/utils/syntax-highlight.d.ts.map +1 -0
  98. package/dist/utils/syntax-highlight.js +55 -0
  99. package/dist/utils/syntax-highlight.js.map +1 -0
  100. package/package.json +19 -4
package/dist/cli.d.ts CHANGED
@@ -3,12 +3,21 @@ export type CliCommand = {
3
3
  kind: "help";
4
4
  } | {
5
5
  kind: "version";
6
+ } | {
7
+ kind: "plugin";
8
+ action: "install" | "list" | "enable" | "disable" | "update" | "remove";
9
+ argument?: string;
6
10
  } | {
7
11
  kind: "run";
8
12
  mode: OutputMode;
9
13
  prompt: string;
10
14
  sessionPath?: string;
11
15
  continueSession?: true;
16
+ imagePaths?: readonly string[];
17
+ noSkills?: true;
18
+ noContextFiles?: true;
19
+ skillPaths?: readonly string[];
20
+ projectTrust?: boolean;
12
21
  };
13
22
  export declare class CliUsageError extends Error {
14
23
  constructor(message: string);
@@ -20,6 +29,9 @@ export interface CliDependencies {
20
29
  run(command: Extract<CliCommand, {
21
30
  kind: "run";
22
31
  }>): Promise<number>;
32
+ plugin?(command: Extract<CliCommand, {
33
+ kind: "plugin";
34
+ }>): Promise<number>;
23
35
  readonly version: string;
24
36
  }
25
37
  export declare function runCli(args: readonly string[], dependencies: CliDependencies): Promise<number>;
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,KAAK,CAAC;IAAC,IAAI,EAAE,UAAU,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAAC,eAAe,CAAC,EAAE,IAAI,CAAA;CAAE,CAAC;AAEnG,qBAAa,aAAc,SAAQ,KAAK;gBAC3B,OAAO,EAAE,MAAM;CAI3B;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,UAAU,CA+EhE;AAcD,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,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,CAsBpG"}
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
@@ -5,6 +5,22 @@ export class CliUsageError extends Error {
5
5
  }
6
6
  }
7
7
  export function parseCliArgs(args) {
8
+ if (args[0] === "plugin") {
9
+ const action = args[1];
10
+ if (action !== "install" &&
11
+ action !== "list" &&
12
+ action !== "enable" &&
13
+ action !== "disable" &&
14
+ action !== "update" &&
15
+ action !== "remove")
16
+ throw new CliUsageError("Plugin command must be install, list, enable, disable, update, or remove.");
17
+ const argument = args[2];
18
+ if (args.length > 3 ||
19
+ (action !== "list" && (argument === undefined || argument.trim() === "")) ||
20
+ (action === "list" && argument !== undefined))
21
+ throw new CliUsageError("Plugin command has invalid arguments.");
22
+ return { kind: "plugin", action, ...(argument ? { argument } : {}) };
23
+ }
8
24
  const staticOption = args.find((argument) => ["-h", "--help", "-v", "--version"].includes(argument));
9
25
  if (staticOption !== undefined) {
10
26
  const kind = staticOption === "-h" || staticOption === "--help" ? "help" : "version";
@@ -17,6 +33,11 @@ export function parseCliArgs(args) {
17
33
  let printAlias = false;
18
34
  let sessionPath;
19
35
  let continueSession = false;
36
+ let noSkills = false;
37
+ let noContextFiles = false;
38
+ let projectTrust;
39
+ const skillPaths = [];
40
+ const imagePaths = [];
20
41
  const promptParts = [];
21
42
  for (let index = 0; index < args.length; index++) {
22
43
  const argument = args[index];
@@ -32,6 +53,40 @@ export function parseCliArgs(args) {
32
53
  continueSession = true;
33
54
  continue;
34
55
  }
56
+ if (argument === "--no-skills") {
57
+ noSkills = true;
58
+ continue;
59
+ }
60
+ if (argument === "--no-context-files") {
61
+ noContextFiles = true;
62
+ continue;
63
+ }
64
+ if (argument === "--trust-project" || argument === "--untrust-project") {
65
+ const nextTrust = argument === "--trust-project";
66
+ if (projectTrust !== undefined && projectTrust !== nextTrust) {
67
+ throw new CliUsageError("Cannot combine --trust-project with --untrust-project.");
68
+ }
69
+ projectTrust = nextTrust;
70
+ continue;
71
+ }
72
+ if (argument === "--skill") {
73
+ const value = args[index + 1];
74
+ if (value === undefined || value.trim().length === 0) {
75
+ throw new CliUsageError("Option --skill requires a non-empty value.");
76
+ }
77
+ skillPaths.push(value);
78
+ index++;
79
+ continue;
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
+ }
35
90
  if (argument === "--mode") {
36
91
  const value = args[index + 1];
37
92
  if (value === undefined) {
@@ -69,6 +124,9 @@ export function parseCliArgs(args) {
69
124
  if (continueSession && sessionPath !== undefined) {
70
125
  throw new CliUsageError("Cannot combine --continue with --session.");
71
126
  }
127
+ if (mode === "interactive" && imagePaths.length > 0) {
128
+ throw new CliUsageError("--image is not available in interactive mode.");
129
+ }
72
130
  if (promptParts.length === 0 && mode !== "interactive") {
73
131
  throw new CliUsageError("A prompt is required.");
74
132
  }
@@ -78,6 +136,11 @@ export function parseCliArgs(args) {
78
136
  prompt: promptParts.join(" "),
79
137
  ...(sessionPath ? { sessionPath } : {}),
80
138
  ...(continueSession ? { continueSession: true } : {}),
139
+ ...(noSkills ? { noSkills: true } : {}),
140
+ ...(noContextFiles ? { noContextFiles: true } : {}),
141
+ ...(skillPaths.length > 0 ? { skillPaths } : {}),
142
+ ...(imagePaths.length > 0 ? { imagePaths } : {}),
143
+ ...(projectTrust === undefined ? {} : { projectTrust }),
81
144
  };
82
145
  }
83
146
  const HELP_TEXT = `Usage: di-code [options] <prompt>
@@ -88,6 +151,13 @@ Options:
88
151
  --interactive Start interactive terminal mode
89
152
  --continue, -c Continue the most recently modified session
90
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)
155
+ --skill <path> Add a SKILL.md file or skill directory (repeatable)
156
+ --no-skills Disable all Skill loading
157
+ --no-context-files Disable AGENTS.md discovery and loading
158
+ --trust-project Persist trust for project-local Skill discovery
159
+ --untrust-project Persist denial for project-local Skill discovery
160
+ plugin <action> Install, list, enable, disable, update, or remove a plugin
91
161
  -h, --help Show help
92
162
  -v, --version Show version
93
163
  `;
@@ -107,6 +177,10 @@ export async function runCli(args, dependencies) {
107
177
  case "help":
108
178
  dependencies.stdout(HELP_TEXT);
109
179
  return 0;
180
+ case "plugin":
181
+ if (!dependencies.plugin)
182
+ throw new Error("Plugin command handler is unavailable.");
183
+ return dependencies.plugin(command);
110
184
  case "version":
111
185
  dependencies.stdout(`${dependencies.version}\n`);
112
186
  return 0;
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: \"run\"; mode: OutputMode; prompt: string; sessionPath?: string; continueSession?: true };\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\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\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 === \"--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};\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 -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\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 \"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"]}
@@ -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 image references while preserving a concise attachment label in 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;AAEhD,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;AAkBD,kGAAkG;AAClG,wBAAsB,eAAe,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,CAKpG;AAMD,uGAAuG;AACvG,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,CA4BnD"}
@@ -0,0 +1,102 @@
1
+ import { readFile, stat } from "node:fs/promises";
2
+ import { basename, resolve } from "node:path";
3
+ export const MAX_IMAGE_INPUTS = 4;
4
+ export const MAX_IMAGE_INPUT_BYTES = 5 * 1024 * 1024;
5
+ const IMAGE_REFERENCE = /(^|\s)@(?:"([^"\r\n]+)"|'([^'\r\n]+)'|([^\s@]+))/g;
6
+ function detectImageMimeType(data) {
7
+ if (data.length >= 8 &&
8
+ data[0] === 137 &&
9
+ data[1] === 80 &&
10
+ data[2] === 78 &&
11
+ data[3] === 71 &&
12
+ data[4] === 13 &&
13
+ data[5] === 10 &&
14
+ data[6] === 26 &&
15
+ data[7] === 10) {
16
+ return "image/png";
17
+ }
18
+ if (data.length >= 3 && data[0] === 255 && data[1] === 216 && data[2] === 255)
19
+ return "image/jpeg";
20
+ if (data.length >= 6 &&
21
+ (Buffer.from(data.subarray(0, 6)).equals(Buffer.from("GIF87a")) ||
22
+ Buffer.from(data.subarray(0, 6)).equals(Buffer.from("GIF89a")))) {
23
+ return "image/gif";
24
+ }
25
+ if (data.length >= 12 &&
26
+ Buffer.from(data.subarray(0, 4)).equals(Buffer.from("RIFF")) &&
27
+ Buffer.from(data.subarray(8, 12)).equals(Buffer.from("WEBP"))) {
28
+ return "image/webp";
29
+ }
30
+ return undefined;
31
+ }
32
+ function displayPath(path) {
33
+ return path.trim() || "<empty path>";
34
+ }
35
+ /** Converts already-read bytes into validated provider-neutral image content. */
36
+ export function imageContentFromBytes(data, source) {
37
+ if (data.byteLength > MAX_IMAGE_INPUT_BYTES) {
38
+ throw new Error(`Image exceeds the 5 MiB limit: ${displayPath(source)}`);
39
+ }
40
+ const mimeType = detectImageMimeType(data);
41
+ if (!mimeType)
42
+ throw new Error(`Unsupported image format: ${displayPath(source)}`);
43
+ return { type: "image", data: Buffer.from(data).toString("base64"), mimeType };
44
+ }
45
+ async function loadImageInput(path, cwd) {
46
+ if (path.trim().length === 0)
47
+ throw new Error("Image path must not be empty.");
48
+ const absolutePath = resolve(cwd, path);
49
+ const metadata = await stat(absolutePath);
50
+ if (!metadata.isFile())
51
+ throw new Error(`Image path is not a regular file: ${displayPath(path)}`);
52
+ if (metadata.size > MAX_IMAGE_INPUT_BYTES) {
53
+ throw new Error(`Image exceeds the 5 MiB limit: ${displayPath(path)}`);
54
+ }
55
+ const data = await readFile(absolutePath);
56
+ if (data.length > MAX_IMAGE_INPUT_BYTES) {
57
+ throw new Error(`Image exceeds the 5 MiB limit: ${displayPath(path)}`);
58
+ }
59
+ return imageContentFromBytes(data, path);
60
+ }
61
+ /** Reads explicitly requested local image files into the provider-neutral user-message format. */
62
+ export async function loadImageInputs(paths, cwd) {
63
+ if (paths.length > MAX_IMAGE_INPUTS) {
64
+ throw new Error(`At most ${MAX_IMAGE_INPUTS} images can be attached to one prompt.`);
65
+ }
66
+ return Promise.all(paths.map((path) => loadImageInput(path, cwd)));
67
+ }
68
+ function isMissingFileError(cause) {
69
+ return cause instanceof Error && "code" in cause && cause.code === "ENOENT";
70
+ }
71
+ /** Extracts @path image references while preserving a concise attachment label in the model prompt. */
72
+ export async function extractImageAttachments(text, cwd) {
73
+ const images = [];
74
+ const labels = [];
75
+ let result = "";
76
+ let cursor = 0;
77
+ for (const match of text.matchAll(IMAGE_REFERENCE)) {
78
+ const index = match.index ?? 0;
79
+ const leading = match[1] ?? "";
80
+ const path = match[2] ?? match[3] ?? match[4] ?? "";
81
+ result += `${text.slice(cursor, index)}${leading}`;
82
+ cursor = index + match[0].length;
83
+ if (images.length >= MAX_IMAGE_INPUTS) {
84
+ throw new Error(`At most ${MAX_IMAGE_INPUTS} images can be attached to one prompt.`);
85
+ }
86
+ try {
87
+ const [image] = await loadImageInputs([path], cwd);
88
+ if (!image)
89
+ throw new Error("Image attachment was not loaded.");
90
+ images.push(image);
91
+ labels.push(`[Attached image: ${basename(path)}]`);
92
+ }
93
+ catch (cause) {
94
+ if (isMissingFileError(cause))
95
+ throw new Error(`Image attachment was not found: ${path}`);
96
+ throw cause;
97
+ }
98
+ }
99
+ const prompt = `${result}${text.slice(cursor)}`.replace(/[ \t]{2,}/g, " ").trim();
100
+ return { text: [...labels, prompt].filter((value) => value.length > 0).join("\n"), images };
101
+ }
102
+ //# 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, resolve } from \"node:path\";\nimport type { ImageContent } from \"@di-code/ai\";\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\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\n/** Extracts @path image references while preserving a concise attachment label in 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 labels: 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\tif (images.length >= MAX_IMAGE_INPUTS) {\n\t\t\tthrow new Error(`At most ${MAX_IMAGE_INPUTS} images can be attached to one prompt.`);\n\t\t}\n\t\ttry {\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\timages.push(image);\n\t\t\tlabels.push(`[Attached image: ${basename(path)}]`);\n\t\t} catch (cause) {\n\t\t\tif (isMissingFileError(cause)) throw new Error(`Image attachment was not found: ${path}`);\n\t\t\tthrow cause;\n\t\t}\n\t}\n\n\tconst prompt = `${result}${text.slice(cursor)}`.replace(/[ \\t]{2,}/g, \" \").trim();\n\treturn { text: [...labels, prompt].filter((value) => value.length > 0).join(\"\\n\"), images };\n}\n"]}
@@ -0,0 +1,3 @@
1
+ export { DefaultResourceLoader, loadResources } from "./loader.ts";
2
+ export type { ContextFile, ResourceDiagnostic, ResourceDiagnosticStage, ResourceLoader, ResourceLoaderOptions, ResourceScope, ResourceSnapshot, SkillResource, } from "./types.ts";
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/core/resources/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACnE,YAAY,EACX,WAAW,EACX,kBAAkB,EAClB,uBAAuB,EACvB,cAAc,EACd,qBAAqB,EACrB,aAAa,EACb,gBAAgB,EAChB,aAAa,GACb,MAAM,YAAY,CAAC"}
@@ -0,0 +1,2 @@
1
+ export { DefaultResourceLoader, loadResources } from "./loader.js";
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/core/resources/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC","sourcesContent":["export { DefaultResourceLoader, loadResources } from \"./loader.ts\";\nexport type {\n\tContextFile,\n\tResourceDiagnostic,\n\tResourceDiagnosticStage,\n\tResourceLoader,\n\tResourceLoaderOptions,\n\tResourceScope,\n\tResourceSnapshot,\n\tSkillResource,\n} from \"./types.ts\";\n"]}
@@ -0,0 +1,8 @@
1
+ import type { ResourceLoader, ResourceLoaderOptions, ResourceSnapshot } from "./types.ts";
2
+ export declare class DefaultResourceLoader implements ResourceLoader {
3
+ private readonly options;
4
+ constructor(options: ResourceLoaderOptions);
5
+ load(): Promise<ResourceSnapshot>;
6
+ }
7
+ export declare function loadResources(options: ResourceLoaderOptions): Promise<ResourceSnapshot>;
8
+ //# sourceMappingURL=loader.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../../src/core/resources/loader.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAGX,cAAc,EACd,qBAAqB,EAErB,gBAAgB,EAEhB,MAAM,YAAY,CAAC;AAyFpB,qBAAa,qBAAsB,YAAW,cAAc;IAC3D,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAwB;gBAEpC,OAAO,EAAE,qBAAqB;IAIpC,IAAI,IAAI,OAAO,CAAC,gBAAgB,CAAC;CAmEvC;AAED,wBAAsB,aAAa,CAAC,OAAO,EAAE,qBAAqB,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAE7F"}