scene-capability-engine 3.0.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 (336) hide show
  1. package/CHANGELOG.md +2513 -0
  2. package/LICENSE +21 -0
  3. package/README.md +765 -0
  4. package/README.zh.md +630 -0
  5. package/bin/kiro-spec-engine.js +796 -0
  6. package/bin/kse.js +3 -0
  7. package/bin/sce.js +3 -0
  8. package/bin/sco.js +3 -0
  9. package/docs/331-poc-adaptation-roadmap.md +156 -0
  10. package/docs/331-poc-dual-track-integration-guide.md +120 -0
  11. package/docs/331-poc-weekly-delivery-checklist.md +52 -0
  12. package/docs/OFFLINE_INSTALL.md +96 -0
  13. package/docs/README.md +279 -0
  14. package/docs/adopt-migration-guide.md +599 -0
  15. package/docs/adoption-guide.md +616 -0
  16. package/docs/agent-hooks-analysis.md +815 -0
  17. package/docs/architecture.md +733 -0
  18. package/docs/articles/ai-driven-development-philosophy-and-practice-review.md +208 -0
  19. package/docs/articles/ai-driven-development-philosophy-and-practice.en.md +459 -0
  20. package/docs/articles/ai-driven-development-philosophy-and-practice.md +492 -0
  21. package/docs/autonomous-control-guide.md +851 -0
  22. package/docs/command-reference.md +1368 -0
  23. package/docs/community.md +115 -0
  24. package/docs/cross-tool-guide.md +555 -0
  25. package/docs/developer-guide.md +619 -0
  26. package/docs/document-governance.md +865 -0
  27. package/docs/environment-management-guide.md +526 -0
  28. package/docs/examples/add-export-command/design.md +194 -0
  29. package/docs/examples/add-export-command/requirements.md +110 -0
  30. package/docs/examples/add-export-command/tasks.md +88 -0
  31. package/docs/examples/add-rest-api/design.md +855 -0
  32. package/docs/examples/add-rest-api/requirements.md +323 -0
  33. package/docs/examples/add-rest-api/tasks.md +355 -0
  34. package/docs/examples/add-user-dashboard/design.md +192 -0
  35. package/docs/examples/add-user-dashboard/requirements.md +143 -0
  36. package/docs/examples/add-user-dashboard/tasks.md +91 -0
  37. package/docs/faq.md +697 -0
  38. package/docs/handoffs/evidence/ontology/moqui-template-baseline-2026-02-17-232922.json +156 -0
  39. package/docs/handoffs/evidence/ontology/moqui-template-baseline-2026-02-17-232922.md +24 -0
  40. package/docs/images/wechat-qr.png +0 -0
  41. package/docs/integration-modes.md +529 -0
  42. package/docs/integration-philosophy.md +313 -0
  43. package/docs/knowledge-management-guide.md +263 -0
  44. package/docs/manual-workflows-guide.md +418 -0
  45. package/docs/moqui-capability-matrix.md +73 -0
  46. package/docs/moqui-template-core-library-playbook.md +109 -0
  47. package/docs/multi-agent-coordination-guide.md +553 -0
  48. package/docs/multi-repo-management-guide.md +1344 -0
  49. package/docs/quick-start-with-ai-tools.md +375 -0
  50. package/docs/quick-start.md +146 -0
  51. package/docs/release-checklist.md +121 -0
  52. package/docs/releases/README.md +13 -0
  53. package/docs/releases/v1.46.2-validation.md +45 -0
  54. package/docs/releases/v1.46.2.md +50 -0
  55. package/docs/scene-runtime-guide.md +347 -0
  56. package/docs/spec-collaboration-guide.md +369 -0
  57. package/docs/spec-locking-guide.md +225 -0
  58. package/docs/spec-numbering-guide.md +348 -0
  59. package/docs/spec-workflow.md +519 -0
  60. package/docs/steering-strategy-guide.md +196 -0
  61. package/docs/team-collaboration-guide.md +465 -0
  62. package/docs/testing-strategy.md +272 -0
  63. package/docs/tools/claude-guide.md +654 -0
  64. package/docs/tools/cursor-guide.md +706 -0
  65. package/docs/tools/generic-guide.md +446 -0
  66. package/docs/tools/kiro-guide.md +308 -0
  67. package/docs/tools/vscode-guide.md +445 -0
  68. package/docs/tools/windsurf-guide.md +391 -0
  69. package/docs/troubleshooting.md +1135 -0
  70. package/docs/upgrade-guide.md +639 -0
  71. package/docs/value-observability-guide.md +127 -0
  72. package/docs/zh/README.md +341 -0
  73. package/docs/zh/quick-start.md +764 -0
  74. package/docs/zh/release-checklist.md +121 -0
  75. package/docs/zh/releases/README.md +13 -0
  76. package/docs/zh/releases/v1.46.2-validation.md +45 -0
  77. package/docs/zh/releases/v1.46.2.md +50 -0
  78. package/docs/zh/spec-numbering-guide.md +348 -0
  79. package/docs/zh/tools/claude-guide.md +349 -0
  80. package/docs/zh/tools/cursor-guide.md +281 -0
  81. package/docs/zh/tools/generic-guide.md +499 -0
  82. package/docs/zh/tools/kiro-guide.md +342 -0
  83. package/docs/zh/tools/vscode-guide.md +449 -0
  84. package/docs/zh/tools/windsurf-guide.md +378 -0
  85. package/docs/zh/value-observability-guide.md +127 -0
  86. package/docs//344/272/244/344/273/230/346/270/205/345/215/225.md +75 -0
  87. package/lib/adoption/adoption-logger.js +487 -0
  88. package/lib/adoption/adoption-strategy.js +538 -0
  89. package/lib/adoption/backup-manager.js +420 -0
  90. package/lib/adoption/conflict-resolver.js +410 -0
  91. package/lib/adoption/detection-engine.js +275 -0
  92. package/lib/adoption/diff-viewer.js +226 -0
  93. package/lib/adoption/error-formatter.js +509 -0
  94. package/lib/adoption/file-classifier.js +385 -0
  95. package/lib/adoption/progress-reporter.js +534 -0
  96. package/lib/adoption/smart-orchestrator.js +470 -0
  97. package/lib/adoption/strategy-selector.js +218 -0
  98. package/lib/adoption/summary-generator.js +493 -0
  99. package/lib/adoption/template-sync.js +605 -0
  100. package/lib/auto/autonomous-engine.js +485 -0
  101. package/lib/auto/checkpoint-manager.js +300 -0
  102. package/lib/auto/close-loop-runner.js +2476 -0
  103. package/lib/auto/config-schema.js +176 -0
  104. package/lib/auto/decision-engine.js +344 -0
  105. package/lib/auto/error-recovery-manager.js +580 -0
  106. package/lib/auto/goal-decomposer.js +278 -0
  107. package/lib/auto/progress-tracker.js +502 -0
  108. package/lib/auto/safety-manager.js +186 -0
  109. package/lib/auto/semantic-decomposer.js +137 -0
  110. package/lib/auto/state-manager.js +126 -0
  111. package/lib/auto/task-queue-manager.js +340 -0
  112. package/lib/backup/backup-system.js +372 -0
  113. package/lib/backup/selective-backup.js +207 -0
  114. package/lib/collab/agent-registry.js +240 -0
  115. package/lib/collab/collab-manager.js +285 -0
  116. package/lib/collab/contract-manager.js +320 -0
  117. package/lib/collab/coordinator.js +370 -0
  118. package/lib/collab/dependency-manager.js +280 -0
  119. package/lib/collab/index.js +20 -0
  120. package/lib/collab/integration-manager.js +202 -0
  121. package/lib/collab/merge-coordinator.js +252 -0
  122. package/lib/collab/metadata-manager.js +233 -0
  123. package/lib/collab/multi-agent-config.js +120 -0
  124. package/lib/collab/spec-lifecycle-manager.js +304 -0
  125. package/lib/collab/sync-barrier.js +88 -0
  126. package/lib/collab/visualizer.js +208 -0
  127. package/lib/commands/adopt.js +749 -0
  128. package/lib/commands/auto.js +19559 -0
  129. package/lib/commands/collab.js +275 -0
  130. package/lib/commands/context.js +99 -0
  131. package/lib/commands/docs.js +808 -0
  132. package/lib/commands/doctor.js +273 -0
  133. package/lib/commands/env.js +420 -0
  134. package/lib/commands/knowledge.js +309 -0
  135. package/lib/commands/lock.js +235 -0
  136. package/lib/commands/ops.js +409 -0
  137. package/lib/commands/orchestrate.js +446 -0
  138. package/lib/commands/prompt.js +105 -0
  139. package/lib/commands/repo.js +118 -0
  140. package/lib/commands/rollback.js +219 -0
  141. package/lib/commands/scene.js +15549 -0
  142. package/lib/commands/spec-bootstrap.js +147 -0
  143. package/lib/commands/spec-gate.js +157 -0
  144. package/lib/commands/spec-pipeline.js +205 -0
  145. package/lib/commands/status.js +321 -0
  146. package/lib/commands/task.js +199 -0
  147. package/lib/commands/templates.js +654 -0
  148. package/lib/commands/upgrade.js +231 -0
  149. package/lib/commands/value.js +569 -0
  150. package/lib/commands/watch.js +684 -0
  151. package/lib/commands/workflows.js +240 -0
  152. package/lib/commands/workspace-multi.js +325 -0
  153. package/lib/commands/workspace.js +189 -0
  154. package/lib/context/context-exporter.js +378 -0
  155. package/lib/context/prompt-generator.js +482 -0
  156. package/lib/data/moqui-capability-lexicon.json +45 -0
  157. package/lib/environment/backup-system.js +189 -0
  158. package/lib/environment/environment-manager.js +379 -0
  159. package/lib/environment/environment-registry.js +168 -0
  160. package/lib/gitignore/gitignore-backup.js +229 -0
  161. package/lib/gitignore/gitignore-detector.js +239 -0
  162. package/lib/gitignore/gitignore-integration.js +267 -0
  163. package/lib/gitignore/gitignore-transformer.js +193 -0
  164. package/lib/gitignore/layered-rules-template.js +42 -0
  165. package/lib/governance/archive-tool.js +284 -0
  166. package/lib/governance/cleanup-tool.js +237 -0
  167. package/lib/governance/config-manager.js +186 -0
  168. package/lib/governance/diagnostic-engine.js +271 -0
  169. package/lib/governance/doc-reference-checker.js +200 -0
  170. package/lib/governance/execution-logger.js +243 -0
  171. package/lib/governance/file-scanner.js +285 -0
  172. package/lib/governance/hooks-manager.js +333 -0
  173. package/lib/governance/reporter.js +337 -0
  174. package/lib/governance/validation-engine.js +181 -0
  175. package/lib/i18n.js +79 -0
  176. package/lib/knowledge/entry-manager.js +208 -0
  177. package/lib/knowledge/index-manager.js +261 -0
  178. package/lib/knowledge/knowledge-manager.js +273 -0
  179. package/lib/knowledge/template-manager.js +191 -0
  180. package/lib/lock/index.js +21 -0
  181. package/lib/lock/lock-file.js +192 -0
  182. package/lib/lock/lock-manager.js +321 -0
  183. package/lib/lock/machine-identifier.js +135 -0
  184. package/lib/lock/steering-file-lock.js +207 -0
  185. package/lib/lock/task-lock-manager.js +345 -0
  186. package/lib/operations/audit-logger.js +293 -0
  187. package/lib/operations/feedback-manager.js +1147 -0
  188. package/lib/operations/index.js +23 -0
  189. package/lib/operations/models/index.js +170 -0
  190. package/lib/operations/operations-manager.js +151 -0
  191. package/lib/operations/operations-validator.js +280 -0
  192. package/lib/operations/permission-manager.js +354 -0
  193. package/lib/operations/template-loader.js +143 -0
  194. package/lib/orchestrator/agent-spawner.js +629 -0
  195. package/lib/orchestrator/bootstrap-prompt-builder.js +236 -0
  196. package/lib/orchestrator/index.js +19 -0
  197. package/lib/orchestrator/orchestration-engine.js +1270 -0
  198. package/lib/orchestrator/orchestrator-config.js +173 -0
  199. package/lib/orchestrator/status-monitor.js +591 -0
  200. package/lib/python-checker.js +209 -0
  201. package/lib/repo/config-manager.js +580 -0
  202. package/lib/repo/errors/config-error.js +13 -0
  203. package/lib/repo/errors/git-error.js +15 -0
  204. package/lib/repo/errors/repo-error.js +14 -0
  205. package/lib/repo/git-operations.js +181 -0
  206. package/lib/repo/handlers/.gitkeep +1 -0
  207. package/lib/repo/handlers/exec-handler.js +155 -0
  208. package/lib/repo/handlers/health-handler.js +169 -0
  209. package/lib/repo/handlers/init-handler.js +197 -0
  210. package/lib/repo/handlers/status-handler.js +176 -0
  211. package/lib/repo/output-formatter.js +184 -0
  212. package/lib/repo/path-resolver.js +178 -0
  213. package/lib/repo/repo-manager.js +514 -0
  214. package/lib/scene-runtime/audit-emitter.js +59 -0
  215. package/lib/scene-runtime/binding-plugin-loader.js +351 -0
  216. package/lib/scene-runtime/binding-registry.js +349 -0
  217. package/lib/scene-runtime/eval-bridge.js +44 -0
  218. package/lib/scene-runtime/index.js +19 -0
  219. package/lib/scene-runtime/moqui-adapter.js +620 -0
  220. package/lib/scene-runtime/moqui-client.js +606 -0
  221. package/lib/scene-runtime/moqui-extractor.js +2029 -0
  222. package/lib/scene-runtime/plan-compiler.js +208 -0
  223. package/lib/scene-runtime/policy-gate.js +58 -0
  224. package/lib/scene-runtime/runtime-executor.js +358 -0
  225. package/lib/scene-runtime/scene-loader.js +96 -0
  226. package/lib/scene-runtime/scene-ontology.js +959 -0
  227. package/lib/scene-runtime/scene-template-linter.js +852 -0
  228. package/lib/scene-runtime/templates/scene-template-erp-query-v0.1.yaml +28 -0
  229. package/lib/scene-runtime/templates/scene-template-hybrid-shadow-v0.1.yaml +34 -0
  230. package/lib/spec/bootstrap/context-collector.js +48 -0
  231. package/lib/spec/bootstrap/draft-generator.js +158 -0
  232. package/lib/spec/bootstrap/questionnaire-engine.js +70 -0
  233. package/lib/spec/bootstrap/trace-emitter.js +59 -0
  234. package/lib/spec/multi-spec-orchestrate.js +93 -0
  235. package/lib/spec/pipeline/constants.js +6 -0
  236. package/lib/spec/pipeline/stage-adapters.js +118 -0
  237. package/lib/spec/pipeline/stage-runner.js +146 -0
  238. package/lib/spec/pipeline/state-store.js +119 -0
  239. package/lib/spec-gate/engine/gate-engine.js +165 -0
  240. package/lib/spec-gate/policy/default-policy.js +22 -0
  241. package/lib/spec-gate/policy/policy-loader.js +103 -0
  242. package/lib/spec-gate/result-emitter.js +81 -0
  243. package/lib/spec-gate/rules/default-rules.js +156 -0
  244. package/lib/spec-gate/rules/rule-registry.js +51 -0
  245. package/lib/steering/adoption-config.js +164 -0
  246. package/lib/steering/compliance-auto-fixer.js +204 -0
  247. package/lib/steering/compliance-cache.js +99 -0
  248. package/lib/steering/compliance-error-reporter.js +70 -0
  249. package/lib/steering/context-sync-manager.js +273 -0
  250. package/lib/steering/index.js +92 -0
  251. package/lib/steering/spec-steering.js +230 -0
  252. package/lib/steering/steering-compliance-checker.js +73 -0
  253. package/lib/steering/steering-loader.js +144 -0
  254. package/lib/steering/steering-manager.js +289 -0
  255. package/lib/task/index.js +12 -0
  256. package/lib/task/task-claimer.js +489 -0
  257. package/lib/task/task-status-store.js +418 -0
  258. package/lib/templates/cache-manager.js +440 -0
  259. package/lib/templates/content-generalizer.js +247 -0
  260. package/lib/templates/frontmatter-generator.js +128 -0
  261. package/lib/templates/git-handler.js +471 -0
  262. package/lib/templates/metadata-collector.js +328 -0
  263. package/lib/templates/path-utils.js +144 -0
  264. package/lib/templates/registry-parser.js +505 -0
  265. package/lib/templates/spec-reader.js +216 -0
  266. package/lib/templates/template-applicator.js +249 -0
  267. package/lib/templates/template-creator.js +256 -0
  268. package/lib/templates/template-error.js +143 -0
  269. package/lib/templates/template-exporter.js +502 -0
  270. package/lib/templates/template-manager.js +782 -0
  271. package/lib/templates/template-validator.js +361 -0
  272. package/lib/upgrade/migration-engine.js +382 -0
  273. package/lib/upgrade/migrations/.gitkeep +52 -0
  274. package/lib/upgrade/migrations/1.0.0-to-1.1.0.js +78 -0
  275. package/lib/utils/file-diff.js +177 -0
  276. package/lib/utils/fs-utils.js +274 -0
  277. package/lib/utils/tool-detector.js +383 -0
  278. package/lib/utils/validation.js +324 -0
  279. package/lib/value/gate-summary-emitter.js +99 -0
  280. package/lib/value/metric-contract-loader.js +210 -0
  281. package/lib/value/risk-evaluator.js +117 -0
  282. package/lib/value/weekly-snapshot-builder.js +61 -0
  283. package/lib/version/version-checker.js +156 -0
  284. package/lib/version/version-manager.js +327 -0
  285. package/lib/watch/action-executor.js +458 -0
  286. package/lib/watch/event-debouncer.js +323 -0
  287. package/lib/watch/execution-logger.js +550 -0
  288. package/lib/watch/file-watcher.js +499 -0
  289. package/lib/watch/presets.js +266 -0
  290. package/lib/watch/watch-manager.js +533 -0
  291. package/lib/workspace/multi/global-config.js +150 -0
  292. package/lib/workspace/multi/index.js +22 -0
  293. package/lib/workspace/multi/path-utils.js +173 -0
  294. package/lib/workspace/multi/workspace-context-resolver.js +244 -0
  295. package/lib/workspace/multi/workspace-registry.js +196 -0
  296. package/lib/workspace/multi/workspace-state-manager.js +537 -0
  297. package/lib/workspace/multi/workspace.js +90 -0
  298. package/lib/workspace/workspace-manager.js +370 -0
  299. package/lib/workspace/workspace-sync.js +356 -0
  300. package/locales/en.json +114 -0
  301. package/locales/zh.json +114 -0
  302. package/package.json +102 -0
  303. package/template/.kiro/README.md +247 -0
  304. package/template/.kiro/hooks/check-spec-on-create.kiro.hook +17 -0
  305. package/template/.kiro/hooks/run-tests-on-save.kiro.hook +13 -0
  306. package/template/.kiro/hooks/sync-tasks-on-edit.kiro.hook +16 -0
  307. package/template/.kiro/specs/SPEC_WORKFLOW_GUIDE.md +134 -0
  308. package/template/.kiro/steering/CORE_PRINCIPLES.md +133 -0
  309. package/template/.kiro/steering/CURRENT_CONTEXT.md +30 -0
  310. package/template/.kiro/steering/ENVIRONMENT.md +35 -0
  311. package/template/.kiro/steering/RULES_GUIDE.md +46 -0
  312. package/template/.kiro/templates/operations/default/change-impact.md +112 -0
  313. package/template/.kiro/templates/operations/default/deployment.md +91 -0
  314. package/template/.kiro/templates/operations/default/feedback-response.md +269 -0
  315. package/template/.kiro/templates/operations/default/migration-plan.md +172 -0
  316. package/template/.kiro/templates/operations/default/monitoring.md +135 -0
  317. package/template/.kiro/templates/operations/default/operations.md +135 -0
  318. package/template/.kiro/templates/operations/default/rollback.md +143 -0
  319. package/template/.kiro/templates/operations/default/tools.yaml +364 -0
  320. package/template/.kiro/templates/operations/default/troubleshooting.md +123 -0
  321. package/template/.kiro/tools/backup_manager.py +295 -0
  322. package/template/.kiro/tools/configuration_manager.py +218 -0
  323. package/template/.kiro/tools/document_evaluator.py +550 -0
  324. package/template/.kiro/tools/enhancement_logger.py +168 -0
  325. package/template/.kiro/tools/error_handler.py +335 -0
  326. package/template/.kiro/tools/improvement_identifier.py +444 -0
  327. package/template/.kiro/tools/modification_applicator.py +737 -0
  328. package/template/.kiro/tools/quality_gate_enforcer.py +207 -0
  329. package/template/.kiro/tools/quality_scorer.py +305 -0
  330. package/template/.kiro/tools/report_generator.py +154 -0
  331. package/template/.kiro/tools/ultrawork_enhancer.py +676 -0
  332. package/template/.kiro/tools/ultrawork_enhancer_refactored.py +0 -0
  333. package/template/.kiro/tools/ultrawork_enhancer_v2.py +463 -0
  334. package/template/.kiro/tools/ultrawork_enhancer_v3.py +606 -0
  335. package/template/.kiro/tools/workflow_quality_gate.py +100 -0
  336. package/template/README.md +111 -0
@@ -0,0 +1,440 @@
1
+ /**
2
+ * CacheManager - Manages local template cache
3
+ *
4
+ * Handles cache directory structure, metadata storage, and cache operations.
5
+ */
6
+
7
+ const fs = require('fs-extra');
8
+ const path = require('path');
9
+ const os = require('os');
10
+ const { FileSystemError } = require('./template-error');
11
+
12
+ class CacheManager {
13
+ constructor(cacheDir = null) {
14
+ // Default cache directory: ~/.kse/templates/
15
+ this.cacheDir = cacheDir || path.join(os.homedir(), '.kse', 'templates');
16
+ this.metadataFile = path.join(this.cacheDir, '.cache-metadata.json');
17
+ this.sourcesFile = path.join(this.cacheDir, '.sources.json');
18
+ }
19
+
20
+ /**
21
+ * Gets the cache directory path
22
+ *
23
+ * @returns {string} Cache directory path
24
+ */
25
+ getCacheDir() {
26
+ return this.cacheDir;
27
+ }
28
+
29
+ /**
30
+ * Gets the cache path for a specific source
31
+ *
32
+ * @param {string} sourceName - Source name (e.g., 'official')
33
+ * @returns {string} Source cache path
34
+ */
35
+ getSourceCachePath(sourceName) {
36
+ return path.join(this.cacheDir, sourceName);
37
+ }
38
+
39
+ /**
40
+ * Ensures cache directory exists
41
+ *
42
+ * @returns {Promise<void>}
43
+ */
44
+ async ensureCacheDir() {
45
+ try {
46
+ await fs.ensureDir(this.cacheDir);
47
+ } catch (error) {
48
+ throw new FileSystemError(
49
+ 'Failed to create cache directory',
50
+ {
51
+ path: this.cacheDir,
52
+ error: error.message
53
+ }
54
+ );
55
+ }
56
+ }
57
+
58
+ /**
59
+ * Checks if cache exists for a source
60
+ *
61
+ * @param {string} sourceName - Source name
62
+ * @returns {Promise<boolean>}
63
+ */
64
+ async cacheExists(sourceName) {
65
+ const sourcePath = this.getSourceCachePath(sourceName);
66
+ return await fs.pathExists(sourcePath);
67
+ }
68
+
69
+ /**
70
+ * Gets cache metadata
71
+ *
72
+ * @returns {Promise<Object>} Cache metadata
73
+ */
74
+ async getMetadata() {
75
+ if (!await fs.pathExists(this.metadataFile)) {
76
+ return {
77
+ sources: {},
78
+ last_check: null
79
+ };
80
+ }
81
+
82
+ try {
83
+ const metadata = await fs.readJson(this.metadataFile);
84
+ return metadata;
85
+ } catch (error) {
86
+ // If metadata is corrupted, return empty metadata
87
+ return {
88
+ sources: {},
89
+ last_check: null
90
+ };
91
+ }
92
+ }
93
+
94
+ /**
95
+ * Updates cache metadata for a source
96
+ *
97
+ * @param {string} sourceName - Source name
98
+ * @param {Object} sourceMetadata - Source metadata
99
+ * @returns {Promise<void>}
100
+ */
101
+ async updateMetadata(sourceName, sourceMetadata) {
102
+ await this.ensureCacheDir();
103
+
104
+ const metadata = await this.getMetadata();
105
+
106
+ metadata.sources[sourceName] = {
107
+ ...sourceMetadata,
108
+ last_updated: new Date().toISOString()
109
+ };
110
+
111
+ metadata.last_check = new Date().toISOString();
112
+
113
+ try {
114
+ await fs.writeJson(this.metadataFile, metadata, { spaces: 2 });
115
+ } catch (error) {
116
+ throw new FileSystemError(
117
+ 'Failed to update cache metadata',
118
+ {
119
+ path: this.metadataFile,
120
+ error: error.message
121
+ }
122
+ );
123
+ }
124
+ }
125
+
126
+ /**
127
+ * Gets metadata for a specific source
128
+ *
129
+ * @param {string} sourceName - Source name
130
+ * @returns {Promise<Object|null>} Source metadata or null
131
+ */
132
+ async getSourceMetadata(sourceName) {
133
+ const metadata = await this.getMetadata();
134
+ return metadata.sources[sourceName] || null;
135
+ }
136
+
137
+ /**
138
+ * Calculates cache size for a source
139
+ *
140
+ * @param {string} sourceName - Source name
141
+ * @returns {Promise<number>} Size in bytes
142
+ */
143
+ async getCacheSize(sourceName) {
144
+ const sourcePath = this.getSourceCachePath(sourceName);
145
+
146
+ if (!await fs.pathExists(sourcePath)) {
147
+ return 0;
148
+ }
149
+
150
+ return await this._calculateDirectorySize(sourcePath);
151
+ }
152
+
153
+ /**
154
+ * Calculates total cache size
155
+ *
156
+ * @returns {Promise<number>} Total size in bytes
157
+ */
158
+ async getTotalCacheSize() {
159
+ if (!await fs.pathExists(this.cacheDir)) {
160
+ return 0;
161
+ }
162
+
163
+ return await this._calculateDirectorySize(this.cacheDir);
164
+ }
165
+
166
+ /**
167
+ * Helper: Recursively calculates directory size
168
+ *
169
+ * @param {string} dirPath - Directory path
170
+ * @returns {Promise<number>} Size in bytes
171
+ * @private
172
+ */
173
+ async _calculateDirectorySize(dirPath) {
174
+ let totalSize = 0;
175
+
176
+ try {
177
+ const items = await fs.readdir(dirPath);
178
+
179
+ for (const item of items) {
180
+ const itemPath = path.join(dirPath, item);
181
+ const stats = await fs.stat(itemPath);
182
+
183
+ if (stats.isDirectory()) {
184
+ totalSize += await this._calculateDirectorySize(itemPath);
185
+ } else {
186
+ totalSize += stats.size;
187
+ }
188
+ }
189
+ } catch (error) {
190
+ // Ignore errors for individual files
191
+ }
192
+
193
+ return totalSize;
194
+ }
195
+
196
+ /**
197
+ * Gets cache information
198
+ *
199
+ * @param {string} sourceName - Source name (optional)
200
+ * @returns {Promise<Object>} Cache info
201
+ */
202
+ async getCacheInfo(sourceName = null) {
203
+ if (sourceName) {
204
+ // Get info for specific source
205
+ const exists = await this.cacheExists(sourceName);
206
+ const metadata = await this.getSourceMetadata(sourceName);
207
+ const size = await this.getCacheSize(sourceName);
208
+
209
+ return {
210
+ source: sourceName,
211
+ exists,
212
+ size,
213
+ metadata
214
+ };
215
+ } else {
216
+ // Get info for all sources
217
+ const metadata = await this.getMetadata();
218
+ const totalSize = await getTotalCacheSize();
219
+
220
+ return {
221
+ cacheDir: this.cacheDir,
222
+ totalSize,
223
+ sources: metadata.sources,
224
+ lastCheck: metadata.last_check
225
+ };
226
+ }
227
+ }
228
+
229
+ /**
230
+ * Formats size in human-readable format
231
+ *
232
+ * @param {number} bytes - Size in bytes
233
+ * @returns {string} Formatted size
234
+ */
235
+ formatSize(bytes) {
236
+ if (bytes === 0) return '0 B';
237
+
238
+ const units = ['B', 'KB', 'MB', 'GB'];
239
+ const k = 1024;
240
+ const i = Math.floor(Math.log(bytes) / Math.log(k));
241
+
242
+ return `${(bytes / Math.pow(k, i)).toFixed(2)} ${units[i]}`;
243
+ }
244
+
245
+ /**
246
+ * Checks if cache is stale
247
+ *
248
+ * @param {string} sourceName - Source name
249
+ * @param {number} maxAge - Maximum age in milliseconds (default: 7 days)
250
+ * @returns {Promise<boolean>} True if cache is stale
251
+ */
252
+ async isStale(sourceName, maxAge = 7 * 24 * 60 * 60 * 1000) {
253
+ const metadata = await this.getSourceMetadata(sourceName);
254
+
255
+ if (!metadata || !metadata.last_updated) {
256
+ return true;
257
+ }
258
+
259
+ const lastUpdated = new Date(metadata.last_updated);
260
+ const now = new Date();
261
+ const age = now - lastUpdated;
262
+
263
+ return age > maxAge;
264
+ }
265
+
266
+ /**
267
+ * Validates cache integrity
268
+ *
269
+ * @param {string} sourceName - Source name
270
+ * @returns {Promise<Object>} Validation result
271
+ */
272
+ async validateCache(sourceName) {
273
+ const result = {
274
+ valid: true,
275
+ errors: [],
276
+ warnings: []
277
+ };
278
+
279
+ // Check if cache exists
280
+ if (!await this.cacheExists(sourceName)) {
281
+ result.valid = false;
282
+ result.errors.push('Cache does not exist');
283
+ return result;
284
+ }
285
+
286
+ const sourcePath = this.getSourceCachePath(sourceName);
287
+
288
+ // Check if template-registry.json exists
289
+ const registryPath = path.join(sourcePath, 'template-registry.json');
290
+ if (!await fs.pathExists(registryPath)) {
291
+ result.valid = false;
292
+ result.errors.push('Missing template-registry.json');
293
+ }
294
+
295
+ // Check if .git directory exists (for Git-based sources)
296
+ const gitPath = path.join(sourcePath, '.git');
297
+ if (!await fs.pathExists(gitPath)) {
298
+ result.warnings.push('Not a Git repository (may be a manual cache)');
299
+ }
300
+
301
+ // Check metadata consistency
302
+ const metadata = await this.getSourceMetadata(sourceName);
303
+ if (!metadata) {
304
+ result.warnings.push('Missing cache metadata');
305
+ }
306
+
307
+ return result;
308
+ }
309
+
310
+ /**
311
+ * Clears cache for a specific source
312
+ *
313
+ * @param {string} sourceName - Source name
314
+ * @returns {Promise<void>}
315
+ */
316
+ async clearCache(sourceName) {
317
+ const sourcePath = this.getSourceCachePath(sourceName);
318
+
319
+ if (!await fs.pathExists(sourcePath)) {
320
+ return; // Already cleared
321
+ }
322
+
323
+ try {
324
+ await fs.remove(sourcePath);
325
+ } catch (error) {
326
+ throw new FileSystemError(
327
+ 'Failed to clear cache',
328
+ {
329
+ source: sourceName,
330
+ path: sourcePath,
331
+ error: error.message
332
+ }
333
+ );
334
+ }
335
+
336
+ // Remove from metadata
337
+ const metadata = await this.getMetadata();
338
+ if (metadata.sources[sourceName]) {
339
+ delete metadata.sources[sourceName];
340
+ await fs.writeJson(this.metadataFile, metadata, { spaces: 2 });
341
+ }
342
+ }
343
+
344
+ /**
345
+ * Clears all cache
346
+ *
347
+ * @returns {Promise<void>}
348
+ */
349
+ async clearAllCache() {
350
+ if (!await fs.pathExists(this.cacheDir)) {
351
+ return; // Already cleared
352
+ }
353
+
354
+ try {
355
+ await fs.remove(this.cacheDir);
356
+ } catch (error) {
357
+ throw new FileSystemError(
358
+ 'Failed to clear all cache',
359
+ {
360
+ path: this.cacheDir,
361
+ error: error.message
362
+ }
363
+ );
364
+ }
365
+ }
366
+
367
+ /**
368
+ * Lists all cached sources
369
+ *
370
+ * @returns {Promise<string[]>} Array of source names
371
+ */
372
+ async listCachedSources() {
373
+ if (!await fs.pathExists(this.cacheDir)) {
374
+ return [];
375
+ }
376
+
377
+ try {
378
+ const items = await fs.readdir(this.cacheDir);
379
+ const sources = [];
380
+
381
+ for (const item of items) {
382
+ // Skip metadata files
383
+ if (item.startsWith('.')) {
384
+ continue;
385
+ }
386
+
387
+ const itemPath = path.join(this.cacheDir, item);
388
+ const stats = await fs.stat(itemPath);
389
+
390
+ if (stats.isDirectory()) {
391
+ sources.push(item);
392
+ }
393
+ }
394
+
395
+ return sources;
396
+ } catch (error) {
397
+ throw new FileSystemError(
398
+ 'Failed to list cached sources',
399
+ {
400
+ path: this.cacheDir,
401
+ error: error.message
402
+ }
403
+ );
404
+ }
405
+ }
406
+
407
+ /**
408
+ * Gets cache statistics
409
+ *
410
+ * @returns {Promise<Object>} Cache statistics
411
+ */
412
+ async getStatistics() {
413
+ const sources = await this.listCachedSources();
414
+ const metadata = await this.getMetadata();
415
+ const totalSize = await this.getTotalCacheSize();
416
+
417
+ const stats = {
418
+ totalSources: sources.length,
419
+ totalSize,
420
+ totalSizeFormatted: this.formatSize(totalSize),
421
+ sources: {}
422
+ };
423
+
424
+ for (const source of sources) {
425
+ const size = await this.getCacheSize(source);
426
+ const sourceMeta = metadata.sources[source];
427
+
428
+ stats.sources[source] = {
429
+ size,
430
+ sizeFormatted: this.formatSize(size),
431
+ lastUpdated: sourceMeta ? sourceMeta.last_updated : null,
432
+ templateCount: sourceMeta ? sourceMeta.template_count : null
433
+ };
434
+ }
435
+
436
+ return stats;
437
+ }
438
+ }
439
+
440
+ module.exports = CacheManager;
@@ -0,0 +1,247 @@
1
+ /**
2
+ * ContentGeneralizer - Replaces project-specific content with template variables
3
+ */
4
+
5
+ class ContentGeneralizer {
6
+ constructor() {
7
+ this.patterns = this.definePatterns();
8
+ }
9
+
10
+ /**
11
+ * Defines generalization patterns
12
+ * @returns {Object} Pattern definitions
13
+ */
14
+ definePatterns() {
15
+ return {
16
+ // Spec name patterns (will be customized per Spec)
17
+ SPEC_NAME: {
18
+ variable: '{{SPEC_NAME}}',
19
+ priority: 1
20
+ },
21
+ SPEC_NAME_TITLE: {
22
+ variable: '{{SPEC_NAME_TITLE}}',
23
+ priority: 2
24
+ },
25
+ // Date patterns
26
+ DATE: {
27
+ pattern: /\b\d{4}-\d{2}-\d{2}\b/g,
28
+ variable: '{{DATE}}',
29
+ priority: 3
30
+ },
31
+ // Version patterns (in context)
32
+ VERSION: {
33
+ pattern: /\bv?\d+\.\d+\.\d+\b/g,
34
+ variable: '{{VERSION}}',
35
+ priority: 4,
36
+ contextKeywords: ['version', 'release', 'v']
37
+ }
38
+ };
39
+ }
40
+
41
+ /**
42
+ * Generalizes Spec content
43
+ * @param {Object} fileContents - Original file contents
44
+ * @param {Object} specMetadata - Spec metadata
45
+ * @returns {Object} Generalized content and flags
46
+ */
47
+ generalize(fileContents, specMetadata) {
48
+ const replacements = this.buildReplacementMap(specMetadata);
49
+ const result = {
50
+ files: {},
51
+ summary: {
52
+ totalReplacements: 0,
53
+ totalFlags: 0
54
+ }
55
+ };
56
+
57
+ for (const [filename, content] of Object.entries(fileContents)) {
58
+ if (!content) {
59
+ result.files[filename] = {
60
+ original: content,
61
+ generalized: content,
62
+ replacements: [],
63
+ flags: []
64
+ };
65
+ continue;
66
+ }
67
+
68
+ const { generalized, replacementList } = this.applyPatterns(content, replacements);
69
+ const flags = this.detectAmbiguousContent(generalized);
70
+
71
+ result.files[filename] = {
72
+ original: content,
73
+ generalized,
74
+ replacements: replacementList,
75
+ flags
76
+ };
77
+
78
+ result.summary.totalReplacements += replacementList.reduce((sum, r) => sum + r.count, 0);
79
+ result.summary.totalFlags += flags.length;
80
+ }
81
+
82
+ return result;
83
+ }
84
+
85
+ /**
86
+ * Builds replacement map from Spec metadata
87
+ * @param {Object} specMetadata - Spec metadata
88
+ * @returns {Array} Replacement patterns
89
+ */
90
+ buildReplacementMap(specMetadata) {
91
+ const replacements = [];
92
+
93
+ // Spec name replacements (most specific first)
94
+ if (specMetadata.fullDirName) {
95
+ replacements.push({
96
+ pattern: new RegExp(this.escapeRegex(specMetadata.fullDirName), 'g'),
97
+ variable: '{{SPEC_NAME}}',
98
+ priority: 1,
99
+ description: 'Full directory name'
100
+ });
101
+ }
102
+
103
+ if (specMetadata.specName) {
104
+ replacements.push({
105
+ pattern: new RegExp(this.escapeRegex(specMetadata.specName), 'g'),
106
+ variable: '{{SPEC_NAME}}',
107
+ priority: 1,
108
+ description: 'Kebab-case name'
109
+ });
110
+ }
111
+
112
+ if (specMetadata.specNameTitle) {
113
+ replacements.push({
114
+ pattern: new RegExp(this.escapeRegex(specMetadata.specNameTitle), 'g'),
115
+ variable: '{{SPEC_NAME_TITLE}}',
116
+ priority: 2,
117
+ description: 'Title case name'
118
+ });
119
+ }
120
+
121
+ // Date replacements
122
+ if (specMetadata.dates) {
123
+ if (specMetadata.dates.created) {
124
+ replacements.push({
125
+ pattern: new RegExp(this.escapeRegex(specMetadata.dates.created), 'g'),
126
+ variable: '{{DATE}}',
127
+ priority: 3,
128
+ description: 'Creation date'
129
+ });
130
+ }
131
+ if (specMetadata.dates.modified && specMetadata.dates.modified !== specMetadata.dates.created) {
132
+ replacements.push({
133
+ pattern: new RegExp(this.escapeRegex(specMetadata.dates.modified), 'g'),
134
+ variable: '{{DATE}}',
135
+ priority: 3,
136
+ description: 'Modified date'
137
+ });
138
+ }
139
+ }
140
+
141
+ // Author replacement
142
+ if (specMetadata.author && specMetadata.author !== 'Unknown') {
143
+ replacements.push({
144
+ pattern: new RegExp(this.escapeRegex(specMetadata.author), 'g'),
145
+ variable: '{{AUTHOR}}',
146
+ priority: 4,
147
+ description: 'Author name'
148
+ });
149
+ }
150
+
151
+ // Path replacements
152
+ if (specMetadata.specPath) {
153
+ replacements.push({
154
+ pattern: new RegExp(this.escapeRegex(specMetadata.specPath), 'g'),
155
+ variable: '.kiro/specs/{{SPEC_NAME}}',
156
+ priority: 5,
157
+ description: 'Spec path'
158
+ });
159
+ }
160
+
161
+ // Sort by priority
162
+ return replacements.sort((a, b) => a.priority - b.priority);
163
+ }
164
+
165
+ /**
166
+ * Applies generalization patterns to text
167
+ * @param {string} content - Original content
168
+ * @param {Array} replacements - Replacement patterns
169
+ * @returns {Object} Generalized content and matches
170
+ */
171
+ applyPatterns(content, replacements) {
172
+ let generalized = content;
173
+ const replacementList = [];
174
+
175
+ for (const replacement of replacements) {
176
+ const matches = content.match(replacement.pattern);
177
+ if (matches && matches.length > 0) {
178
+ generalized = generalized.replace(replacement.pattern, replacement.variable);
179
+ replacementList.push({
180
+ pattern: replacement.description || replacement.pattern.toString(),
181
+ variable: replacement.variable,
182
+ count: matches.length
183
+ });
184
+ }
185
+ }
186
+
187
+ return { generalized, replacementList };
188
+ }
189
+
190
+ /**
191
+ * Detects ambiguous content that needs review
192
+ * @param {string} content - Content to analyze
193
+ * @returns {Array} Flagged items
194
+ */
195
+ detectAmbiguousContent(content) {
196
+ const flags = [];
197
+ const lines = content.split('\n');
198
+
199
+ // Patterns for ambiguous content
200
+ const ambiguousPatterns = [
201
+ {
202
+ pattern: /\b[A-Z][a-z]+\s+(?:Corp|Inc|LLC|Ltd|Company)\b/g,
203
+ severity: 'warning',
204
+ message: 'Possible company name detected'
205
+ },
206
+ {
207
+ pattern: /https?:\/\/(?!github\.com|npmjs\.com)[^\s]+/g,
208
+ severity: 'info',
209
+ message: 'Specific URL detected (not GitHub/npm)'
210
+ },
211
+ {
212
+ pattern: /\b(?:API_KEY|SECRET|PASSWORD|TOKEN)\s*[:=]\s*['"][^'"]+['"]/g,
213
+ severity: 'warning',
214
+ message: 'Hardcoded credential detected'
215
+ }
216
+ ];
217
+
218
+ lines.forEach((line, index) => {
219
+ ambiguousPatterns.forEach(({ pattern, severity, message }) => {
220
+ const matches = line.match(pattern);
221
+ if (matches) {
222
+ matches.forEach(match => {
223
+ flags.push({
224
+ line: index + 1,
225
+ content: match,
226
+ severity,
227
+ message
228
+ });
229
+ });
230
+ }
231
+ });
232
+ });
233
+
234
+ return flags;
235
+ }
236
+
237
+ /**
238
+ * Escapes special regex characters
239
+ * @param {string} str - String to escape
240
+ * @returns {string} Escaped string
241
+ */
242
+ escapeRegex(str) {
243
+ return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
244
+ }
245
+ }
246
+
247
+ module.exports = ContentGeneralizer;