@m4ike1/ion-cue 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 (66) hide show
  1. package/README.md +92 -0
  2. package/dist/dispatcher.d.ts +31 -0
  3. package/dist/dispatcher.d.ts.map +1 -0
  4. package/dist/dispatcher.js +230 -0
  5. package/dist/dispatcher.js.map +1 -0
  6. package/dist/harness-bridge.d.ts +13 -0
  7. package/dist/harness-bridge.d.ts.map +1 -0
  8. package/dist/harness-bridge.js +29 -0
  9. package/dist/harness-bridge.js.map +1 -0
  10. package/dist/harness-router.d.ts +12 -0
  11. package/dist/harness-router.d.ts.map +1 -0
  12. package/dist/harness-router.js +189 -0
  13. package/dist/harness-router.js.map +1 -0
  14. package/dist/index.d.ts +16 -0
  15. package/dist/index.d.ts.map +1 -0
  16. package/dist/index.js +12 -0
  17. package/dist/index.js.map +1 -0
  18. package/dist/injector.d.ts +23 -0
  19. package/dist/injector.d.ts.map +1 -0
  20. package/dist/injector.js +62 -0
  21. package/dist/injector.js.map +1 -0
  22. package/dist/marks.d.ts +26 -0
  23. package/dist/marks.d.ts.map +1 -0
  24. package/dist/marks.js +59 -0
  25. package/dist/marks.js.map +1 -0
  26. package/dist/messages.d.ts +23 -0
  27. package/dist/messages.d.ts.map +1 -0
  28. package/dist/messages.js +2 -0
  29. package/dist/messages.js.map +1 -0
  30. package/dist/registry.d.ts +94 -0
  31. package/dist/registry.d.ts.map +1 -0
  32. package/dist/registry.js +582 -0
  33. package/dist/registry.js.map +1 -0
  34. package/dist/resolver.d.ts +15 -0
  35. package/dist/resolver.d.ts.map +1 -0
  36. package/dist/resolver.js +50 -0
  37. package/dist/resolver.js.map +1 -0
  38. package/dist/scanner.d.ts +32 -0
  39. package/dist/scanner.d.ts.map +1 -0
  40. package/dist/scanner.js +252 -0
  41. package/dist/scanner.js.map +1 -0
  42. package/dist/scope.d.ts +25 -0
  43. package/dist/scope.d.ts.map +1 -0
  44. package/dist/scope.js +180 -0
  45. package/dist/scope.js.map +1 -0
  46. package/dist/secret-store.d.ts +16 -0
  47. package/dist/secret-store.d.ts.map +1 -0
  48. package/dist/secret-store.js +89 -0
  49. package/dist/secret-store.js.map +1 -0
  50. package/dist/stream-events.d.ts +26 -0
  51. package/dist/stream-events.d.ts.map +1 -0
  52. package/dist/stream-events.js +2 -0
  53. package/dist/stream-events.js.map +1 -0
  54. package/dist/toml.d.ts +3 -0
  55. package/dist/toml.d.ts.map +1 -0
  56. package/dist/toml.js +117 -0
  57. package/dist/toml.js.map +1 -0
  58. package/dist/types.d.ts +182 -0
  59. package/dist/types.d.ts.map +1 -0
  60. package/dist/types.js +2 -0
  61. package/dist/types.js.map +1 -0
  62. package/dist/validation.d.ts +5 -0
  63. package/dist/validation.d.ts.map +1 -0
  64. package/dist/validation.js +61 -0
  65. package/dist/validation.js.map +1 -0
  66. package/package.json +23 -0
package/dist/scope.js ADDED
@@ -0,0 +1,180 @@
1
+ import { existsSync, readdirSync, readFileSync, statSync } from "fs";
2
+ import { isAbsolute, join, relative } from "path";
3
+ const MAX_FILE_CHARS = 200_000;
4
+ /**
5
+ * Resolve a scope statement to its backing content.
6
+ *
7
+ * - `file` → reads the single file at the given path (relative to root)
8
+ * - `glob` → reads every file matching the glob
9
+ *
10
+ * Paths are resolved relative to `projectRoot` when provided, otherwise the
11
+ * current working directory. Absolute paths are used as-is. A `file` scope
12
+ * that points at a directory on disk is treated as a glob over its contents.
13
+ * An `id` scope has no direct backing content — marks resolve it.
14
+ */
15
+ export function resolveScope(scope, projectRoot) {
16
+ if (scope.type === "id")
17
+ return null;
18
+ if (scope.type === "file") {
19
+ const path = resolvePath(scope.value, projectRoot);
20
+ if (!path || !existsSync(path))
21
+ return null;
22
+ let isDir = false;
23
+ try {
24
+ isDir = statSync(path).isDirectory();
25
+ }
26
+ catch {
27
+ return null;
28
+ }
29
+ if (isDir) {
30
+ return resolveScope({ type: "glob", value: `${scope.value}/**/*`, range: scope.range }, projectRoot);
31
+ }
32
+ let content;
33
+ try {
34
+ content = readFileSync(path, "utf-8");
35
+ }
36
+ catch {
37
+ return null;
38
+ }
39
+ // Apply line range if specified (1-indexed inclusive, e.g., 105-210 means lines 105 through 210)
40
+ if (scope.range) {
41
+ const lines = content.split("\n");
42
+ const start = scope.range.start !== undefined ? Math.max(0, scope.range.start - 1) : 0;
43
+ const end = scope.range.end !== undefined ? Math.min(lines.length, scope.range.end) : lines.length;
44
+ let sliced = lines.slice(start, end).join("\n");
45
+ if (content.endsWith("\n") && end === lines.length) {
46
+ sliced = sliced.replace(/\n$/, "");
47
+ }
48
+ content = sliced;
49
+ }
50
+ const display = projectRoot ? relative(projectRoot, path) : path;
51
+ const label = rangeLabel(display, scope.range);
52
+ return { label, content, paths: [display] };
53
+ }
54
+ const matched = walkGlob(scope.value, projectRoot ?? process.cwd());
55
+ if (matched.length === 0)
56
+ return null;
57
+ const parts = matched.map(({ display, content }) => {
58
+ const capped = content.length > MAX_FILE_CHARS ? `${content.slice(0, MAX_FILE_CHARS)}\n…(truncated)` : content;
59
+ return `--- ${display} ---\n${capped}`;
60
+ });
61
+ return {
62
+ label: scope.value,
63
+ content: parts.join("\n\n"),
64
+ paths: matched.map((m) => m.display),
65
+ };
66
+ }
67
+ function rangeLabel(display, range) {
68
+ if (!range)
69
+ return display;
70
+ if (range.start !== undefined && range.end !== undefined) {
71
+ return range.start === range.end ? `${display}:${range.start}` : `${display}:${range.start}-${range.end}`;
72
+ }
73
+ if (range.start !== undefined)
74
+ return `${display}:${range.start}-`;
75
+ return `${display}:-${range.end}`;
76
+ }
77
+ function resolvePath(value, projectRoot) {
78
+ if (isAbsolute(value))
79
+ return value;
80
+ if (projectRoot)
81
+ return join(projectRoot, value);
82
+ return value;
83
+ }
84
+ function walkGlob(pattern, base) {
85
+ const out = [];
86
+ const segments = pattern.split("/").filter(Boolean);
87
+ collect(base, segments, "", out);
88
+ return out;
89
+ }
90
+ function collect(dir, segments, prefix, out) {
91
+ if (segments.length === 0)
92
+ return;
93
+ const [seg, ...rest] = segments;
94
+ let entries = [];
95
+ try {
96
+ entries = readdirSync(dir);
97
+ }
98
+ catch {
99
+ return;
100
+ }
101
+ if (seg === "**") {
102
+ // Match zero-or-more path segments.
103
+ collect(dir, rest, prefix, out);
104
+ for (const e of entries) {
105
+ const full = join(dir, e);
106
+ let s;
107
+ try {
108
+ s = statSync(full);
109
+ }
110
+ catch {
111
+ continue;
112
+ }
113
+ if (s.isDirectory()) {
114
+ collect(full, segments, prefix ? `${prefix}/${e}` : e, out);
115
+ }
116
+ }
117
+ return;
118
+ }
119
+ const segRe = globToRegExp(seg);
120
+ for (const e of entries) {
121
+ const full = join(dir, e);
122
+ let s;
123
+ try {
124
+ s = statSync(full);
125
+ }
126
+ catch {
127
+ continue;
128
+ }
129
+ const isDir = s.isDirectory();
130
+ if (segRe.test(e)) {
131
+ if (rest.length === 0) {
132
+ if (!isDir) {
133
+ let content = "";
134
+ try {
135
+ content = readFileSync(full, "utf-8");
136
+ }
137
+ catch {
138
+ continue;
139
+ }
140
+ out.push({ display: prefix ? `${prefix}/${e}` : e, content });
141
+ }
142
+ }
143
+ else if (isDir) {
144
+ collect(full, rest, prefix ? `${prefix}/${e}` : e, out);
145
+ }
146
+ }
147
+ }
148
+ }
149
+ function globToRegExp(globStr) {
150
+ const escaped = globStr
151
+ .replace(/[.+^${}()|[\]\\]/g, "\\$&")
152
+ .replace(/\*\*\//g, "→DOUBLESTAR→")
153
+ .replace(/\*/g, "[^/]*")
154
+ .replace(/→DOUBLESTAR→/g, "(?:.*/)?");
155
+ return new RegExp(`^${escaped}$`);
156
+ }
157
+ // ─── Directory scopes ────────────────────────────────────────────────────────
158
+ /**
159
+ * Resolve a directory scope to its absolute path.
160
+ *
161
+ * Returns null when the value does not resolve to an existing directory.
162
+ */
163
+ export function resolveDirPath(value, projectRoot) {
164
+ let path = resolvePath(value, projectRoot);
165
+ if (!path || !existsSync(path))
166
+ return null;
167
+ let isDir = false;
168
+ try {
169
+ isDir = statSync(path).isDirectory();
170
+ }
171
+ catch {
172
+ return null;
173
+ }
174
+ if (!isDir)
175
+ return null;
176
+ if (path.length > 1)
177
+ path = path.replace(/\/+$/, "");
178
+ return path;
179
+ }
180
+ //# sourceMappingURL=scope.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scope.js","sourceRoot":"","sources":["../src/scope.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync, readdirSync, readFileSync, statSync } from \"fs\";\nimport { isAbsolute, join, relative } from \"path\";\nimport type { CueScope } from \"./types.ts\";\n\nexport interface ResolvedScope {\n\tlabel: string;\n\tcontent: string;\n\tpaths: string[];\n}\n\nconst MAX_FILE_CHARS = 200_000;\n\n/**\n * Resolve a scope statement to its backing content.\n *\n * - `file` → reads the single file at the given path (relative to root)\n * - `glob` → reads every file matching the glob\n *\n * Paths are resolved relative to `projectRoot` when provided, otherwise the\n * current working directory. Absolute paths are used as-is. A `file` scope\n * that points at a directory on disk is treated as a glob over its contents.\n * An `id` scope has no direct backing content — marks resolve it.\n */\nexport function resolveScope(scope: CueScope, projectRoot?: string): ResolvedScope | null {\n\tif (scope.type === \"id\") return null;\n\n\tif (scope.type === \"file\") {\n\t\tconst path = resolvePath(scope.value, projectRoot);\n\t\tif (!path || !existsSync(path)) return null;\n\n\t\tlet isDir = false;\n\t\ttry {\n\t\t\tisDir = statSync(path).isDirectory();\n\t\t} catch {\n\t\t\treturn null;\n\t\t}\n\t\tif (isDir) {\n\t\t\treturn resolveScope({ type: \"glob\", value: `${scope.value}/**/*`, range: scope.range }, projectRoot);\n\t\t}\n\n\t\tlet content: string;\n\t\ttry {\n\t\t\tcontent = readFileSync(path, \"utf-8\");\n\t\t} catch {\n\t\t\treturn null;\n\t\t}\n\t\t// Apply line range if specified (1-indexed inclusive, e.g., 105-210 means lines 105 through 210)\n\t\tif (scope.range) {\n\t\t\tconst lines = content.split(\"\\n\");\n\t\t\tconst start = scope.range.start !== undefined ? Math.max(0, scope.range.start - 1) : 0;\n\t\t\tconst end = scope.range.end !== undefined ? Math.min(lines.length, scope.range.end) : lines.length;\n\t\t\tlet sliced = lines.slice(start, end).join(\"\\n\");\n\t\t\tif (content.endsWith(\"\\n\") && end === lines.length) {\n\t\t\t\tsliced = sliced.replace(/\\n$/, \"\");\n\t\t\t}\n\t\t\tcontent = sliced;\n\t\t}\n\t\tconst display = projectRoot ? relative(projectRoot, path) : path;\n\t\tconst label = rangeLabel(display, scope.range);\n\t\treturn { label, content, paths: [display] };\n\t}\n\n\tconst matched = walkGlob(scope.value, projectRoot ?? process.cwd());\n\tif (matched.length === 0) return null;\n\tconst parts = matched.map(({ display, content }) => {\n\t\tconst capped = content.length > MAX_FILE_CHARS ? `${content.slice(0, MAX_FILE_CHARS)}\\n…(truncated)` : content;\n\t\treturn `--- ${display} ---\\n${capped}`;\n\t});\n\treturn {\n\t\tlabel: scope.value,\n\t\tcontent: parts.join(\"\\n\\n\"),\n\t\tpaths: matched.map((m) => m.display),\n\t};\n}\n\nfunction rangeLabel(display: string, range?: { start?: number; end?: number }): string {\n\tif (!range) return display;\n\tif (range.start !== undefined && range.end !== undefined) {\n\t\treturn range.start === range.end ? `${display}:${range.start}` : `${display}:${range.start}-${range.end}`;\n\t}\n\tif (range.start !== undefined) return `${display}:${range.start}-`;\n\treturn `${display}:-${range.end}`;\n}\n\nfunction resolvePath(value: string, projectRoot?: string): string | null {\n\tif (isAbsolute(value)) return value;\n\tif (projectRoot) return join(projectRoot, value);\n\treturn value;\n}\n\ninterface MatchedFile {\n\tdisplay: string;\n\tcontent: string;\n}\n\nfunction walkGlob(pattern: string, base: string): MatchedFile[] {\n\tconst out: MatchedFile[] = [];\n\tconst segments = pattern.split(\"/\").filter(Boolean);\n\tcollect(base, segments, \"\", out);\n\treturn out;\n}\n\nfunction collect(dir: string, segments: string[], prefix: string, out: MatchedFile[]): void {\n\tif (segments.length === 0) return;\n\tconst [seg, ...rest] = segments;\n\n\tlet entries: string[] = [];\n\ttry {\n\t\tentries = readdirSync(dir);\n\t} catch {\n\t\treturn;\n\t}\n\n\tif (seg === \"**\") {\n\t\t// Match zero-or-more path segments.\n\t\tcollect(dir, rest, prefix, out);\n\t\tfor (const e of entries) {\n\t\t\tconst full = join(dir, e);\n\t\t\tlet s: { isDirectory(): boolean };\n\t\t\ttry {\n\t\t\t\ts = statSync(full);\n\t\t\t} catch {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (s.isDirectory()) {\n\t\t\t\tcollect(full, segments, prefix ? `${prefix}/${e}` : e, out);\n\t\t\t}\n\t\t}\n\t\treturn;\n\t}\n\n\tconst segRe = globToRegExp(seg);\n\tfor (const e of entries) {\n\t\tconst full = join(dir, e);\n\t\tlet s: { isDirectory(): boolean };\n\t\ttry {\n\t\t\ts = statSync(full);\n\t\t} catch {\n\t\t\tcontinue;\n\t\t}\n\t\tconst isDir = s.isDirectory();\n\t\tif (segRe.test(e)) {\n\t\t\tif (rest.length === 0) {\n\t\t\t\tif (!isDir) {\n\t\t\t\t\tlet content = \"\";\n\t\t\t\t\ttry {\n\t\t\t\t\t\tcontent = readFileSync(full, \"utf-8\");\n\t\t\t\t\t} catch {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\tout.push({ display: prefix ? `${prefix}/${e}` : e, content });\n\t\t\t\t}\n\t\t\t} else if (isDir) {\n\t\t\t\tcollect(full, rest, prefix ? `${prefix}/${e}` : e, out);\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunction globToRegExp(globStr: string): RegExp {\n\tconst escaped = globStr\n\t\t.replace(/[.+^${}()|[\\]\\\\]/g, \"\\\\$&\")\n\t\t.replace(/\\*\\*\\//g, \"→DOUBLESTAR→\")\n\t\t.replace(/\\*/g, \"[^/]*\")\n\t\t.replace(/→DOUBLESTAR→/g, \"(?:.*/)?\");\n\treturn new RegExp(`^${escaped}$`);\n}\n\n// ─── Directory scopes ────────────────────────────────────────────────────────\n\n/**\n * Resolve a directory scope to its absolute path.\n *\n * Returns null when the value does not resolve to an existing directory.\n */\nexport function resolveDirPath(value: string, projectRoot?: string): string | null {\n\tlet path = resolvePath(value, projectRoot);\n\tif (!path || !existsSync(path)) return null;\n\tlet isDir = false;\n\ttry {\n\t\tisDir = statSync(path).isDirectory();\n\t} catch {\n\t\treturn null;\n\t}\n\tif (!isDir) return null;\n\tif (path.length > 1) path = path.replace(/\\/+$/, \"\");\n\treturn path;\n}\n"]}
@@ -0,0 +1,16 @@
1
+ export interface SecretStoreOptions {
2
+ projectRoot: string;
3
+ }
4
+ export declare class SecretStore {
5
+ private envPath;
6
+ private cache;
7
+ constructor(options: SecretStoreOptions);
8
+ load(): Map<string, string>;
9
+ get(key: string): string | undefined;
10
+ has(key: string): boolean;
11
+ set(key: string, value: string): void;
12
+ delete(key: string): void;
13
+ getSecretKey(elementName: string, inputName: string): string;
14
+ substituteVariables(text: string, elementName: string, inputs: string[]): string;
15
+ }
16
+ //# sourceMappingURL=secret-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"secret-store.d.ts","sourceRoot":"","sources":["../src/secret-store.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,kBAAkB;IAClC,WAAW,EAAE,MAAM,CAAC;CACpB;AAED,qBAAa,WAAW;IACvB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,KAAK,CAAoC;IAEjD,YAAY,OAAO,EAAE,kBAAkB,EAStC;IAED,IAAI,IAAI,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAwB1B;IAED,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAGnC;IAED,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAGxB;IAED,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAepC;IAED,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAgBxB;IAED,YAAY,CAAC,WAAW,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAK3D;IAED,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,CAa/E;CACD","sourcesContent":["import { existsSync, mkdirSync, readFileSync, writeFileSync } from \"fs\";\nimport { homedir } from \"os\";\nimport { join } from \"path\";\n\nexport interface SecretStoreOptions {\n\tprojectRoot: string;\n}\n\nexport class SecretStore {\n\tprivate envPath: string;\n\tprivate cache: Map<string, string> | null = null;\n\n\tconstructor(options: SecretStoreOptions) {\n\t\tconst slug =\n\t\t\toptions.projectRoot\n\t\t\t\t.split(\"/\")\n\t\t\t\t.pop()\n\t\t\t\t?.toLowerCase()\n\t\t\t\t.replace(/[^a-z0-9]+/g, \"-\") || \"default\";\n\n\t\tthis.envPath = join(homedir(), \".ion\", \"agent\", \"cue\", \"secrets\", slug, \".env\");\n\t}\n\n\tload(): Map<string, string> {\n\t\tif (this.cache) return this.cache;\n\n\t\tthis.cache = new Map();\n\n\t\tif (!existsSync(this.envPath)) {\n\t\t\treturn this.cache;\n\t\t}\n\n\t\tconst content = readFileSync(this.envPath, \"utf-8\");\n\t\tfor (const line of content.split(\"\\n\")) {\n\t\t\tconst trimmed = line.trim();\n\t\t\tif (!trimmed || trimmed.startsWith(\"#\")) continue;\n\n\t\t\tconst eqIdx = trimmed.indexOf(\"=\");\n\t\t\tif (eqIdx === -1) continue;\n\n\t\t\tconst key = trimmed.slice(0, eqIdx).trim();\n\t\t\tconst value = trimmed.slice(eqIdx + 1).trim();\n\n\t\t\tthis.cache.set(key, value);\n\t\t}\n\n\t\treturn this.cache;\n\t}\n\n\tget(key: string): string | undefined {\n\t\tconst secrets = this.load();\n\t\treturn secrets.get(key);\n\t}\n\n\thas(key: string): boolean {\n\t\tconst secrets = this.load();\n\t\treturn secrets.has(key);\n\t}\n\n\tset(key: string, value: string): void {\n\t\tconst dir = this.envPath.split(\"/\").slice(0, -1).join(\"/\");\n\t\tif (!existsSync(dir)) {\n\t\t\tmkdirSync(dir, { recursive: true });\n\t\t}\n\n\t\tconst secrets = this.load();\n\t\tsecrets.set(key, value);\n\n\t\tconst lines: string[] = [];\n\t\tfor (const [k, v] of secrets) {\n\t\t\tlines.push(`${k}=${v}`);\n\t\t}\n\n\t\twriteFileSync(this.envPath, `${lines.join(\"\\n\")}\\n`, \"utf-8\");\n\t}\n\n\tdelete(key: string): void {\n\t\tconst secrets = this.load();\n\t\tsecrets.delete(key);\n\n\t\tconst dir = this.envPath.split(\"/\").slice(0, -1).join(\"/\");\n\t\tif (!existsSync(dir)) {\n\t\t\tmkdirSync(dir, { recursive: true });\n\t\t}\n\n\t\tconst lines: string[] = [];\n\t\tfor (const [k, v] of secrets) {\n\t\t\tlines.push(`${k}=${v}`);\n\t\t}\n\n\t\twriteFileSync(this.envPath, `${lines.join(\"\\n\")}\\n`, \"utf-8\");\n\t\tthis.cache = null;\n\t}\n\n\tgetSecretKey(elementName: string, inputName: string): string {\n\t\tif (inputName === inputName.toUpperCase() && inputName.includes(\"_\")) {\n\t\t\treturn inputName;\n\t\t}\n\t\treturn `${elementName.toUpperCase()}_${inputName.toUpperCase()}`;\n\t}\n\n\tsubstituteVariables(text: string, elementName: string, inputs: string[]): string {\n\t\tlet result = text;\n\n\t\tfor (const input of inputs) {\n\t\t\tconst key = this.getSecretKey(elementName, input);\n\t\t\tconst value = this.get(key);\n\n\t\t\tif (value !== undefined) {\n\t\t\t\tresult = result.replace(new RegExp(`\\\\$${input}`, \"g\"), value);\n\t\t\t}\n\t\t}\n\n\t\treturn result;\n\t}\n}\n"]}
@@ -0,0 +1,89 @@
1
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
2
+ import { homedir } from "os";
3
+ import { join } from "path";
4
+ export class SecretStore {
5
+ envPath;
6
+ cache = null;
7
+ constructor(options) {
8
+ const slug = options.projectRoot
9
+ .split("/")
10
+ .pop()
11
+ ?.toLowerCase()
12
+ .replace(/[^a-z0-9]+/g, "-") || "default";
13
+ this.envPath = join(homedir(), ".ion", "agent", "cue", "secrets", slug, ".env");
14
+ }
15
+ load() {
16
+ if (this.cache)
17
+ return this.cache;
18
+ this.cache = new Map();
19
+ if (!existsSync(this.envPath)) {
20
+ return this.cache;
21
+ }
22
+ const content = readFileSync(this.envPath, "utf-8");
23
+ for (const line of content.split("\n")) {
24
+ const trimmed = line.trim();
25
+ if (!trimmed || trimmed.startsWith("#"))
26
+ continue;
27
+ const eqIdx = trimmed.indexOf("=");
28
+ if (eqIdx === -1)
29
+ continue;
30
+ const key = trimmed.slice(0, eqIdx).trim();
31
+ const value = trimmed.slice(eqIdx + 1).trim();
32
+ this.cache.set(key, value);
33
+ }
34
+ return this.cache;
35
+ }
36
+ get(key) {
37
+ const secrets = this.load();
38
+ return secrets.get(key);
39
+ }
40
+ has(key) {
41
+ const secrets = this.load();
42
+ return secrets.has(key);
43
+ }
44
+ set(key, value) {
45
+ const dir = this.envPath.split("/").slice(0, -1).join("/");
46
+ if (!existsSync(dir)) {
47
+ mkdirSync(dir, { recursive: true });
48
+ }
49
+ const secrets = this.load();
50
+ secrets.set(key, value);
51
+ const lines = [];
52
+ for (const [k, v] of secrets) {
53
+ lines.push(`${k}=${v}`);
54
+ }
55
+ writeFileSync(this.envPath, `${lines.join("\n")}\n`, "utf-8");
56
+ }
57
+ delete(key) {
58
+ const secrets = this.load();
59
+ secrets.delete(key);
60
+ const dir = this.envPath.split("/").slice(0, -1).join("/");
61
+ if (!existsSync(dir)) {
62
+ mkdirSync(dir, { recursive: true });
63
+ }
64
+ const lines = [];
65
+ for (const [k, v] of secrets) {
66
+ lines.push(`${k}=${v}`);
67
+ }
68
+ writeFileSync(this.envPath, `${lines.join("\n")}\n`, "utf-8");
69
+ this.cache = null;
70
+ }
71
+ getSecretKey(elementName, inputName) {
72
+ if (inputName === inputName.toUpperCase() && inputName.includes("_")) {
73
+ return inputName;
74
+ }
75
+ return `${elementName.toUpperCase()}_${inputName.toUpperCase()}`;
76
+ }
77
+ substituteVariables(text, elementName, inputs) {
78
+ let result = text;
79
+ for (const input of inputs) {
80
+ const key = this.getSecretKey(elementName, input);
81
+ const value = this.get(key);
82
+ if (value !== undefined) {
83
+ result = result.replace(new RegExp(`\\$${input}`, "g"), value);
84
+ }
85
+ }
86
+ return result;
87
+ }
88
+ }
89
+ //# sourceMappingURL=secret-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"secret-store.js","sourceRoot":"","sources":["../src/secret-store.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync, mkdirSync, readFileSync, writeFileSync } from \"fs\";\nimport { homedir } from \"os\";\nimport { join } from \"path\";\n\nexport interface SecretStoreOptions {\n\tprojectRoot: string;\n}\n\nexport class SecretStore {\n\tprivate envPath: string;\n\tprivate cache: Map<string, string> | null = null;\n\n\tconstructor(options: SecretStoreOptions) {\n\t\tconst slug =\n\t\t\toptions.projectRoot\n\t\t\t\t.split(\"/\")\n\t\t\t\t.pop()\n\t\t\t\t?.toLowerCase()\n\t\t\t\t.replace(/[^a-z0-9]+/g, \"-\") || \"default\";\n\n\t\tthis.envPath = join(homedir(), \".ion\", \"agent\", \"cue\", \"secrets\", slug, \".env\");\n\t}\n\n\tload(): Map<string, string> {\n\t\tif (this.cache) return this.cache;\n\n\t\tthis.cache = new Map();\n\n\t\tif (!existsSync(this.envPath)) {\n\t\t\treturn this.cache;\n\t\t}\n\n\t\tconst content = readFileSync(this.envPath, \"utf-8\");\n\t\tfor (const line of content.split(\"\\n\")) {\n\t\t\tconst trimmed = line.trim();\n\t\t\tif (!trimmed || trimmed.startsWith(\"#\")) continue;\n\n\t\t\tconst eqIdx = trimmed.indexOf(\"=\");\n\t\t\tif (eqIdx === -1) continue;\n\n\t\t\tconst key = trimmed.slice(0, eqIdx).trim();\n\t\t\tconst value = trimmed.slice(eqIdx + 1).trim();\n\n\t\t\tthis.cache.set(key, value);\n\t\t}\n\n\t\treturn this.cache;\n\t}\n\n\tget(key: string): string | undefined {\n\t\tconst secrets = this.load();\n\t\treturn secrets.get(key);\n\t}\n\n\thas(key: string): boolean {\n\t\tconst secrets = this.load();\n\t\treturn secrets.has(key);\n\t}\n\n\tset(key: string, value: string): void {\n\t\tconst dir = this.envPath.split(\"/\").slice(0, -1).join(\"/\");\n\t\tif (!existsSync(dir)) {\n\t\t\tmkdirSync(dir, { recursive: true });\n\t\t}\n\n\t\tconst secrets = this.load();\n\t\tsecrets.set(key, value);\n\n\t\tconst lines: string[] = [];\n\t\tfor (const [k, v] of secrets) {\n\t\t\tlines.push(`${k}=${v}`);\n\t\t}\n\n\t\twriteFileSync(this.envPath, `${lines.join(\"\\n\")}\\n`, \"utf-8\");\n\t}\n\n\tdelete(key: string): void {\n\t\tconst secrets = this.load();\n\t\tsecrets.delete(key);\n\n\t\tconst dir = this.envPath.split(\"/\").slice(0, -1).join(\"/\");\n\t\tif (!existsSync(dir)) {\n\t\t\tmkdirSync(dir, { recursive: true });\n\t\t}\n\n\t\tconst lines: string[] = [];\n\t\tfor (const [k, v] of secrets) {\n\t\t\tlines.push(`${k}=${v}`);\n\t\t}\n\n\t\twriteFileSync(this.envPath, `${lines.join(\"\\n\")}\\n`, \"utf-8\");\n\t\tthis.cache = null;\n\t}\n\n\tgetSecretKey(elementName: string, inputName: string): string {\n\t\tif (inputName === inputName.toUpperCase() && inputName.includes(\"_\")) {\n\t\t\treturn inputName;\n\t\t}\n\t\treturn `${elementName.toUpperCase()}_${inputName.toUpperCase()}`;\n\t}\n\n\tsubstituteVariables(text: string, elementName: string, inputs: string[]): string {\n\t\tlet result = text;\n\n\t\tfor (const input of inputs) {\n\t\t\tconst key = this.getSecretKey(elementName, input);\n\t\t\tconst value = this.get(key);\n\n\t\t\tif (value !== undefined) {\n\t\t\t\tresult = result.replace(new RegExp(`\\\\$${input}`, \"g\"), value);\n\t\t\t}\n\t\t}\n\n\t\treturn result;\n\t}\n}\n"]}
@@ -0,0 +1,26 @@
1
+ export interface CueTextDeltaEvent {
2
+ type: "text_delta";
3
+ text: string;
4
+ }
5
+ export interface CueToolUseDeltaEvent {
6
+ type: "tool_use_delta";
7
+ id: string;
8
+ name: string;
9
+ partialInput: string;
10
+ }
11
+ export interface CueToolUseEndEvent {
12
+ type: "tool_use_end";
13
+ id: string;
14
+ name: string;
15
+ input: Record<string, unknown>;
16
+ }
17
+ export interface CueDoneEvent {
18
+ type: "done";
19
+ stopReason: "end_turn" | "tool_use" | "max_tokens" | "aborted";
20
+ }
21
+ export interface CueErrorEvent {
22
+ type: "error";
23
+ error: string;
24
+ }
25
+ export type CueStreamEvent = CueTextDeltaEvent | CueToolUseDeltaEvent | CueToolUseEndEvent | CueDoneEvent | CueErrorEvent;
26
+ //# sourceMappingURL=stream-events.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stream-events.d.ts","sourceRoot":"","sources":["../src/stream-events.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,iBAAiB;IACjC,IAAI,EAAE,YAAY,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,oBAAoB;IACpC,IAAI,EAAE,gBAAgB,CAAC;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,kBAAkB;IAClC,IAAI,EAAE,cAAc,CAAC;IACrB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC/B;AAED,MAAM,WAAW,YAAY;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,UAAU,GAAG,UAAU,GAAG,YAAY,GAAG,SAAS,CAAC;CAC/D;AAED,MAAM,WAAW,aAAa;IAC7B,IAAI,EAAE,OAAO,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;CACd;AAED,MAAM,MAAM,cAAc,GACvB,iBAAiB,GACjB,oBAAoB,GACpB,kBAAkB,GAClB,YAAY,GACZ,aAAa,CAAC","sourcesContent":["export interface CueTextDeltaEvent {\n\ttype: \"text_delta\";\n\ttext: string;\n}\n\nexport interface CueToolUseDeltaEvent {\n\ttype: \"tool_use_delta\";\n\tid: string;\n\tname: string;\n\tpartialInput: string;\n}\n\nexport interface CueToolUseEndEvent {\n\ttype: \"tool_use_end\";\n\tid: string;\n\tname: string;\n\tinput: Record<string, unknown>;\n}\n\nexport interface CueDoneEvent {\n\ttype: \"done\";\n\tstopReason: \"end_turn\" | \"tool_use\" | \"max_tokens\" | \"aborted\";\n}\n\nexport interface CueErrorEvent {\n\ttype: \"error\";\n\terror: string;\n}\n\nexport type CueStreamEvent =\n\t| CueTextDeltaEvent\n\t| CueToolUseDeltaEvent\n\t| CueToolUseEndEvent\n\t| CueDoneEvent\n\t| CueErrorEvent;\n"]}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=stream-events.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stream-events.js","sourceRoot":"","sources":["../src/stream-events.ts"],"names":[],"mappings":"","sourcesContent":["export interface CueTextDeltaEvent {\n\ttype: \"text_delta\";\n\ttext: string;\n}\n\nexport interface CueToolUseDeltaEvent {\n\ttype: \"tool_use_delta\";\n\tid: string;\n\tname: string;\n\tpartialInput: string;\n}\n\nexport interface CueToolUseEndEvent {\n\ttype: \"tool_use_end\";\n\tid: string;\n\tname: string;\n\tinput: Record<string, unknown>;\n}\n\nexport interface CueDoneEvent {\n\ttype: \"done\";\n\tstopReason: \"end_turn\" | \"tool_use\" | \"max_tokens\" | \"aborted\";\n}\n\nexport interface CueErrorEvent {\n\ttype: \"error\";\n\terror: string;\n}\n\nexport type CueStreamEvent =\n\t| CueTextDeltaEvent\n\t| CueToolUseDeltaEvent\n\t| CueToolUseEndEvent\n\t| CueDoneEvent\n\t| CueErrorEvent;\n"]}
package/dist/toml.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ import type { ElementDef } from "./types.ts";
2
+ export declare function parseElementToml(content: string): ElementDef;
3
+ //# sourceMappingURL=toml.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"toml.d.ts","sourceRoot":"","sources":["../src/toml.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAqB,MAAM,YAAY,CAAC;AAEhE,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,UAAU,CA8E5D","sourcesContent":["import type { ElementDef, TagDef, UsesEntry } from \"./types.ts\";\n\nexport function parseElementToml(content: string): ElementDef {\n\tconst result: Partial<ElementDef> = {};\n\tconst tags: Record<string, TagDef> = {};\n\tlet currentTag: string | null = null;\n\tlet currentTagDef: Partial<TagDef> = {};\n\tconst uses: UsesEntry[] = [];\n\n\tconst lines = content.split(\"\\n\");\n\n\tfor (const line of lines) {\n\t\tconst trimmed = line.trim();\n\t\tif (!trimmed || trimmed.startsWith(\"#\")) continue;\n\n\t\tconst elementMatch = trimmed.match(/^\\[element\\]$/);\n\t\tif (elementMatch) continue;\n\n\t\tconst tagMatch = trimmed.match(/^\\[tags\\.([^\\]]+)\\]$/);\n\t\tif (tagMatch) {\n\t\t\tif (currentTag && currentTagDef.description) {\n\t\t\t\ttags[currentTag] = currentTagDef as TagDef;\n\t\t\t}\n\t\t\tcurrentTag = tagMatch[1];\n\t\t\tcurrentTagDef = { overrides: [] };\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst usesMatch = trimmed.match(/^\\[\\[uses\\]\\]$/);\n\t\tif (usesMatch) {\n\t\t\tif (currentTag && currentTagDef.description) {\n\t\t\t\ttags[currentTag] = currentTagDef as TagDef;\n\t\t\t\tcurrentTag = null;\n\t\t\t\tcurrentTagDef = {};\n\t\t\t}\n\t\t\tuses.push({ tag: \"\", source: \"\" });\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst kvMatch = trimmed.match(/^([a-zA-Z_-]+)\\s*=\\s*(.+)$/);\n\t\tif (!kvMatch) continue;\n\n\t\tconst [, key, valueStr] = kvMatch;\n\t\tconst value = parseTomlValue(valueStr);\n\n\t\tif (currentTag) {\n\t\t\tif (key === \"description\") currentTagDef.description = value as string;\n\t\t\telse if (key === \"overrides\") currentTagDef.overrides = value as any[];\n\t\t\telse if (key === \"exclusive\") currentTagDef.exclusive = value as boolean;\n\t\t\telse if (key === \"inline\") currentTagDef.inline = value as string;\n\t\t} else if (uses.length > 0) {\n\t\t\tconst lastUse = uses[uses.length - 1];\n\t\t\tif (key === \"tag\") lastUse.tag = value as string;\n\t\t\telse if (key === \"source\") lastUse.source = value as string;\n\t\t} else {\n\t\t\tif (key === \"name\") result.name = value as string;\n\t\t\telse if (key === \"description\") result.description = value as string;\n\t\t\telse if (key === \"version\") result.version = value as string;\n\t\t\telse if (key === \"class\") result.class = value as \"model\" | \"harness\";\n\t\t\telse if (key === \"handler\") result.handler = value as string;\n\t\t\telse if (key === \"allowed-tools\") result.allowedTools = value as string;\n\t\t\telse if (key === \"inputs\") result.inputs = value as string[];\n\t\t}\n\t}\n\n\tif (currentTag && currentTagDef.description) {\n\t\ttags[currentTag] = currentTagDef as TagDef;\n\t}\n\n\treturn {\n\t\tname: result.name || \"\",\n\t\tdescription: result.description || \"\",\n\t\tversion: result.version || \"0.0.0\",\n\t\tclass: result.class || \"model\",\n\t\thandler: result.handler,\n\t\tallowedTools: result.allowedTools,\n\t\ttags,\n\t\tinputs: result.inputs,\n\t\tuses: uses.length > 0 ? uses : [],\n\t};\n}\n\nfunction parseTomlValue(raw: string): unknown {\n\tconst trimmed = raw.trim();\n\n\tif (trimmed.startsWith(\"[\") && trimmed.endsWith(\"]\")) {\n\t\tconst inner = trimmed.slice(1, -1).trim();\n\t\tif (!inner) return [];\n\t\treturn inner.split(\",\").map((s) => {\n\t\t\tconst v = s\n\t\t\t\t.trim()\n\t\t\t\t.replace(/^\"(.*)\"$/, \"$1\")\n\t\t\t\t.replace(/^'(.*)'$/, \"$1\");\n\t\t\treturn v;\n\t\t});\n\t}\n\n\tif (trimmed === \"true\") return true;\n\tif (trimmed === \"false\") return false;\n\n\tif (trimmed.startsWith('\"') && trimmed.endsWith('\"')) {\n\t\treturn trimmed.slice(1, -1);\n\t}\n\tif (trimmed.startsWith(\"'\") && trimmed.endsWith(\"'\")) {\n\t\treturn trimmed.slice(1, -1);\n\t}\n\n\tconst num = Number(trimmed);\n\tif (!Number.isNaN(num)) return num;\n\n\treturn trimmed;\n}\n"]}
package/dist/toml.js ADDED
@@ -0,0 +1,117 @@
1
+ export function parseElementToml(content) {
2
+ const result = {};
3
+ const tags = {};
4
+ let currentTag = null;
5
+ let currentTagDef = {};
6
+ const uses = [];
7
+ const lines = content.split("\n");
8
+ for (const line of lines) {
9
+ const trimmed = line.trim();
10
+ if (!trimmed || trimmed.startsWith("#"))
11
+ continue;
12
+ const elementMatch = trimmed.match(/^\[element\]$/);
13
+ if (elementMatch)
14
+ continue;
15
+ const tagMatch = trimmed.match(/^\[tags\.([^\]]+)\]$/);
16
+ if (tagMatch) {
17
+ if (currentTag && currentTagDef.description) {
18
+ tags[currentTag] = currentTagDef;
19
+ }
20
+ currentTag = tagMatch[1];
21
+ currentTagDef = { overrides: [] };
22
+ continue;
23
+ }
24
+ const usesMatch = trimmed.match(/^\[\[uses\]\]$/);
25
+ if (usesMatch) {
26
+ if (currentTag && currentTagDef.description) {
27
+ tags[currentTag] = currentTagDef;
28
+ currentTag = null;
29
+ currentTagDef = {};
30
+ }
31
+ uses.push({ tag: "", source: "" });
32
+ continue;
33
+ }
34
+ const kvMatch = trimmed.match(/^([a-zA-Z_-]+)\s*=\s*(.+)$/);
35
+ if (!kvMatch)
36
+ continue;
37
+ const [, key, valueStr] = kvMatch;
38
+ const value = parseTomlValue(valueStr);
39
+ if (currentTag) {
40
+ if (key === "description")
41
+ currentTagDef.description = value;
42
+ else if (key === "overrides")
43
+ currentTagDef.overrides = value;
44
+ else if (key === "exclusive")
45
+ currentTagDef.exclusive = value;
46
+ else if (key === "inline")
47
+ currentTagDef.inline = value;
48
+ }
49
+ else if (uses.length > 0) {
50
+ const lastUse = uses[uses.length - 1];
51
+ if (key === "tag")
52
+ lastUse.tag = value;
53
+ else if (key === "source")
54
+ lastUse.source = value;
55
+ }
56
+ else {
57
+ if (key === "name")
58
+ result.name = value;
59
+ else if (key === "description")
60
+ result.description = value;
61
+ else if (key === "version")
62
+ result.version = value;
63
+ else if (key === "class")
64
+ result.class = value;
65
+ else if (key === "handler")
66
+ result.handler = value;
67
+ else if (key === "allowed-tools")
68
+ result.allowedTools = value;
69
+ else if (key === "inputs")
70
+ result.inputs = value;
71
+ }
72
+ }
73
+ if (currentTag && currentTagDef.description) {
74
+ tags[currentTag] = currentTagDef;
75
+ }
76
+ return {
77
+ name: result.name || "",
78
+ description: result.description || "",
79
+ version: result.version || "0.0.0",
80
+ class: result.class || "model",
81
+ handler: result.handler,
82
+ allowedTools: result.allowedTools,
83
+ tags,
84
+ inputs: result.inputs,
85
+ uses: uses.length > 0 ? uses : [],
86
+ };
87
+ }
88
+ function parseTomlValue(raw) {
89
+ const trimmed = raw.trim();
90
+ if (trimmed.startsWith("[") && trimmed.endsWith("]")) {
91
+ const inner = trimmed.slice(1, -1).trim();
92
+ if (!inner)
93
+ return [];
94
+ return inner.split(",").map((s) => {
95
+ const v = s
96
+ .trim()
97
+ .replace(/^"(.*)"$/, "$1")
98
+ .replace(/^'(.*)'$/, "$1");
99
+ return v;
100
+ });
101
+ }
102
+ if (trimmed === "true")
103
+ return true;
104
+ if (trimmed === "false")
105
+ return false;
106
+ if (trimmed.startsWith('"') && trimmed.endsWith('"')) {
107
+ return trimmed.slice(1, -1);
108
+ }
109
+ if (trimmed.startsWith("'") && trimmed.endsWith("'")) {
110
+ return trimmed.slice(1, -1);
111
+ }
112
+ const num = Number(trimmed);
113
+ if (!Number.isNaN(num))
114
+ return num;
115
+ return trimmed;
116
+ }
117
+ //# sourceMappingURL=toml.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"toml.js","sourceRoot":"","sources":["../src/toml.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ElementDef, TagDef, UsesEntry } from \"./types.ts\";\n\nexport function parseElementToml(content: string): ElementDef {\n\tconst result: Partial<ElementDef> = {};\n\tconst tags: Record<string, TagDef> = {};\n\tlet currentTag: string | null = null;\n\tlet currentTagDef: Partial<TagDef> = {};\n\tconst uses: UsesEntry[] = [];\n\n\tconst lines = content.split(\"\\n\");\n\n\tfor (const line of lines) {\n\t\tconst trimmed = line.trim();\n\t\tif (!trimmed || trimmed.startsWith(\"#\")) continue;\n\n\t\tconst elementMatch = trimmed.match(/^\\[element\\]$/);\n\t\tif (elementMatch) continue;\n\n\t\tconst tagMatch = trimmed.match(/^\\[tags\\.([^\\]]+)\\]$/);\n\t\tif (tagMatch) {\n\t\t\tif (currentTag && currentTagDef.description) {\n\t\t\t\ttags[currentTag] = currentTagDef as TagDef;\n\t\t\t}\n\t\t\tcurrentTag = tagMatch[1];\n\t\t\tcurrentTagDef = { overrides: [] };\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst usesMatch = trimmed.match(/^\\[\\[uses\\]\\]$/);\n\t\tif (usesMatch) {\n\t\t\tif (currentTag && currentTagDef.description) {\n\t\t\t\ttags[currentTag] = currentTagDef as TagDef;\n\t\t\t\tcurrentTag = null;\n\t\t\t\tcurrentTagDef = {};\n\t\t\t}\n\t\t\tuses.push({ tag: \"\", source: \"\" });\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst kvMatch = trimmed.match(/^([a-zA-Z_-]+)\\s*=\\s*(.+)$/);\n\t\tif (!kvMatch) continue;\n\n\t\tconst [, key, valueStr] = kvMatch;\n\t\tconst value = parseTomlValue(valueStr);\n\n\t\tif (currentTag) {\n\t\t\tif (key === \"description\") currentTagDef.description = value as string;\n\t\t\telse if (key === \"overrides\") currentTagDef.overrides = value as any[];\n\t\t\telse if (key === \"exclusive\") currentTagDef.exclusive = value as boolean;\n\t\t\telse if (key === \"inline\") currentTagDef.inline = value as string;\n\t\t} else if (uses.length > 0) {\n\t\t\tconst lastUse = uses[uses.length - 1];\n\t\t\tif (key === \"tag\") lastUse.tag = value as string;\n\t\t\telse if (key === \"source\") lastUse.source = value as string;\n\t\t} else {\n\t\t\tif (key === \"name\") result.name = value as string;\n\t\t\telse if (key === \"description\") result.description = value as string;\n\t\t\telse if (key === \"version\") result.version = value as string;\n\t\t\telse if (key === \"class\") result.class = value as \"model\" | \"harness\";\n\t\t\telse if (key === \"handler\") result.handler = value as string;\n\t\t\telse if (key === \"allowed-tools\") result.allowedTools = value as string;\n\t\t\telse if (key === \"inputs\") result.inputs = value as string[];\n\t\t}\n\t}\n\n\tif (currentTag && currentTagDef.description) {\n\t\ttags[currentTag] = currentTagDef as TagDef;\n\t}\n\n\treturn {\n\t\tname: result.name || \"\",\n\t\tdescription: result.description || \"\",\n\t\tversion: result.version || \"0.0.0\",\n\t\tclass: result.class || \"model\",\n\t\thandler: result.handler,\n\t\tallowedTools: result.allowedTools,\n\t\ttags,\n\t\tinputs: result.inputs,\n\t\tuses: uses.length > 0 ? uses : [],\n\t};\n}\n\nfunction parseTomlValue(raw: string): unknown {\n\tconst trimmed = raw.trim();\n\n\tif (trimmed.startsWith(\"[\") && trimmed.endsWith(\"]\")) {\n\t\tconst inner = trimmed.slice(1, -1).trim();\n\t\tif (!inner) return [];\n\t\treturn inner.split(\",\").map((s) => {\n\t\t\tconst v = s\n\t\t\t\t.trim()\n\t\t\t\t.replace(/^\"(.*)\"$/, \"$1\")\n\t\t\t\t.replace(/^'(.*)'$/, \"$1\");\n\t\t\treturn v;\n\t\t});\n\t}\n\n\tif (trimmed === \"true\") return true;\n\tif (trimmed === \"false\") return false;\n\n\tif (trimmed.startsWith('\"') && trimmed.endsWith('\"')) {\n\t\treturn trimmed.slice(1, -1);\n\t}\n\tif (trimmed.startsWith(\"'\") && trimmed.endsWith(\"'\")) {\n\t\treturn trimmed.slice(1, -1);\n\t}\n\n\tconst num = Number(trimmed);\n\tif (!Number.isNaN(num)) return num;\n\n\treturn trimmed;\n}\n"]}