indusagi-coding-agent 0.1.0

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 (240) hide show
  1. package/CHANGELOG.md +2249 -0
  2. package/README.md +546 -0
  3. package/dist/cli/args.js +282 -0
  4. package/dist/cli/config-selector.js +30 -0
  5. package/dist/cli/file-processor.js +78 -0
  6. package/dist/cli/list-models.js +91 -0
  7. package/dist/cli/session-picker.js +31 -0
  8. package/dist/cli.js +10 -0
  9. package/dist/config.js +158 -0
  10. package/dist/core/agent-session.js +2097 -0
  11. package/dist/core/auth-storage.js +278 -0
  12. package/dist/core/bash-executor.js +211 -0
  13. package/dist/core/compaction/branch-summarization.js +241 -0
  14. package/dist/core/compaction/compaction.js +606 -0
  15. package/dist/core/compaction/index.js +6 -0
  16. package/dist/core/compaction/utils.js +137 -0
  17. package/dist/core/diagnostics.js +1 -0
  18. package/dist/core/event-bus.js +24 -0
  19. package/dist/core/exec.js +70 -0
  20. package/dist/core/export-html/ansi-to-html.js +248 -0
  21. package/dist/core/export-html/index.js +221 -0
  22. package/dist/core/export-html/template.css +905 -0
  23. package/dist/core/export-html/template.html +54 -0
  24. package/dist/core/export-html/template.js +1549 -0
  25. package/dist/core/export-html/tool-renderer.js +56 -0
  26. package/dist/core/export-html/vendor/highlight.min.js +1213 -0
  27. package/dist/core/export-html/vendor/marked.min.js +6 -0
  28. package/dist/core/extensions/index.js +8 -0
  29. package/dist/core/extensions/loader.js +395 -0
  30. package/dist/core/extensions/runner.js +499 -0
  31. package/dist/core/extensions/types.js +31 -0
  32. package/dist/core/extensions/wrapper.js +101 -0
  33. package/dist/core/footer-data-provider.js +133 -0
  34. package/dist/core/index.js +8 -0
  35. package/dist/core/keybindings.js +140 -0
  36. package/dist/core/messages.js +122 -0
  37. package/dist/core/model-registry.js +454 -0
  38. package/dist/core/model-resolver.js +309 -0
  39. package/dist/core/package-manager.js +1142 -0
  40. package/dist/core/prompt-templates.js +250 -0
  41. package/dist/core/resource-loader.js +569 -0
  42. package/dist/core/sdk.js +225 -0
  43. package/dist/core/session-manager.js +1078 -0
  44. package/dist/core/settings-manager.js +430 -0
  45. package/dist/core/skills.js +339 -0
  46. package/dist/core/system-prompt.js +136 -0
  47. package/dist/core/timings.js +24 -0
  48. package/dist/core/tools/bash.js +226 -0
  49. package/dist/core/tools/edit-diff.js +242 -0
  50. package/dist/core/tools/edit.js +145 -0
  51. package/dist/core/tools/find.js +205 -0
  52. package/dist/core/tools/grep.js +238 -0
  53. package/dist/core/tools/index.js +60 -0
  54. package/dist/core/tools/ls.js +117 -0
  55. package/dist/core/tools/path-utils.js +52 -0
  56. package/dist/core/tools/read.js +165 -0
  57. package/dist/core/tools/truncate.js +204 -0
  58. package/dist/core/tools/write.js +77 -0
  59. package/dist/index.js +41 -0
  60. package/dist/main.js +565 -0
  61. package/dist/migrations.js +260 -0
  62. package/dist/modes/index.js +7 -0
  63. package/dist/modes/interactive/components/armin.js +328 -0
  64. package/dist/modes/interactive/components/assistant-message.js +86 -0
  65. package/dist/modes/interactive/components/bash-execution.js +155 -0
  66. package/dist/modes/interactive/components/bordered-loader.js +47 -0
  67. package/dist/modes/interactive/components/branch-summary-message.js +41 -0
  68. package/dist/modes/interactive/components/compaction-summary-message.js +42 -0
  69. package/dist/modes/interactive/components/config-selector.js +458 -0
  70. package/dist/modes/interactive/components/countdown-timer.js +27 -0
  71. package/dist/modes/interactive/components/custom-editor.js +61 -0
  72. package/dist/modes/interactive/components/custom-message.js +80 -0
  73. package/dist/modes/interactive/components/diff.js +132 -0
  74. package/dist/modes/interactive/components/dynamic-border.js +19 -0
  75. package/dist/modes/interactive/components/extension-editor.js +96 -0
  76. package/dist/modes/interactive/components/extension-input.js +54 -0
  77. package/dist/modes/interactive/components/extension-selector.js +70 -0
  78. package/dist/modes/interactive/components/footer.js +213 -0
  79. package/dist/modes/interactive/components/index.js +31 -0
  80. package/dist/modes/interactive/components/keybinding-hints.js +60 -0
  81. package/dist/modes/interactive/components/login-dialog.js +138 -0
  82. package/dist/modes/interactive/components/model-selector.js +253 -0
  83. package/dist/modes/interactive/components/oauth-selector.js +91 -0
  84. package/dist/modes/interactive/components/scoped-models-selector.js +262 -0
  85. package/dist/modes/interactive/components/session-selector-search.js +145 -0
  86. package/dist/modes/interactive/components/session-selector.js +698 -0
  87. package/dist/modes/interactive/components/settings-selector.js +250 -0
  88. package/dist/modes/interactive/components/show-images-selector.js +33 -0
  89. package/dist/modes/interactive/components/skill-invocation-message.js +44 -0
  90. package/dist/modes/interactive/components/theme-selector.js +43 -0
  91. package/dist/modes/interactive/components/thinking-selector.js +45 -0
  92. package/dist/modes/interactive/components/tool-execution.js +608 -0
  93. package/dist/modes/interactive/components/tree-selector.js +892 -0
  94. package/dist/modes/interactive/components/user-message-selector.js +109 -0
  95. package/dist/modes/interactive/components/user-message.js +15 -0
  96. package/dist/modes/interactive/components/visual-truncate.js +32 -0
  97. package/dist/modes/interactive/interactive-mode.js +3576 -0
  98. package/dist/modes/interactive/theme/dark.json +85 -0
  99. package/dist/modes/interactive/theme/light.json +84 -0
  100. package/dist/modes/interactive/theme/theme-schema.json +335 -0
  101. package/dist/modes/interactive/theme/theme.js +938 -0
  102. package/dist/modes/print-mode.js +96 -0
  103. package/dist/modes/rpc/rpc-client.js +390 -0
  104. package/dist/modes/rpc/rpc-mode.js +448 -0
  105. package/dist/modes/rpc/rpc-types.js +7 -0
  106. package/dist/utils/changelog.js +86 -0
  107. package/dist/utils/clipboard-image.js +116 -0
  108. package/dist/utils/clipboard.js +58 -0
  109. package/dist/utils/frontmatter.js +25 -0
  110. package/dist/utils/git.js +5 -0
  111. package/dist/utils/image-convert.js +34 -0
  112. package/dist/utils/image-resize.js +180 -0
  113. package/dist/utils/mime.js +25 -0
  114. package/dist/utils/photon.js +120 -0
  115. package/dist/utils/shell.js +164 -0
  116. package/dist/utils/sleep.js +16 -0
  117. package/dist/utils/tools-manager.js +186 -0
  118. package/docs/compaction.md +390 -0
  119. package/docs/custom-provider.md +538 -0
  120. package/docs/development.md +69 -0
  121. package/docs/extensions.md +1733 -0
  122. package/docs/images/doom-extension.png +0 -0
  123. package/docs/images/interactive-mode.png +0 -0
  124. package/docs/images/tree-view.png +0 -0
  125. package/docs/json.md +79 -0
  126. package/docs/keybindings.md +162 -0
  127. package/docs/models.md +193 -0
  128. package/docs/packages.md +163 -0
  129. package/docs/prompt-templates.md +67 -0
  130. package/docs/providers.md +147 -0
  131. package/docs/rpc.md +1048 -0
  132. package/docs/sdk.md +957 -0
  133. package/docs/session.md +412 -0
  134. package/docs/settings.md +216 -0
  135. package/docs/shell-aliases.md +13 -0
  136. package/docs/skills.md +226 -0
  137. package/docs/terminal-setup.md +65 -0
  138. package/docs/themes.md +295 -0
  139. package/docs/tree.md +219 -0
  140. package/docs/tui.md +887 -0
  141. package/docs/windows.md +17 -0
  142. package/examples/README.md +25 -0
  143. package/examples/extensions/README.md +192 -0
  144. package/examples/extensions/antigravity-image-gen.ts +414 -0
  145. package/examples/extensions/auto-commit-on-exit.ts +49 -0
  146. package/examples/extensions/bookmark.ts +50 -0
  147. package/examples/extensions/claude-rules.ts +86 -0
  148. package/examples/extensions/confirm-destructive.ts +59 -0
  149. package/examples/extensions/custom-compaction.ts +115 -0
  150. package/examples/extensions/custom-footer.ts +65 -0
  151. package/examples/extensions/custom-header.ts +73 -0
  152. package/examples/extensions/custom-provider-anthropic/index.ts +605 -0
  153. package/examples/extensions/custom-provider-anthropic/package-lock.json +24 -0
  154. package/examples/extensions/custom-provider-anthropic/package.json +19 -0
  155. package/examples/extensions/custom-provider-gitlab-duo/index.ts +350 -0
  156. package/examples/extensions/custom-provider-gitlab-duo/package.json +16 -0
  157. package/examples/extensions/custom-provider-gitlab-duo/test.ts +83 -0
  158. package/examples/extensions/dirty-repo-guard.ts +56 -0
  159. package/examples/extensions/doom-overlay/README.md +46 -0
  160. package/examples/extensions/doom-overlay/doom/build/doom.js +21 -0
  161. package/examples/extensions/doom-overlay/doom/build/doom.wasm +0 -0
  162. package/examples/extensions/doom-overlay/doom/build.sh +152 -0
  163. package/examples/extensions/doom-overlay/doom/doomgeneric_pi.c +72 -0
  164. package/examples/extensions/doom-overlay/doom-component.ts +133 -0
  165. package/examples/extensions/doom-overlay/doom-engine.ts +173 -0
  166. package/examples/extensions/doom-overlay/doom-keys.ts +105 -0
  167. package/examples/extensions/doom-overlay/index.ts +74 -0
  168. package/examples/extensions/doom-overlay/wad-finder.ts +51 -0
  169. package/examples/extensions/event-bus.ts +43 -0
  170. package/examples/extensions/file-trigger.ts +41 -0
  171. package/examples/extensions/git-checkpoint.ts +53 -0
  172. package/examples/extensions/handoff.ts +151 -0
  173. package/examples/extensions/hello.ts +25 -0
  174. package/examples/extensions/inline-bash.ts +94 -0
  175. package/examples/extensions/input-transform.ts +43 -0
  176. package/examples/extensions/interactive-shell.ts +196 -0
  177. package/examples/extensions/mac-system-theme.ts +47 -0
  178. package/examples/extensions/message-renderer.ts +60 -0
  179. package/examples/extensions/modal-editor.ts +86 -0
  180. package/examples/extensions/model-status.ts +31 -0
  181. package/examples/extensions/notify.ts +25 -0
  182. package/examples/extensions/overlay-qa-tests.ts +882 -0
  183. package/examples/extensions/overlay-test.ts +151 -0
  184. package/examples/extensions/permission-gate.ts +34 -0
  185. package/examples/extensions/pirate.ts +47 -0
  186. package/examples/extensions/plan-mode/README.md +65 -0
  187. package/examples/extensions/plan-mode/index.ts +341 -0
  188. package/examples/extensions/plan-mode/utils.ts +168 -0
  189. package/examples/extensions/preset.ts +399 -0
  190. package/examples/extensions/protected-paths.ts +30 -0
  191. package/examples/extensions/qna.ts +120 -0
  192. package/examples/extensions/question.ts +265 -0
  193. package/examples/extensions/questionnaire.ts +428 -0
  194. package/examples/extensions/rainbow-editor.ts +88 -0
  195. package/examples/extensions/sandbox/index.ts +318 -0
  196. package/examples/extensions/sandbox/package-lock.json +92 -0
  197. package/examples/extensions/sandbox/package.json +19 -0
  198. package/examples/extensions/send-user-message.ts +97 -0
  199. package/examples/extensions/session-name.ts +27 -0
  200. package/examples/extensions/shutdown-command.ts +63 -0
  201. package/examples/extensions/snake.ts +344 -0
  202. package/examples/extensions/space-invaders.ts +561 -0
  203. package/examples/extensions/ssh.ts +220 -0
  204. package/examples/extensions/status-line.ts +40 -0
  205. package/examples/extensions/subagent/README.md +172 -0
  206. package/examples/extensions/subagent/agents/planner.md +37 -0
  207. package/examples/extensions/subagent/agents/reviewer.md +35 -0
  208. package/examples/extensions/subagent/agents/scout.md +50 -0
  209. package/examples/extensions/subagent/agents/worker.md +24 -0
  210. package/examples/extensions/subagent/agents.ts +127 -0
  211. package/examples/extensions/subagent/index.ts +964 -0
  212. package/examples/extensions/subagent/prompts/implement-and-review.md +10 -0
  213. package/examples/extensions/subagent/prompts/implement.md +10 -0
  214. package/examples/extensions/subagent/prompts/scout-and-plan.md +9 -0
  215. package/examples/extensions/summarize.ts +196 -0
  216. package/examples/extensions/timed-confirm.ts +70 -0
  217. package/examples/extensions/todo.ts +300 -0
  218. package/examples/extensions/tool-override.ts +144 -0
  219. package/examples/extensions/tools.ts +147 -0
  220. package/examples/extensions/trigger-compact.ts +40 -0
  221. package/examples/extensions/truncated-tool.ts +193 -0
  222. package/examples/extensions/widget-placement.ts +17 -0
  223. package/examples/extensions/with-deps/index.ts +36 -0
  224. package/examples/extensions/with-deps/package-lock.json +31 -0
  225. package/examples/extensions/with-deps/package.json +22 -0
  226. package/examples/sdk/01-minimal.ts +22 -0
  227. package/examples/sdk/02-custom-model.ts +50 -0
  228. package/examples/sdk/03-custom-prompt.ts +55 -0
  229. package/examples/sdk/04-skills.ts +46 -0
  230. package/examples/sdk/05-tools.ts +56 -0
  231. package/examples/sdk/06-extensions.ts +88 -0
  232. package/examples/sdk/07-context-files.ts +40 -0
  233. package/examples/sdk/08-prompt-templates.ts +47 -0
  234. package/examples/sdk/09-api-keys-and-oauth.ts +48 -0
  235. package/examples/sdk/10-settings.ts +38 -0
  236. package/examples/sdk/11-sessions.ts +48 -0
  237. package/examples/sdk/12-full-control.ts +82 -0
  238. package/examples/sdk/13-codex-oauth.ts +37 -0
  239. package/examples/sdk/README.md +144 -0
  240. package/package.json +85 -0
@@ -0,0 +1,250 @@
1
+ import { existsSync, readdirSync, readFileSync, statSync } from "fs";
2
+ import { homedir } from "os";
3
+ import { basename, isAbsolute, join, resolve, sep } from "path";
4
+ import { CONFIG_DIR_NAME, getPromptsDir } from "../config.js";
5
+ import { parseFrontmatter } from "../utils/frontmatter.js";
6
+ /**
7
+ * Parse command arguments respecting quoted strings (bash-style)
8
+ * Returns array of arguments
9
+ */
10
+ export function parseCommandArgs(argsString) {
11
+ const args = [];
12
+ let current = "";
13
+ let inQuote = null;
14
+ for (let i = 0; i < argsString.length; i++) {
15
+ const char = argsString[i];
16
+ if (inQuote) {
17
+ if (char === inQuote) {
18
+ inQuote = null;
19
+ }
20
+ else {
21
+ current += char;
22
+ }
23
+ }
24
+ else if (char === '"' || char === "'") {
25
+ inQuote = char;
26
+ }
27
+ else if (char === " " || char === "\t") {
28
+ if (current) {
29
+ args.push(current);
30
+ current = "";
31
+ }
32
+ }
33
+ else {
34
+ current += char;
35
+ }
36
+ }
37
+ if (current) {
38
+ args.push(current);
39
+ }
40
+ return args;
41
+ }
42
+ /**
43
+ * Substitute argument placeholders in template content
44
+ * Supports:
45
+ * - $1, $2, ... for positional args
46
+ * - $@ and $ARGUMENTS for all args
47
+ * - ${@:N} for args from Nth onwards (bash-style slicing)
48
+ * - ${@:N:L} for L args starting from Nth
49
+ *
50
+ * Note: Replacement happens on the template string only. Argument values
51
+ * containing patterns like $1, $@, or $ARGUMENTS are NOT recursively substituted.
52
+ */
53
+ export function substituteArgs(content, args) {
54
+ let result = content;
55
+ // Replace $1, $2, etc. with positional args FIRST (before wildcards)
56
+ // This prevents wildcard replacement values containing $<digit> patterns from being re-substituted
57
+ result = result.replace(/\$(\d+)/g, (_, num) => {
58
+ const index = parseInt(num, 10) - 1;
59
+ return args[index] ?? "";
60
+ });
61
+ // Replace ${@:start} or ${@:start:length} with sliced args (bash-style)
62
+ // Process BEFORE simple $@ to avoid conflicts
63
+ result = result.replace(/\$\{@:(\d+)(?::(\d+))?\}/g, (_, startStr, lengthStr) => {
64
+ let start = parseInt(startStr, 10) - 1; // Convert to 0-indexed (user provides 1-indexed)
65
+ // Treat 0 as 1 (bash convention: args start at 1)
66
+ if (start < 0)
67
+ start = 0;
68
+ if (lengthStr) {
69
+ const length = parseInt(lengthStr, 10);
70
+ return args.slice(start, start + length).join(" ");
71
+ }
72
+ return args.slice(start).join(" ");
73
+ });
74
+ // Pre-compute all args joined (optimization)
75
+ const allArgs = args.join(" ");
76
+ // Replace $ARGUMENTS with all args joined (new syntax, aligns with Claude, Codex, OpenCode)
77
+ result = result.replace(/\$ARGUMENTS/g, allArgs);
78
+ // Replace $@ with all args joined (existing syntax)
79
+ result = result.replace(/\$@/g, allArgs);
80
+ return result;
81
+ }
82
+ function loadTemplateFromFile(filePath, source, sourceLabel) {
83
+ try {
84
+ const rawContent = readFileSync(filePath, "utf-8");
85
+ const { frontmatter, body } = parseFrontmatter(rawContent);
86
+ const name = basename(filePath).replace(/\.md$/, "");
87
+ // Get description from frontmatter or first non-empty line
88
+ let description = frontmatter.description || "";
89
+ if (!description) {
90
+ const firstLine = body.split("\n").find((line) => line.trim());
91
+ if (firstLine) {
92
+ // Truncate if too long
93
+ description = firstLine.slice(0, 60);
94
+ if (firstLine.length > 60)
95
+ description += "...";
96
+ }
97
+ }
98
+ // Append source to description
99
+ description = description ? `${description} ${sourceLabel}` : sourceLabel;
100
+ return {
101
+ name,
102
+ description,
103
+ content: body,
104
+ source,
105
+ filePath,
106
+ };
107
+ }
108
+ catch {
109
+ return null;
110
+ }
111
+ }
112
+ /**
113
+ * Scan a directory for .md files (non-recursive) and load them as prompt templates.
114
+ */
115
+ function loadTemplatesFromDir(dir, source, sourceLabel) {
116
+ const templates = [];
117
+ if (!existsSync(dir)) {
118
+ return templates;
119
+ }
120
+ try {
121
+ const entries = readdirSync(dir, { withFileTypes: true });
122
+ for (const entry of entries) {
123
+ const fullPath = join(dir, entry.name);
124
+ // For symlinks, check if they point to a file
125
+ let isFile = entry.isFile();
126
+ if (entry.isSymbolicLink()) {
127
+ try {
128
+ const stats = statSync(fullPath);
129
+ isFile = stats.isFile();
130
+ }
131
+ catch {
132
+ // Broken symlink, skip it
133
+ continue;
134
+ }
135
+ }
136
+ if (isFile && entry.name.endsWith(".md")) {
137
+ const template = loadTemplateFromFile(fullPath, source, sourceLabel);
138
+ if (template) {
139
+ templates.push(template);
140
+ }
141
+ }
142
+ }
143
+ }
144
+ catch {
145
+ return templates;
146
+ }
147
+ return templates;
148
+ }
149
+ function normalizePath(input) {
150
+ const trimmed = input.trim();
151
+ if (trimmed === "~")
152
+ return homedir();
153
+ if (trimmed.startsWith("~/"))
154
+ return join(homedir(), trimmed.slice(2));
155
+ if (trimmed.startsWith("~"))
156
+ return join(homedir(), trimmed.slice(1));
157
+ return trimmed;
158
+ }
159
+ function resolvePromptPath(p, cwd) {
160
+ const normalized = normalizePath(p);
161
+ return isAbsolute(normalized) ? normalized : resolve(cwd, normalized);
162
+ }
163
+ function buildPathSourceLabel(p) {
164
+ const base = basename(p).replace(/\.md$/, "") || "path";
165
+ return `(path:${base})`;
166
+ }
167
+ /**
168
+ * Load all prompt templates from:
169
+ * 1. Global: agentDir/prompts/
170
+ * 2. Project: cwd/{CONFIG_DIR_NAME}/prompts/
171
+ * 3. Explicit prompt paths
172
+ */
173
+ export function loadPromptTemplates(options = {}) {
174
+ const resolvedCwd = options.cwd ?? process.cwd();
175
+ const resolvedAgentDir = options.agentDir ?? getPromptsDir();
176
+ const promptPaths = options.promptPaths ?? [];
177
+ const includeDefaults = options.includeDefaults ?? true;
178
+ const templates = [];
179
+ if (includeDefaults) {
180
+ // 1. Load global templates from agentDir/prompts/
181
+ // Note: if agentDir is provided, it should be the agent dir, not the prompts dir
182
+ const globalPromptsDir = options.agentDir ? join(options.agentDir, "prompts") : resolvedAgentDir;
183
+ templates.push(...loadTemplatesFromDir(globalPromptsDir, "user", "(user)"));
184
+ // 2. Load project templates from cwd/{CONFIG_DIR_NAME}/prompts/
185
+ const projectPromptsDir = resolve(resolvedCwd, CONFIG_DIR_NAME, "prompts");
186
+ templates.push(...loadTemplatesFromDir(projectPromptsDir, "project", "(project)"));
187
+ }
188
+ const userPromptsDir = options.agentDir ? join(options.agentDir, "prompts") : resolvedAgentDir;
189
+ const projectPromptsDir = resolve(resolvedCwd, CONFIG_DIR_NAME, "prompts");
190
+ const isUnderPath = (target, root) => {
191
+ const normalizedRoot = resolve(root);
192
+ if (target === normalizedRoot) {
193
+ return true;
194
+ }
195
+ const prefix = normalizedRoot.endsWith(sep) ? normalizedRoot : `${normalizedRoot}${sep}`;
196
+ return target.startsWith(prefix);
197
+ };
198
+ const getSourceInfo = (resolvedPath) => {
199
+ if (!includeDefaults) {
200
+ if (isUnderPath(resolvedPath, userPromptsDir)) {
201
+ return { source: "user", label: "(user)" };
202
+ }
203
+ if (isUnderPath(resolvedPath, projectPromptsDir)) {
204
+ return { source: "project", label: "(project)" };
205
+ }
206
+ }
207
+ return { source: "path", label: buildPathSourceLabel(resolvedPath) };
208
+ };
209
+ // 3. Load explicit prompt paths
210
+ for (const rawPath of promptPaths) {
211
+ const resolvedPath = resolvePromptPath(rawPath, resolvedCwd);
212
+ if (!existsSync(resolvedPath)) {
213
+ continue;
214
+ }
215
+ try {
216
+ const stats = statSync(resolvedPath);
217
+ const { source, label } = getSourceInfo(resolvedPath);
218
+ if (stats.isDirectory()) {
219
+ templates.push(...loadTemplatesFromDir(resolvedPath, source, label));
220
+ }
221
+ else if (stats.isFile() && resolvedPath.endsWith(".md")) {
222
+ const template = loadTemplateFromFile(resolvedPath, source, label);
223
+ if (template) {
224
+ templates.push(template);
225
+ }
226
+ }
227
+ }
228
+ catch {
229
+ // Ignore read failures
230
+ }
231
+ }
232
+ return templates;
233
+ }
234
+ /**
235
+ * Expand a prompt template if it matches a template name.
236
+ * Returns the expanded content or the original text if not a template.
237
+ */
238
+ export function expandPromptTemplate(text, templates) {
239
+ if (!text.startsWith("/"))
240
+ return text;
241
+ const spaceIndex = text.indexOf(" ");
242
+ const templateName = spaceIndex === -1 ? text.slice(1) : text.slice(1, spaceIndex);
243
+ const argsString = spaceIndex === -1 ? "" : text.slice(spaceIndex + 1);
244
+ const template = templates.find((t) => t.name === templateName);
245
+ if (template) {
246
+ const args = parseCommandArgs(argsString);
247
+ return substituteArgs(template.content, args);
248
+ }
249
+ return text;
250
+ }