@deimoscloud/coreai 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 (216) hide show
  1. package/.prettierrc +9 -0
  2. package/AGENT_SPEC.md +347 -0
  3. package/ARCHITECTURE.md +547 -0
  4. package/DRAFT_PRD.md +1440 -0
  5. package/IMPLEMENTATION_PLAN.md +256 -0
  6. package/PRODUCT.md +473 -0
  7. package/README.md +303 -0
  8. package/WORKFLOWS.md +295 -0
  9. package/agents/_templates/ic-engineer.md +185 -0
  10. package/agents/_templates/reviewer.md +182 -0
  11. package/agents/backend-engineer.yaml +72 -0
  12. package/agents/devops-engineer.yaml +72 -0
  13. package/agents/engineering-manager.yaml +70 -0
  14. package/agents/examples/android-engineer.md +302 -0
  15. package/agents/examples/backend-engineer.md +320 -0
  16. package/agents/examples/devops-engineer.md +742 -0
  17. package/agents/examples/engineering-manager.md +469 -0
  18. package/agents/examples/frontend-engineer.md +58 -0
  19. package/agents/examples/product-manager.md +315 -0
  20. package/agents/examples/qa-engineer.md +371 -0
  21. package/agents/examples/security-engineer.md +525 -0
  22. package/agents/examples/solutions-architect.md +351 -0
  23. package/agents/examples/wearos-engineer.md +359 -0
  24. package/agents/frontend-engineer.yaml +72 -0
  25. package/commands/core/check-inbox.md +34 -0
  26. package/commands/core/delegate.md +30 -0
  27. package/commands/core/git-commit.md +144 -0
  28. package/commands/core/pr-create.md +193 -0
  29. package/commands/core/review.md +56 -0
  30. package/commands/core/sprint-status.md +65 -0
  31. package/commands/optional/docs-update.md +200 -0
  32. package/commands/optional/jira-create.md +200 -0
  33. package/commands/optional/jira-transition.md +184 -0
  34. package/commands/optional/worktree-cleanup.md +167 -0
  35. package/commands/optional/worktree-setup.md +110 -0
  36. package/dist/cli/index.js +4037 -0
  37. package/dist/cli/index.js.map +1 -0
  38. package/dist/index.d.ts +2978 -0
  39. package/dist/index.js +3867 -0
  40. package/dist/index.js.map +1 -0
  41. package/eslint.config.js +29 -0
  42. package/jest.config.js +22 -0
  43. package/knowledge-library/README.md +118 -0
  44. package/knowledge-library/android-engineer/context/current.txt +42 -0
  45. package/knowledge-library/android-engineer/control/decisions.txt +9 -0
  46. package/knowledge-library/android-engineer/control/dependencies.txt +19 -0
  47. package/knowledge-library/android-engineer/control/objectives.txt +26 -0
  48. package/knowledge-library/android-engineer/history/.gitkeep +0 -0
  49. package/knowledge-library/android-engineer/inbox/processed/.gitkeep +0 -0
  50. package/knowledge-library/android-engineer/outbox/.gitkeep +0 -0
  51. package/knowledge-library/android-engineer/tech/.gitkeep +0 -0
  52. package/knowledge-library/architecture.txt +61 -0
  53. package/knowledge-library/backend-engineer/context/current.txt +42 -0
  54. package/knowledge-library/backend-engineer/control/decisions.txt +9 -0
  55. package/knowledge-library/backend-engineer/control/dependencies.txt +19 -0
  56. package/knowledge-library/backend-engineer/control/objectives.txt +26 -0
  57. package/knowledge-library/backend-engineer/history/.gitkeep +0 -0
  58. package/knowledge-library/backend-engineer/inbox/processed/.gitkeep +0 -0
  59. package/knowledge-library/backend-engineer/outbox/.gitkeep +0 -0
  60. package/knowledge-library/backend-engineer/tech/.gitkeep +0 -0
  61. package/knowledge-library/context.txt +52 -0
  62. package/knowledge-library/devops-engineer/context/current.txt +42 -0
  63. package/knowledge-library/devops-engineer/control/decisions.txt +9 -0
  64. package/knowledge-library/devops-engineer/control/dependencies.txt +19 -0
  65. package/knowledge-library/devops-engineer/control/objectives.txt +26 -0
  66. package/knowledge-library/devops-engineer/history/.gitkeep +0 -0
  67. package/knowledge-library/devops-engineer/inbox/processed/.gitkeep +0 -0
  68. package/knowledge-library/devops-engineer/outbox/.gitkeep +0 -0
  69. package/knowledge-library/devops-engineer/tech/.gitkeep +0 -0
  70. package/knowledge-library/engineering-manager/context/current.txt +40 -0
  71. package/knowledge-library/engineering-manager/control/decisions.txt +9 -0
  72. package/knowledge-library/engineering-manager/control/objectives.txt +27 -0
  73. package/knowledge-library/engineering-manager/history/.gitkeep +0 -0
  74. package/knowledge-library/engineering-manager/inbox/processed/.gitkeep +0 -0
  75. package/knowledge-library/engineering-manager/outbox/.gitkeep +0 -0
  76. package/knowledge-library/engineering-manager/tech/.gitkeep +0 -0
  77. package/knowledge-library/prd.txt +81 -0
  78. package/knowledge-library/product-manager/context/current.txt +42 -0
  79. package/knowledge-library/product-manager/control/decisions.txt +9 -0
  80. package/knowledge-library/product-manager/control/dependencies.txt +19 -0
  81. package/knowledge-library/product-manager/control/objectives.txt +26 -0
  82. package/knowledge-library/product-manager/history/.gitkeep +0 -0
  83. package/knowledge-library/product-manager/inbox/processed/.gitkeep +0 -0
  84. package/knowledge-library/product-manager/outbox/.gitkeep +0 -0
  85. package/knowledge-library/product-manager/tech/.gitkeep +0 -0
  86. package/knowledge-library/qa-engineer/context/current.txt +42 -0
  87. package/knowledge-library/qa-engineer/control/decisions.txt +9 -0
  88. package/knowledge-library/qa-engineer/control/dependencies.txt +19 -0
  89. package/knowledge-library/qa-engineer/control/objectives.txt +26 -0
  90. package/knowledge-library/qa-engineer/history/.gitkeep +0 -0
  91. package/knowledge-library/qa-engineer/inbox/processed/.gitkeep +0 -0
  92. package/knowledge-library/qa-engineer/outbox/.gitkeep +0 -0
  93. package/knowledge-library/qa-engineer/tech/.gitkeep +0 -0
  94. package/knowledge-library/security-engineer/context/current.txt +42 -0
  95. package/knowledge-library/security-engineer/control/decisions.txt +9 -0
  96. package/knowledge-library/security-engineer/control/dependencies.txt +19 -0
  97. package/knowledge-library/security-engineer/control/objectives.txt +26 -0
  98. package/knowledge-library/security-engineer/history/.gitkeep +0 -0
  99. package/knowledge-library/security-engineer/inbox/processed/.gitkeep +0 -0
  100. package/knowledge-library/security-engineer/outbox/.gitkeep +0 -0
  101. package/knowledge-library/security-engineer/tech/.gitkeep +0 -0
  102. package/knowledge-library/solutions-architect/context/current.txt +42 -0
  103. package/knowledge-library/solutions-architect/control/decisions.txt +9 -0
  104. package/knowledge-library/solutions-architect/control/dependencies.txt +19 -0
  105. package/knowledge-library/solutions-architect/control/objectives.txt +26 -0
  106. package/knowledge-library/solutions-architect/history/.gitkeep +0 -0
  107. package/knowledge-library/solutions-architect/inbox/processed/.gitkeep +0 -0
  108. package/knowledge-library/solutions-architect/outbox/.gitkeep +0 -0
  109. package/knowledge-library/solutions-architect/tech/.gitkeep +0 -0
  110. package/knowledge-library/wearos-engineer/context/current.txt +42 -0
  111. package/knowledge-library/wearos-engineer/control/decisions.txt +9 -0
  112. package/knowledge-library/wearos-engineer/control/dependencies.txt +19 -0
  113. package/knowledge-library/wearos-engineer/control/objectives.txt +26 -0
  114. package/knowledge-library/wearos-engineer/history/.gitkeep +0 -0
  115. package/knowledge-library/wearos-engineer/inbox/processed/.gitkeep +0 -0
  116. package/knowledge-library/wearos-engineer/outbox/.gitkeep +0 -0
  117. package/knowledge-library/wearos-engineer/tech/.gitkeep +0 -0
  118. package/package.json +66 -0
  119. package/schemas/agent.schema.json +171 -0
  120. package/schemas/coreai.config.schema.json +257 -0
  121. package/scripts/add-agent.sh +323 -0
  122. package/scripts/install.sh +354 -0
  123. package/src/adapters/factory.test.ts +386 -0
  124. package/src/adapters/factory.ts +305 -0
  125. package/src/adapters/index.ts +113 -0
  126. package/src/adapters/interfaces.ts +268 -0
  127. package/src/adapters/mcp/client.test.ts +130 -0
  128. package/src/adapters/mcp/client.ts +451 -0
  129. package/src/adapters/mcp/discovery.test.ts +315 -0
  130. package/src/adapters/mcp/discovery.ts +340 -0
  131. package/src/adapters/mcp/index.ts +66 -0
  132. package/src/adapters/mcp/mapper.test.ts +218 -0
  133. package/src/adapters/mcp/mapper.ts +536 -0
  134. package/src/adapters/mcp/registry.test.ts +433 -0
  135. package/src/adapters/mcp/registry.ts +550 -0
  136. package/src/adapters/mcp/types.ts +258 -0
  137. package/src/adapters/native/filesystem.test.ts +350 -0
  138. package/src/adapters/native/filesystem.ts +393 -0
  139. package/src/adapters/native/github.test.ts +173 -0
  140. package/src/adapters/native/github.ts +627 -0
  141. package/src/adapters/native/index.ts +22 -0
  142. package/src/adapters/native/selector.test.ts +224 -0
  143. package/src/adapters/native/selector.ts +150 -0
  144. package/src/adapters/types.ts +270 -0
  145. package/src/agents/compiler.test.ts +399 -0
  146. package/src/agents/compiler.ts +359 -0
  147. package/src/agents/index.ts +36 -0
  148. package/src/agents/loader.test.ts +319 -0
  149. package/src/agents/loader.ts +143 -0
  150. package/src/agents/resolver.test.ts +282 -0
  151. package/src/agents/resolver.ts +262 -0
  152. package/src/agents/types.ts +87 -0
  153. package/src/cache/index.ts +38 -0
  154. package/src/cache/interfaces.ts +283 -0
  155. package/src/cache/manager.test.ts +266 -0
  156. package/src/cache/manager.ts +388 -0
  157. package/src/cache/provider.test.ts +485 -0
  158. package/src/cache/provider.ts +745 -0
  159. package/src/cache/types.test.ts +192 -0
  160. package/src/cache/types.ts +313 -0
  161. package/src/cli/commands/build.test.ts +248 -0
  162. package/src/cli/commands/build.ts +244 -0
  163. package/src/cli/commands/cache.test.ts +221 -0
  164. package/src/cli/commands/cache.ts +229 -0
  165. package/src/cli/commands/index.ts +63 -0
  166. package/src/cli/commands/init.test.ts +173 -0
  167. package/src/cli/commands/init.ts +296 -0
  168. package/src/cli/commands/skills.test.ts +272 -0
  169. package/src/cli/commands/skills.ts +348 -0
  170. package/src/cli/commands/status.test.ts +392 -0
  171. package/src/cli/commands/status.ts +332 -0
  172. package/src/cli/commands/sync.test.ts +213 -0
  173. package/src/cli/commands/sync.ts +251 -0
  174. package/src/cli/commands/validate.test.ts +216 -0
  175. package/src/cli/commands/validate.ts +340 -0
  176. package/src/cli/index.test.ts +190 -0
  177. package/src/cli/index.ts +493 -0
  178. package/src/commands/context.test.ts +163 -0
  179. package/src/commands/context.ts +111 -0
  180. package/src/commands/index.ts +56 -0
  181. package/src/commands/loader.test.ts +273 -0
  182. package/src/commands/loader.ts +355 -0
  183. package/src/commands/registry.test.ts +384 -0
  184. package/src/commands/registry.ts +248 -0
  185. package/src/commands/runner.test.ts +297 -0
  186. package/src/commands/runner.ts +222 -0
  187. package/src/commands/types.ts +361 -0
  188. package/src/config/index.ts +19 -0
  189. package/src/config/loader.test.ts +262 -0
  190. package/src/config/loader.ts +188 -0
  191. package/src/config/types.ts +154 -0
  192. package/src/context/index.ts +14 -0
  193. package/src/context/loader.test.ts +334 -0
  194. package/src/context/loader.ts +357 -0
  195. package/src/index.test.ts +13 -0
  196. package/src/index.ts +244 -0
  197. package/src/knowledge-library/index.ts +44 -0
  198. package/src/knowledge-library/manager.test.ts +536 -0
  199. package/src/knowledge-library/manager.ts +804 -0
  200. package/src/knowledge-library/types.ts +432 -0
  201. package/src/skills/generator.test.ts +602 -0
  202. package/src/skills/generator.ts +491 -0
  203. package/src/skills/index.ts +27 -0
  204. package/src/skills/templates.ts +520 -0
  205. package/src/skills/types.ts +251 -0
  206. package/templates/completion-report.md +72 -0
  207. package/templates/feedback.md +56 -0
  208. package/templates/project-files/CLAUDE.md.template +109 -0
  209. package/templates/project-files/coreai.json.example +47 -0
  210. package/templates/project-files/mcp.json.template +20 -0
  211. package/templates/review-complete.md +64 -0
  212. package/templates/review-request.md +67 -0
  213. package/templates/task-assignment.md +51 -0
  214. package/tsconfig.build.json +4 -0
  215. package/tsconfig.json +26 -0
  216. package/tsup.config.ts +23 -0
package/dist/index.js ADDED
@@ -0,0 +1,3867 @@
1
+ // src/config/loader.ts
2
+ import { existsSync, readFileSync } from "fs";
3
+ import { dirname, join, resolve } from "path";
4
+ import { parse as parseYaml } from "yaml";
5
+ import Ajv from "ajv";
6
+ import addFormats from "ajv-formats";
7
+ import { createRequire } from "module";
8
+ var require2 = createRequire(import.meta.url);
9
+ var configSchema = require2("../../schemas/coreai.config.schema.json");
10
+ var CONFIG_FILE_NAME = "coreai.config.yaml";
11
+ var CONFIG_FILE_NAMES = [CONFIG_FILE_NAME, "coreai.config.yml"];
12
+ var ConfigError = class extends Error {
13
+ constructor(message, code, details) {
14
+ super(message);
15
+ this.code = code;
16
+ this.details = details;
17
+ this.name = "ConfigError";
18
+ }
19
+ };
20
+ var DEFAULT_AGENTS = [
21
+ "backend-engineer",
22
+ "frontend-engineer",
23
+ "devops-engineer",
24
+ "engineering-manager"
25
+ ];
26
+ function findConfigFile(startDir = process.cwd()) {
27
+ let currentDir = resolve(startDir);
28
+ const root = dirname(currentDir);
29
+ while (currentDir !== root) {
30
+ for (const fileName of CONFIG_FILE_NAMES) {
31
+ const configPath = join(currentDir, fileName);
32
+ if (existsSync(configPath)) {
33
+ return configPath;
34
+ }
35
+ }
36
+ const parentDir = dirname(currentDir);
37
+ if (parentDir === currentDir) {
38
+ break;
39
+ }
40
+ currentDir = parentDir;
41
+ }
42
+ for (const fileName of CONFIG_FILE_NAMES) {
43
+ const configPath = join(currentDir, fileName);
44
+ if (existsSync(configPath)) {
45
+ return configPath;
46
+ }
47
+ }
48
+ return null;
49
+ }
50
+ function parseConfig(content, filePath) {
51
+ try {
52
+ return parseYaml(content);
53
+ } catch (error) {
54
+ const message = error instanceof Error ? error.message : "Unknown parse error";
55
+ throw new ConfigError(
56
+ `Failed to parse YAML${filePath ? ` in ${filePath}` : ""}: ${message}`,
57
+ "PARSE_ERROR",
58
+ error
59
+ );
60
+ }
61
+ }
62
+ function validateConfig(config) {
63
+ const ajv = new Ajv.default({ allErrors: true, strict: false });
64
+ addFormats.default(ajv);
65
+ const validate = ajv.compile(configSchema);
66
+ const valid = validate(config);
67
+ if (!valid) {
68
+ const errors = validate.errors ?? [];
69
+ const errorMessages = errors.map((err) => {
70
+ const path = err.instancePath || "root";
71
+ return `${path}: ${err.message ?? "unknown error"}`;
72
+ });
73
+ throw new ConfigError(
74
+ `Configuration validation failed:
75
+ - ${errorMessages.join("\n - ")}`,
76
+ "VALIDATION_ERROR",
77
+ errors
78
+ );
79
+ }
80
+ return config;
81
+ }
82
+ function applyDefaults(config) {
83
+ return {
84
+ ...config,
85
+ project: {
86
+ name: config.project?.name ?? "unnamed",
87
+ type: config.project?.type ?? "software",
88
+ root: config.project?.root ?? process.cwd()
89
+ },
90
+ team: {
91
+ agents: config.team?.agents ?? DEFAULT_AGENTS
92
+ }
93
+ };
94
+ }
95
+ function loadConfigFromFile(filePath) {
96
+ let content;
97
+ try {
98
+ content = readFileSync(filePath, "utf-8");
99
+ } catch (error) {
100
+ const message = error instanceof Error ? error.message : "Unknown read error";
101
+ throw new ConfigError(
102
+ `Failed to read config file ${filePath}: ${message}`,
103
+ "READ_ERROR",
104
+ error
105
+ );
106
+ }
107
+ const parsed = parseConfig(content, filePath);
108
+ const validated = validateConfig(parsed);
109
+ return applyDefaults(validated);
110
+ }
111
+ function loadConfig(startDir) {
112
+ const configPath = findConfigFile(startDir);
113
+ if (!configPath) {
114
+ throw new ConfigError(
115
+ `Configuration file not found. Create a ${CONFIG_FILE_NAME} file or run 'coreai init'.`,
116
+ "NOT_FOUND"
117
+ );
118
+ }
119
+ return loadConfigFromFile(configPath);
120
+ }
121
+ function configExists(startDir) {
122
+ return findConfigFile(startDir) !== null;
123
+ }
124
+ function getConfigPath(startDir) {
125
+ return findConfigFile(startDir);
126
+ }
127
+
128
+ // src/agents/loader.ts
129
+ import { existsSync as existsSync2, readdirSync, readFileSync as readFileSync2 } from "fs";
130
+ import { basename, extname, join as join2 } from "path";
131
+ import { parse as parseYaml2 } from "yaml";
132
+ import Ajv2 from "ajv";
133
+ import { createRequire as createRequire2 } from "module";
134
+ var require3 = createRequire2(import.meta.url);
135
+ var agentSchema = require3("../../schemas/agent.schema.json");
136
+ var AgentError = class extends Error {
137
+ constructor(message, code, details) {
138
+ super(message);
139
+ this.code = code;
140
+ this.details = details;
141
+ this.name = "AgentError";
142
+ }
143
+ };
144
+ function parseAgentYaml(content, filePath) {
145
+ try {
146
+ return parseYaml2(content);
147
+ } catch (error) {
148
+ const message = error instanceof Error ? error.message : "Unknown parse error";
149
+ throw new AgentError(
150
+ `Failed to parse agent YAML${filePath ? ` in ${filePath}` : ""}: ${message}`,
151
+ "PARSE_ERROR",
152
+ error
153
+ );
154
+ }
155
+ }
156
+ function validateAgentDefinition(agent) {
157
+ const ajv = new Ajv2.default({ allErrors: true, strict: false });
158
+ const validate = ajv.compile(agentSchema);
159
+ const valid = validate(agent);
160
+ if (!valid) {
161
+ const errors = validate.errors ?? [];
162
+ const errorMessages = errors.map((err) => {
163
+ const path = err.instancePath || "root";
164
+ return `${path}: ${err.message ?? "unknown error"}`;
165
+ });
166
+ throw new AgentError(
167
+ `Agent validation failed:
168
+ - ${errorMessages.join("\n - ")}`,
169
+ "VALIDATION_ERROR",
170
+ errors
171
+ );
172
+ }
173
+ return agent;
174
+ }
175
+ function loadAgentFromFile(filePath) {
176
+ if (!existsSync2(filePath)) {
177
+ throw new AgentError(`Agent file not found: ${filePath}`, "NOT_FOUND");
178
+ }
179
+ let content;
180
+ try {
181
+ content = readFileSync2(filePath, "utf-8");
182
+ } catch (error) {
183
+ const message = error instanceof Error ? error.message : "Unknown read error";
184
+ throw new AgentError(`Failed to read agent file ${filePath}: ${message}`, "READ_ERROR", error);
185
+ }
186
+ const parsed = parseAgentYaml(content, filePath);
187
+ return validateAgentDefinition(parsed);
188
+ }
189
+ function listYamlFiles(dir) {
190
+ if (!existsSync2(dir)) {
191
+ return [];
192
+ }
193
+ return readdirSync(dir).filter((file) => {
194
+ const ext = extname(file).toLowerCase();
195
+ return ext === ".yaml" || ext === ".yml";
196
+ }).map((file) => join2(dir, file));
197
+ }
198
+ function loadAgentsFromDirectory(dir, source) {
199
+ const agents = /* @__PURE__ */ new Map();
200
+ const files = listYamlFiles(dir);
201
+ for (const filePath of files) {
202
+ try {
203
+ const definition = loadAgentFromFile(filePath);
204
+ agents.set(definition.role, {
205
+ definition,
206
+ source,
207
+ filePath
208
+ });
209
+ } catch (error) {
210
+ const fileName = basename(filePath);
211
+ console.warn(`Warning: Failed to load agent from ${fileName}: ${error.message}`);
212
+ }
213
+ }
214
+ return agents;
215
+ }
216
+ function getRoleFromFilename(filePath) {
217
+ const fileName = basename(filePath);
218
+ const ext = extname(fileName);
219
+ return fileName.slice(0, -ext.length);
220
+ }
221
+
222
+ // src/agents/resolver.ts
223
+ var ResolutionError = class extends Error {
224
+ constructor(message, variable, path) {
225
+ super(message);
226
+ this.variable = variable;
227
+ this.path = path;
228
+ this.name = "ResolutionError";
229
+ }
230
+ };
231
+ var VARIABLE_PATTERN = /\$\{([a-z_][a-z0-9_]*(?:\.[a-z_][a-z0-9_]*)*)\}/gi;
232
+ function getNestedValue(obj, path) {
233
+ const parts = path.split(".");
234
+ let current = obj;
235
+ for (const part of parts) {
236
+ if (current === null || current === void 0) {
237
+ return void 0;
238
+ }
239
+ if (typeof current !== "object") {
240
+ return void 0;
241
+ }
242
+ current = current[part];
243
+ }
244
+ return current;
245
+ }
246
+ function resolveVariable(variable, context, options) {
247
+ const parts = variable.split(".");
248
+ const namespace = parts[0];
249
+ const path = parts.slice(1).join(".");
250
+ let value;
251
+ switch (namespace) {
252
+ case "config":
253
+ if (!context.config) {
254
+ if (options.strict) {
255
+ throw new ResolutionError(
256
+ `Cannot resolve \${${variable}}: no config context provided`,
257
+ variable
258
+ );
259
+ }
260
+ return void 0;
261
+ }
262
+ value = getNestedValue(context.config, path);
263
+ break;
264
+ case "agent":
265
+ if (!context.agent) {
266
+ if (options.strict) {
267
+ throw new ResolutionError(
268
+ `Cannot resolve \${${variable}}: no agent context provided`,
269
+ variable
270
+ );
271
+ }
272
+ return void 0;
273
+ }
274
+ value = getNestedValue(context.agent, path);
275
+ break;
276
+ case "remote":
277
+ value = resolveRemoteVariable(path, context, options);
278
+ break;
279
+ default:
280
+ if (options.strict) {
281
+ throw new ResolutionError(`Unknown variable namespace: ${namespace}`, variable);
282
+ }
283
+ return void 0;
284
+ }
285
+ if (value === void 0) {
286
+ if (options.strict) {
287
+ throw new ResolutionError(`Cannot resolve \${${variable}}: path not found`, variable, path);
288
+ }
289
+ return void 0;
290
+ }
291
+ if (typeof value === "string") {
292
+ return value;
293
+ }
294
+ if (typeof value === "number" || typeof value === "boolean") {
295
+ return String(value);
296
+ }
297
+ return JSON.stringify(value);
298
+ }
299
+ function resolveRemoteVariable(path, context, options) {
300
+ if (!context.config?.integrations) {
301
+ if (options.strict) {
302
+ throw new ResolutionError(
303
+ `Cannot resolve \${remote.${path}}: no integrations configured`,
304
+ `remote.${path}`
305
+ );
306
+ }
307
+ return void 0;
308
+ }
309
+ const integrations = context.config.integrations;
310
+ switch (path) {
311
+ case "documentation":
312
+ return integrations.documentation?.config?.base_url ?? integrations.documentation?.config?.base_path;
313
+ case "issues":
314
+ return integrations.issue_tracker?.config?.base_url;
315
+ case "git":
316
+ return integrations.git?.config?.repo;
317
+ case "state":
318
+ return integrations.state?.config?.base_path ?? integrations.state?.config?.bucket;
319
+ default:
320
+ return getNestedValue(integrations, path);
321
+ }
322
+ }
323
+ function resolveString(input, context, options = {}) {
324
+ return input.replace(VARIABLE_PATTERN, (match, variable) => {
325
+ const resolved = resolveVariable(variable, context, options);
326
+ return resolved !== void 0 ? resolved : match;
327
+ });
328
+ }
329
+ function hasVariables(input) {
330
+ const pattern = /\$\{([a-z_][a-z0-9_]*(?:\.[a-z_][a-z0-9_]*)*)\}/i;
331
+ return pattern.test(input);
332
+ }
333
+ function extractVariables(input) {
334
+ const matches = input.matchAll(VARIABLE_PATTERN);
335
+ return Array.from(matches, (m) => m[1]).filter((v) => v !== void 0);
336
+ }
337
+ function resolveObject(obj, context, options = {}) {
338
+ if (obj === null || obj === void 0) {
339
+ return obj;
340
+ }
341
+ if (typeof obj === "string") {
342
+ return resolveString(obj, context, options);
343
+ }
344
+ if (Array.isArray(obj)) {
345
+ return obj.map((item) => resolveObject(item, context, options));
346
+ }
347
+ if (typeof obj === "object") {
348
+ const result = {};
349
+ for (const [key, value] of Object.entries(obj)) {
350
+ result[key] = resolveObject(value, context, options);
351
+ }
352
+ return result;
353
+ }
354
+ return obj;
355
+ }
356
+ function resolveAgentDefinition(agent, config, options = {}) {
357
+ const context = {
358
+ agent
359
+ };
360
+ if (config) {
361
+ context.config = config;
362
+ }
363
+ return resolveObject(agent, context, options);
364
+ }
365
+
366
+ // src/agents/compiler.ts
367
+ import { existsSync as existsSync3, mkdirSync, writeFileSync } from "fs";
368
+ import { join as join3, dirname as dirname2 } from "path";
369
+ function generateAgentMarkdown(agent) {
370
+ const lines = [];
371
+ lines.push(`# ${agent.display_name}`);
372
+ lines.push("");
373
+ lines.push(`**Role:** ${agent.role}`);
374
+ lines.push(`**Type:** ${agent.type}`);
375
+ lines.push("");
376
+ lines.push("## Description");
377
+ lines.push("");
378
+ lines.push(agent.description.trim());
379
+ lines.push("");
380
+ if (agent.responsibilities && agent.responsibilities.length > 0) {
381
+ lines.push("## Responsibilities");
382
+ lines.push("");
383
+ for (const responsibility of agent.responsibilities) {
384
+ lines.push(`- ${responsibility}`);
385
+ }
386
+ lines.push("");
387
+ }
388
+ if (agent.expertise) {
389
+ lines.push("## Expertise");
390
+ lines.push("");
391
+ if (agent.expertise.primary && agent.expertise.primary.length > 0) {
392
+ lines.push("### Primary Areas");
393
+ lines.push("");
394
+ for (const area of agent.expertise.primary) {
395
+ lines.push(`- ${area}`);
396
+ }
397
+ lines.push("");
398
+ }
399
+ if (agent.expertise.tech_stack) {
400
+ lines.push("### Tech Stack");
401
+ lines.push("");
402
+ const techStack = agent.expertise.tech_stack;
403
+ if (typeof techStack === "string") {
404
+ lines.push(techStack);
405
+ } else if (typeof techStack === "object") {
406
+ lines.push("```json");
407
+ lines.push(JSON.stringify(techStack, null, 2));
408
+ lines.push("```");
409
+ }
410
+ lines.push("");
411
+ }
412
+ }
413
+ if (agent.skills && agent.skills.length > 0) {
414
+ lines.push("## Skills");
415
+ lines.push("");
416
+ for (const skill of agent.skills) {
417
+ lines.push(`- ${skill}`);
418
+ }
419
+ lines.push("");
420
+ }
421
+ if (agent.principles) {
422
+ lines.push("## Principles");
423
+ lines.push("");
424
+ for (const [category, items] of Object.entries(agent.principles)) {
425
+ if (items && Array.isArray(items) && items.length > 0) {
426
+ const title = formatTitle(category);
427
+ lines.push(`### ${title}`);
428
+ lines.push("");
429
+ for (const item of items) {
430
+ lines.push(`- ${item}`);
431
+ }
432
+ lines.push("");
433
+ }
434
+ }
435
+ }
436
+ if (agent.behaviors) {
437
+ lines.push("## Behaviors");
438
+ lines.push("");
439
+ if (agent.behaviors.workflow) {
440
+ lines.push(`**Workflow:** ${agent.behaviors.workflow}`);
441
+ lines.push("");
442
+ }
443
+ if (agent.behaviors.quality_gates) {
444
+ lines.push("### Quality Gates");
445
+ lines.push("");
446
+ const gates = agent.behaviors.quality_gates;
447
+ if (typeof gates === "string") {
448
+ lines.push(gates);
449
+ } else if (typeof gates === "object") {
450
+ lines.push("```json");
451
+ lines.push(JSON.stringify(gates, null, 2));
452
+ lines.push("```");
453
+ }
454
+ lines.push("");
455
+ }
456
+ }
457
+ if (agent.context_sources) {
458
+ lines.push("## Context Sources");
459
+ lines.push("");
460
+ if (agent.context_sources.shared && agent.context_sources.shared.length > 0) {
461
+ lines.push("### Shared");
462
+ lines.push("");
463
+ for (const source of agent.context_sources.shared) {
464
+ lines.push(`- ${source}`);
465
+ }
466
+ lines.push("");
467
+ }
468
+ if (agent.context_sources.personal && agent.context_sources.personal.length > 0) {
469
+ lines.push("### Personal");
470
+ lines.push("");
471
+ for (const source of agent.context_sources.personal) {
472
+ lines.push(`- ${source}`);
473
+ }
474
+ lines.push("");
475
+ }
476
+ }
477
+ if (agent.communication) {
478
+ lines.push("## Communication");
479
+ lines.push("");
480
+ if (agent.communication.inbox) {
481
+ lines.push(`**Inbox:** ${agent.communication.inbox}`);
482
+ }
483
+ if (agent.communication.outbox) {
484
+ lines.push(`**Outbox:** ${agent.communication.outbox}`);
485
+ }
486
+ lines.push("");
487
+ }
488
+ lines.push("---");
489
+ lines.push("");
490
+ lines.push("*Generated by CoreAI*");
491
+ lines.push("");
492
+ return lines.join("\n");
493
+ }
494
+ function formatTitle(str) {
495
+ return str.replace(/[_-]/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
496
+ }
497
+ function compileAgent(agent, config) {
498
+ const resolved = resolveAgentDefinition(agent, config);
499
+ return generateAgentMarkdown(resolved);
500
+ }
501
+ function loadAllAgents(options = {}) {
502
+ const agents = /* @__PURE__ */ new Map();
503
+ if (options.coreAgentsDir && existsSync3(options.coreAgentsDir)) {
504
+ const coreAgents = loadAgentsFromDirectory(options.coreAgentsDir, "core");
505
+ for (const [role, metadata] of coreAgents) {
506
+ agents.set(role, metadata);
507
+ }
508
+ }
509
+ if (options.customAgentsDir && existsSync3(options.customAgentsDir)) {
510
+ const customAgents = loadAgentsFromDirectory(options.customAgentsDir, "custom");
511
+ for (const [role, metadata] of customAgents) {
512
+ if (agents.has(role)) {
513
+ metadata.source = "override";
514
+ }
515
+ agents.set(role, metadata);
516
+ }
517
+ }
518
+ return agents;
519
+ }
520
+ function filterAgentsByTeam(agents, config) {
521
+ if (!config?.team?.agents || config.team.agents.length === 0) {
522
+ return agents;
523
+ }
524
+ const filtered = /* @__PURE__ */ new Map();
525
+ for (const role of config.team.agents) {
526
+ const metadata = agents.get(role);
527
+ if (metadata) {
528
+ filtered.set(role, metadata);
529
+ }
530
+ }
531
+ return filtered;
532
+ }
533
+ function compileAgents(config, options = {}) {
534
+ const projectRoot = options.projectRoot ?? process.cwd();
535
+ const outputDir = options.outputDir ?? join3(projectRoot, ".claude", "agents");
536
+ const customAgentsDir = options.customAgentsDir ?? join3(projectRoot, "coreai", "agents");
537
+ const result = {
538
+ compiled: [],
539
+ errors: []
540
+ };
541
+ const allAgents = loadAllAgents({
542
+ ...options,
543
+ customAgentsDir
544
+ });
545
+ const agents = filterAgentsByTeam(allAgents, config);
546
+ if (!existsSync3(outputDir)) {
547
+ mkdirSync(outputDir, { recursive: true });
548
+ }
549
+ for (const [role, metadata] of agents) {
550
+ if (options.filter && !options.filter(metadata.definition)) {
551
+ continue;
552
+ }
553
+ try {
554
+ const markdown = compileAgent(metadata.definition, config);
555
+ const outputPath = join3(outputDir, `${role}.md`);
556
+ writeFileSync(outputPath, markdown, "utf-8");
557
+ result.compiled.push({
558
+ role,
559
+ source: metadata.source,
560
+ outputPath
561
+ });
562
+ } catch (error) {
563
+ result.errors.push({
564
+ role,
565
+ source: metadata.source,
566
+ error: error instanceof Error ? error.message : String(error)
567
+ });
568
+ }
569
+ }
570
+ return result;
571
+ }
572
+ function getCoreAgentsDir() {
573
+ return join3(dirname2(dirname2(dirname2(import.meta.url.replace("file://", "")))), "agents");
574
+ }
575
+
576
+ // src/adapters/types.ts
577
+ var AdapterError = class extends Error {
578
+ code;
579
+ adapter;
580
+ constructor(message, code, adapter, cause) {
581
+ super(message, { cause });
582
+ this.name = "AdapterError";
583
+ this.code = code;
584
+ if (adapter) {
585
+ this.adapter = adapter;
586
+ }
587
+ }
588
+ };
589
+
590
+ // src/adapters/factory.ts
591
+ var AdapterFactory = class {
592
+ config;
593
+ adapters = /* @__PURE__ */ new Map();
594
+ /**
595
+ * Registry of adapter creators by type
596
+ */
597
+ creators = {
598
+ issue_tracker: {},
599
+ git: {},
600
+ documentation: {},
601
+ state: {}
602
+ };
603
+ constructor(config) {
604
+ this.config = config;
605
+ }
606
+ /**
607
+ * Register an adapter creator
608
+ */
609
+ registerCreator(type, implementation, creator) {
610
+ const typeCreators = this.creators[type];
611
+ typeCreators[implementation] = creator;
612
+ }
613
+ /**
614
+ * Get an issue tracker adapter
615
+ */
616
+ async getIssueTracker(options) {
617
+ return this.getAdapter("issue_tracker", options);
618
+ }
619
+ /**
620
+ * Get a git provider adapter
621
+ */
622
+ async getGitProvider(options) {
623
+ return this.getAdapter("git", options);
624
+ }
625
+ /**
626
+ * Get a documentation provider adapter
627
+ */
628
+ async getDocumentationProvider(options) {
629
+ return this.getAdapter("documentation", options);
630
+ }
631
+ /**
632
+ * Get a state provider adapter
633
+ */
634
+ async getStateProvider(options) {
635
+ return this.getAdapter("state", options);
636
+ }
637
+ /**
638
+ * Get an adapter by type
639
+ */
640
+ async getAdapter(type, options) {
641
+ const cached = this.adapters.get(type);
642
+ if (cached && cached.isConnected()) {
643
+ return cached;
644
+ }
645
+ const strategy = this.getStrategy(type, options);
646
+ const implementation = options?.implementation ?? this.selectImplementation(type, strategy);
647
+ const adapter = await this.createAdapter(type, implementation);
648
+ this.adapters.set(type, adapter);
649
+ return adapter;
650
+ }
651
+ /**
652
+ * Check if an adapter type is configured
653
+ */
654
+ hasIntegration(type) {
655
+ const integrations = this.config.integrations;
656
+ if (!integrations) return false;
657
+ switch (type) {
658
+ case "issue_tracker":
659
+ return !!integrations.issue_tracker?.provider;
660
+ case "git":
661
+ return !!integrations.git?.provider;
662
+ case "documentation":
663
+ return !!integrations.documentation?.provider;
664
+ case "state":
665
+ return !!integrations.state?.provider;
666
+ default:
667
+ return false;
668
+ }
669
+ }
670
+ /**
671
+ * Get information about a configured integration
672
+ */
673
+ getIntegrationInfo(type) {
674
+ const integrations = this.config.integrations;
675
+ if (!integrations) return null;
676
+ let integration;
677
+ switch (type) {
678
+ case "issue_tracker":
679
+ integration = integrations.issue_tracker;
680
+ break;
681
+ case "git":
682
+ integration = integrations.git;
683
+ break;
684
+ case "documentation":
685
+ integration = integrations.documentation;
686
+ break;
687
+ case "state":
688
+ integration = integrations.state;
689
+ break;
690
+ }
691
+ if (!integration?.provider) return null;
692
+ return {
693
+ provider: integration.provider,
694
+ strategy: integration.strategy ?? "auto"
695
+ };
696
+ }
697
+ /**
698
+ * Disconnect and clear all cached adapters
699
+ */
700
+ async disconnectAll() {
701
+ const disconnects = [];
702
+ for (const adapter of this.adapters.values()) {
703
+ if (adapter.isConnected()) {
704
+ disconnects.push(adapter.disconnect());
705
+ }
706
+ }
707
+ await Promise.all(disconnects);
708
+ this.adapters.clear();
709
+ }
710
+ /**
711
+ * Get the strategy for an adapter type
712
+ */
713
+ getStrategy(type, options) {
714
+ if (options?.strategy) {
715
+ return options.strategy;
716
+ }
717
+ const info = this.getIntegrationInfo(type);
718
+ return info?.strategy ?? "auto";
719
+ }
720
+ /**
721
+ * Select the implementation based on strategy and availability
722
+ */
723
+ selectImplementation(type, strategy) {
724
+ const creators = this.creators[type];
725
+ switch (strategy) {
726
+ case "mcp":
727
+ if (creators.mcp) return "mcp";
728
+ throw new AdapterError(
729
+ `MCP adapter not available for ${type}`,
730
+ "not_implemented",
731
+ void 0
732
+ );
733
+ case "native":
734
+ if (creators.native) return "native";
735
+ throw new AdapterError(
736
+ `Native adapter not available for ${type}`,
737
+ "not_implemented",
738
+ void 0
739
+ );
740
+ case "auto":
741
+ default:
742
+ if (creators.mcp) return "mcp";
743
+ if (creators.native) return "native";
744
+ if (creators.mock) return "mock";
745
+ throw new AdapterError(
746
+ `No adapter implementation available for ${type}`,
747
+ "not_implemented",
748
+ void 0
749
+ );
750
+ }
751
+ }
752
+ /**
753
+ * Create an adapter instance
754
+ */
755
+ async createAdapter(type, implementation) {
756
+ const creators = this.creators[type];
757
+ const creator = creators[implementation];
758
+ if (!creator) {
759
+ throw new AdapterError(
760
+ `No ${implementation} adapter creator registered for ${type}`,
761
+ "not_implemented",
762
+ void 0
763
+ );
764
+ }
765
+ const adapter = await creator(this.config);
766
+ await adapter.connect();
767
+ return adapter;
768
+ }
769
+ };
770
+ function createAdapterFactory(config) {
771
+ return new AdapterFactory(config);
772
+ }
773
+ function createAdapterInfo(type, provider, implementation, connected = false) {
774
+ return {
775
+ type,
776
+ provider,
777
+ implementation,
778
+ connected
779
+ };
780
+ }
781
+
782
+ // src/adapters/mcp/client.ts
783
+ import { Client } from "@modelcontextprotocol/sdk/client/index.js";
784
+ import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
785
+
786
+ // src/adapters/native/github.ts
787
+ import { execFile } from "child_process";
788
+ import { promisify } from "util";
789
+ var execFileAsync = promisify(execFile);
790
+
791
+ // src/cache/types.ts
792
+ var CacheError = class extends Error {
793
+ constructor(message, code, key, cause) {
794
+ super(message);
795
+ this.code = code;
796
+ this.key = key;
797
+ this.cause = cause;
798
+ this.name = "CacheError";
799
+ }
800
+ };
801
+ var CACHE_PATHS = {
802
+ /**
803
+ * Root cache directory (relative to project root)
804
+ */
805
+ ROOT: ".coreai/cache",
806
+ /**
807
+ * Content storage directory
808
+ */
809
+ CONTENT: ".coreai/cache/content",
810
+ /**
811
+ * Metadata storage directory
812
+ */
813
+ METADATA: ".coreai/cache/metadata",
814
+ /**
815
+ * Index file for fast lookups
816
+ */
817
+ INDEX: ".coreai/cache/index.json",
818
+ /**
819
+ * Lock file for concurrent access
820
+ */
821
+ LOCK: ".coreai/cache/.lock"
822
+ };
823
+ var DEFAULT_CACHE_CONFIG = {
824
+ /**
825
+ * Default TTL in seconds (1 hour)
826
+ */
827
+ ttl: 3600,
828
+ /**
829
+ * Maximum cache size in bytes (100MB)
830
+ */
831
+ maxSize: 100 * 1024 * 1024,
832
+ /**
833
+ * Maximum number of entries
834
+ */
835
+ maxEntries: 1e3,
836
+ /**
837
+ * Enable automatic cleanup of expired entries
838
+ */
839
+ autoCleanup: true,
840
+ /**
841
+ * Cleanup interval in seconds (1 hour)
842
+ */
843
+ cleanupInterval: 3600
844
+ };
845
+
846
+ // src/cache/provider.ts
847
+ import { promises as fs } from "fs";
848
+ import { join as join4, dirname as dirname3 } from "path";
849
+ import { createHash } from "crypto";
850
+ function noop() {
851
+ }
852
+ var INDEX_VERSION = 1;
853
+ var FileCacheProvider = class {
854
+ basePath;
855
+ cachePath;
856
+ contentPath;
857
+ metadataPath;
858
+ indexPath;
859
+ ttl;
860
+ maxSize;
861
+ maxEntries;
862
+ initialized = false;
863
+ index = null;
864
+ constructor(options) {
865
+ this.basePath = options.basePath;
866
+ this.cachePath = join4(this.basePath, CACHE_PATHS.ROOT);
867
+ this.contentPath = join4(this.basePath, CACHE_PATHS.CONTENT);
868
+ this.metadataPath = join4(this.basePath, CACHE_PATHS.METADATA);
869
+ this.indexPath = join4(this.basePath, CACHE_PATHS.INDEX);
870
+ this.ttl = options.ttl ?? DEFAULT_CACHE_CONFIG.ttl;
871
+ this.maxSize = options.maxSize ?? DEFAULT_CACHE_CONFIG.maxSize;
872
+ this.maxEntries = options.maxEntries ?? DEFAULT_CACHE_CONFIG.maxEntries;
873
+ }
874
+ /**
875
+ * Initialize the cache (create directories, load index)
876
+ */
877
+ async initialize() {
878
+ if (this.initialized) return;
879
+ try {
880
+ await fs.mkdir(this.contentPath, { recursive: true });
881
+ await fs.mkdir(this.metadataPath, { recursive: true });
882
+ this.index = await this.loadIndex();
883
+ await this.saveIndex();
884
+ this.initialized = true;
885
+ } catch (error) {
886
+ throw new CacheError(
887
+ `Failed to initialize cache: ${error instanceof Error ? error.message : String(error)}`,
888
+ "write_failed",
889
+ void 0,
890
+ error instanceof Error ? error : void 0
891
+ );
892
+ }
893
+ }
894
+ /**
895
+ * Check if the cache is initialized
896
+ */
897
+ isInitialized() {
898
+ return this.initialized;
899
+ }
900
+ /**
901
+ * Get a cached entry by key
902
+ */
903
+ async get(key, options) {
904
+ this.ensureInitialized();
905
+ if (options?.skipCache) {
906
+ return null;
907
+ }
908
+ const indexEntry = this.index?.entries[key];
909
+ if (!indexEntry) {
910
+ return null;
911
+ }
912
+ if (!options?.forceRefresh) {
913
+ const status = this.getEntryStatus(indexEntry);
914
+ if (status === "expired") {
915
+ return null;
916
+ }
917
+ }
918
+ try {
919
+ const metadataContent = await fs.readFile(indexEntry.metadataFile, "utf-8");
920
+ const metadata = JSON.parse(metadataContent);
921
+ const contentRaw = await fs.readFile(indexEntry.contentFile, "utf-8");
922
+ let content;
923
+ if (metadata.contentType.includes("json")) {
924
+ content = JSON.parse(contentRaw);
925
+ } else {
926
+ content = contentRaw;
927
+ }
928
+ return { metadata, content };
929
+ } catch {
930
+ await this.delete(key);
931
+ return null;
932
+ }
933
+ }
934
+ /**
935
+ * Get the content only (convenience method)
936
+ */
937
+ async getContent(key, options) {
938
+ const entry = await this.get(key, options);
939
+ return entry?.content ?? null;
940
+ }
941
+ /**
942
+ * Set a cache entry
943
+ */
944
+ async set(key, content, metadata, options) {
945
+ this.ensureInitialized();
946
+ const now = /* @__PURE__ */ new Date();
947
+ const ttl = options?.ttl ?? this.ttl;
948
+ const expiresAt = new Date(now.getTime() + ttl * 1e3);
949
+ const contentStr = typeof content === "string" ? content : JSON.stringify(content, null, 2);
950
+ const contentHash = this.hashContent(contentStr);
951
+ const size = Buffer.byteLength(contentStr, "utf-8");
952
+ const safeKey = this.sanitizeKey(key);
953
+ const contentFile = join4(this.contentPath, `${safeKey}.cache`);
954
+ const metadataFile = join4(this.metadataPath, `${safeKey}.json`);
955
+ const fullMetadata = {
956
+ key,
957
+ source: metadata.source ?? "custom",
958
+ sourceUrl: metadata.sourceUrl ?? "",
959
+ cachedAt: now.toISOString(),
960
+ expiresAt: expiresAt.toISOString(),
961
+ contentHash,
962
+ size,
963
+ contentType: metadata.contentType ?? (typeof content === "string" ? "text/plain" : "application/json")
964
+ };
965
+ if (metadata.etag) {
966
+ fullMetadata.etag = metadata.etag;
967
+ }
968
+ if (metadata.title) {
969
+ fullMetadata.title = metadata.title;
970
+ }
971
+ if (metadata.lastModified) {
972
+ fullMetadata.lastModified = metadata.lastModified;
973
+ }
974
+ const tags = options?.tags ?? metadata.tags;
975
+ if (tags) {
976
+ fullMetadata.tags = tags;
977
+ }
978
+ try {
979
+ await fs.mkdir(dirname3(contentFile), { recursive: true });
980
+ await fs.mkdir(dirname3(metadataFile), { recursive: true });
981
+ await fs.writeFile(contentFile, contentStr, "utf-8");
982
+ await fs.writeFile(metadataFile, JSON.stringify(fullMetadata, null, 2), "utf-8");
983
+ if (this.index) {
984
+ const oldEntry = this.index.entries[key];
985
+ if (oldEntry) {
986
+ this.index.stats.totalSize -= oldEntry.size;
987
+ } else {
988
+ this.index.stats.entryCount++;
989
+ }
990
+ this.index.entries[key] = {
991
+ key,
992
+ source: fullMetadata.source,
993
+ cachedAt: fullMetadata.cachedAt,
994
+ expiresAt: fullMetadata.expiresAt,
995
+ size,
996
+ contentFile,
997
+ metadataFile
998
+ };
999
+ this.index.stats.totalSize += size;
1000
+ await this.saveIndex();
1001
+ }
1002
+ } catch (error) {
1003
+ throw new CacheError(
1004
+ `Failed to write cache entry: ${error instanceof Error ? error.message : String(error)}`,
1005
+ "write_failed",
1006
+ key,
1007
+ error instanceof Error ? error : void 0
1008
+ );
1009
+ }
1010
+ }
1011
+ /**
1012
+ * Check if a key exists in the cache
1013
+ */
1014
+ async has(key) {
1015
+ this.ensureInitialized();
1016
+ return key in (this.index?.entries ?? {});
1017
+ }
1018
+ /**
1019
+ * Delete a cache entry
1020
+ */
1021
+ async delete(key) {
1022
+ this.ensureInitialized();
1023
+ const indexEntry = this.index?.entries[key];
1024
+ if (!indexEntry) {
1025
+ return false;
1026
+ }
1027
+ try {
1028
+ await fs.unlink(indexEntry.contentFile).catch(noop);
1029
+ await fs.unlink(indexEntry.metadataFile).catch(noop);
1030
+ if (this.index) {
1031
+ this.index.stats.totalSize -= indexEntry.size;
1032
+ this.index.stats.entryCount--;
1033
+ const { [key]: _removed, ...remaining } = this.index.entries;
1034
+ this.index.entries = remaining;
1035
+ await this.saveIndex();
1036
+ }
1037
+ return true;
1038
+ } catch (error) {
1039
+ throw new CacheError(
1040
+ `Failed to delete cache entry: ${error instanceof Error ? error.message : String(error)}`,
1041
+ "write_failed",
1042
+ key,
1043
+ error instanceof Error ? error : void 0
1044
+ );
1045
+ }
1046
+ }
1047
+ /**
1048
+ * Get the status of a cache entry
1049
+ */
1050
+ async getStatus(key) {
1051
+ this.ensureInitialized();
1052
+ const indexEntry = this.index?.entries[key];
1053
+ if (!indexEntry) {
1054
+ return null;
1055
+ }
1056
+ return this.getEntryStatus(indexEntry);
1057
+ }
1058
+ /**
1059
+ * Get metadata for a cache entry
1060
+ */
1061
+ async getMetadata(key) {
1062
+ this.ensureInitialized();
1063
+ const indexEntry = this.index?.entries[key];
1064
+ if (!indexEntry) {
1065
+ return null;
1066
+ }
1067
+ try {
1068
+ const content = await fs.readFile(indexEntry.metadataFile, "utf-8");
1069
+ return JSON.parse(content);
1070
+ } catch {
1071
+ return null;
1072
+ }
1073
+ }
1074
+ /**
1075
+ * Update metadata for a cache entry
1076
+ */
1077
+ async updateMetadata(key, metadata) {
1078
+ this.ensureInitialized();
1079
+ const existing = await this.getMetadata(key);
1080
+ if (!existing) {
1081
+ throw new CacheError(`Cache entry not found: ${key}`, "not_found", key);
1082
+ }
1083
+ const indexEntry = this.index?.entries[key];
1084
+ if (!indexEntry) {
1085
+ throw new CacheError(`Cache entry not found: ${key}`, "not_found", key);
1086
+ }
1087
+ const updated = {
1088
+ ...existing,
1089
+ ...metadata,
1090
+ key: existing.key
1091
+ // Can't change key
1092
+ };
1093
+ try {
1094
+ await fs.writeFile(indexEntry.metadataFile, JSON.stringify(updated, null, 2), "utf-8");
1095
+ if (this.index && indexEntry) {
1096
+ if (metadata.source) indexEntry.source = metadata.source;
1097
+ if (metadata.expiresAt) indexEntry.expiresAt = metadata.expiresAt;
1098
+ await this.saveIndex();
1099
+ }
1100
+ } catch (error) {
1101
+ throw new CacheError(
1102
+ `Failed to update metadata: ${error instanceof Error ? error.message : String(error)}`,
1103
+ "write_failed",
1104
+ key,
1105
+ error instanceof Error ? error : void 0
1106
+ );
1107
+ }
1108
+ }
1109
+ /**
1110
+ * List cache entries
1111
+ */
1112
+ async list(options) {
1113
+ this.ensureInitialized();
1114
+ if (!this.index) return [];
1115
+ let entries = Object.values(this.index.entries);
1116
+ if (options?.source) {
1117
+ entries = entries.filter((e) => e.source === options.source);
1118
+ }
1119
+ if (options?.status) {
1120
+ entries = entries.filter((e) => this.getEntryStatus(e) === options.status);
1121
+ }
1122
+ const metadataPromises = entries.map(async (e) => {
1123
+ const metadata = await this.getMetadata(e.key);
1124
+ return metadata;
1125
+ });
1126
+ let results = (await Promise.all(metadataPromises)).filter(
1127
+ (m) => m !== null
1128
+ );
1129
+ if (options?.tag) {
1130
+ const tag = options.tag;
1131
+ results = results.filter((m) => m.tags?.includes(tag));
1132
+ }
1133
+ if (options?.limit && results.length > options.limit) {
1134
+ results = results.slice(0, options.limit);
1135
+ }
1136
+ return results;
1137
+ }
1138
+ /**
1139
+ * Get cache statistics
1140
+ */
1141
+ async getStats() {
1142
+ this.ensureInitialized();
1143
+ if (!this.index) {
1144
+ return {
1145
+ totalEntries: 0,
1146
+ totalSize: 0,
1147
+ validEntries: 0,
1148
+ staleEntries: 0,
1149
+ expiredEntries: 0,
1150
+ bySource: {
1151
+ confluence: 0,
1152
+ github: 0,
1153
+ notion: 0,
1154
+ local: 0,
1155
+ custom: 0
1156
+ }
1157
+ };
1158
+ }
1159
+ const entries = Object.values(this.index.entries);
1160
+ const bySource = {
1161
+ confluence: 0,
1162
+ github: 0,
1163
+ notion: 0,
1164
+ local: 0,
1165
+ custom: 0
1166
+ };
1167
+ let validEntries = 0;
1168
+ let staleEntries = 0;
1169
+ let expiredEntries = 0;
1170
+ let oldestEntry;
1171
+ let newestEntry;
1172
+ for (const entry of entries) {
1173
+ bySource[entry.source]++;
1174
+ const status = this.getEntryStatus(entry);
1175
+ if (status === "valid") validEntries++;
1176
+ else if (status === "stale") staleEntries++;
1177
+ else if (status === "expired") expiredEntries++;
1178
+ if (!oldestEntry || entry.cachedAt < oldestEntry) {
1179
+ oldestEntry = entry.cachedAt;
1180
+ }
1181
+ if (!newestEntry || entry.cachedAt > newestEntry) {
1182
+ newestEntry = entry.cachedAt;
1183
+ }
1184
+ }
1185
+ const stats = {
1186
+ totalEntries: this.index.stats.entryCount,
1187
+ totalSize: this.index.stats.totalSize,
1188
+ validEntries,
1189
+ staleEntries,
1190
+ expiredEntries,
1191
+ bySource
1192
+ };
1193
+ if (oldestEntry) stats.oldestEntry = oldestEntry;
1194
+ if (newestEntry) stats.newestEntry = newestEntry;
1195
+ return stats;
1196
+ }
1197
+ /**
1198
+ * Clear all cache entries
1199
+ */
1200
+ async clear() {
1201
+ this.ensureInitialized();
1202
+ if (!this.index) return 0;
1203
+ const count = this.index.stats.entryCount;
1204
+ try {
1205
+ await fs.rm(this.contentPath, { recursive: true, force: true });
1206
+ await fs.rm(this.metadataPath, { recursive: true, force: true });
1207
+ await fs.mkdir(this.contentPath, { recursive: true });
1208
+ await fs.mkdir(this.metadataPath, { recursive: true });
1209
+ this.index = this.createEmptyIndex();
1210
+ await this.saveIndex();
1211
+ return count;
1212
+ } catch (error) {
1213
+ throw new CacheError(
1214
+ `Failed to clear cache: ${error instanceof Error ? error.message : String(error)}`,
1215
+ "write_failed",
1216
+ void 0,
1217
+ error instanceof Error ? error : void 0
1218
+ );
1219
+ }
1220
+ }
1221
+ /**
1222
+ * Clear expired entries only
1223
+ */
1224
+ async clearExpired() {
1225
+ this.ensureInitialized();
1226
+ if (!this.index) return 0;
1227
+ const expiredKeys = Object.entries(this.index.entries).filter(([, entry]) => this.getEntryStatus(entry) === "expired").map(([key]) => key);
1228
+ for (const key of expiredKeys) {
1229
+ await this.delete(key);
1230
+ }
1231
+ if (this.index) {
1232
+ this.index.stats.lastCleanup = (/* @__PURE__ */ new Date()).toISOString();
1233
+ await this.saveIndex();
1234
+ }
1235
+ return expiredKeys.length;
1236
+ }
1237
+ /**
1238
+ * Clear entries by source
1239
+ */
1240
+ async clearBySource(source) {
1241
+ this.ensureInitialized();
1242
+ if (!this.index) return 0;
1243
+ const keys = Object.entries(this.index.entries).filter(([, entry]) => entry.source === source).map(([key]) => key);
1244
+ for (const key of keys) {
1245
+ await this.delete(key);
1246
+ }
1247
+ return keys.length;
1248
+ }
1249
+ /**
1250
+ * Clear entries by tag
1251
+ */
1252
+ async clearByTag(tag) {
1253
+ this.ensureInitialized();
1254
+ const entries = await this.list({ tag });
1255
+ for (const entry of entries) {
1256
+ await this.delete(entry.key);
1257
+ }
1258
+ return entries.length;
1259
+ }
1260
+ // Private helpers
1261
+ ensureInitialized() {
1262
+ if (!this.initialized) {
1263
+ throw new CacheError("Cache not initialized. Call initialize() first.", "invalid_config");
1264
+ }
1265
+ }
1266
+ async loadIndex() {
1267
+ try {
1268
+ const content = await fs.readFile(this.indexPath, "utf-8");
1269
+ const index = JSON.parse(content);
1270
+ if (index.version !== INDEX_VERSION) {
1271
+ return this.rebuildIndex();
1272
+ }
1273
+ return index;
1274
+ } catch {
1275
+ return this.createEmptyIndex();
1276
+ }
1277
+ }
1278
+ async saveIndex() {
1279
+ if (!this.index) return;
1280
+ try {
1281
+ await fs.writeFile(this.indexPath, JSON.stringify(this.index, null, 2), "utf-8");
1282
+ } catch (error) {
1283
+ throw new CacheError(
1284
+ `Failed to save cache index: ${error instanceof Error ? error.message : String(error)}`,
1285
+ "write_failed",
1286
+ void 0,
1287
+ error instanceof Error ? error : void 0
1288
+ );
1289
+ }
1290
+ }
1291
+ createEmptyIndex() {
1292
+ return {
1293
+ version: INDEX_VERSION,
1294
+ entries: {},
1295
+ stats: {
1296
+ totalSize: 0,
1297
+ entryCount: 0,
1298
+ lastCleanup: null
1299
+ }
1300
+ };
1301
+ }
1302
+ async rebuildIndex() {
1303
+ const index = this.createEmptyIndex();
1304
+ try {
1305
+ const metadataFiles = await fs.readdir(this.metadataPath);
1306
+ for (const file of metadataFiles) {
1307
+ if (!file.endsWith(".json")) continue;
1308
+ try {
1309
+ const metadataPath = join4(this.metadataPath, file);
1310
+ const content = await fs.readFile(metadataPath, "utf-8");
1311
+ const metadata = JSON.parse(content);
1312
+ const safeKey = this.sanitizeKey(metadata.key);
1313
+ const contentFile = join4(this.contentPath, `${safeKey}.cache`);
1314
+ await fs.access(contentFile);
1315
+ index.entries[metadata.key] = {
1316
+ key: metadata.key,
1317
+ source: metadata.source,
1318
+ cachedAt: metadata.cachedAt,
1319
+ expiresAt: metadata.expiresAt,
1320
+ size: metadata.size,
1321
+ contentFile,
1322
+ metadataFile: metadataPath
1323
+ };
1324
+ index.stats.totalSize += metadata.size;
1325
+ index.stats.entryCount++;
1326
+ } catch {
1327
+ }
1328
+ }
1329
+ } catch {
1330
+ }
1331
+ return index;
1332
+ }
1333
+ getEntryStatus(entry) {
1334
+ const now = /* @__PURE__ */ new Date();
1335
+ const expiresAt = new Date(entry.expiresAt);
1336
+ const cachedAt = new Date(entry.cachedAt);
1337
+ if (now > expiresAt) {
1338
+ return "expired";
1339
+ }
1340
+ const totalTtl = expiresAt.getTime() - cachedAt.getTime();
1341
+ const elapsed = now.getTime() - cachedAt.getTime();
1342
+ if (elapsed > totalTtl * 0.8) {
1343
+ return "stale";
1344
+ }
1345
+ return "valid";
1346
+ }
1347
+ sanitizeKey(key) {
1348
+ return createHash("sha256").update(key).digest("hex").substring(0, 32);
1349
+ }
1350
+ hashContent(content) {
1351
+ return createHash("sha256").update(content).digest("hex");
1352
+ }
1353
+ };
1354
+ function createFileCacheProvider(options) {
1355
+ return new FileCacheProvider(options);
1356
+ }
1357
+
1358
+ // src/cache/manager.ts
1359
+ var CacheManager = class {
1360
+ cache;
1361
+ fetchers = /* @__PURE__ */ new Map();
1362
+ defaultTtl;
1363
+ defaultSource;
1364
+ constructor(options) {
1365
+ this.cache = options.cache;
1366
+ this.defaultTtl = options.defaultTtl ?? 3600;
1367
+ this.defaultSource = options.defaultSource ?? "custom";
1368
+ }
1369
+ /**
1370
+ * Get content with cache-first strategy
1371
+ */
1372
+ async getWithFallback(key, url, options) {
1373
+ if (!options?.skipCache && !options?.forceRefresh) {
1374
+ const cached = await this.cache.get(key);
1375
+ if (cached) {
1376
+ const status = await this.cache.getStatus(key);
1377
+ if (status === "valid") {
1378
+ return cached;
1379
+ }
1380
+ if (status === "stale") {
1381
+ try {
1382
+ return await this.fetchAndCache(key, url, options);
1383
+ } catch {
1384
+ return cached;
1385
+ }
1386
+ }
1387
+ }
1388
+ }
1389
+ return this.fetchAndCache(key, url, options);
1390
+ }
1391
+ /**
1392
+ * Sync all entries from a source
1393
+ */
1394
+ async syncSource(source, options) {
1395
+ const startTime = Date.now();
1396
+ const result = {
1397
+ added: 0,
1398
+ updated: 0,
1399
+ removed: 0,
1400
+ failed: 0,
1401
+ errors: [],
1402
+ duration: 0
1403
+ };
1404
+ const entries = await this.cache.list({ source });
1405
+ const concurrency = options?.concurrency ?? 5;
1406
+ const chunks = this.chunkArray(entries, concurrency);
1407
+ for (const chunk of chunks) {
1408
+ const promises = chunk.map(async (entry) => {
1409
+ try {
1410
+ const fetcher = this.fetchers.get(source);
1411
+ if (!fetcher) {
1412
+ throw new Error(`No fetcher registered for source: ${source}`);
1413
+ }
1414
+ const hasChanged = await fetcher.hasChanged(entry.sourceUrl, entry.etag);
1415
+ if (hasChanged || options?.force) {
1416
+ const fetchOptions = {};
1417
+ if (entry.etag) {
1418
+ fetchOptions.etag = entry.etag;
1419
+ }
1420
+ const { content, metadata } = await fetcher.fetch(entry.sourceUrl, fetchOptions);
1421
+ await this.cache.set(entry.key, content, {
1422
+ ...entry,
1423
+ ...metadata
1424
+ });
1425
+ result.updated++;
1426
+ }
1427
+ } catch (error) {
1428
+ result.failed++;
1429
+ result.errors.push({
1430
+ key: entry.key,
1431
+ error: error instanceof Error ? error.message : String(error)
1432
+ });
1433
+ if (!options?.continueOnError) {
1434
+ throw error;
1435
+ }
1436
+ }
1437
+ });
1438
+ await Promise.all(promises);
1439
+ }
1440
+ if (options?.onProgress) {
1441
+ options.onProgress(entries.length, entries.length);
1442
+ }
1443
+ result.duration = Date.now() - startTime;
1444
+ return result;
1445
+ }
1446
+ /**
1447
+ * Sync specific entries
1448
+ */
1449
+ async syncEntries(keys, options) {
1450
+ const startTime = Date.now();
1451
+ const result = {
1452
+ added: 0,
1453
+ updated: 0,
1454
+ removed: 0,
1455
+ failed: 0,
1456
+ errors: [],
1457
+ duration: 0
1458
+ };
1459
+ const concurrency = options?.concurrency ?? 5;
1460
+ const chunks = this.chunkArray(keys, concurrency);
1461
+ for (const chunk of chunks) {
1462
+ const promises = chunk.map(async (key) => {
1463
+ try {
1464
+ const metadata = await this.cache.getMetadata(key);
1465
+ if (!metadata) {
1466
+ result.failed++;
1467
+ result.errors.push({ key, error: "Entry not found in cache" });
1468
+ return;
1469
+ }
1470
+ const fetcher = this.fetchers.get(metadata.source);
1471
+ if (!fetcher) {
1472
+ result.failed++;
1473
+ result.errors.push({ key, error: `No fetcher for source: ${metadata.source}` });
1474
+ return;
1475
+ }
1476
+ const hasChanged = await fetcher.hasChanged(metadata.sourceUrl, metadata.etag);
1477
+ if (hasChanged || options?.force) {
1478
+ const fetchOpts = {};
1479
+ if (metadata.etag) {
1480
+ fetchOpts.etag = metadata.etag;
1481
+ }
1482
+ const { content, metadata: newMeta } = await fetcher.fetch(
1483
+ metadata.sourceUrl,
1484
+ fetchOpts
1485
+ );
1486
+ await this.cache.set(key, content, {
1487
+ ...metadata,
1488
+ ...newMeta
1489
+ });
1490
+ result.updated++;
1491
+ }
1492
+ } catch (error) {
1493
+ result.failed++;
1494
+ result.errors.push({
1495
+ key,
1496
+ error: error instanceof Error ? error.message : String(error)
1497
+ });
1498
+ if (!options?.continueOnError) {
1499
+ throw error;
1500
+ }
1501
+ }
1502
+ });
1503
+ await Promise.all(promises);
1504
+ }
1505
+ if (options?.onProgress) {
1506
+ options.onProgress(keys.length, keys.length);
1507
+ }
1508
+ result.duration = Date.now() - startTime;
1509
+ return result;
1510
+ }
1511
+ /**
1512
+ * Register a fetcher for a source
1513
+ */
1514
+ registerFetcher(source, fetcher) {
1515
+ this.fetchers.set(source, fetcher);
1516
+ }
1517
+ /**
1518
+ * Get the underlying cache provider
1519
+ */
1520
+ getCache() {
1521
+ return this.cache;
1522
+ }
1523
+ /**
1524
+ * Check if a fetcher is registered for a source
1525
+ */
1526
+ hasFetcher(source) {
1527
+ return this.fetchers.has(source);
1528
+ }
1529
+ /**
1530
+ * Get all registered sources
1531
+ */
1532
+ getRegisteredSources() {
1533
+ return Array.from(this.fetchers.keys());
1534
+ }
1535
+ // Private helpers
1536
+ async fetchAndCache(key, url, options) {
1537
+ const source = this.getSourceFromUrl(url);
1538
+ const fetcher = this.fetchers.get(source);
1539
+ if (!fetcher) {
1540
+ throw new CacheError(
1541
+ `No fetcher registered for source: ${source}. Register one with registerFetcher().`,
1542
+ "fetch_failed",
1543
+ key
1544
+ );
1545
+ }
1546
+ try {
1547
+ const fetchOpts = {};
1548
+ if (options?.timeout) {
1549
+ fetchOpts.timeout = options.timeout;
1550
+ }
1551
+ if (options?.headers) {
1552
+ fetchOpts.headers = options.headers;
1553
+ }
1554
+ const { content, metadata } = await fetcher.fetch(url, fetchOpts);
1555
+ const fullMetadata = {
1556
+ source,
1557
+ sourceUrl: url,
1558
+ contentType: metadata.contentType ?? "text/plain"
1559
+ };
1560
+ if (metadata.etag) {
1561
+ fullMetadata.etag = metadata.etag;
1562
+ }
1563
+ if (metadata.title) {
1564
+ fullMetadata.title = metadata.title;
1565
+ }
1566
+ if (metadata.lastModified) {
1567
+ fullMetadata.lastModified = metadata.lastModified;
1568
+ }
1569
+ if (options?.tags) {
1570
+ fullMetadata.tags = options.tags;
1571
+ }
1572
+ const cacheOpts = {
1573
+ ttl: options?.ttl ?? this.defaultTtl
1574
+ };
1575
+ if (options?.tags) {
1576
+ cacheOpts.tags = options.tags;
1577
+ }
1578
+ await this.cache.set(key, content, fullMetadata, cacheOpts);
1579
+ const entry = await this.cache.get(key);
1580
+ if (!entry) {
1581
+ throw new CacheError("Failed to retrieve cached entry after write", "read_failed", key);
1582
+ }
1583
+ return entry;
1584
+ } catch (error) {
1585
+ if (error instanceof CacheError) {
1586
+ throw error;
1587
+ }
1588
+ throw new CacheError(
1589
+ `Failed to fetch content: ${error instanceof Error ? error.message : String(error)}`,
1590
+ "fetch_failed",
1591
+ key,
1592
+ error instanceof Error ? error : void 0
1593
+ );
1594
+ }
1595
+ }
1596
+ getSourceFromUrl(url) {
1597
+ try {
1598
+ const parsed = new URL(url);
1599
+ const hostname = parsed.hostname.toLowerCase();
1600
+ if (hostname.includes("confluence") || hostname.includes("atlassian.net")) {
1601
+ return "confluence";
1602
+ }
1603
+ if (hostname.includes("github.com") || hostname.includes("github")) {
1604
+ return "github";
1605
+ }
1606
+ if (hostname.includes("notion.so") || hostname.includes("notion")) {
1607
+ return "notion";
1608
+ }
1609
+ return this.defaultSource;
1610
+ } catch {
1611
+ return "local";
1612
+ }
1613
+ }
1614
+ chunkArray(array, size) {
1615
+ const chunks = [];
1616
+ for (let i = 0; i < array.length; i += size) {
1617
+ chunks.push(array.slice(i, i + size));
1618
+ }
1619
+ return chunks;
1620
+ }
1621
+ };
1622
+ function createCacheManager(options) {
1623
+ return new CacheManager(options);
1624
+ }
1625
+
1626
+ // src/context/loader.ts
1627
+ var ContextLoader = class {
1628
+ cacheManager;
1629
+ defaultTtl;
1630
+ failOnRequired;
1631
+ concurrency;
1632
+ constructor(options) {
1633
+ this.cacheManager = options.cacheManager;
1634
+ this.defaultTtl = options.defaultTtl ?? 3600;
1635
+ this.failOnRequired = options.failOnRequired ?? true;
1636
+ this.concurrency = options.concurrency ?? 5;
1637
+ }
1638
+ /**
1639
+ * Load a single context
1640
+ */
1641
+ async load(source, options) {
1642
+ try {
1643
+ const cacheOptions = {
1644
+ ...options,
1645
+ ttl: options?.ttl ?? this.defaultTtl
1646
+ };
1647
+ if (source.tags) {
1648
+ cacheOptions.tags = source.tags;
1649
+ }
1650
+ const entry = await this.cacheManager.getWithFallback(
1651
+ source.key,
1652
+ source.url,
1653
+ cacheOptions
1654
+ );
1655
+ return entry;
1656
+ } catch (error) {
1657
+ const message = error instanceof Error ? error.message : String(error);
1658
+ if (source.required && this.failOnRequired) {
1659
+ throw new Error(`Failed to load required context "${source.key}": ${message}`);
1660
+ }
1661
+ throw error;
1662
+ }
1663
+ }
1664
+ /**
1665
+ * Load multiple contexts
1666
+ */
1667
+ async loadMany(sources, options) {
1668
+ const startTime = Date.now();
1669
+ const result = {
1670
+ loaded: [],
1671
+ failed: [],
1672
+ duration: 0
1673
+ };
1674
+ const cacheStatuses = /* @__PURE__ */ new Map();
1675
+ for (const source of sources) {
1676
+ const status = await this.cacheManager.getCache().getStatus(source.key);
1677
+ cacheStatuses.set(source.key, status === "valid");
1678
+ }
1679
+ const chunks = this.chunkArray(sources, this.concurrency);
1680
+ let completed = 0;
1681
+ for (const chunk of chunks) {
1682
+ const promises = chunk.map(async (source) => {
1683
+ try {
1684
+ const itemCacheOptions = {
1685
+ ...options,
1686
+ ttl: options?.ttl ?? this.defaultTtl
1687
+ };
1688
+ if (source.tags) {
1689
+ itemCacheOptions.tags = source.tags;
1690
+ }
1691
+ const entry = await this.cacheManager.getWithFallback(
1692
+ source.key,
1693
+ source.url,
1694
+ itemCacheOptions
1695
+ );
1696
+ result.loaded.push({
1697
+ key: source.key,
1698
+ content: entry.content,
1699
+ fromCache: cacheStatuses.get(source.key) ?? false,
1700
+ metadata: entry.metadata
1701
+ });
1702
+ } catch (error) {
1703
+ const message = error instanceof Error ? error.message : String(error);
1704
+ result.failed.push({
1705
+ key: source.key,
1706
+ error: message,
1707
+ required: source.required ?? false
1708
+ });
1709
+ if (source.required && this.failOnRequired && !options?.continueOnError) {
1710
+ throw new Error(`Failed to load required context "${source.key}": ${message}`);
1711
+ }
1712
+ }
1713
+ });
1714
+ await Promise.all(promises);
1715
+ completed += chunk.length;
1716
+ if (options?.onProgress) {
1717
+ const currentKey = chunk[chunk.length - 1]?.key ?? "";
1718
+ options.onProgress(completed, sources.length, currentKey);
1719
+ }
1720
+ }
1721
+ result.duration = Date.now() - startTime;
1722
+ if (this.failOnRequired && !options?.continueOnError) {
1723
+ const requiredFailures = result.failed.filter((f) => f.required);
1724
+ if (requiredFailures.length > 0) {
1725
+ throw new Error(
1726
+ `Failed to load ${requiredFailures.length} required context(s): ${requiredFailures.map((f) => f.key).join(", ")}`
1727
+ );
1728
+ }
1729
+ }
1730
+ return result;
1731
+ }
1732
+ /**
1733
+ * Load contexts by tag
1734
+ */
1735
+ async loadByTag(tag, _options) {
1736
+ const startTime = Date.now();
1737
+ const result = {
1738
+ loaded: [],
1739
+ failed: [],
1740
+ duration: 0
1741
+ };
1742
+ const entries = await this.cacheManager.getCache().list({ tag });
1743
+ for (const entry of entries) {
1744
+ try {
1745
+ const cached = await this.cacheManager.getCache().get(entry.key);
1746
+ if (cached) {
1747
+ result.loaded.push({
1748
+ key: entry.key,
1749
+ content: cached.content,
1750
+ fromCache: true,
1751
+ metadata: cached.metadata
1752
+ });
1753
+ }
1754
+ } catch (error) {
1755
+ result.failed.push({
1756
+ key: entry.key,
1757
+ error: error instanceof Error ? error.message : String(error),
1758
+ required: false
1759
+ });
1760
+ }
1761
+ }
1762
+ result.duration = Date.now() - startTime;
1763
+ return result;
1764
+ }
1765
+ /**
1766
+ * Refresh all contexts (sync from remote)
1767
+ */
1768
+ async refresh(sources, options) {
1769
+ return this.loadMany(sources, {
1770
+ ...options,
1771
+ forceRefresh: true
1772
+ });
1773
+ }
1774
+ /**
1775
+ * Check if all required contexts are available (cached or fetchable)
1776
+ */
1777
+ async checkAvailability(sources) {
1778
+ const available = [];
1779
+ const missing = [];
1780
+ const errors = [];
1781
+ for (const source of sources) {
1782
+ try {
1783
+ const hasCached = await this.cacheManager.getCache().has(source.key);
1784
+ if (hasCached) {
1785
+ available.push(source.key);
1786
+ continue;
1787
+ }
1788
+ const url = new URL(source.url);
1789
+ const source_type = this.getSourceFromHostname(url.hostname);
1790
+ if (this.cacheManager.hasFetcher(source_type)) {
1791
+ missing.push(source.key);
1792
+ } else {
1793
+ errors.push(`${source.key}: No fetcher for ${source_type}`);
1794
+ }
1795
+ } catch (error) {
1796
+ errors.push(`${source.key}: ${error instanceof Error ? error.message : String(error)}`);
1797
+ }
1798
+ }
1799
+ return { available, missing, errors };
1800
+ }
1801
+ /**
1802
+ * Get the cache manager
1803
+ */
1804
+ getCacheManager() {
1805
+ return this.cacheManager;
1806
+ }
1807
+ // Private helpers
1808
+ getSourceFromHostname(hostname) {
1809
+ const lower = hostname.toLowerCase();
1810
+ if (lower.includes("confluence") || lower.includes("atlassian.net")) return "confluence";
1811
+ if (lower.includes("github.com") || lower.includes("github")) return "github";
1812
+ if (lower.includes("notion.so") || lower.includes("notion")) return "notion";
1813
+ return "custom";
1814
+ }
1815
+ chunkArray(array, size) {
1816
+ const chunks = [];
1817
+ for (let i = 0; i < array.length; i += size) {
1818
+ chunks.push(array.slice(i, i + size));
1819
+ }
1820
+ return chunks;
1821
+ }
1822
+ };
1823
+ function createContextLoader(options) {
1824
+ return new ContextLoader(options);
1825
+ }
1826
+
1827
+ // src/commands/context.ts
1828
+ function createCommandContext(options = {}) {
1829
+ const projectRoot = options.projectRoot ?? process.cwd();
1830
+ let config = options.config ?? null;
1831
+ if (!config && configExists(projectRoot)) {
1832
+ try {
1833
+ config = loadConfig(projectRoot);
1834
+ } catch {
1835
+ config = null;
1836
+ }
1837
+ }
1838
+ let adapterFactory = options.adapterFactory ?? null;
1839
+ if (!adapterFactory && config) {
1840
+ try {
1841
+ adapterFactory = createAdapterFactory(config);
1842
+ } catch {
1843
+ adapterFactory = null;
1844
+ }
1845
+ }
1846
+ return {
1847
+ config,
1848
+ adapterFactory,
1849
+ projectRoot,
1850
+ hasIntegration(type) {
1851
+ if (!adapterFactory) return false;
1852
+ return adapterFactory.hasIntegration(type);
1853
+ },
1854
+ async getAdapterSafe(type) {
1855
+ if (!adapterFactory) return null;
1856
+ if (!adapterFactory.hasIntegration(type)) return null;
1857
+ try {
1858
+ const adapter = await adapterFactory.getAdapter(type);
1859
+ return adapter;
1860
+ } catch {
1861
+ return null;
1862
+ }
1863
+ }
1864
+ };
1865
+ }
1866
+ async function cleanupContext(context) {
1867
+ if (context.adapterFactory) {
1868
+ await context.adapterFactory.disconnectAll();
1869
+ }
1870
+ }
1871
+ async function withContext(options, fn) {
1872
+ const context = createCommandContext(options);
1873
+ try {
1874
+ return await fn(context);
1875
+ } finally {
1876
+ await cleanupContext(context);
1877
+ }
1878
+ }
1879
+
1880
+ // src/commands/registry.ts
1881
+ var CommandRegistry = class {
1882
+ commands = /* @__PURE__ */ new Map();
1883
+ adapterFactory = null;
1884
+ /**
1885
+ * Set the adapter factory for dependency checking
1886
+ */
1887
+ setAdapterFactory(factory) {
1888
+ this.adapterFactory = factory;
1889
+ this.updateAvailability();
1890
+ }
1891
+ /**
1892
+ * Register a programmatic command
1893
+ */
1894
+ register(definition) {
1895
+ const metadata = {
1896
+ name: definition.name,
1897
+ description: definition.description,
1898
+ category: definition.category,
1899
+ dependencies: definition.dependencies ?? [],
1900
+ sourcePath: "<programmatic>",
1901
+ available: true
1902
+ };
1903
+ this.checkAvailability(metadata);
1904
+ this.commands.set(definition.name, {
1905
+ metadata,
1906
+ definition,
1907
+ source: "programmatic"
1908
+ });
1909
+ }
1910
+ /**
1911
+ * Register a markdown command
1912
+ */
1913
+ registerMarkdown(command) {
1914
+ this.checkAvailability(command.metadata);
1915
+ this.commands.set(command.metadata.name, {
1916
+ metadata: command.metadata,
1917
+ markdownCommand: command,
1918
+ source: "markdown"
1919
+ });
1920
+ }
1921
+ /**
1922
+ * Register multiple commands
1923
+ */
1924
+ registerAll(definitions) {
1925
+ for (const def of definitions) {
1926
+ this.register(def);
1927
+ }
1928
+ }
1929
+ /**
1930
+ * Register multiple markdown commands
1931
+ */
1932
+ registerAllMarkdown(commands) {
1933
+ for (const cmd of commands) {
1934
+ this.registerMarkdown(cmd);
1935
+ }
1936
+ }
1937
+ /**
1938
+ * Unregister a command
1939
+ */
1940
+ unregister(name) {
1941
+ return this.commands.delete(name);
1942
+ }
1943
+ /**
1944
+ * Get a command by name
1945
+ */
1946
+ get(name) {
1947
+ return this.commands.get(name);
1948
+ }
1949
+ /**
1950
+ * Check if a command exists
1951
+ */
1952
+ has(name) {
1953
+ return this.commands.has(name);
1954
+ }
1955
+ /**
1956
+ * Get all registered commands
1957
+ */
1958
+ getAll() {
1959
+ return Array.from(this.commands.values());
1960
+ }
1961
+ /**
1962
+ * Get available commands (dependencies satisfied)
1963
+ */
1964
+ getAvailable() {
1965
+ return this.getAll().filter((entry) => entry.metadata.available);
1966
+ }
1967
+ /**
1968
+ * Get unavailable commands
1969
+ */
1970
+ getUnavailable() {
1971
+ return this.getAll().filter((entry) => !entry.metadata.available);
1972
+ }
1973
+ /**
1974
+ * Get commands by category
1975
+ */
1976
+ getByCategory(category) {
1977
+ return this.getAll().filter((entry) => entry.metadata.category === category);
1978
+ }
1979
+ /**
1980
+ * Get command names
1981
+ */
1982
+ getNames() {
1983
+ return Array.from(this.commands.keys());
1984
+ }
1985
+ /**
1986
+ * Clear all registered commands
1987
+ */
1988
+ clear() {
1989
+ this.commands.clear();
1990
+ }
1991
+ /**
1992
+ * Get the number of registered commands
1993
+ */
1994
+ get size() {
1995
+ return this.commands.size;
1996
+ }
1997
+ /**
1998
+ * Check and update availability for a command metadata
1999
+ */
2000
+ checkAvailability(metadata) {
2001
+ const missingDeps = this.getMissingDependencies(metadata.dependencies);
2002
+ if (missingDeps.length > 0) {
2003
+ const requiredMissing = missingDeps.filter((d) => d.required);
2004
+ if (requiredMissing.length > 0) {
2005
+ metadata.available = false;
2006
+ metadata.unavailableReason = `Missing required integrations: ${requiredMissing.map((d) => d.type).join(", ")}`;
2007
+ } else {
2008
+ metadata.available = true;
2009
+ }
2010
+ } else {
2011
+ metadata.available = true;
2012
+ delete metadata.unavailableReason;
2013
+ }
2014
+ }
2015
+ /**
2016
+ * Get missing dependencies
2017
+ */
2018
+ getMissingDependencies(dependencies) {
2019
+ const factory = this.adapterFactory;
2020
+ if (!factory) {
2021
+ return dependencies.filter((d) => d.required);
2022
+ }
2023
+ return dependencies.filter((dep) => !factory.hasIntegration(dep.type));
2024
+ }
2025
+ /**
2026
+ * Update availability for all commands
2027
+ */
2028
+ updateAvailability() {
2029
+ for (const entry of this.commands.values()) {
2030
+ this.checkAvailability(entry.metadata);
2031
+ }
2032
+ }
2033
+ /**
2034
+ * Get dependency status for a command
2035
+ */
2036
+ getDependencyStatus(name) {
2037
+ const entry = this.commands.get(name);
2038
+ if (!entry) return null;
2039
+ const deps = entry.metadata.dependencies;
2040
+ const missing = this.getMissingDependencies(deps);
2041
+ const satisfied = deps.filter((d) => !missing.includes(d));
2042
+ return { satisfied, missing };
2043
+ }
2044
+ };
2045
+ function createCommandRegistry() {
2046
+ return new CommandRegistry();
2047
+ }
2048
+ var globalRegistry = null;
2049
+ function getGlobalRegistry() {
2050
+ if (!globalRegistry) {
2051
+ globalRegistry = new CommandRegistry();
2052
+ }
2053
+ return globalRegistry;
2054
+ }
2055
+ function resetGlobalRegistry() {
2056
+ globalRegistry = null;
2057
+ }
2058
+
2059
+ // src/commands/loader.ts
2060
+ import { promises as fs2 } from "fs";
2061
+ import { join as join5, basename as basename2, dirname as dirname4, relative } from "path";
2062
+ function parseFrontmatter(content) {
2063
+ const match = content.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n([\s\S]*)$/);
2064
+ if (!match) {
2065
+ return { frontmatter: {}, body: content };
2066
+ }
2067
+ const frontmatterText = match[1] ?? "";
2068
+ const body = match[2] ?? "";
2069
+ const frontmatter = {};
2070
+ const lines = frontmatterText.split(/\r?\n/);
2071
+ for (const line of lines) {
2072
+ const colonIndex = line.indexOf(":");
2073
+ if (colonIndex === -1) continue;
2074
+ const key = line.slice(0, colonIndex).trim();
2075
+ let value = line.slice(colonIndex + 1).trim();
2076
+ if (value.startsWith("[") && value.endsWith("]")) {
2077
+ const arrayContent = value.slice(1, -1);
2078
+ const items = arrayContent.split(",").map((s) => s.trim().replace(/['"]/g, ""));
2079
+ frontmatter[key] = items;
2080
+ } else {
2081
+ if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
2082
+ value = value.slice(1, -1);
2083
+ }
2084
+ frontmatter[key] = value;
2085
+ }
2086
+ }
2087
+ return { frontmatter, body };
2088
+ }
2089
+ function parseSections(body) {
2090
+ const sections = {};
2091
+ const titleMatch = body.match(/^#\s+(.+)$/m);
2092
+ if (titleMatch?.[1]) {
2093
+ sections.title = titleMatch[1].trim();
2094
+ }
2095
+ const instructionsMatch = body.match(/##\s*Instructions?\s*\n([\s\S]*?)(?=\n##|$)/i);
2096
+ if (instructionsMatch?.[1]) {
2097
+ sections.instructions = instructionsMatch[1].trim();
2098
+ }
2099
+ const fallbacksMatch = body.match(/##\s*Fallbacks?\s*\n([\s\S]*?)(?=\n##|$)/i);
2100
+ if (fallbacksMatch?.[1]) {
2101
+ sections.fallbacks = fallbacksMatch[1].trim();
2102
+ }
2103
+ const outputMatch = body.match(/##\s*Output\s*(Format)?\s*\n([\s\S]*?)(?=\n##|$)/i);
2104
+ if (outputMatch?.[2]) {
2105
+ sections.outputFormat = outputMatch[2].trim();
2106
+ }
2107
+ return sections;
2108
+ }
2109
+ function mapIntegrationToAdapterType(integration) {
2110
+ const mapping = {
2111
+ // Issue tracker mappings
2112
+ jira: "issue_tracker",
2113
+ issue_tracker: "issue_tracker",
2114
+ issues: "issue_tracker",
2115
+ linear: "issue_tracker",
2116
+ github_issues: "issue_tracker",
2117
+ // Git provider mappings
2118
+ git: "git",
2119
+ github: "git",
2120
+ gitlab: "git",
2121
+ bitbucket: "git",
2122
+ // Documentation mappings
2123
+ docs: "documentation",
2124
+ documentation: "documentation",
2125
+ confluence: "documentation",
2126
+ notion: "documentation",
2127
+ wiki: "documentation",
2128
+ // State mappings
2129
+ state: "state",
2130
+ filesystem: "state"
2131
+ };
2132
+ return mapping[integration.toLowerCase()] ?? null;
2133
+ }
2134
+ function parseDependencies(frontmatter) {
2135
+ const dependencies = [];
2136
+ if (frontmatter.requires && Array.isArray(frontmatter.requires)) {
2137
+ for (const req of frontmatter.requires) {
2138
+ const type = mapIntegrationToAdapterType(req);
2139
+ if (type) {
2140
+ dependencies.push({
2141
+ type,
2142
+ required: true,
2143
+ description: `Requires ${req} integration`
2144
+ });
2145
+ }
2146
+ }
2147
+ }
2148
+ if (frontmatter.optional && Array.isArray(frontmatter.optional)) {
2149
+ for (const opt of frontmatter.optional) {
2150
+ const type = mapIntegrationToAdapterType(opt);
2151
+ if (type) {
2152
+ dependencies.push({
2153
+ type,
2154
+ required: false,
2155
+ description: `Optionally uses ${opt} integration`
2156
+ });
2157
+ }
2158
+ }
2159
+ }
2160
+ return dependencies;
2161
+ }
2162
+ function deriveCommandName(filePath, baseDir) {
2163
+ const relativePath = relative(baseDir, filePath);
2164
+ const name = basename2(filePath, ".md");
2165
+ const dir = dirname4(relativePath);
2166
+ if (dir === "." || dir === "core" || dir === "optional") {
2167
+ return name;
2168
+ }
2169
+ return name;
2170
+ }
2171
+ function deriveCategoryFromPath(filePath, baseDir) {
2172
+ const relativePath = relative(baseDir, filePath);
2173
+ const parts = relativePath.split("/");
2174
+ if (parts.includes("optional")) {
2175
+ return "optional";
2176
+ }
2177
+ if (parts.includes("core")) {
2178
+ return "core";
2179
+ }
2180
+ return "custom";
2181
+ }
2182
+ async function loadCommandFromFile(filePath, baseDir, categoryOverride) {
2183
+ const content = await fs2.readFile(filePath, "utf-8");
2184
+ const { frontmatter, body } = parseFrontmatter(content);
2185
+ const sections = parseSections(body);
2186
+ const name = deriveCommandName(filePath, baseDir);
2187
+ const category = categoryOverride ?? deriveCategoryFromPath(filePath, baseDir);
2188
+ const dependencies = parseDependencies(frontmatter);
2189
+ const metadata = {
2190
+ name,
2191
+ description: frontmatter.description ?? sections.title ?? name,
2192
+ category,
2193
+ dependencies,
2194
+ sourcePath: filePath,
2195
+ available: true
2196
+ // Will be updated by registry
2197
+ };
2198
+ if (frontmatter["argument-hint"]) {
2199
+ metadata.argumentHint = frontmatter["argument-hint"];
2200
+ }
2201
+ return {
2202
+ metadata,
2203
+ content: body,
2204
+ sections
2205
+ };
2206
+ }
2207
+ async function findMarkdownFiles(dir, recursive) {
2208
+ const files = [];
2209
+ try {
2210
+ const entries = await fs2.readdir(dir, { withFileTypes: true });
2211
+ for (const entry of entries) {
2212
+ const fullPath = join5(dir, entry.name);
2213
+ if (entry.isDirectory() && recursive) {
2214
+ const subFiles = await findMarkdownFiles(fullPath, recursive);
2215
+ files.push(...subFiles);
2216
+ } else if (entry.isFile() && entry.name.endsWith(".md")) {
2217
+ files.push(fullPath);
2218
+ }
2219
+ }
2220
+ } catch (error) {
2221
+ if (error.code !== "ENOENT") {
2222
+ throw error;
2223
+ }
2224
+ }
2225
+ return files;
2226
+ }
2227
+ async function loadCommandsFromDirectory(options) {
2228
+ const result = {
2229
+ loaded: [],
2230
+ errors: []
2231
+ };
2232
+ const files = await findMarkdownFiles(options.directory, options.recursive ?? true);
2233
+ for (const filePath of files) {
2234
+ try {
2235
+ const command = await loadCommandFromFile(filePath, options.directory, options.category);
2236
+ if (options.filter && !options.filter(command.metadata)) {
2237
+ continue;
2238
+ }
2239
+ result.loaded.push(command);
2240
+ } catch (error) {
2241
+ result.errors.push({
2242
+ path: filePath,
2243
+ error: error instanceof Error ? error.message : String(error)
2244
+ });
2245
+ }
2246
+ }
2247
+ return result;
2248
+ }
2249
+ async function loadCoreAICommands(projectRoot) {
2250
+ const commandsDir = join5(projectRoot, "coreai", "commands");
2251
+ return loadCommandsFromDirectory({
2252
+ directory: commandsDir,
2253
+ category: "core",
2254
+ // Will be overridden by path derivation
2255
+ recursive: true
2256
+ });
2257
+ }
2258
+ async function loadAllCommands(coreCommandsDir, customCommandsDir) {
2259
+ const result = {
2260
+ loaded: [],
2261
+ errors: []
2262
+ };
2263
+ const coreResult = await loadCommandsFromDirectory({
2264
+ directory: coreCommandsDir,
2265
+ category: "core",
2266
+ recursive: true
2267
+ });
2268
+ result.loaded.push(...coreResult.loaded);
2269
+ result.errors.push(...coreResult.errors);
2270
+ if (customCommandsDir) {
2271
+ const customResult = await loadCommandsFromDirectory({
2272
+ directory: customCommandsDir,
2273
+ category: "custom",
2274
+ recursive: true
2275
+ });
2276
+ result.loaded.push(...customResult.loaded);
2277
+ result.errors.push(...customResult.errors);
2278
+ }
2279
+ return result;
2280
+ }
2281
+
2282
+ // src/commands/runner.ts
2283
+ async function runCommand(registry, name, args, options = {}) {
2284
+ const entry = registry.get(name);
2285
+ if (!entry) {
2286
+ return {
2287
+ success: false,
2288
+ error: `Command not found: ${name}`
2289
+ };
2290
+ }
2291
+ if (!entry.metadata.available) {
2292
+ return {
2293
+ success: false,
2294
+ error: entry.metadata.unavailableReason ?? "Command is unavailable"
2295
+ };
2296
+ }
2297
+ if (!entry.definition) {
2298
+ return {
2299
+ success: false,
2300
+ error: `Command ${name} is a markdown command and cannot be executed programmatically`
2301
+ };
2302
+ }
2303
+ const contextOptions = {};
2304
+ if (options.projectRoot) {
2305
+ contextOptions.projectRoot = options.projectRoot;
2306
+ }
2307
+ const context = options.context ?? createCommandContext(contextOptions);
2308
+ try {
2309
+ const result = await entry.definition.handler(
2310
+ args,
2311
+ options,
2312
+ context
2313
+ );
2314
+ if (entry.metadata.dependencies) {
2315
+ const optionalDeps = entry.metadata.dependencies.filter((d) => !d.required);
2316
+ const optionalUnavailable = optionalDeps.filter((d) => !context.hasIntegration(d.type));
2317
+ if (optionalUnavailable.length > 0) {
2318
+ result.skippedSteps = result.skippedSteps ?? [];
2319
+ for (const dep of optionalUnavailable) {
2320
+ result.skippedSteps.push({
2321
+ step: `${dep.type} integration`,
2322
+ reason: dep.description ?? `${dep.type} not configured`
2323
+ });
2324
+ }
2325
+ }
2326
+ }
2327
+ return result;
2328
+ } catch (error) {
2329
+ return {
2330
+ success: false,
2331
+ error: error instanceof Error ? error.message : String(error)
2332
+ };
2333
+ } finally {
2334
+ if (options.cleanupAfter !== false && !options.context) {
2335
+ await cleanupContext(context);
2336
+ }
2337
+ }
2338
+ }
2339
+ async function executeWithDegradation(context, dependency, step, fallback) {
2340
+ if (!context.hasIntegration(dependency.type)) {
2341
+ if (dependency.required) {
2342
+ throw new Error(`Required integration missing: ${dependency.type}`);
2343
+ }
2344
+ if (fallback) {
2345
+ try {
2346
+ const result2 = await fallback();
2347
+ return { result: result2, skipped: false };
2348
+ } catch {
2349
+ return {
2350
+ result: null,
2351
+ skipped: true,
2352
+ reason: dependency.description ?? `${dependency.type} not available`
2353
+ };
2354
+ }
2355
+ }
2356
+ return {
2357
+ result: null,
2358
+ skipped: true,
2359
+ reason: dependency.description ?? `${dependency.type} not available`
2360
+ };
2361
+ }
2362
+ const result = await step();
2363
+ return { result, skipped: false };
2364
+ }
2365
+ function createDegradingHandler(handler) {
2366
+ return async (args, options, context) => {
2367
+ const tracker = new StepTracker();
2368
+ try {
2369
+ const data = await handler(args, options, context, tracker);
2370
+ return {
2371
+ success: true,
2372
+ data,
2373
+ warnings: tracker.warnings,
2374
+ skippedSteps: tracker.skippedSteps
2375
+ };
2376
+ } catch (error) {
2377
+ return {
2378
+ success: false,
2379
+ error: error instanceof Error ? error.message : String(error),
2380
+ warnings: tracker.warnings,
2381
+ skippedSteps: tracker.skippedSteps
2382
+ };
2383
+ }
2384
+ };
2385
+ }
2386
+ var StepTracker = class {
2387
+ skippedSteps = [];
2388
+ warnings = [];
2389
+ /**
2390
+ * Record a skipped step
2391
+ */
2392
+ skip(step, reason) {
2393
+ this.skippedSteps.push({ step, reason });
2394
+ }
2395
+ /**
2396
+ * Record a warning
2397
+ */
2398
+ warn(message) {
2399
+ this.warnings.push(message);
2400
+ }
2401
+ /**
2402
+ * Execute a step with optional fallback
2403
+ */
2404
+ async tryStep(stepName, context, dependency, step, fallback) {
2405
+ const result = await executeWithDegradation(context, dependency, step, fallback);
2406
+ if (result.skipped) {
2407
+ this.skip(stepName, result.reason ?? "Integration not available");
2408
+ }
2409
+ return result.result;
2410
+ }
2411
+ };
2412
+
2413
+ // src/skills/generator.ts
2414
+ import { existsSync as existsSync4, mkdirSync as mkdirSync2, writeFileSync as writeFileSync2, readFileSync as readFileSync3, readdirSync as readdirSync2, statSync } from "fs";
2415
+ import { join as join6, basename as basename3 } from "path";
2416
+
2417
+ // src/skills/templates.ts
2418
+ var checkInboxSkill = {
2419
+ name: "check-inbox",
2420
+ description: "Check your inbox for pending tasks and messages",
2421
+ category: "core",
2422
+ content: `---
2423
+ description: Check your inbox for pending tasks and messages
2424
+ ---
2425
+
2426
+ # Check Inbox
2427
+
2428
+ Check the inbox at \`KnowledgeLibrary/{{AGENT_NAME}}/inbox/\` for new messages.
2429
+
2430
+ ## Instructions
2431
+
2432
+ 1. Read all unprocessed messages in the inbox directory
2433
+ 2. For each message:
2434
+ - Parse the frontmatter (type, from, date, priority)
2435
+ - Understand the request or task
2436
+ - Take appropriate action based on message type
2437
+ 3. After processing, move message to \`inbox/processed/\`
2438
+ 4. Update your context file at \`KnowledgeLibrary/{{AGENT_NAME}}/context/current.txt\`
2439
+
2440
+ ## Message Types
2441
+
2442
+ - **task-assignment**: New work assigned to you
2443
+ - **completion-report**: Another agent completed work
2444
+ - **review-request**: Code review needed
2445
+ - **feedback**: Response to your previous work
2446
+
2447
+ ## Output Format
2448
+
2449
+ Report what messages were processed and actions taken.
2450
+ `
2451
+ };
2452
+ var delegateSkill = {
2453
+ name: "delegate",
2454
+ description: "Delegate a task to another agent via inbox messaging",
2455
+ argumentHint: "<task-description> to <agent-name>",
2456
+ category: "core",
2457
+ content: `---
2458
+ description: Delegate a task to another agent via inbox messaging
2459
+ argument-hint: <task-description> to <agent-name>
2460
+ ---
2461
+
2462
+ # Delegate Task
2463
+
2464
+ Delegate work to another agent using the inbox-based messaging system.
2465
+
2466
+ ## CRITICAL: Do NOT use the Task tool
2467
+
2468
+ Agent-to-agent delegation MUST use file-based messaging, not the Task tool.
2469
+ The Task tool spawns subagents that lose MCP access.
2470
+
2471
+ ## Instructions
2472
+
2473
+ 1. Parse the delegation request to identify:
2474
+ - The task to delegate
2475
+ - The target agent
2476
+
2477
+ 2. Create a message file in the target agent's inbox:
2478
+ - Path: \`KnowledgeLibrary/<target-agent>/inbox/\`
2479
+ - Filename: \`YYYYMMDD_HHMM-{{AGENT_NAME}}-<subject>.md\`
2480
+
2481
+ 3. Use this message format:
2482
+ \`\`\`markdown
2483
+ ---
2484
+ type: task-assignment
2485
+ from: {{AGENT_NAME}}
2486
+ to: <target-agent>
2487
+ date: YYYY-MM-DD HH:MM
2488
+ priority: P2
2489
+ ---
2490
+
2491
+ ## Task Assignment
2492
+
2493
+ ### Description
2494
+ <Clear description of what needs to be done>
2495
+
2496
+ ### Context
2497
+ <Any relevant context or background>
2498
+
2499
+ ### Expected Deliverables
2500
+ 1. <Deliverable 1>
2501
+ 2. <Deliverable 2>
2502
+
2503
+ ### Success Criteria
2504
+ - <Criterion 1>
2505
+ - <Criterion 2>
2506
+ \`\`\`
2507
+
2508
+ 4. Tell the user to invoke the target agent:
2509
+ "Please invoke @<target-agent> to process this task."
2510
+
2511
+ ## Output
2512
+
2513
+ Confirm the delegation message was created and instruct user to invoke the agent.
2514
+ `
2515
+ };
2516
+ var gitCommitSkill = {
2517
+ name: "git-commit",
2518
+ description: "Create a quality-gated git commit",
2519
+ argumentHint: "<commit-message>",
2520
+ category: "core",
2521
+ dependencies: [{ type: "git", required: false, description: "For commit operations" }],
2522
+ content: `---
2523
+ description: Create a quality-gated git commit
2524
+ argument-hint: <commit-message>
2525
+ optional: [git]
2526
+ ---
2527
+
2528
+ # Git Commit
2529
+
2530
+ Create a git commit after passing all quality gates.
2531
+
2532
+ ## Quality Gates
2533
+
2534
+ Run these checks before committing:
2535
+
2536
+ 1. **Lint**: \`{{LINT_CMD}}\`
2537
+ 2. **Tests**: \`{{TEST_CMD}}\`
2538
+ 3. **Build**: \`{{BUILD_CMD}}\`
2539
+
2540
+ ## Instructions
2541
+
2542
+ 1. Stage the relevant files with \`git add\`
2543
+ 2. Run all quality gate commands
2544
+ 3. If any gate fails:
2545
+ - Fix the issues
2546
+ - Re-run the failed gate
2547
+ - Continue only when all pass
2548
+ 4. Create the commit with the provided message
2549
+ 5. Format: Include ticket reference if applicable
2550
+
2551
+ ## Commit Message Format
2552
+
2553
+ \`\`\`
2554
+ <type>(<scope>): <description>
2555
+
2556
+ [optional body]
2557
+
2558
+ [optional footer]
2559
+ \`\`\`
2560
+
2561
+ Types: feat, fix, docs, style, refactor, test, chore
2562
+
2563
+ ## Fallbacks
2564
+
2565
+ If quality gate commands are not configured:
2566
+ - Ask the user what commands to run
2567
+ - Or skip gates with user confirmation
2568
+ `
2569
+ };
2570
+ var prCreateSkill = {
2571
+ name: "pr-create",
2572
+ description: "Create a pull request with proper format",
2573
+ argumentHint: "[branch-name]",
2574
+ category: "core",
2575
+ dependencies: [{ type: "git", required: true, description: "For PR creation" }],
2576
+ content: `---
2577
+ description: Create a pull request with proper format
2578
+ argument-hint: [branch-name]
2579
+ requires: [git]
2580
+ ---
2581
+
2582
+ # Create Pull Request
2583
+
2584
+ Create a well-formatted pull request for the current branch.
2585
+
2586
+ ## Instructions
2587
+
2588
+ 1. Ensure all changes are committed
2589
+ 2. Push the branch to remote
2590
+ 3. Create PR with proper format:
2591
+
2592
+ \`\`\`markdown
2593
+ ## Summary
2594
+ <Brief description of changes>
2595
+
2596
+ ## Changes
2597
+ - <Change 1>
2598
+ - <Change 2>
2599
+
2600
+ ## Test Plan
2601
+ - [ ] <Test case 1>
2602
+ - [ ] <Test case 2>
2603
+
2604
+ ## Related Issues
2605
+ Closes {{JIRA_PROJECT}}-XXX
2606
+ \`\`\`
2607
+
2608
+ 4. Request reviewers if specified
2609
+
2610
+ ## Using GitHub CLI
2611
+
2612
+ \`\`\`bash
2613
+ gh pr create --title "<title>" --body "<body>"
2614
+ \`\`\`
2615
+
2616
+ ## Output
2617
+
2618
+ Provide the PR URL and summary of what was created.
2619
+ `
2620
+ };
2621
+ var reviewSkill = {
2622
+ name: "review",
2623
+ description: "Request or perform a code review",
2624
+ argumentHint: "<pr-number-or-url>",
2625
+ category: "core",
2626
+ dependencies: [{ type: "git", required: true, description: "For PR review" }],
2627
+ content: `---
2628
+ description: Request or perform a code review
2629
+ argument-hint: <pr-number-or-url>
2630
+ requires: [git]
2631
+ ---
2632
+
2633
+ # Code Review
2634
+
2635
+ Review a pull request or delegate review to a specialist.
2636
+
2637
+ ## Instructions
2638
+
2639
+ ### If you are reviewing:
2640
+
2641
+ 1. Fetch the PR details and diff
2642
+ 2. Review for:
2643
+ - Code quality and style
2644
+ - Logic errors or bugs
2645
+ - Security concerns
2646
+ - Test coverage
2647
+ - Documentation
2648
+ 3. Provide feedback with specific line references
2649
+ 4. Approve, request changes, or comment
2650
+
2651
+ ### If delegating to a reviewer:
2652
+
2653
+ 1. Identify the appropriate reviewer based on the changes
2654
+ 2. Create a review request message in their inbox
2655
+ 3. Include PR link and context
2656
+
2657
+ ## Review Checklist
2658
+
2659
+ - [ ] Code follows project conventions
2660
+ - [ ] No obvious bugs or edge cases
2661
+ - [ ] Tests cover the changes
2662
+ - [ ] Documentation updated if needed
2663
+ - [ ] No security vulnerabilities
2664
+
2665
+ ## Output
2666
+
2667
+ Provide review summary with actionable feedback.
2668
+ `
2669
+ };
2670
+ var sprintStatusSkill = {
2671
+ name: "sprint-status",
2672
+ description: "Get current sprint status and progress",
2673
+ category: "optional",
2674
+ dependencies: [{ type: "issue_tracker", required: true, description: "For sprint data" }],
2675
+ content: `---
2676
+ description: Get current sprint status and progress
2677
+ requires: [issue_tracker]
2678
+ ---
2679
+
2680
+ # Sprint Status
2681
+
2682
+ Get the current sprint status and team progress.
2683
+
2684
+ ## Instructions
2685
+
2686
+ 1. Query the active sprint for project {{JIRA_PROJECT}}
2687
+ 2. Gather metrics:
2688
+ - Total story points committed
2689
+ - Points completed
2690
+ - Points in progress
2691
+ - Points remaining
2692
+ 3. List tickets by status
2693
+ 4. Identify blockers or at-risk items
2694
+
2695
+ ## Output Format
2696
+
2697
+ \`\`\`
2698
+ Sprint: <sprint-name>
2699
+ Progress: XX/YY points (ZZ%)
2700
+
2701
+ ## Completed
2702
+ - [{{JIRA_PROJECT}}-123] Task name (3 pts)
2703
+
2704
+ ## In Progress
2705
+ - [{{JIRA_PROJECT}}-124] Task name (5 pts) - @assignee
2706
+
2707
+ ## To Do
2708
+ - [{{JIRA_PROJECT}}-125] Task name (2 pts)
2709
+
2710
+ ## Blocked
2711
+ - [{{JIRA_PROJECT}}-126] Task name - Reason
2712
+ \`\`\`
2713
+
2714
+ ## Fallbacks
2715
+
2716
+ If issue tracker is unavailable:
2717
+ - Report that sprint data cannot be fetched
2718
+ - Suggest checking the issue tracker directly at {{JIRA_URL}}
2719
+ `
2720
+ };
2721
+ var jiraCreateSkill = {
2722
+ name: "jira-create",
2723
+ description: "Create a new Jira ticket",
2724
+ argumentHint: "<ticket-type> <summary>",
2725
+ category: "optional",
2726
+ dependencies: [{ type: "issue_tracker", required: true, description: "For ticket creation" }],
2727
+ content: `---
2728
+ description: Create a new Jira ticket
2729
+ argument-hint: <ticket-type> <summary>
2730
+ requires: [issue_tracker]
2731
+ ---
2732
+
2733
+ # Create Jira Ticket
2734
+
2735
+ Create a new ticket in project {{JIRA_PROJECT}}.
2736
+
2737
+ ## Instructions
2738
+
2739
+ 1. Parse the ticket type and summary from arguments
2740
+ 2. Gather additional details:
2741
+ - Description
2742
+ - Priority
2743
+ - Labels
2744
+ - Components (if applicable)
2745
+ 3. Create the ticket via the issue tracker integration
2746
+ 4. Return the ticket key and URL
2747
+
2748
+ ## Ticket Types
2749
+
2750
+ - **Story**: User-facing feature
2751
+ - **Bug**: Defect to fix
2752
+ - **Task**: Technical work
2753
+ - **Spike**: Research/investigation
2754
+
2755
+ ## Output
2756
+
2757
+ \`\`\`
2758
+ Created: {{JIRA_PROJECT}}-XXX
2759
+ URL: {{JIRA_URL}}/browse/{{JIRA_PROJECT}}-XXX
2760
+ Summary: <summary>
2761
+ Type: <type>
2762
+ \`\`\`
2763
+
2764
+ ## Fallbacks
2765
+
2766
+ If issue tracker is unavailable:
2767
+ - Provide the user with manual creation instructions
2768
+ - Include all details they should enter
2769
+ `
2770
+ };
2771
+ var jiraTransitionSkill = {
2772
+ name: "jira-transition",
2773
+ description: "Transition a Jira ticket to a new status",
2774
+ argumentHint: "<ticket-key> to <status>",
2775
+ category: "optional",
2776
+ dependencies: [{ type: "issue_tracker", required: true, description: "For ticket transitions" }],
2777
+ content: `---
2778
+ description: Transition a Jira ticket to a new status
2779
+ argument-hint: <ticket-key> to <status>
2780
+ requires: [issue_tracker]
2781
+ ---
2782
+
2783
+ # Transition Jira Ticket
2784
+
2785
+ Update the status of a ticket in {{JIRA_PROJECT}}.
2786
+
2787
+ ## Status Mapping
2788
+
2789
+ | Workflow Status | Jira Status |
2790
+ |-----------------|-------------|
2791
+ | BACKLOG | Backlog |
2792
+ | IN_PROGRESS | In Progress |
2793
+ | PR_CREATED | In Review |
2794
+ | IN_REVIEW | In Review |
2795
+ | APPROVED | Ready to Merge |
2796
+ | MERGED | Done |
2797
+ | DONE | Done |
2798
+
2799
+ ## Instructions
2800
+
2801
+ 1. Parse ticket key and target status
2802
+ 2. Validate the transition is allowed
2803
+ 3. Add a comment explaining the transition
2804
+ 4. Execute the transition
2805
+
2806
+ ## Transition Comment Format
2807
+
2808
+ \`\`\`
2809
+ Status updated to <status>.
2810
+ <optional context about why>
2811
+ \`\`\`
2812
+
2813
+ ## Fallbacks
2814
+
2815
+ If issue tracker is unavailable:
2816
+ - Instruct user to manually transition at {{JIRA_URL}}
2817
+ - Provide the target status name
2818
+ `
2819
+ };
2820
+ var docsUpdateSkill = {
2821
+ name: "docs-update",
2822
+ description: "Update project documentation",
2823
+ argumentHint: "<doc-path-or-topic>",
2824
+ category: "optional",
2825
+ dependencies: [{ type: "documentation", required: false, description: "For remote docs" }],
2826
+ content: `---
2827
+ description: Update project documentation
2828
+ argument-hint: <doc-path-or-topic>
2829
+ optional: [documentation]
2830
+ ---
2831
+
2832
+ # Update Documentation
2833
+
2834
+ Update project documentation for a specific topic or file.
2835
+
2836
+ ## Instructions
2837
+
2838
+ 1. Identify the documentation to update:
2839
+ - Local: \`{{DOCS_PATH}}/\`
2840
+ - Remote: {{CONFLUENCE_SPACE}} (if configured)
2841
+
2842
+ 2. Make the necessary updates:
2843
+ - Keep formatting consistent
2844
+ - Update examples if code changed
2845
+ - Add/update version information
2846
+
2847
+ 3. For remote documentation:
2848
+ - Use the documentation integration
2849
+ - Or provide content for manual update
2850
+
2851
+ ## Documentation Types
2852
+
2853
+ - **README**: Project overview and setup
2854
+ - **API Docs**: Endpoint documentation
2855
+ - **Architecture**: Design decisions
2856
+ - **Runbooks**: Operational procedures
2857
+
2858
+ ## Fallbacks
2859
+
2860
+ If documentation integration is unavailable:
2861
+ - Create/update local markdown files
2862
+ - Provide instructions for manual remote update
2863
+ `
2864
+ };
2865
+ var builtInSkills = [
2866
+ checkInboxSkill,
2867
+ delegateSkill,
2868
+ gitCommitSkill,
2869
+ prCreateSkill,
2870
+ reviewSkill,
2871
+ sprintStatusSkill,
2872
+ jiraCreateSkill,
2873
+ jiraTransitionSkill,
2874
+ docsUpdateSkill
2875
+ ];
2876
+
2877
+ // src/skills/generator.ts
2878
+ function extractVariables2(config) {
2879
+ const vars = {};
2880
+ if (!config) {
2881
+ return vars;
2882
+ }
2883
+ vars.PROJECT_NAME = config.project.name;
2884
+ vars.PROJECT_ROOT = config.project.root;
2885
+ if (config.project.type) {
2886
+ vars.PROJECT_TYPE = config.project.type;
2887
+ }
2888
+ if (config.integrations?.issue_tracker) {
2889
+ const tracker = config.integrations.issue_tracker;
2890
+ if (tracker.config?.project_key) {
2891
+ vars.JIRA_PROJECT = tracker.config.project_key;
2892
+ }
2893
+ if (tracker.config?.base_url) {
2894
+ vars.JIRA_URL = tracker.config.base_url;
2895
+ }
2896
+ }
2897
+ if (config.integrations?.git) {
2898
+ const git = config.integrations.git;
2899
+ if (git.config?.repo) {
2900
+ vars.GITHUB_REPO = git.config.repo;
2901
+ }
2902
+ if (git.config?.owner) {
2903
+ vars.GITHUB_OWNER = git.config.owner;
2904
+ }
2905
+ if (git.config?.default_branch) {
2906
+ vars.DEFAULT_BRANCH = git.config.default_branch;
2907
+ }
2908
+ }
2909
+ if (config.integrations?.documentation) {
2910
+ const docs = config.integrations.documentation;
2911
+ if (docs.config?.space_key) {
2912
+ vars.CONFLUENCE_SPACE = docs.config.space_key;
2913
+ }
2914
+ if (docs.config?.base_url) {
2915
+ vars.CONFLUENCE_URL = docs.config.base_url;
2916
+ }
2917
+ if (docs.config?.base_path) {
2918
+ vars.DOCS_PATH = docs.config.base_path;
2919
+ }
2920
+ }
2921
+ if (config.quality_gates) {
2922
+ const gates = config.quality_gates;
2923
+ const gateMappings = {
2924
+ lint: "LINT_CMD",
2925
+ test: "TEST_CMD",
2926
+ build: "BUILD_CMD",
2927
+ static_analysis: "STATIC_ANALYSIS_CMD",
2928
+ staticAnalysis: "STATIC_ANALYSIS_CMD"
2929
+ };
2930
+ for (const [gateName, gate] of Object.entries(gates)) {
2931
+ const varName = gateMappings[gateName];
2932
+ if (varName) {
2933
+ vars[varName] = gate.command;
2934
+ }
2935
+ }
2936
+ }
2937
+ if (config.tech_stack?.primary_language) {
2938
+ vars.PRIMARY_LANGUAGE = config.tech_stack.primary_language;
2939
+ }
2940
+ return vars;
2941
+ }
2942
+ function substituteVariables(content, variables) {
2943
+ let result = content;
2944
+ for (const [key, value] of Object.entries(variables)) {
2945
+ if (value !== void 0) {
2946
+ const pattern = new RegExp(`\\{\\{${key}\\}\\}`, "g");
2947
+ result = result.replace(pattern, value);
2948
+ }
2949
+ }
2950
+ return result;
2951
+ }
2952
+ function checkDependencies(skill, config) {
2953
+ if (!skill.dependencies || skill.dependencies.length === 0) {
2954
+ return { satisfied: true, missing: [] };
2955
+ }
2956
+ const missing = [];
2957
+ for (const dep of skill.dependencies) {
2958
+ if (!dep.required) {
2959
+ continue;
2960
+ }
2961
+ let hasIntegration = false;
2962
+ if (config?.integrations) {
2963
+ switch (dep.type) {
2964
+ case "issue_tracker":
2965
+ hasIntegration = !!config.integrations.issue_tracker;
2966
+ break;
2967
+ case "git":
2968
+ hasIntegration = !!config.integrations.git;
2969
+ break;
2970
+ case "documentation":
2971
+ hasIntegration = !!config.integrations.documentation;
2972
+ break;
2973
+ case "state":
2974
+ hasIntegration = !!config.integrations.state;
2975
+ break;
2976
+ }
2977
+ }
2978
+ if (!hasIntegration) {
2979
+ missing.push(dep);
2980
+ }
2981
+ }
2982
+ return {
2983
+ satisfied: missing.length === 0,
2984
+ missing
2985
+ };
2986
+ }
2987
+ function loadCustomTemplates(templatesDir) {
2988
+ const templates = [];
2989
+ if (!existsSync4(templatesDir)) {
2990
+ return templates;
2991
+ }
2992
+ const files = readdirSync2(templatesDir);
2993
+ for (const file of files) {
2994
+ if (!file.endsWith(".md")) continue;
2995
+ const filePath = join6(templatesDir, file);
2996
+ const stat = statSync(filePath);
2997
+ if (!stat.isFile()) continue;
2998
+ try {
2999
+ const content = readFileSync3(filePath, "utf-8");
3000
+ const template = parseSkillTemplate(file, content);
3001
+ templates.push(template);
3002
+ } catch {
3003
+ }
3004
+ }
3005
+ return templates;
3006
+ }
3007
+ function parseSkillTemplate(filename, content) {
3008
+ const name = basename3(filename, ".md");
3009
+ const frontmatterMatch = content.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n([\s\S]*)$/);
3010
+ let description = name;
3011
+ let argumentHint;
3012
+ const dependencies = [];
3013
+ if (frontmatterMatch) {
3014
+ const frontmatter = frontmatterMatch[1] ?? "";
3015
+ const lines = frontmatter.split(/\r?\n/);
3016
+ for (const line of lines) {
3017
+ const colonIndex = line.indexOf(":");
3018
+ if (colonIndex === -1) continue;
3019
+ const key = line.slice(0, colonIndex).trim();
3020
+ let value = line.slice(colonIndex + 1).trim();
3021
+ if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
3022
+ value = value.slice(1, -1);
3023
+ }
3024
+ switch (key) {
3025
+ case "description":
3026
+ description = value;
3027
+ break;
3028
+ case "argument-hint":
3029
+ argumentHint = value;
3030
+ break;
3031
+ case "requires":
3032
+ if (value.startsWith("[") && value.endsWith("]")) {
3033
+ const items = value.slice(1, -1).split(",").map((s) => s.trim().replace(/['"]/g, ""));
3034
+ for (const item of items) {
3035
+ if (item) {
3036
+ dependencies.push({
3037
+ type: mapIntegrationName(item),
3038
+ required: true
3039
+ });
3040
+ }
3041
+ }
3042
+ }
3043
+ break;
3044
+ case "optional":
3045
+ if (value.startsWith("[") && value.endsWith("]")) {
3046
+ const items = value.slice(1, -1).split(",").map((s) => s.trim().replace(/['"]/g, ""));
3047
+ for (const item of items) {
3048
+ if (item) {
3049
+ dependencies.push({
3050
+ type: mapIntegrationName(item),
3051
+ required: false
3052
+ });
3053
+ }
3054
+ }
3055
+ }
3056
+ break;
3057
+ }
3058
+ }
3059
+ }
3060
+ const template = {
3061
+ name,
3062
+ description,
3063
+ category: "custom",
3064
+ content
3065
+ };
3066
+ if (argumentHint) {
3067
+ template.argumentHint = argumentHint;
3068
+ }
3069
+ if (dependencies.length > 0) {
3070
+ template.dependencies = dependencies;
3071
+ }
3072
+ return template;
3073
+ }
3074
+ function mapIntegrationName(name) {
3075
+ const lower = name.toLowerCase();
3076
+ if (["jira", "linear", "issue_tracker", "issues", "github-issues"].includes(lower)) {
3077
+ return "issue_tracker";
3078
+ }
3079
+ if (["git", "github", "gitlab", "bitbucket"].includes(lower)) {
3080
+ return "git";
3081
+ }
3082
+ if (["docs", "documentation", "confluence", "notion", "wiki"].includes(lower)) {
3083
+ return "documentation";
3084
+ }
3085
+ return "state";
3086
+ }
3087
+ function generateSkills(config, options = {}) {
3088
+ const projectRoot = options.projectRoot ?? process.cwd();
3089
+ const outputDir = options.outputDir ?? join6(projectRoot, ".claude", "commands");
3090
+ const includeCoreSkills = options.includeCoreSkills ?? true;
3091
+ const includeOptionalSkills = options.includeOptionalSkills ?? true;
3092
+ const overwrite = options.overwrite ?? false;
3093
+ const result = {
3094
+ generated: [],
3095
+ errors: [],
3096
+ variables: {}
3097
+ };
3098
+ const variables = extractVariables2(config);
3099
+ if (options.variables) {
3100
+ Object.assign(variables, options.variables);
3101
+ }
3102
+ result.variables = variables;
3103
+ let templates = [];
3104
+ if (includeCoreSkills) {
3105
+ templates.push(...builtInSkills.filter((s) => s.category === "core"));
3106
+ }
3107
+ if (includeOptionalSkills) {
3108
+ templates.push(...builtInSkills.filter((s) => s.category === "optional"));
3109
+ }
3110
+ if (options.customTemplatesDir && existsSync4(options.customTemplatesDir)) {
3111
+ templates.push(...loadCustomTemplates(options.customTemplatesDir));
3112
+ }
3113
+ if (options.skills && options.skills.length > 0) {
3114
+ const skillsToInclude = options.skills;
3115
+ templates = templates.filter((t) => skillsToInclude.includes(t.name));
3116
+ }
3117
+ if (!existsSync4(outputDir)) {
3118
+ mkdirSync2(outputDir, { recursive: true });
3119
+ }
3120
+ for (const template of templates) {
3121
+ try {
3122
+ const generated = generateSkill(template, variables, config, outputDir, overwrite);
3123
+ result.generated.push(generated);
3124
+ } catch (error) {
3125
+ result.errors.push({
3126
+ name: template.name,
3127
+ error: error instanceof Error ? error.message : String(error)
3128
+ });
3129
+ }
3130
+ }
3131
+ return result;
3132
+ }
3133
+ function generateSkill(template, variables, config, outputDir, overwrite) {
3134
+ const outputPath = join6(outputDir, `${template.name}.md`);
3135
+ if (existsSync4(outputPath) && !overwrite) {
3136
+ return {
3137
+ name: template.name,
3138
+ category: template.category,
3139
+ outputPath,
3140
+ action: "skipped",
3141
+ skipReason: "File already exists"
3142
+ };
3143
+ }
3144
+ const { satisfied, missing } = checkDependencies(template, config);
3145
+ if (!satisfied) {
3146
+ const missingTypes = missing.map((d) => d.type).join(", ");
3147
+ return {
3148
+ name: template.name,
3149
+ category: template.category,
3150
+ outputPath,
3151
+ action: "skipped",
3152
+ skipReason: `Missing required integrations: ${missingTypes}`
3153
+ };
3154
+ }
3155
+ const content = substituteVariables(template.content, variables);
3156
+ const isUpdate = existsSync4(outputPath);
3157
+ writeFileSync2(outputPath, content, "utf-8");
3158
+ return {
3159
+ name: template.name,
3160
+ category: template.category,
3161
+ outputPath,
3162
+ action: isUpdate ? "updated" : "created"
3163
+ };
3164
+ }
3165
+ function formatGenerateResult(result) {
3166
+ const lines = [];
3167
+ const created = result.generated.filter((g) => g.action === "created");
3168
+ const updated = result.generated.filter((g) => g.action === "updated");
3169
+ const skipped = result.generated.filter((g) => g.action === "skipped");
3170
+ if (created.length > 0) {
3171
+ lines.push(`Created ${created.length} skill(s):`);
3172
+ for (const skill of created) {
3173
+ lines.push(` \u2713 ${skill.name}`);
3174
+ }
3175
+ lines.push("");
3176
+ }
3177
+ if (updated.length > 0) {
3178
+ lines.push(`Updated ${updated.length} skill(s):`);
3179
+ for (const skill of updated) {
3180
+ lines.push(` \u2713 ${skill.name}`);
3181
+ }
3182
+ lines.push("");
3183
+ }
3184
+ if (skipped.length > 0) {
3185
+ lines.push(`Skipped ${skipped.length} skill(s):`);
3186
+ for (const skill of skipped) {
3187
+ lines.push(` - ${skill.name}: ${skill.skipReason}`);
3188
+ }
3189
+ lines.push("");
3190
+ }
3191
+ if (result.errors.length > 0) {
3192
+ lines.push(`Failed to generate ${result.errors.length} skill(s):`);
3193
+ for (const error of result.errors) {
3194
+ lines.push(` \u2717 ${error.name}: ${error.error}`);
3195
+ }
3196
+ lines.push("");
3197
+ }
3198
+ const total = created.length + updated.length;
3199
+ if (total > 0) {
3200
+ lines.push(`Generated ${total} skill(s) to .claude/commands/`);
3201
+ } else if (result.generated.length === 0 && result.errors.length === 0) {
3202
+ lines.push("No skills to generate.");
3203
+ }
3204
+ return lines.join("\n");
3205
+ }
3206
+
3207
+ // src/knowledge-library/manager.ts
3208
+ import {
3209
+ existsSync as existsSync5,
3210
+ mkdirSync as mkdirSync3,
3211
+ writeFileSync as writeFileSync3,
3212
+ readFileSync as readFileSync4,
3213
+ readdirSync as readdirSync3,
3214
+ renameSync,
3215
+ statSync as statSync2
3216
+ } from "fs";
3217
+ import { join as join7, basename as basename4 } from "path";
3218
+ var DEFAULT_KNOWLEDGE_LIBRARY_PATH = "KnowledgeLibrary";
3219
+ var STANDARD_FILES = {
3220
+ context: "context.txt",
3221
+ architecture: "architecture.txt",
3222
+ prd: "prd.txt"
3223
+ };
3224
+ var AGENT_DIRECTORIES = [
3225
+ "inbox",
3226
+ "inbox/processed",
3227
+ "outbox",
3228
+ "context",
3229
+ "control",
3230
+ "history",
3231
+ "tech"
3232
+ ];
3233
+ var CONTROL_FILES = {
3234
+ objectives: "objectives.txt",
3235
+ decisions: "decisions.txt",
3236
+ dependencies: "dependencies.txt"
3237
+ };
3238
+ function getAgentDirectories(basePath, agentName) {
3239
+ const root = join7(basePath, agentName);
3240
+ return {
3241
+ root,
3242
+ inbox: join7(root, "inbox"),
3243
+ inboxProcessed: join7(root, "inbox", "processed"),
3244
+ outbox: join7(root, "outbox"),
3245
+ context: join7(root, "context"),
3246
+ control: join7(root, "control"),
3247
+ history: join7(root, "history"),
3248
+ tech: join7(root, "tech")
3249
+ };
3250
+ }
3251
+ function initKnowledgeLibrary(options = {}) {
3252
+ const projectRoot = options.projectRoot ?? process.cwd();
3253
+ const basePath = join7(projectRoot, options.basePath ?? DEFAULT_KNOWLEDGE_LIBRARY_PATH);
3254
+ const createDefaults = options.createDefaults ?? true;
3255
+ const createdDirs = [];
3256
+ const createdFiles = [];
3257
+ try {
3258
+ if (!existsSync5(basePath)) {
3259
+ mkdirSync3(basePath, { recursive: true });
3260
+ createdDirs.push(basePath);
3261
+ }
3262
+ if (createDefaults) {
3263
+ const contextPath = join7(basePath, STANDARD_FILES.context);
3264
+ if (!existsSync5(contextPath)) {
3265
+ writeFileSync3(
3266
+ contextPath,
3267
+ `# Project Context
3268
+
3269
+ ## Current Sprint
3270
+ - Sprint: [Sprint name/number]
3271
+ - Goals: [Sprint goals]
3272
+ - Deadline: [Sprint deadline]
3273
+
3274
+ ## Priorities
3275
+ 1. [Priority 1]
3276
+ 2. [Priority 2]
3277
+ 3. [Priority 3]
3278
+
3279
+ ## Notes
3280
+ [Project-wide notes and context]
3281
+ `,
3282
+ "utf-8"
3283
+ );
3284
+ createdFiles.push(contextPath);
3285
+ }
3286
+ const architecturePath = join7(basePath, STANDARD_FILES.architecture);
3287
+ if (!existsSync5(architecturePath)) {
3288
+ writeFileSync3(
3289
+ architecturePath,
3290
+ `# Architecture Notes
3291
+
3292
+ ## Technical Decisions
3293
+ [Record major technical decisions here]
3294
+
3295
+ ## System Overview
3296
+ [High-level system architecture]
3297
+
3298
+ ## Key Components
3299
+ [Important system components]
3300
+ `,
3301
+ "utf-8"
3302
+ );
3303
+ createdFiles.push(architecturePath);
3304
+ }
3305
+ const prdPath = join7(basePath, STANDARD_FILES.prd);
3306
+ if (!existsSync5(prdPath)) {
3307
+ writeFileSync3(
3308
+ prdPath,
3309
+ `# Product Requirements Document
3310
+
3311
+ ## Overview
3312
+ [Product overview]
3313
+
3314
+ ## Goals
3315
+ [Product goals]
3316
+
3317
+ ## Features
3318
+ [Feature list]
3319
+
3320
+ ## Requirements
3321
+ [Detailed requirements]
3322
+ `,
3323
+ "utf-8"
3324
+ );
3325
+ createdFiles.push(prdPath);
3326
+ }
3327
+ }
3328
+ return {
3329
+ success: true,
3330
+ createdDirs,
3331
+ createdFiles
3332
+ };
3333
+ } catch (error) {
3334
+ return {
3335
+ success: false,
3336
+ createdDirs,
3337
+ createdFiles,
3338
+ error: error instanceof Error ? error.message : String(error)
3339
+ };
3340
+ }
3341
+ }
3342
+ function initAgentKnowledgeLibrary(agentName, options = {}) {
3343
+ const projectRoot = options.projectRoot ?? process.cwd();
3344
+ const basePath = join7(projectRoot, options.basePath ?? DEFAULT_KNOWLEDGE_LIBRARY_PATH);
3345
+ const createDefaults = options.createDefaults ?? true;
3346
+ const createdDirs = [];
3347
+ const createdFiles = [];
3348
+ try {
3349
+ if (!existsSync5(basePath)) {
3350
+ const baseResult = initKnowledgeLibrary(options);
3351
+ if (!baseResult.success) {
3352
+ return baseResult;
3353
+ }
3354
+ createdDirs.push(...baseResult.createdDirs);
3355
+ createdFiles.push(...baseResult.createdFiles);
3356
+ }
3357
+ const dirs = getAgentDirectories(basePath, agentName);
3358
+ for (const dir of AGENT_DIRECTORIES) {
3359
+ const dirPath = join7(dirs.root, dir);
3360
+ if (!existsSync5(dirPath)) {
3361
+ mkdirSync3(dirPath, { recursive: true });
3362
+ createdDirs.push(dirPath);
3363
+ }
3364
+ }
3365
+ if (createDefaults) {
3366
+ const currentContextPath = join7(dirs.context, "current.txt");
3367
+ if (!existsSync5(currentContextPath)) {
3368
+ writeFileSync3(
3369
+ currentContextPath,
3370
+ `# ${agentName} Current Context
3371
+
3372
+ ## Status
3373
+ - State: idle
3374
+ - Current Task: None
3375
+ - Last Updated: ${(/* @__PURE__ */ new Date()).toISOString()}
3376
+
3377
+ ## Notes
3378
+ [Agent-specific context notes]
3379
+ `,
3380
+ "utf-8"
3381
+ );
3382
+ createdFiles.push(currentContextPath);
3383
+ }
3384
+ const objectivesPath = join7(dirs.control, CONTROL_FILES.objectives);
3385
+ if (!existsSync5(objectivesPath)) {
3386
+ writeFileSync3(
3387
+ objectivesPath,
3388
+ `# ${agentName} Objectives
3389
+
3390
+ ## Current Objectives
3391
+ [None]
3392
+
3393
+ ## Success Criteria
3394
+ [Define success criteria for objectives]
3395
+ `,
3396
+ "utf-8"
3397
+ );
3398
+ createdFiles.push(objectivesPath);
3399
+ }
3400
+ const decisionsPath = join7(dirs.control, CONTROL_FILES.decisions);
3401
+ if (!existsSync5(decisionsPath)) {
3402
+ writeFileSync3(
3403
+ decisionsPath,
3404
+ `# ${agentName} Decision Log
3405
+
3406
+ ## Decisions
3407
+ [Record important decisions here]
3408
+
3409
+ Format:
3410
+ - Date: YYYY-MM-DD
3411
+ - Decision: [What was decided]
3412
+ - Reasoning: [Why]
3413
+ - Related: [Ticket or task reference]
3414
+ `,
3415
+ "utf-8"
3416
+ );
3417
+ createdFiles.push(decisionsPath);
3418
+ }
3419
+ const dependenciesPath = join7(dirs.control, CONTROL_FILES.dependencies);
3420
+ if (!existsSync5(dependenciesPath)) {
3421
+ writeFileSync3(
3422
+ dependenciesPath,
3423
+ `# ${agentName} Dependencies
3424
+
3425
+ ## Blocked By
3426
+ [Tasks/agents blocking this agent]
3427
+
3428
+ ## Blocking
3429
+ [Tasks/agents this agent is blocking]
3430
+
3431
+ Last Updated: ${(/* @__PURE__ */ new Date()).toISOString()}
3432
+ `,
3433
+ "utf-8"
3434
+ );
3435
+ createdFiles.push(dependenciesPath);
3436
+ }
3437
+ }
3438
+ return {
3439
+ success: true,
3440
+ createdDirs,
3441
+ createdFiles
3442
+ };
3443
+ } catch (error) {
3444
+ return {
3445
+ success: false,
3446
+ createdDirs,
3447
+ createdFiles,
3448
+ error: error instanceof Error ? error.message : String(error)
3449
+ };
3450
+ }
3451
+ }
3452
+ function agentKnowledgeLibraryExists(agentName, options = {}) {
3453
+ const projectRoot = options.projectRoot ?? process.cwd();
3454
+ const basePath = join7(projectRoot, options.basePath ?? DEFAULT_KNOWLEDGE_LIBRARY_PATH);
3455
+ const agentRoot = join7(basePath, agentName);
3456
+ return existsSync5(agentRoot) && existsSync5(join7(agentRoot, "inbox"));
3457
+ }
3458
+ function getAgentKnowledgeState(agentName, options = {}) {
3459
+ const projectRoot = options.projectRoot ?? process.cwd();
3460
+ const basePath = join7(projectRoot, options.basePath ?? DEFAULT_KNOWLEDGE_LIBRARY_PATH);
3461
+ const dirs = getAgentDirectories(basePath, agentName);
3462
+ const initialized = agentKnowledgeLibraryExists(agentName, options);
3463
+ const pendingMessages = initialized ? readInboxMessages(agentName, options) : [];
3464
+ let context;
3465
+ const currentContextPath = join7(dirs.context, "current.txt");
3466
+ if (existsSync5(currentContextPath)) {
3467
+ const content = readFileSync4(currentContextPath, "utf-8");
3468
+ context = parseContextFile(content);
3469
+ }
3470
+ const state = {
3471
+ agentName,
3472
+ directories: dirs,
3473
+ pendingMessages,
3474
+ initialized
3475
+ };
3476
+ if (context) {
3477
+ state.context = context;
3478
+ }
3479
+ return state;
3480
+ }
3481
+ function parseContextFile(content) {
3482
+ const context = {
3483
+ lastUpdated: /* @__PURE__ */ new Date()
3484
+ };
3485
+ const statusMatch = content.match(/State:\s*(.+)/i);
3486
+ if (statusMatch && statusMatch[1]) {
3487
+ context.status = statusMatch[1].trim();
3488
+ }
3489
+ const taskMatch = content.match(/Current Task:\s*(.+)/i);
3490
+ if (taskMatch && taskMatch[1] && taskMatch[1].trim() !== "None") {
3491
+ context.currentTask = taskMatch[1].trim();
3492
+ }
3493
+ const ticketMatch = content.match(/Current Ticket:\s*([A-Z]+-\d+)/i);
3494
+ if (ticketMatch && ticketMatch[1]) {
3495
+ context.currentTicket = ticketMatch[1];
3496
+ }
3497
+ const updatedMatch = content.match(/Last Updated:\s*(.+)/i);
3498
+ if (updatedMatch) {
3499
+ const dateStr = updatedMatch[1]?.trim();
3500
+ if (dateStr) {
3501
+ const parsed = new Date(dateStr);
3502
+ if (!isNaN(parsed.getTime())) {
3503
+ context.lastUpdated = parsed;
3504
+ }
3505
+ }
3506
+ }
3507
+ return context;
3508
+ }
3509
+ function generateMessageFilename(from, subject) {
3510
+ const now = /* @__PURE__ */ new Date();
3511
+ const timestamp = now.toISOString().replace(/[-:T]/g, "").slice(0, 12);
3512
+ const sanitizedSubject = subject.toLowerCase().replace(/[^a-z0-9]+/g, "-").slice(0, 30);
3513
+ return `${timestamp}-${from}-${sanitizedSubject}.md`;
3514
+ }
3515
+ function parseMessageFrontmatter(content) {
3516
+ const match = content.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n([\s\S]*)$/);
3517
+ if (!match) {
3518
+ return { metadata: {}, body: content };
3519
+ }
3520
+ const frontmatter = match[1] ?? "";
3521
+ const body = match[2] ?? "";
3522
+ const metadata = {};
3523
+ for (const line of frontmatter.split(/\r?\n/)) {
3524
+ const colonIndex = line.indexOf(":");
3525
+ if (colonIndex === -1) continue;
3526
+ const key = line.slice(0, colonIndex).trim();
3527
+ const value = line.slice(colonIndex + 1).trim();
3528
+ switch (key) {
3529
+ case "type":
3530
+ metadata.type = value;
3531
+ break;
3532
+ case "from":
3533
+ metadata.from = value;
3534
+ break;
3535
+ case "to":
3536
+ metadata.to = value;
3537
+ break;
3538
+ case "date":
3539
+ metadata.date = new Date(value);
3540
+ break;
3541
+ case "ticket":
3542
+ metadata.ticket = value;
3543
+ break;
3544
+ case "priority":
3545
+ if (value === "P0" || value === "P1" || value === "P2" || value === "P3") {
3546
+ metadata.priority = value;
3547
+ }
3548
+ break;
3549
+ case "subject":
3550
+ metadata.subject = value;
3551
+ break;
3552
+ }
3553
+ }
3554
+ return { metadata, body };
3555
+ }
3556
+ function readInboxMessages(agentName, options = {}) {
3557
+ const projectRoot = options.projectRoot ?? process.cwd();
3558
+ const basePath = join7(projectRoot, options.basePath ?? DEFAULT_KNOWLEDGE_LIBRARY_PATH);
3559
+ const dirs = getAgentDirectories(basePath, agentName);
3560
+ const messages = [];
3561
+ if (existsSync5(dirs.inbox)) {
3562
+ const files = readdirSync3(dirs.inbox).filter(
3563
+ (f) => f.endsWith(".md") && statSync2(join7(dirs.inbox, f)).isFile()
3564
+ );
3565
+ for (const file of files) {
3566
+ const filePath = join7(dirs.inbox, file);
3567
+ const rawContent = readFileSync4(filePath, "utf-8");
3568
+ const { metadata, body } = parseMessageFrontmatter(rawContent);
3569
+ if (options.type && metadata.type !== options.type) continue;
3570
+ if (options.from && metadata.from !== options.from) continue;
3571
+ if (options.priority && metadata.priority !== options.priority) continue;
3572
+ messages.push({
3573
+ filename: file,
3574
+ path: filePath,
3575
+ metadata,
3576
+ rawContent,
3577
+ body
3578
+ });
3579
+ }
3580
+ }
3581
+ if (options.includeProcessed && existsSync5(dirs.inboxProcessed)) {
3582
+ const files = readdirSync3(dirs.inboxProcessed).filter(
3583
+ (f) => f.endsWith(".md") && statSync2(join7(dirs.inboxProcessed, f)).isFile()
3584
+ );
3585
+ for (const file of files) {
3586
+ const filePath = join7(dirs.inboxProcessed, file);
3587
+ const rawContent = readFileSync4(filePath, "utf-8");
3588
+ const { metadata, body } = parseMessageFrontmatter(rawContent);
3589
+ if (options.type && metadata.type !== options.type) continue;
3590
+ if (options.from && metadata.from !== options.from) continue;
3591
+ if (options.priority && metadata.priority !== options.priority) continue;
3592
+ messages.push({
3593
+ filename: file,
3594
+ path: filePath,
3595
+ metadata,
3596
+ rawContent,
3597
+ body
3598
+ });
3599
+ }
3600
+ }
3601
+ messages.sort((a, b) => {
3602
+ const dateA = a.metadata.date?.getTime() ?? 0;
3603
+ const dateB = b.metadata.date?.getTime() ?? 0;
3604
+ return dateB - dateA;
3605
+ });
3606
+ if (options.limit && messages.length > options.limit) {
3607
+ return messages.slice(0, options.limit);
3608
+ }
3609
+ return messages;
3610
+ }
3611
+ function writeInboxMessage(options) {
3612
+ const projectRoot = options.projectRoot ?? process.cwd();
3613
+ const basePath = join7(projectRoot, options.basePath ?? DEFAULT_KNOWLEDGE_LIBRARY_PATH);
3614
+ const dirs = getAgentDirectories(basePath, options.to);
3615
+ try {
3616
+ if (!existsSync5(dirs.inbox)) {
3617
+ mkdirSync3(dirs.inbox, { recursive: true });
3618
+ }
3619
+ const filename = generateMessageFilename(options.from, options.subject);
3620
+ const filePath = join7(dirs.inbox, filename);
3621
+ const now = /* @__PURE__ */ new Date();
3622
+ const content = formatMessage(options, now);
3623
+ writeFileSync3(filePath, content, "utf-8");
3624
+ const senderDirs = getAgentDirectories(basePath, options.from);
3625
+ if (existsSync5(senderDirs.outbox)) {
3626
+ writeFileSync3(join7(senderDirs.outbox, filename), content, "utf-8");
3627
+ }
3628
+ return { success: true, path: filePath };
3629
+ } catch (error) {
3630
+ return {
3631
+ success: false,
3632
+ error: error instanceof Error ? error.message : String(error)
3633
+ };
3634
+ }
3635
+ }
3636
+ function formatMessage(options, date) {
3637
+ let frontmatter = `---
3638
+ type: ${options.type}
3639
+ from: ${options.from}
3640
+ to: ${options.to}
3641
+ date: ${date.toISOString().slice(0, 16).replace("T", " ")}`;
3642
+ if (options.ticket) {
3643
+ frontmatter += `
3644
+ ticket: ${options.ticket}`;
3645
+ }
3646
+ if (options.priority) {
3647
+ frontmatter += `
3648
+ priority: ${options.priority}`;
3649
+ }
3650
+ frontmatter += `
3651
+ subject: ${options.subject}`;
3652
+ frontmatter += `
3653
+ ---
3654
+
3655
+ ## ${options.subject}
3656
+
3657
+ ${options.body}`;
3658
+ return frontmatter;
3659
+ }
3660
+ function markMessageProcessed(agentName, messageFilename, options = {}) {
3661
+ const projectRoot = options.projectRoot ?? process.cwd();
3662
+ const basePath = join7(projectRoot, options.basePath ?? DEFAULT_KNOWLEDGE_LIBRARY_PATH);
3663
+ const dirs = getAgentDirectories(basePath, agentName);
3664
+ const sourcePath = join7(dirs.inbox, messageFilename);
3665
+ const destPath = join7(dirs.inboxProcessed, messageFilename);
3666
+ try {
3667
+ if (!existsSync5(sourcePath)) {
3668
+ return { success: false, error: `Message not found: ${messageFilename}` };
3669
+ }
3670
+ if (!existsSync5(dirs.inboxProcessed)) {
3671
+ mkdirSync3(dirs.inboxProcessed, { recursive: true });
3672
+ }
3673
+ renameSync(sourcePath, destPath);
3674
+ return { success: true };
3675
+ } catch (error) {
3676
+ return {
3677
+ success: false,
3678
+ error: error instanceof Error ? error.message : String(error)
3679
+ };
3680
+ }
3681
+ }
3682
+ function getKnowledgeLibraryState(options = {}) {
3683
+ const projectRoot = options.projectRoot ?? process.cwd();
3684
+ const basePath = join7(projectRoot, options.basePath ?? DEFAULT_KNOWLEDGE_LIBRARY_PATH);
3685
+ if (!existsSync5(basePath)) {
3686
+ return null;
3687
+ }
3688
+ const agents = [];
3689
+ const entries = readdirSync3(basePath);
3690
+ for (const entry of entries) {
3691
+ const entryPath = join7(basePath, entry);
3692
+ if (statSync2(entryPath).isDirectory() && existsSync5(join7(entryPath, "inbox"))) {
3693
+ agents.push(entry);
3694
+ }
3695
+ }
3696
+ return {
3697
+ basePath,
3698
+ contextPath: join7(basePath, STANDARD_FILES.context),
3699
+ architecturePath: join7(basePath, STANDARD_FILES.architecture),
3700
+ prdPath: join7(basePath, STANDARD_FILES.prd),
3701
+ agents
3702
+ };
3703
+ }
3704
+ function updateAgentContext(agentName, context, options = {}) {
3705
+ const projectRoot = options.projectRoot ?? process.cwd();
3706
+ const basePath = join7(projectRoot, options.basePath ?? DEFAULT_KNOWLEDGE_LIBRARY_PATH);
3707
+ const dirs = getAgentDirectories(basePath, agentName);
3708
+ const contextPath = join7(dirs.context, "current.txt");
3709
+ try {
3710
+ const now = /* @__PURE__ */ new Date();
3711
+ const content = `# ${agentName} Current Context
3712
+
3713
+ ## Status
3714
+ - State: ${context.status ?? "idle"}
3715
+ - Current Task: ${context.currentTask ?? "None"}
3716
+ ${context.currentTicket ? `- Current Ticket: ${context.currentTicket}` : ""}- Last Updated: ${now.toISOString()}
3717
+
3718
+ ## Notes
3719
+ ${context.notes ?? "[Agent-specific context notes]"}
3720
+ `;
3721
+ if (!existsSync5(dirs.context)) {
3722
+ mkdirSync3(dirs.context, { recursive: true });
3723
+ }
3724
+ writeFileSync3(contextPath, content, "utf-8");
3725
+ return { success: true };
3726
+ } catch (error) {
3727
+ return {
3728
+ success: false,
3729
+ error: error instanceof Error ? error.message : String(error)
3730
+ };
3731
+ }
3732
+ }
3733
+ function formatKnowledgeLibraryState(state) {
3734
+ if (!state) {
3735
+ return "KnowledgeLibrary not initialized.";
3736
+ }
3737
+ const lines = [];
3738
+ lines.push(`KnowledgeLibrary: ${state.basePath}
3739
+ `);
3740
+ lines.push("Global files:");
3741
+ lines.push(` - ${basename4(state.contextPath)}`);
3742
+ lines.push(` - ${basename4(state.architecturePath)}`);
3743
+ lines.push(` - ${basename4(state.prdPath)}`);
3744
+ lines.push("");
3745
+ if (state.agents.length > 0) {
3746
+ lines.push(`Agents (${state.agents.length}):`);
3747
+ for (const agent of state.agents) {
3748
+ lines.push(` - ${agent}`);
3749
+ }
3750
+ } else {
3751
+ lines.push("No agents initialized.");
3752
+ }
3753
+ return lines.join("\n");
3754
+ }
3755
+ function formatAgentKnowledgeState(state) {
3756
+ const lines = [];
3757
+ lines.push(`Agent: ${state.agentName}`);
3758
+ lines.push(`Status: ${state.initialized ? "Initialized" : "Not initialized"}`);
3759
+ lines.push("");
3760
+ if (state.context) {
3761
+ lines.push("Context:");
3762
+ lines.push(` State: ${state.context.status ?? "unknown"}`);
3763
+ if (state.context.currentTask) {
3764
+ lines.push(` Current Task: ${state.context.currentTask}`);
3765
+ }
3766
+ if (state.context.currentTicket) {
3767
+ lines.push(` Current Ticket: ${state.context.currentTicket}`);
3768
+ }
3769
+ lines.push(` Last Updated: ${state.context.lastUpdated.toISOString()}`);
3770
+ lines.push("");
3771
+ }
3772
+ if (state.pendingMessages.length > 0) {
3773
+ lines.push(`Pending Messages (${state.pendingMessages.length}):`);
3774
+ for (const msg of state.pendingMessages) {
3775
+ const type = msg.metadata.type ?? "unknown";
3776
+ const from = msg.metadata.from ?? "unknown";
3777
+ const subject = msg.metadata.subject ?? msg.filename;
3778
+ lines.push(` - [${type}] from ${from}: ${subject}`);
3779
+ }
3780
+ } else {
3781
+ lines.push("No pending messages.");
3782
+ }
3783
+ return lines.join("\n");
3784
+ }
3785
+
3786
+ // src/index.ts
3787
+ var VERSION = "0.1.0";
3788
+ export {
3789
+ AGENT_DIRECTORIES,
3790
+ AdapterError,
3791
+ AdapterFactory,
3792
+ AgentError,
3793
+ CACHE_PATHS,
3794
+ CONTROL_FILES,
3795
+ CacheError,
3796
+ CommandRegistry,
3797
+ ConfigError,
3798
+ ContextLoader,
3799
+ DEFAULT_CACHE_CONFIG,
3800
+ DEFAULT_KNOWLEDGE_LIBRARY_PATH,
3801
+ CacheManager as FileCacheManager,
3802
+ FileCacheProvider,
3803
+ ResolutionError,
3804
+ STANDARD_FILES,
3805
+ StepTracker,
3806
+ VERSION,
3807
+ agentKnowledgeLibraryExists,
3808
+ builtInSkills,
3809
+ checkDependencies,
3810
+ cleanupContext,
3811
+ compileAgent,
3812
+ compileAgents,
3813
+ configExists,
3814
+ createAdapterFactory,
3815
+ createAdapterInfo,
3816
+ createCacheManager,
3817
+ createCommandContext,
3818
+ createCommandRegistry,
3819
+ createContextLoader,
3820
+ createDegradingHandler,
3821
+ createFileCacheProvider,
3822
+ executeWithDegradation,
3823
+ extractVariables2 as extractSkillVariables,
3824
+ extractVariables,
3825
+ filterAgentsByTeam,
3826
+ findConfigFile,
3827
+ formatAgentKnowledgeState,
3828
+ formatGenerateResult,
3829
+ formatKnowledgeLibraryState,
3830
+ generateAgentMarkdown,
3831
+ generateMessageFilename,
3832
+ generateSkills,
3833
+ getAgentDirectories,
3834
+ getAgentKnowledgeState,
3835
+ getConfigPath,
3836
+ getCoreAgentsDir,
3837
+ getGlobalRegistry,
3838
+ getKnowledgeLibraryState,
3839
+ getRoleFromFilename,
3840
+ hasVariables,
3841
+ initAgentKnowledgeLibrary,
3842
+ initKnowledgeLibrary,
3843
+ loadAgentFromFile,
3844
+ loadAgentsFromDirectory,
3845
+ loadAllAgents,
3846
+ loadAllCommands,
3847
+ loadCommandFromFile,
3848
+ loadCommandsFromDirectory,
3849
+ loadConfig,
3850
+ loadConfigFromFile,
3851
+ loadCoreAICommands,
3852
+ loadCustomTemplates,
3853
+ markMessageProcessed,
3854
+ parseAgentYaml,
3855
+ readInboxMessages,
3856
+ resetGlobalRegistry,
3857
+ resolveAgentDefinition,
3858
+ resolveObject,
3859
+ resolveString,
3860
+ runCommand,
3861
+ substituteVariables,
3862
+ updateAgentContext,
3863
+ validateAgentDefinition,
3864
+ withContext,
3865
+ writeInboxMessage
3866
+ };
3867
+ //# sourceMappingURL=index.js.map