yandecode 0.1.0 → 0.2.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 (222) hide show
  1. package/dist/bin.js +14 -8
  2. package/dist/bin.js.map +7 -1
  3. package/dist/chunks/chunk-23DG7PZZ.js +58 -0
  4. package/dist/chunks/chunk-23DG7PZZ.js.map +7 -0
  5. package/dist/chunks/chunk-2S6B3DDQ.js +1769 -0
  6. package/dist/chunks/chunk-2S6B3DDQ.js.map +7 -0
  7. package/dist/chunks/chunk-6J5CZVCJ.js +120 -0
  8. package/dist/chunks/chunk-6J5CZVCJ.js.map +7 -0
  9. package/dist/chunks/chunk-7L6DD2VD.js +768 -0
  10. package/dist/chunks/chunk-7L6DD2VD.js.map +7 -0
  11. package/dist/chunks/chunk-DWD37AI2.js +39 -0
  12. package/dist/chunks/chunk-DWD37AI2.js.map +7 -0
  13. package/dist/chunks/chunk-KPDBXQ62.js +62 -0
  14. package/dist/chunks/chunk-KPDBXQ62.js.map +7 -0
  15. package/dist/chunks/chunk-KVBKQXTU.js +351 -0
  16. package/dist/chunks/chunk-KVBKQXTU.js.map +7 -0
  17. package/dist/chunks/chunk-L2DDIZPI.js +53 -0
  18. package/dist/chunks/chunk-L2DDIZPI.js.map +7 -0
  19. package/dist/chunks/chunk-OIAMKDTQ.js +27 -0
  20. package/dist/chunks/chunk-OIAMKDTQ.js.map +7 -0
  21. package/dist/chunks/chunk-PUWSEWX3.js +61 -0
  22. package/dist/chunks/chunk-PUWSEWX3.js.map +7 -0
  23. package/dist/chunks/chunk-QCQC73WX.js +122 -0
  24. package/dist/chunks/chunk-QCQC73WX.js.map +7 -0
  25. package/dist/chunks/chunk-TYLH4NIC.js +39 -0
  26. package/dist/chunks/chunk-TYLH4NIC.js.map +7 -0
  27. package/dist/chunks/chunk-VKVJGBNJ.js +72 -0
  28. package/dist/chunks/chunk-VKVJGBNJ.js.map +7 -0
  29. package/dist/chunks/chunk-Y2MIXROU.js +20072 -0
  30. package/dist/chunks/chunk-Y2MIXROU.js.map +7 -0
  31. package/dist/chunks/cli-V6PJTDLM.js +3464 -0
  32. package/dist/chunks/cli-V6PJTDLM.js.map +7 -0
  33. package/dist/chunks/doctor-LLDVEPWL.js +184 -0
  34. package/dist/chunks/doctor-LLDVEPWL.js.map +7 -0
  35. package/dist/chunks/entry-YAOEX3EB.js +187 -0
  36. package/dist/chunks/entry-YAOEX3EB.js.map +7 -0
  37. package/dist/chunks/init-4ZJFCKIJ.js +46 -0
  38. package/dist/chunks/init-4ZJFCKIJ.js.map +7 -0
  39. package/dist/chunks/mcp-serve-KWKMUGWZ.js +22575 -0
  40. package/dist/chunks/mcp-serve-KWKMUGWZ.js.map +7 -0
  41. package/dist/chunks/modules-CJB5IKUJ.js +121 -0
  42. package/dist/chunks/modules-CJB5IKUJ.js.map +7 -0
  43. package/dist/chunks/runtime-3E4NIFAL.js +208 -0
  44. package/dist/chunks/runtime-3E4NIFAL.js.map +7 -0
  45. package/dist/chunks/runtime-7CRR63B5.js +395 -0
  46. package/dist/chunks/runtime-7CRR63B5.js.map +7 -0
  47. package/dist/chunks/runtime-CKMVHAU4.js +64 -0
  48. package/dist/chunks/runtime-CKMVHAU4.js.map +7 -0
  49. package/dist/chunks/runtime-CVZMWIJO.js +318 -0
  50. package/dist/chunks/runtime-CVZMWIJO.js.map +7 -0
  51. package/dist/chunks/runtime-DBNXBOAL.js +295 -0
  52. package/dist/chunks/runtime-DBNXBOAL.js.map +7 -0
  53. package/dist/chunks/runtime-EKHO2JXB.js +197 -0
  54. package/dist/chunks/runtime-EKHO2JXB.js.map +7 -0
  55. package/dist/chunks/runtime-EY6SVZYP.js +539 -0
  56. package/dist/chunks/runtime-EY6SVZYP.js.map +7 -0
  57. package/dist/chunks/runtime-UB2O2HUN.js +212 -0
  58. package/dist/chunks/runtime-UB2O2HUN.js.map +7 -0
  59. package/dist/chunks/runtime-WAFQWW4M.js +755 -0
  60. package/dist/chunks/runtime-WAFQWW4M.js.map +7 -0
  61. package/dist/chunks/runtime-ZGGF6RVA.js +271 -0
  62. package/dist/chunks/runtime-ZGGF6RVA.js.map +7 -0
  63. package/dist/chunks/status-SPIESL4F.js +38 -0
  64. package/dist/chunks/status-SPIESL4F.js.map +7 -0
  65. package/dist/chunks/uninstall-J2OWCX4A.js +54 -0
  66. package/dist/chunks/uninstall-J2OWCX4A.js.map +7 -0
  67. package/dist/chunks/update-OX5MZYQY.js +34 -0
  68. package/dist/chunks/update-OX5MZYQY.js.map +7 -0
  69. package/dist/content/agents/yandecode-reviewer.md +22 -0
  70. package/dist/content/agents/yandecode-security-reviewer.md +23 -0
  71. package/dist/content/skills/NOTICE.md +29 -0
  72. package/dist/content/skills/yandecode-code-review/SKILL.md +37 -0
  73. package/dist/content/skills/yandecode-debugging/SKILL.md +33 -0
  74. package/dist/content/skills/yandecode-instructions/SKILL.md +26 -0
  75. package/dist/content/skills/yandecode-memory/SKILL.md +36 -0
  76. package/dist/content/skills/yandecode-security-review/SKILL.md +24 -0
  77. package/dist/content/skills/yandecode-tdd/SKILL.md +38 -0
  78. package/dist/content/skills/yandecode-verification/SKILL.md +29 -0
  79. package/dist/content/skills/yandecode-workflow/SKILL.md +50 -0
  80. package/package.json +25 -19
  81. package/dist/bin.d.ts +0 -3
  82. package/dist/bin.d.ts.map +0 -1
  83. package/dist/cli.d.ts +0 -6
  84. package/dist/cli.d.ts.map +0 -1
  85. package/dist/cli.js +0 -21
  86. package/dist/cli.js.map +0 -1
  87. package/dist/commands/doctor.d.ts +0 -2
  88. package/dist/commands/doctor.d.ts.map +0 -1
  89. package/dist/commands/doctor.js +0 -19
  90. package/dist/commands/doctor.js.map +0 -1
  91. package/dist/commands/hook.d.ts +0 -2
  92. package/dist/commands/hook.d.ts.map +0 -1
  93. package/dist/commands/hook.js +0 -23
  94. package/dist/commands/hook.js.map +0 -1
  95. package/dist/commands/index-cmd.d.ts +0 -2
  96. package/dist/commands/index-cmd.d.ts.map +0 -1
  97. package/dist/commands/index-cmd.js +0 -47
  98. package/dist/commands/index-cmd.js.map +0 -1
  99. package/dist/commands/index.d.ts +0 -13
  100. package/dist/commands/index.d.ts.map +0 -1
  101. package/dist/commands/index.js +0 -15
  102. package/dist/commands/index.js.map +0 -1
  103. package/dist/commands/init.d.ts +0 -2
  104. package/dist/commands/init.d.ts.map +0 -1
  105. package/dist/commands/init.js +0 -22
  106. package/dist/commands/init.js.map +0 -1
  107. package/dist/commands/mcp.d.ts +0 -2
  108. package/dist/commands/mcp.d.ts.map +0 -1
  109. package/dist/commands/mcp.js +0 -71
  110. package/dist/commands/mcp.js.map +0 -1
  111. package/dist/commands/rag.d.ts +0 -2
  112. package/dist/commands/rag.d.ts.map +0 -1
  113. package/dist/commands/rag.js +0 -27
  114. package/dist/commands/rag.js.map +0 -1
  115. package/dist/commands/start.d.ts +0 -6
  116. package/dist/commands/start.d.ts.map +0 -1
  117. package/dist/commands/start.js +0 -76
  118. package/dist/commands/start.js.map +0 -1
  119. package/dist/commands/status.d.ts +0 -2
  120. package/dist/commands/status.d.ts.map +0 -1
  121. package/dist/commands/status.js +0 -29
  122. package/dist/commands/status.js.map +0 -1
  123. package/dist/commands/statusline.d.ts +0 -2
  124. package/dist/commands/statusline.d.ts.map +0 -1
  125. package/dist/commands/statusline.js +0 -90
  126. package/dist/commands/statusline.js.map +0 -1
  127. package/dist/commands/swarm.d.ts +0 -4
  128. package/dist/commands/swarm.d.ts.map +0 -1
  129. package/dist/commands/swarm.js +0 -48
  130. package/dist/commands/swarm.js.map +0 -1
  131. package/dist/commands/uninstall.d.ts +0 -2
  132. package/dist/commands/uninstall.d.ts.map +0 -1
  133. package/dist/commands/uninstall.js +0 -16
  134. package/dist/commands/uninstall.js.map +0 -1
  135. package/dist/context.d.ts +0 -13
  136. package/dist/context.d.ts.map +0 -1
  137. package/dist/context.js +0 -31
  138. package/dist/context.js.map +0 -1
  139. package/dist/doctor/checks.d.ts +0 -18
  140. package/dist/doctor/checks.d.ts.map +0 -1
  141. package/dist/doctor/checks.js +0 -269
  142. package/dist/doctor/checks.js.map +0 -1
  143. package/dist/hooks/handlers.d.ts +0 -21
  144. package/dist/hooks/handlers.d.ts.map +0 -1
  145. package/dist/hooks/handlers.js +0 -191
  146. package/dist/hooks/handlers.js.map +0 -1
  147. package/dist/index.d.ts +0 -9
  148. package/dist/index.d.ts.map +0 -1
  149. package/dist/index.js +0 -9
  150. package/dist/index.js.map +0 -1
  151. package/dist/integration/claude-md.d.ts +0 -6
  152. package/dist/integration/claude-md.d.ts.map +0 -1
  153. package/dist/integration/claude-md.js +0 -30
  154. package/dist/integration/claude-md.js.map +0 -1
  155. package/dist/integration/gitignore.d.ts +0 -3
  156. package/dist/integration/gitignore.d.ts.map +0 -1
  157. package/dist/integration/gitignore.js +0 -13
  158. package/dist/integration/gitignore.js.map +0 -1
  159. package/dist/integration/init.d.ts +0 -17
  160. package/dist/integration/init.d.ts.map +0 -1
  161. package/dist/integration/init.js +0 -86
  162. package/dist/integration/init.js.map +0 -1
  163. package/dist/integration/json-utils.d.ts +0 -13
  164. package/dist/integration/json-utils.d.ts.map +0 -1
  165. package/dist/integration/json-utils.js +0 -33
  166. package/dist/integration/json-utils.js.map +0 -1
  167. package/dist/integration/manifest.d.ts +0 -17
  168. package/dist/integration/manifest.d.ts.map +0 -1
  169. package/dist/integration/manifest.js +0 -26
  170. package/dist/integration/manifest.js.map +0 -1
  171. package/dist/integration/materialize.d.ts +0 -9
  172. package/dist/integration/materialize.d.ts.map +0 -1
  173. package/dist/integration/materialize.js +0 -21
  174. package/dist/integration/materialize.js.map +0 -1
  175. package/dist/integration/mcp-config.d.ts +0 -4
  176. package/dist/integration/mcp-config.d.ts.map +0 -1
  177. package/dist/integration/mcp-config.js +0 -11
  178. package/dist/integration/mcp-config.js.map +0 -1
  179. package/dist/integration/settings.d.ts +0 -7
  180. package/dist/integration/settings.d.ts.map +0 -1
  181. package/dist/integration/settings.js +0 -70
  182. package/dist/integration/settings.js.map +0 -1
  183. package/dist/integration/uninstall.d.ts +0 -10
  184. package/dist/integration/uninstall.d.ts.map +0 -1
  185. package/dist/integration/uninstall.js +0 -71
  186. package/dist/integration/uninstall.js.map +0 -1
  187. package/dist/launcher.d.ts +0 -8
  188. package/dist/launcher.d.ts.map +0 -1
  189. package/dist/launcher.js +0 -18
  190. package/dist/launcher.js.map +0 -1
  191. package/dist/mcp/server.d.ts +0 -27
  192. package/dist/mcp/server.d.ts.map +0 -1
  193. package/dist/mcp/server.js +0 -311
  194. package/dist/mcp/server.js.map +0 -1
  195. package/dist/plugin-content.d.ts +0 -21
  196. package/dist/plugin-content.d.ts.map +0 -1
  197. package/dist/plugin-content.js +0 -67
  198. package/dist/plugin-content.js.map +0 -1
  199. package/dist/rag/format.d.ts +0 -3
  200. package/dist/rag/format.d.ts.map +0 -1
  201. package/dist/rag/format.js +0 -12
  202. package/dist/rag/format.js.map +0 -1
  203. package/dist/retrieval-runtime.d.ts +0 -21
  204. package/dist/retrieval-runtime.d.ts.map +0 -1
  205. package/dist/retrieval-runtime.js +0 -47
  206. package/dist/retrieval-runtime.js.map +0 -1
  207. package/dist/status-line/git.d.ts +0 -3
  208. package/dist/status-line/git.d.ts.map +0 -1
  209. package/dist/status-line/git.js +0 -34
  210. package/dist/status-line/git.js.map +0 -1
  211. package/dist/status-line/render.d.ts +0 -29
  212. package/dist/status-line/render.d.ts.map +0 -1
  213. package/dist/status-line/render.js +0 -72
  214. package/dist/status-line/render.js.map +0 -1
  215. package/dist/swarm-runtime.d.ts +0 -11
  216. package/dist/swarm-runtime.d.ts.map +0 -1
  217. package/dist/swarm-runtime.js +0 -76
  218. package/dist/swarm-runtime.js.map +0 -1
  219. package/dist/version.d.ts +0 -2
  220. package/dist/version.d.ts.map +0 -1
  221. package/dist/version.js +0 -5
  222. package/dist/version.js.map +0 -1
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/modules/knowledge/runtime.ts", "../../src/modules/knowledge/index-store.ts", "../../src/modules/knowledge/legacy.ts", "../../src/modules/knowledge/memories.ts", "../../src/modules/knowledge/session.ts"],
4
+ "sourcesContent": ["import { existsSync, readFileSync } from 'node:fs';\nimport { isAbsolute, join, relative } from 'node:path';\nimport { resolveInsideRoot } from '@yandecode/core';\nimport { z } from 'zod';\nimport { fitRows } from '@cli/shared/budget';\nimport type {\n HookInput,\n HookResult,\n ModuleContext,\n ModuleRuntime,\n ToolResult,\n} from '@cli/modules/contract';\nimport { parseSettings } from '@cli/modules/host';\nimport { forgetInput, getInput, knowledgeSettings, searchInput, writeInput } from './definition';\nimport { KnowledgeIndex, type KnowledgeHit } from './index-store';\nimport { importLegacyMemories } from './legacy';\nimport { MemoryRepository } from './memories';\nimport type { Memory } from './memory-file';\nimport { promptRecall, sessionStartIndex, summarizeSession } from './session';\n\ntype Settings = z.infer<typeof knowledgeSettings>;\n\ninterface State {\n settings: Settings;\n repo: MemoryRepository;\n index: KnowledgeIndex;\n lastSync: number;\n}\n\nconst SYNC_INTERVAL_MS = 1_500;\nconst states = new Map<string, State>();\n\nfunction stateFor(ctx: ModuleContext): State {\n let state = states.get(ctx.root);\n if (!state) {\n const settings = parseSettings('knowledge', knowledgeSettings, ctx.settings);\n const memoryDir = isAbsolute(settings.memoryDir)\n ? settings.memoryDir\n : join(ctx.root, settings.memoryDir);\n const repo = new MemoryRepository(memoryDir);\n const imported = importLegacyMemories(ctx.paths.legacyStateDb, repo);\n if (imported > 0) ctx.log('imported_v0_memories', { count: imported });\n const index = KnowledgeIndex.open(join(ctx.paths.yandecodeDir, 'knowledge.db'), {\n root: ctx.root,\n memories: repo,\n extraDirs: settings.extraDirs,\n });\n state = { settings, repo, index, lastSync: 0 };\n states.set(ctx.root, state);\n }\n return state;\n}\n\nfunction fresh(ctx: ModuleContext): State {\n const state = stateFor(ctx);\n if (Date.now() - state.lastSync > SYNC_INTERVAL_MS) {\n state.index.sync();\n state.lastSync = Date.now();\n }\n return state;\n}\n\nfunction hitRow(hit: KnowledgeHit): string {\n if (hit.type === 'doc') {\n return `${hit.path}:${hit.startLine}-${hit.endLine}${hit.heading ? ` \u00A7 ${hit.heading}` : ''} \u2014 ${hit.snippet}`;\n }\n const stale = hit.stale.length > 0 ? ` (stale: ${hit.stale.join(', ')} missing)` : '';\n return `[${hit.id}] ${hit.kind} \u00B7 ${hit.updated.slice(0, 10)} \u00B7 ${hit.title}${stale}`;\n}\n\nfunction renderMemory(m: Memory, index: KnowledgeIndex): string {\n const missing = index.missingSources(m.sources);\n return [\n `# ${m.title}`,\n `[${m.id}] ${m.kind} \u00B7 ${m.durability} \u00B7 updated ${m.updated.slice(0, 10)}${m.expires ? ` \u00B7 expires ${m.expires.slice(0, 10)}` : ''}`,\n ...(m.tags.length > 0 ? [`tags: ${m.tags.join(', ')}`] : []),\n ...(m.sources.length > 0 ? [`sources: ${m.sources.join(', ')}`] : []),\n ...(m.supersedes.length > 0 ? [`supersedes: ${m.supersedes.join(', ')}`] : []),\n ...(missing.length > 0\n ? [`WARNING: sources no longer exist (${missing.join(', ')}); verify before relying on this.`]\n : []),\n '',\n m.body,\n ].join('\\n');\n}\n\n/** \"path\" or \"path:start-end\" inside the project (or an absolute path under an extra dir). */\nfunction renderDoc(ref: string, ctx: ModuleContext, settings: Settings): string | null {\n const match = /^(.*?)(?::(\\d+)(?:-(\\d+))?)?$/.exec(ref)!;\n const path = match[1]!;\n const inExtra =\n isAbsolute(path) && settings.extraDirs.some((d) => !relative(d, path).startsWith('..'));\n let abs: string;\n try {\n abs = inExtra ? path : resolveInsideRoot(ctx.root, path);\n } catch {\n return null;\n }\n if (!existsSync(abs)) return null;\n const lines = readFileSync(abs, 'utf8').split('\\n');\n const start = match[2] ? Number(match[2]) : 1;\n const end = match[3] ? Number(match[3]) : match[2] ? start : lines.length;\n return [`## ${path}:${start}-${end}`, ...lines.slice(start - 1, end)].join('\\n');\n}\n\nfunction knowledgeSearch(raw: Record<string, unknown>, ctx: ModuleContext): Promise<ToolResult> {\n const args = z.object(searchInput).parse(raw);\n const { index } = fresh(ctx);\n const hits = index.search(args.query, {\n scope: args.scope ?? 'all',\n limit: args.limit ?? 6,\n includeSuperseded: args.include_superseded ?? false,\n });\n if (hits.length === 0)\n return Promise.resolve({ text: `No docs or memories match \"${args.query}\".` });\n return Promise.resolve({\n text: fitRows(\n `knowledge_search \"${args.query}\" \u2014 knowledge_get(ids) for details`,\n hits.map(hitRow),\n 3_000,\n ),\n });\n}\n\nfunction knowledgeGet(raw: Record<string, unknown>, ctx: ModuleContext): Promise<ToolResult> {\n const args = z.object(getInput).parse(raw);\n const state = fresh(ctx);\n const blocks = args.ids.map((id) => {\n const memory = state.repo.get(id);\n if (memory) return renderMemory(memory, state.index);\n return (\n renderDoc(id, ctx, state.settings) ??\n `## ${id}\\nnot found (unknown memory id or document path)`\n );\n });\n return Promise.resolve({\n text: fitRows(`${blocks.length} item(s)`, blocks, args.max_chars ?? 8_000),\n });\n}\n\nfunction memoryWrite(raw: Record<string, unknown>, ctx: ModuleContext): Promise<ToolResult> {\n const args = z.object(writeInput).parse(raw);\n const state = stateFor(ctx);\n const result = state.repo.write({\n title: args.title,\n body: args.body,\n kind: args.kind,\n ...(args.durability ? { durability: args.durability } : {}),\n ...(args.tags ? { tags: args.tags } : {}),\n ...(args.sources ? { sources: args.sources } : {}),\n ...(args.supersedes ? { supersedes: args.supersedes } : {}),\n ...(args.expires_in_days ? { expiresInDays: args.expires_in_days } : {}),\n });\n state.lastSync = 0;\n ctx.log('memory_write', { id: result.id, action: result.action });\n const verb = result.action === 'created' ? 'Saved' : 'Updated near-duplicate';\n return Promise.resolve({\n text: `${verb} memory [${result.id}] (${relative(ctx.root, join(state.repo.dir, `${result.id}.md`))}).`,\n });\n}\n\nfunction memoryForget(raw: Record<string, unknown>, ctx: ModuleContext): Promise<ToolResult> {\n const args = z.object(forgetInput).parse(raw);\n const state = stateFor(ctx);\n const removed = state.repo.forget(args.id);\n state.lastSync = 0;\n return Promise.resolve(\n removed\n ? { text: `Forgot memory [${args.id}].` }\n : { isError: true, text: `No memory with id \"${args.id}\".` },\n );\n}\n\nfunction failedTool(response: unknown): boolean {\n if (typeof response !== 'object' || response === null) return false;\n const r = response as Record<string, unknown>;\n if (r.is_error === true || r.interrupted === true) return true;\n return ['exit_code', 'exitCode', 'returnCode'].some(\n (k) => typeof r[k] === 'number' && r[k] !== 0,\n );\n}\n\nconst YANDECODE_TOOL = 'mcp__yandecode__';\nconst EDIT_TOOLS = new Set(['Edit', 'Write', 'MultiEdit', 'NotebookEdit']);\n\ntype Journaled = { tool: string; detail: string; failed: boolean } | null;\n\nconst str = (value: unknown): string | null => (typeof value === 'string' ? value : null);\n\nfunction bashEntry(input: HookInput): Journaled {\n const command = str(input.tool_input?.command);\n return command\n ? { tool: 'Bash', detail: command.slice(0, 200), failed: failedTool(input.tool_response) }\n : null;\n}\n\nfunction editEntry(input: HookInput, root: string): Journaled {\n const path = str(input.tool_input?.file_path) ?? str(input.tool_input?.notebook_path);\n return path\n ? { tool: input.tool_name!, detail: relative(root, path) || path, failed: false }\n : null;\n}\n\nfunction yandecodeEntry(input: HookInput): Journaled {\n const name = input.tool_name!.slice(YANDECODE_TOOL.length);\n const args = input.tool_input ?? {};\n const detail = str(args.command) ?? str(args.title) ?? str(args.query) ?? name;\n // ctx_run answers \"$ cmd (exit N \u00B7 \u2026)\": a non-zero exit is a failing command.\n const exit = /\\(exit (\\d+)/.exec(JSON.stringify(input.tool_response ?? ''))?.[1];\n return { tool: name, detail: detail.slice(0, 200), failed: exit !== undefined && exit !== '0' };\n}\n\n/** What a tool call did, for the session journal; null when it is not worth recording. */\nfunction journalEntry(input: HookInput, root: string): Journaled {\n const tool = input.tool_name ?? '';\n if (tool === 'Bash') return bashEntry(input);\n if (EDIT_TOOLS.has(tool)) return editEntry(input, root);\n return tool.startsWith(YANDECODE_TOOL) ? yandecodeEntry(input) : null;\n}\n\nfunction onPostToolUse(input: HookInput, ctx: ModuleContext): Promise<HookResult> {\n const state = stateFor(ctx);\n if (!state.settings.capture || !input.session_id) return Promise.resolve({ kind: 'none' });\n const entry = journalEntry(input, ctx.root);\n if (entry) state.index.record(input.session_id, { at: new Date().toISOString(), ...entry });\n return Promise.resolve({ kind: 'none' });\n}\n\nfunction onSessionEnd(input: HookInput, ctx: ModuleContext): Promise<HookResult> {\n const state = stateFor(ctx);\n if (!input.session_id) return Promise.resolve({ kind: 'none' });\n const summary = summarizeSession(state.index.drainJournal(input.session_id), new Date());\n if (summary) {\n const { id } = state.repo.write({\n ...summary,\n kind: 'session',\n durability: 'ephemeral',\n expiresInDays: state.settings.sessionTtlDays,\n dedupe: false,\n });\n ctx.log('session_summary', { id });\n }\n return Promise.resolve({ kind: 'none' });\n}\n\nexport const runtime: ModuleRuntime = {\n tools: {\n knowledge_search: knowledgeSearch,\n knowledge_get: knowledgeGet,\n memory_write: memoryWrite,\n memory_forget: memoryForget,\n },\n hooks: {\n SessionStart: (_input, ctx) => {\n const state = fresh(ctx);\n const text = sessionStartIndex(state.index, state.repo, state.settings.sessionStartChars);\n return Promise.resolve(text ? { kind: 'context', text } : { kind: 'none' });\n },\n UserPromptSubmit: (input, ctx) => {\n const state = fresh(ctx);\n if (!state.settings.promptRecall || typeof input.prompt !== 'string')\n return Promise.resolve({ kind: 'none' });\n const text = promptRecall(state.index, input.prompt);\n return Promise.resolve(text ? { kind: 'context', text } : { kind: 'none' });\n },\n PostToolUse: onPostToolUse,\n SessionEnd: onSessionEnd,\n },\n doctor: (ctx) => {\n const state = fresh(ctx);\n const invalid = state.repo.invalidFiles();\n return Promise.resolve([\n {\n name: 'memories',\n status: 'ok',\n detail: `${state.repo.list().length} in ${relative(ctx.root, state.repo.dir) || state.repo.dir}`,\n },\n invalid.length > 0\n ? {\n name: 'memory files',\n status: 'warn',\n detail: `unreadable: ${invalid.join(', ')}`,\n fix: 'fix their front matter (id, title) or delete them',\n }\n : { name: 'memory files', status: 'ok', detail: 'all parse' },\n ]);\n },\n dispose: () => {\n for (const state of states.values()) state.index.close();\n states.clear();\n return Promise.resolve();\n },\n};\n", "import { existsSync, mkdirSync, readdirSync, readFileSync, statSync } from 'node:fs';\nimport { dirname, isAbsolute, join, relative, sep } from 'node:path';\nimport { openModuleDb, toFtsQuery, type Database } from '@yandecode/core';\nimport { listCandidatePaths } from '@yandecode/retrieval';\nimport { splitSections } from '@cli/shared/markdown';\nimport type { MemoryRepository } from './memories';\nimport type { Memory } from './memory-file';\n\nconst MIGRATIONS: readonly string[] = [\n `\n CREATE TABLE docs (path TEXT PRIMARY KEY, mtime_ms INTEGER NOT NULL, size INTEGER NOT NULL);\n CREATE TABLE sections (\n id INTEGER PRIMARY KEY,\n source TEXT NOT NULL,\n memory_id TEXT,\n heading TEXT NOT NULL,\n start_line INTEGER NOT NULL,\n end_line INTEGER NOT NULL\n );\n CREATE INDEX sections_source ON sections (source);\n CREATE VIRTUAL TABLE sections_fts USING fts5 (content, heading, title, tokenize = 'porter unicode61');\n CREATE TABLE memories (\n id TEXT PRIMARY KEY,\n title TEXT NOT NULL,\n kind TEXT NOT NULL,\n durability TEXT NOT NULL,\n updated TEXT NOT NULL,\n superseded_by TEXT,\n sources TEXT NOT NULL\n );\n CREATE TABLE meta (key TEXT PRIMARY KEY, value TEXT NOT NULL);\n CREATE TABLE journal (\n session_id TEXT NOT NULL,\n at TEXT NOT NULL,\n tool TEXT NOT NULL,\n detail TEXT NOT NULL,\n failed INTEGER NOT NULL DEFAULT 0\n );\n CREATE INDEX journal_session ON journal (session_id);\n `,\n];\n\nconst MARKDOWN = /\\.(md|mdx|markdown)$/i;\n\nexport interface MemoryHit {\n type: 'memory';\n id: string;\n title: string;\n kind: string;\n updated: string;\n stale: string[];\n snippet: string;\n}\n\nexport interface DocHit {\n type: 'doc';\n path: string;\n heading: string;\n startLine: number;\n endLine: number;\n snippet: string;\n}\n\nexport type KnowledgeHit = MemoryHit | DocHit;\nexport type Scope = 'all' | 'docs' | 'memory';\n\nexport interface SearchOptions {\n scope?: Scope;\n limit?: number;\n includeSuperseded?: boolean;\n}\n\ninterface SectionRow {\n source: string;\n memory_id: string | null;\n heading: string;\n start_line: number;\n end_line: number;\n snippet: string;\n title: string | null;\n kind: string | null;\n updated: string | null;\n superseded_by: string | null;\n sources: string | null;\n}\n\nexport interface JournalEntry {\n at: string;\n tool: string;\n detail: string;\n failed: boolean;\n}\n\nexport interface KnowledgeIndexOptions {\n root: string;\n memories: MemoryRepository;\n /** Extra directories of Markdown (absolute), e.g. personal notes shared across projects. */\n extraDirs?: readonly string[];\n}\n\nfunction toPosix(path: string): string {\n return path.split(sep).join('/');\n}\n\nfunction walkMarkdown(dir: string): string[] {\n if (!existsSync(dir)) return [];\n const out: string[] = [];\n for (const entry of readdirSync(dir, { withFileTypes: true })) {\n if (entry.name.startsWith('.') || entry.name === 'node_modules') continue;\n const abs = join(dir, entry.name);\n if (entry.isDirectory()) out.push(...walkMarkdown(abs));\n else if (MARKDOWN.test(entry.name)) out.push(abs);\n }\n return out;\n}\n\n/** A source mentioned by a memory that looks like a repository path (optionally `:line`). */\nfunction repoPathOf(source: string): string | null {\n if (\n /^[a-z]+:\\/\\//i.test(source) ||\n /^[0-9a-f]{7,40}$/i.test(source) ||\n /^o[0-9a-f]{6}$/.test(source)\n )\n return null;\n const path = source.replace(/:\\d+(-\\d+)?$/, '');\n return /[./]/.test(path) && !/\\s/.test(path) ? path : null;\n}\n\n/**\n * Searchable index over the project's Markdown and the memory files (ADR-020). Files are the\n * source of truth; this database is derived state, refreshed by `sync()` on every query.\n */\nexport class KnowledgeIndex {\n private constructor(\n private readonly db: Database,\n private readonly options: KnowledgeIndexOptions,\n ) {}\n\n static open(file: string, options: KnowledgeIndexOptions): KnowledgeIndex {\n mkdirSync(dirname(file), { recursive: true });\n return new KnowledgeIndex(openModuleDb(file, MIGRATIONS), options);\n }\n\n close(): void {\n this.db.close();\n }\n\n private memoryDirRelative(): string | null {\n const rel = relative(this.options.root, this.options.memories.dir);\n return rel.startsWith('..') || isAbsolute(rel) ? null : toPosix(rel);\n }\n\n private docPaths(): Map<string, string> {\n const memoryDir = this.memoryDirRelative();\n const docs = new Map<string, string>();\n for (const rel of listCandidatePaths(this.options.root)) {\n if (!MARKDOWN.test(rel)) continue;\n if (memoryDir && (rel === memoryDir || rel.startsWith(`${memoryDir}/`))) continue;\n // Claude Code already loads .claude/ content (skills, agents, commands) by itself.\n if (rel.startsWith('.claude/')) continue;\n docs.set(rel, join(this.options.root, rel));\n }\n for (const dir of this.options.extraDirs ?? []) {\n for (const abs of walkMarkdown(dir)) docs.set(toPosix(abs), abs);\n }\n return docs;\n }\n\n private deleteSource(source: string): void {\n const ids = this.db.prepare('SELECT id FROM sections WHERE source = ?').all(source) as {\n id: number;\n }[];\n const del = this.db.prepare('DELETE FROM sections_fts WHERE rowid = ?');\n for (const { id } of ids) del.run(id);\n this.db.prepare('DELETE FROM sections WHERE source = ?').run(source);\n }\n\n private insertSections(\n source: string,\n title: string,\n text: string,\n memoryId: string | null,\n ): void {\n const insert = this.db.prepare(\n 'INSERT INTO sections (source, memory_id, heading, start_line, end_line) VALUES (?, ?, ?, ?, ?)',\n );\n const fts = this.db.prepare(\n 'INSERT INTO sections_fts (rowid, content, heading, title) VALUES (?, ?, ?, ?)',\n );\n for (const s of splitSections(text)) {\n const id = insert.run(source, memoryId, s.heading, s.startLine, s.endLine).lastInsertRowid;\n fts.run(id, s.content, s.heading, title);\n }\n }\n\n private syncDocs(): void {\n const wanted = this.docPaths();\n const known = new Map(\n (\n this.db.prepare('SELECT path, mtime_ms, size FROM docs').all() as {\n path: string;\n mtime_ms: number;\n size: number;\n }[]\n ).map((r) => [r.path, r]),\n );\n for (const path of known.keys()) {\n if (wanted.has(path)) continue;\n this.deleteSource(path);\n this.db.prepare('DELETE FROM docs WHERE path = ?').run(path);\n }\n for (const [path, abs] of wanted) {\n const st = statSync(abs, { throwIfNoEntry: false });\n if (!st) continue;\n const prev = known.get(path);\n if (prev && prev.mtime_ms === Math.trunc(st.mtimeMs) && prev.size === st.size) continue;\n this.deleteSource(path);\n this.insertSections(path, path, readFileSync(abs, 'utf8'), null);\n this.db\n .prepare('INSERT OR REPLACE INTO docs (path, mtime_ms, size) VALUES (?, ?, ?)')\n .run(path, Math.trunc(st.mtimeMs), st.size);\n }\n }\n\n /** Memories are few: rebuild them whenever the directory's content signature changes. */\n private syncMemories(memories: readonly Memory[]): void {\n const signature = memories\n .map((m) => `${m.id}@${m.updated}@${m.supersedes.join(',')}`)\n .join('|');\n const previous = this.db.prepare(\"SELECT value FROM meta WHERE key = 'memories'\").get() as\n { value: string } | undefined;\n if (previous?.value === signature) return;\n const supersededBy = new Map<string, string>();\n for (const m of memories) for (const old of m.supersedes) supersededBy.set(old, m.id);\n for (const { id } of this.db.prepare('SELECT id FROM memories').all() as { id: string }[]) {\n this.deleteSource(`memory:${id}`);\n }\n this.db.prepare('DELETE FROM memories').run();\n const insert = this.db.prepare(\n 'INSERT INTO memories (id, title, kind, durability, updated, superseded_by, sources) VALUES (?, ?, ?, ?, ?, ?, ?)',\n );\n for (const m of memories) {\n insert.run(\n m.id,\n m.title,\n m.kind,\n m.durability,\n m.updated,\n supersededBy.get(m.id) ?? null,\n JSON.stringify(m.sources),\n );\n this.insertSections(\n `memory:${m.id}`,\n m.title,\n `${m.title}\\n${m.tags.join(' ')}\\n${m.body}`,\n m.id,\n );\n }\n this.db\n .prepare(\"INSERT OR REPLACE INTO meta (key, value) VALUES ('memories', ?)\")\n .run(signature);\n }\n\n /** Repository paths a memory cites that no longer exist (evaluated now: the repo changes). */\n missingSources(sources: readonly string[]): string[] {\n return sources.filter((source) => {\n const path = repoPathOf(source);\n return path !== null && !existsSync(join(this.options.root, path));\n });\n }\n\n sync(): void {\n this.options.memories.pruneExpired();\n const memories = this.options.memories.list();\n this.db.transaction(() => {\n this.syncDocs();\n this.syncMemories(memories);\n })();\n }\n\n search(query: string, options: SearchOptions = {}): KnowledgeHit[] {\n const fts = toFtsQuery(query);\n if (!fts) return [];\n const limit = options.limit ?? 10;\n const rows = this.db\n .prepare(\n `SELECT s.source, s.memory_id, s.heading, s.start_line, s.end_line,\n snippet(sections_fts, 0, '', '', ' \u2026 ', 14) AS snippet,\n m.title, m.kind, m.updated, m.superseded_by, m.sources\n FROM sections_fts JOIN sections s ON s.id = sections_fts.rowid\n LEFT JOIN memories m ON m.id = s.memory_id\n WHERE sections_fts MATCH ? ORDER BY bm25(sections_fts, 1.0, 2.0, 3.0) LIMIT ?`,\n )\n .all(fts, limit * 5) as SectionRow[];\n const hits: KnowledgeHit[] = [];\n // One hit per memory / per document (its best section), so the budget covers distinct sources.\n const seen = new Set<string>();\n // No relative score floor here: small doc sets collapse BM25's IDF towards 0 (every term is\n // in most sections), so the right section can score ~0 while a single other one scores high.\n for (const row of rows) {\n const hit = this.toHit(row, options.scope ?? 'all', options.includeSuperseded ?? false);\n const key = hit?.type === 'memory' ? `m:${hit.id}` : hit ? `d:${hit.path}` : '';\n if (!hit || seen.has(key)) continue;\n seen.add(key);\n hits.push(hit);\n if (hits.length >= limit) break;\n }\n return hits;\n }\n\n /** A search row as a hit, or null when scope/supersession filters it out. */\n private toHit(row: SectionRow, scope: Scope, includeSuperseded: boolean): KnowledgeHit | null {\n const snippet = row.snippet.replace(/\\s+/g, ' ').trim().slice(0, 140);\n if (row.memory_id === null) {\n if (scope === 'memory') return null;\n return {\n type: 'doc',\n path: row.source,\n heading: row.heading,\n startLine: row.start_line,\n endLine: row.end_line,\n snippet,\n };\n }\n if (scope === 'docs' || (row.superseded_by && !includeSuperseded)) return null;\n return {\n type: 'memory',\n id: row.memory_id,\n title: row.title ?? '',\n kind: row.kind ?? 'note',\n updated: row.updated ?? '',\n stale: this.missingSources(JSON.parse(row.sources ?? '[]') as string[]),\n snippet,\n };\n }\n\n /** Active durable knowledge, newest first, for the SessionStart index. */\n activeMemories(): {\n id: string;\n title: string;\n kind: string;\n updated: string;\n durability: string;\n }[] {\n return this.db\n .prepare(\n 'SELECT id, title, kind, updated, durability FROM memories WHERE superseded_by IS NULL ORDER BY updated DESC',\n )\n .all() as { id: string; title: string; kind: string; updated: string; durability: string }[];\n }\n\n record(sessionId: string, entry: JournalEntry): void {\n this.db\n .prepare('INSERT INTO journal (session_id, at, tool, detail, failed) VALUES (?, ?, ?, ?, ?)')\n .run(sessionId, entry.at, entry.tool, entry.detail, entry.failed ? 1 : 0);\n }\n\n /** Returns and clears the activity recorded for a session. */\n drainJournal(sessionId: string): JournalEntry[] {\n const rows = this.db\n .prepare('SELECT at, tool, detail, failed FROM journal WHERE session_id = ? ORDER BY rowid')\n .all(sessionId) as { at: string; tool: string; detail: string; failed: number }[];\n this.db.prepare('DELETE FROM journal WHERE session_id = ?').run(sessionId);\n return rows.map((r) => ({ at: r.at, tool: r.tool, detail: r.detail, failed: r.failed === 1 }));\n }\n}\n", "import { existsSync, writeFileSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { openDatabase } from '@yandecode/core';\nimport type { MemoryRepository } from './memories';\nimport type { MemoryKind } from './memory-file';\n\nconst KIND_BY_NAMESPACE: Readonly<Record<string, MemoryKind>> = {\n decisions: 'decision',\n patterns: 'pattern',\n solutions: 'fact',\n failures: 'failure',\n tasks: 'note',\n feedback: 'note',\n};\n\ninterface LegacyRow {\n id: string;\n namespace: string;\n content: string;\n summary: string | null;\n}\n\n/**\n * One-time import of v0 SQLite memories into memory files (ADR-020). A marker file makes it\n * idempotent; archived rows are skipped. Returns the number of imported memories.\n */\nexport function importLegacyMemories(legacyDb: string, repo: MemoryRepository): number {\n const marker = join(repo.dir, '.imported-v0');\n if (!existsSync(legacyDb) || existsSync(marker)) return 0;\n const db = openDatabase(legacyDb);\n try {\n const table = db\n .prepare(\"SELECT name FROM sqlite_master WHERE type = 'table' AND name = 'memories'\")\n .get();\n const rows = table\n ? (db\n .prepare(\n 'SELECT id, namespace, content, summary FROM memories WHERE archived_at IS NULL ORDER BY created_at',\n )\n .all() as LegacyRow[])\n : [];\n for (const row of rows) {\n const firstLine = row.content.split('\\n')[0]!.slice(0, 80);\n repo.write({\n title: row.summary?.trim() || firstLine,\n body: row.content,\n kind: KIND_BY_NAMESPACE[row.namespace] ?? 'note',\n sources: [`yandecode-v0-memory:${row.id}`],\n tags: ['imported-v0'],\n });\n }\n writeFileSync(marker, `${new Date().toISOString()}\\n`);\n return rows.length;\n } finally {\n db.close();\n }\n}\n", "import { existsSync, mkdirSync, readdirSync, readFileSync, statSync, unlinkSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { writeFileAtomic } from '@yandecode/core';\nimport {\n parseMemory,\n serializeMemory,\n type Durability,\n type Memory,\n type MemoryKind,\n} from './memory-file';\n\nconst DAY_MS = 86_400_000;\n/** Same-kind memories whose word sets overlap this much are treated as the same memory. */\nconst DUPLICATE_JACCARD = 0.8;\n\nexport interface WriteMemoryInput {\n title: string;\n body: string;\n kind: MemoryKind;\n durability?: Durability;\n tags?: readonly string[];\n sources?: readonly string[];\n supersedes?: readonly string[];\n /** Ephemeral lifetime; default 14 days. Ignored for durable memories. */\n expiresInDays?: number;\n /** Merge into a near-duplicate of the same kind (default true). */\n dedupe?: boolean;\n}\n\nexport interface WriteResult {\n id: string;\n action: 'created' | 'updated';\n}\n\nfunction words(text: string): Set<string> {\n return new Set(text.toLowerCase().match(/[\\p{L}\\p{N}]{3,}/gu) ?? []);\n}\n\nfunction jaccard(a: ReadonlySet<string>, b: ReadonlySet<string>): number {\n if (a.size === 0 && b.size === 0) return 1;\n let shared = 0;\n for (const w of a) if (b.has(w)) shared++;\n return shared / (a.size + b.size - shared);\n}\n\nfunction slug(title: string): string {\n const base = title\n .normalize('NFKD')\n .replace(/[\u0300-\u036F]/g, '')\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-|-$/g, '')\n .slice(0, 50)\n .replace(/-$/, '');\n return base || 'memory';\n}\n\nconst union = (a: readonly string[], b: readonly string[] = []): string[] => [\n ...new Set([...a, ...b]),\n];\n\n/** File-backed memories: `<dir>/<id>.md`, one Markdown file each (ADR-020). */\nexport class MemoryRepository {\n constructor(\n readonly dir: string,\n private readonly clock: () => Date = () => new Date(),\n ) {}\n\n private file(id: string): string {\n return join(this.dir, `${id}.md`);\n }\n\n private files(): string[] {\n return existsSync(this.dir)\n ? readdirSync(this.dir)\n .filter((f) => f.endsWith('.md'))\n .sort()\n : [];\n }\n\n private read(fileName: string): Memory | null {\n const path = join(this.dir, fileName);\n try {\n const memory = parseMemory(readFileSync(path, 'utf8'));\n if (memory.created !== '') return memory;\n const mtime = statSync(path).mtime.toISOString();\n return { ...memory, created: mtime, updated: memory.updated || mtime };\n } catch {\n return null;\n }\n }\n\n get(id: string): Memory | null {\n return existsSync(this.file(id)) ? this.read(`${id}.md`) : null;\n }\n\n /** Valid memories, most recently updated first. */\n list(): Memory[] {\n return this.files()\n .flatMap((f) => this.read(f) ?? [])\n .sort((a, b) => b.updated.localeCompare(a.updated));\n }\n\n invalidFiles(): string[] {\n return this.files().filter((f) => this.read(f) === null);\n }\n\n write(input: WriteMemoryInput): WriteResult {\n mkdirSync(this.dir, { recursive: true });\n const now = this.clock().toISOString();\n const durability = input.durability ?? (input.kind === 'session' ? 'ephemeral' : 'durable');\n const expires =\n durability === 'ephemeral'\n ? new Date(this.clock().getTime() + (input.expiresInDays ?? 14) * DAY_MS).toISOString()\n : null;\n const fingerprint = words(`${input.title} ${input.body}`);\n const duplicate =\n (input.dedupe ?? true) &&\n this.list().find(\n (m) =>\n m.kind === input.kind &&\n jaccard(words(`${m.title} ${m.body}`), fingerprint) >= DUPLICATE_JACCARD,\n );\n if (duplicate) {\n writeFileAtomic(\n this.file(duplicate.id),\n serializeMemory({\n ...duplicate,\n title: input.title,\n body: input.body,\n updated: now,\n expires: durability === 'ephemeral' ? expires : duplicate.expires,\n tags: union(duplicate.tags, input.tags),\n sources: union(duplicate.sources, input.sources),\n supersedes: union(duplicate.supersedes, input.supersedes),\n }),\n );\n return { id: duplicate.id, action: 'updated' };\n }\n const base = `${now.slice(0, 10).replace(/-/g, '')}-${slug(input.title)}`;\n let id = base;\n for (let n = 2; existsSync(this.file(id)); n++) id = `${base}-${n}`;\n writeFileAtomic(\n this.file(id),\n serializeMemory({\n id,\n title: input.title,\n kind: input.kind,\n durability,\n created: now,\n updated: now,\n expires,\n supersedes: [...(input.supersedes ?? [])],\n tags: [...(input.tags ?? [])],\n sources: [...(input.sources ?? [])],\n body: input.body,\n }),\n );\n return { id, action: 'created' };\n }\n\n forget(id: string): boolean {\n if (!existsSync(this.file(id))) return false;\n unlinkSync(this.file(id));\n return true;\n }\n\n /** Deletes ephemeral memories past their expiry; returns their ids. */\n pruneExpired(): string[] {\n const now = this.clock().toISOString();\n const expired = this.list().filter((m) => m.expires !== null && m.expires < now);\n for (const m of expired) unlinkSync(this.file(m.id));\n return expired.map((m) => m.id);\n }\n}\n", "import type { JournalEntry, KnowledgeIndex } from './index-store';\nimport type { MemoryRepository } from './memories';\n\nconst LISTED_FILES = 15;\n\nexport interface SessionSummary {\n title: string;\n body: string;\n sources: string[];\n}\n\n/** Deterministic summary of what a session did, from the PostToolUse journal. */\nconst EDIT_TOOLS = new Set(['Edit', 'Write', 'MultiEdit', 'NotebookEdit']);\nconst COMMAND_TOOLS = new Set(['Bash', 'ctx_run']);\n\nfunction toolUsage(entries: readonly JournalEntry[]): string {\n const counts = new Map<string, number>();\n for (const e of entries.filter((e) => !EDIT_TOOLS.has(e.tool) && e.tool !== 'Bash')) {\n counts.set(e.tool, (counts.get(e.tool) ?? 0) + 1);\n }\n return [...counts].map(([tool, n]) => `${tool} \u00D7${n}`).join(', ');\n}\n\n/** Deterministic summary of what a session did, from the PostToolUse journal. */\nexport function summarizeSession(\n entries: readonly JournalEntry[],\n endedAt: Date,\n): SessionSummary | null {\n if (entries.length === 0) return null;\n const edited = [...new Set(entries.filter((e) => EDIT_TOOLS.has(e.tool)).map((e) => e.detail))];\n const commands = entries.filter((e) => COMMAND_TOOLS.has(e.tool));\n const failed = [...new Set(commands.filter((e) => e.failed).map((e) => e.detail))];\n const usage = toolUsage(entries);\n const when = endedAt.toISOString().slice(0, 16).replace('T', ' ');\n const title =\n edited.length > 0\n ? `Session ${when}: edited ${edited.slice(0, 3).join(', ')}${edited.length > 3 ? ` +${edited.length - 3}` : ''}`\n : `Session ${when}: ${commands.length} command(s)`;\n const failing =\n failed.length > 0\n ? `; failing: ${failed\n .slice(0, 5)\n .map((c) => `\\`${c}\\``)\n .join(', ')}`\n : '';\n const lines = [\n `Started ${entries[0]!.at}, ended ${endedAt.toISOString()}.`,\n edited.length > 0\n ? `Edited ${edited.length} file(s): ${edited.slice(0, LISTED_FILES).join(', ')}${edited.length > LISTED_FILES ? ', \u2026' : ''}.`\n : 'No files edited.',\n `Ran ${commands.length} command(s)${failing}.`,\n ...(usage ? [`yandecode tools: ${usage}.`] : []),\n ];\n return { title, body: lines.join('\\n'), sources: edited.slice(0, LISTED_FILES) };\n}\n\n/**\n * Compact index of active knowledge for SessionStart (progressive disclosure: titles and ids\n * only; bodies via knowledge_get). Whole lines are dropped, oldest first, to fit the budget.\n */\nexport function sessionStartIndex(\n index: KnowledgeIndex,\n repo: MemoryRepository,\n maxChars: number,\n): string {\n const active = index.activeMemories();\n const durable = active.filter((m) => m.durability === 'durable');\n const lastSession = active.find((m) => m.kind === 'session');\n if (durable.length === 0 && !lastSession) return '';\n const header = 'Project memory (YandeCode) \u2014 titles only; read bodies with knowledge_get(ids):';\n const lines = durable.map((m) => `- [${m.id}] (${m.kind}) ${m.title}`);\n const last = lastSession ? repo.get(lastSession.id) : null;\n const tail = last ? [`Last session [${last.id}]: ${last.body.replace(/\\n/g, ' ')}`] : [];\n let kept = lines;\n const render = (): string =>\n [\n header,\n ...kept,\n ...(kept.length < lines.length\n ? [`\u2026 ${lines.length - kept.length} older memory(ies): knowledge_search to find them`]\n : []),\n ...tail,\n ].join('\\n');\n while (render().length > maxChars && kept.length > 0) kept = kept.slice(0, -1);\n const text = render();\n return text.length > maxChars ? text.slice(0, maxChars) : text;\n}\n\nconst STOPWORDS = new Set([\n 'the',\n 'and',\n 'for',\n 'with',\n 'this',\n 'that',\n 'from',\n 'what',\n 'where',\n 'como',\n 'para',\n 'uma',\n 'que',\n 'com',\n 'por',\n 'n\u00E3o',\n 'isso',\n 'esse',\n 'essa',\n 'have',\n 'does',\n 'should',\n 'please',\n 'can',\n 'you',\n]);\n\n/**\n * Memories clearly related to a user prompt: at least two distinct prompt words (4+ letters) must\n * appear in the memory. Returns a short block or '' \u2014 never costs context when nothing matches.\n */\nexport function promptRecall(index: KnowledgeIndex, prompt: string, maxItems = 3): string {\n const terms = [\n ...new Set(\n (prompt.toLowerCase().match(/[\\p{L}\\p{N}_]{4,}/gu) ?? []).filter((w) => !STOPWORDS.has(w)),\n ),\n ];\n if (terms.length < 2) return '';\n const hits = index\n .search(terms.join(' '), { scope: 'memory', limit: 8 })\n .filter((h) => h.type === 'memory')\n .filter((h) => {\n const text = `${h.title} ${h.snippet}`.toLowerCase();\n return terms.filter((t) => text.includes(t)).length >= 2;\n })\n .slice(0, maxItems);\n if (hits.length === 0) return '';\n return [\n 'Possibly relevant project memory (knowledge_get for details):',\n ...hits.map((h) => `- [${h.id}] (${h.kind}) ${h.title}`),\n ].join('\\n');\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["existsSync", "readFileSync", "isAbsolute", "join", "relative", "existsSync", "join", "join", "existsSync", "existsSync", "mkdirSync", "readdirSync", "readFileSync", "statSync", "join", "join", "existsSync", "readdirSync", "readFileSync", "statSync", "mkdirSync", "e", "isAbsolute", "join", "relative", "existsSync", "readFileSync", "EDIT_TOOLS"]
7
+ }
@@ -0,0 +1,271 @@
1
+ import { createRequire as __yandecodeCreateRequire } from 'node:module';
2
+ const require = __yandecodeCreateRequire(import.meta.url);
3
+ import {
4
+ decideChoice
5
+ } from "./chunk-TYLH4NIC.js";
6
+ import {
7
+ parseSettings
8
+ } from "./chunk-QCQC73WX.js";
9
+ import {
10
+ guardSettings
11
+ } from "./chunk-7L6DD2VD.js";
12
+ import {
13
+ findSecrets
14
+ } from "./chunk-Y2MIXROU.js";
15
+
16
+ // packages/cli/src/modules/guard/adjudicator.ts
17
+ var CRITERIA = {
18
+ allow: "The call is safe in this context; let it run silently.",
19
+ warn: "Let it run but surface a caution to the agent; there is some risk.",
20
+ deny: "Block it: real, avoidable risk to the repository or to credentials."
21
+ };
22
+ function state(call, ruleVerdict) {
23
+ return JSON.stringify({
24
+ tool: call.tool,
25
+ command: call.command,
26
+ file: call.filePath ?? void 0,
27
+ cwd: call.cwd,
28
+ flagged_rule: ruleVerdict.rule,
29
+ rule_reason: ruleVerdict.reason
30
+ });
31
+ }
32
+ async function adjudicate(call, ruleVerdict, settings, apiKey, fetchImpl = fetch) {
33
+ const answer = await decideChoice(
34
+ settings,
35
+ state(call, ruleVerdict),
36
+ "A deterministic rule flagged this coding-agent tool call as ambiguous. Decide what to do.",
37
+ CRITERIA,
38
+ apiKey,
39
+ fetchImpl
40
+ );
41
+ return answer ? { decision: answer.choice, confidence: answer.confidence } : null;
42
+ }
43
+ function resolveEnforced(adj, denyConfidence) {
44
+ if (adj === null) return "warn";
45
+ if (adj.decision === "deny" && adj.confidence >= denyConfidence) return "deny";
46
+ if (adj.decision === "allow") return "allow";
47
+ return "warn";
48
+ }
49
+
50
+ // packages/cli/src/modules/guard/commit-scan.ts
51
+ import { spawnSync } from "node:child_process";
52
+ function secretsInPendingCommit(cwd, includeUnstaged, timeoutMs) {
53
+ const diffArgs = includeUnstaged ? ["diff", "HEAD", "-U0", "--no-color"] : ["diff", "--cached", "-U0", "--no-color"];
54
+ const run = spawnSync("git", diffArgs, {
55
+ cwd,
56
+ encoding: "utf8",
57
+ timeout: timeoutMs,
58
+ maxBuffer: 32 * 1024 * 1024
59
+ });
60
+ const diff = run.status === 0 ? run.stdout : spawnSync("git", ["diff", "--cached", "-U0", "--no-color"], {
61
+ cwd,
62
+ encoding: "utf8",
63
+ timeout: timeoutMs
64
+ }).stdout;
65
+ const found = [];
66
+ let file = "";
67
+ for (const line of diff.split("\n")) {
68
+ if (line.startsWith("+++ ")) file = line.replace(/^\+\+\+ (b\/)?/, "");
69
+ else if (line.startsWith("+") && !line.startsWith("+++")) {
70
+ for (const hit of findSecrets(line.slice(1)))
71
+ found.push(`${hit.rule} (${hit.preview}) in ${file}`);
72
+ }
73
+ }
74
+ return [...new Set(found)];
75
+ }
76
+
77
+ // packages/cli/src/modules/guard/rules.ts
78
+ import { basename } from "node:path";
79
+ var OVERRIDE = /(?:#\s*|\[)guard-ok:\s*([^\]\n]+?)\s*\]?\s*$/m;
80
+ var OVERRIDE_HINT = "If the user explicitly asked for this, re-run it with `# guard-ok: <reason>` appended to the command.";
81
+ var CREDENTIAL_FILE = /^(\.env(\..+)?|id_(rsa|dsa|ecdsa|ed25519)|.+\.(pem|key|p12|pfx|keystore)|\.netrc|\.git-credentials|\.pgpass|credentials(\.json)?)$/;
82
+ var CREDENTIAL_TEMPLATE = /\.(example|sample|template|dist|defaults)$/;
83
+ var READERS = /^(cat|less|more|head|tail|bat|xxd|strings|od|nl|source|\.)\b/;
84
+ function isCredentialFile(path) {
85
+ const name = basename(path);
86
+ return CREDENTIAL_FILE.test(name) && !CREDENTIAL_TEMPLATE.test(name);
87
+ }
88
+ function parse(call) {
89
+ const command = typeof call.input.command === "string" ? call.input.command : "";
90
+ const bare = command.replace(
91
+ /'[^']*'|"(?:\\.|[^"\\])*"/g,
92
+ (quoted) => /^"\$\{?HOME\}?"$/.test(quoted) ? "$HOME" : "''"
93
+ );
94
+ const filePath = typeof call.input.file_path === "string" ? call.input.file_path : typeof call.input.notebook_path === "string" ? call.input.notebook_path : null;
95
+ const content = ["content", "new_string", "new_source"].map((k) => call.input[k]).filter((v) => typeof v === "string").join("\n");
96
+ const segments = bare.replace(/#.*$/gm, "").split(/&&|\|\||;|\||\n/).map((s) => s.trim()).filter(Boolean);
97
+ return { tool: call.tool, command, segments, filePath, content };
98
+ }
99
+ var anySegment = (call, test) => call.tool === "Bash" && call.segments.some(test);
100
+ var RM_RECURSIVE_FORCE = /^rm\s+(-\w*r\w*f\w*|-\w*f\w*r\w*|(-\w+\s+)*--recursive\s+--force|-r\s+-f|-f\s+-r)\b/;
101
+ var RM_CRITICAL_TARGET = /\s(\/|\/\*|~|~\/|~\/\*|\$HOME|\$HOME\/\*?|\.|\.\.|\*)\s*$/;
102
+ var RULES = [
103
+ {
104
+ id: "secrets-in-command",
105
+ decision: "deny",
106
+ check: (call) => {
107
+ if (call.tool !== "Bash") return null;
108
+ const hits = findSecrets(call.command);
109
+ return hits.length > 0 ? `The command contains a credential (${hits.map((h) => `${h.rule} ${h.preview}`).join(", ")}); it would be stored in the transcript and shell history. Read it from an environment variable instead.` : null;
110
+ }
111
+ },
112
+ {
113
+ id: "secrets-in-content",
114
+ decision: "deny",
115
+ check: (call) => {
116
+ if (!call.content) return null;
117
+ const hits = findSecrets(call.content);
118
+ return hits.length > 0 ? `The new content contains a credential (${hits.map((h) => `${h.rule} ${h.preview}`).join(", ")}). Load it from the environment or a secret manager instead of writing it to ${call.filePath ?? "a file"}.` : null;
119
+ }
120
+ },
121
+ {
122
+ id: "credential-file",
123
+ decision: "deny",
124
+ check: (call) => {
125
+ if (call.tool === "Read" && call.filePath && isCredentialFile(call.filePath)) {
126
+ return `${basename(call.filePath)} holds credentials; reading it copies them into the conversation. Ask the user for the specific non-secret value you need, or read the template (e.g. .env.example).`;
127
+ }
128
+ const reader = call.segments.find(
129
+ (s) => READERS.test(s) && s.split(/\s+/).slice(1).some(isCredentialFile)
130
+ );
131
+ return reader ? `\`${reader}\` would print credentials into the conversation.` : null;
132
+ }
133
+ },
134
+ {
135
+ id: "sudo",
136
+ decision: "deny",
137
+ check: (call) => anySegment(call, (s) => /^(sudo|doas)\b/.test(s)) ? "Privilege escalation from the agent is blocked. Ask the user to run it themselves (they can type `! <command>`)." : null
138
+ },
139
+ {
140
+ id: "destructive-rm",
141
+ decision: "deny",
142
+ check: (call) => anySegment(call, (s) => RM_RECURSIVE_FORCE.test(s) && RM_CRITICAL_TARGET.test(s)) ? "Recursive forced delete of the filesystem root, the home directory or the whole working directory." : null
143
+ },
144
+ {
145
+ id: "disk",
146
+ decision: "deny",
147
+ check: (call) => anySegment(call, (s) => /^mkfs(\.\w+)?\b|^dd\b.*\bof=\/dev\/|>\s*\/dev\/(sd|nvme|hd)/.test(s)) ? "Writes directly to a block device or formats a filesystem." : null
148
+ },
149
+ {
150
+ id: "force-push",
151
+ decision: "deny",
152
+ check: (call) => anySegment(
153
+ call,
154
+ (s) => /^git\s+push\b/.test(s) && /\s(--force(?!-with-lease)|-f)\b/.test(s) && /\b(main|master)\b|\s\+/.test(s)
155
+ ) ? "Force-pushing to main/master rewrites shared history." : null
156
+ },
157
+ {
158
+ id: "force-push",
159
+ decision: "warn",
160
+ check: (call) => anySegment(call, (s) => /^git\s+push\b/.test(s) && /\s(--force(?!-with-lease)|-f)\b/.test(s)) ? "Force push without --force-with-lease can overwrite collaborators\u2019 commits; prefer --force-with-lease." : null
161
+ },
162
+ {
163
+ id: "history-rewrite",
164
+ decision: "warn",
165
+ check: (call) => anySegment(
166
+ call,
167
+ (s) => /^git\s+(reset\s+--hard|clean\s+-\w*f|checkout\s+--\s+\.|restore\s+\.)/.test(s)
168
+ ) ? "This discards uncommitted work irreversibly; make sure the user wants that (git stash keeps a copy)." : null
169
+ },
170
+ {
171
+ id: "credential-file",
172
+ decision: "warn",
173
+ check: (call) => (call.tool === "Edit" || call.tool === "Write" || call.tool === "MultiEdit") && call.filePath && isCredentialFile(call.filePath) ? `Editing ${basename(call.filePath)}, a credentials file: do not echo its values back into the conversation.` : null
174
+ }
175
+ ];
176
+ function evaluate(call, options) {
177
+ const parsed = parse(call);
178
+ const active = RULES.filter((r) => !options.disabled.includes(r.id));
179
+ for (const decision of ["deny", "warn"]) {
180
+ for (const rule of active.filter((r) => r.decision === decision)) {
181
+ const reason = rule.check(parsed);
182
+ if (reason === null) continue;
183
+ const override = OVERRIDE.exec(parsed.command)?.[1];
184
+ if (decision === "deny" && override)
185
+ return { decision: "allow", rule: rule.id, overridden: override };
186
+ return {
187
+ decision,
188
+ rule: rule.id,
189
+ reason: decision === "deny" ? `${reason} ${OVERRIDE_HINT}` : reason
190
+ };
191
+ }
192
+ }
193
+ return null;
194
+ }
195
+
196
+ // packages/cli/src/modules/guard/runtime.ts
197
+ var COMMIT = /(^|[;&|]\s*)git\s+(-C\s+\S+\s+)?commit\b/m;
198
+ function commitVerdict(command, cwd, disabled) {
199
+ if (disabled.includes("commit-secrets") || !COMMIT.test(command)) return null;
200
+ const all = /\scommit\b[^;&|]*\s(-a|--all|-\w*a\w*)\b/.test(command);
201
+ const found = secretsInPendingCommit(cwd, all, 800);
202
+ if (found.length === 0) return null;
203
+ return {
204
+ kind: "deny",
205
+ reason: `The commit would record credentials: ${found.join("; ")}. Remove them from the change (and rotate them if they were ever pushed). If they are test fixtures the user approved, re-run with \`# guard-ok: <reason>\`.`
206
+ };
207
+ }
208
+ var warnContext = (verdict, note = "") => ({
209
+ kind: "context",
210
+ text: `yandecode guard (${verdict.rule}): ${verdict.reason}${note}`
211
+ });
212
+ async function resolveWarn(verdict, call, adj, ctx) {
213
+ const apiKey = process.env.OPENROUTER_API_KEY;
214
+ if (adj.mode === "off" || !apiKey) return warnContext(verdict);
215
+ const opinion = await adjudicate(call, verdict, adj, apiKey);
216
+ ctx.log("adjudicated", {
217
+ rule: verdict.rule,
218
+ tool: call.tool,
219
+ mode: adj.mode,
220
+ decision: opinion?.decision ?? "unavailable",
221
+ confidence: opinion?.confidence
222
+ });
223
+ if (adj.mode === "shadow") return warnContext(verdict);
224
+ const enforced = resolveEnforced(opinion, adj.denyConfidence);
225
+ if (enforced === "deny")
226
+ return {
227
+ kind: "deny",
228
+ reason: `${verdict.reason} Jev judged this too risky (confidence ${opinion.confidence.toFixed(2)}). If you meant to do this, re-run with \`# guard-ok: <reason>\`.`
229
+ };
230
+ if (enforced === "allow") return { kind: "none" };
231
+ return warnContext(verdict);
232
+ }
233
+ function commitDeny(input, verdict, command, cwd, disabled, ctx) {
234
+ if (input.tool_name !== "Bash" || verdict?.overridden !== void 0) return null;
235
+ const commit = commitVerdict(command, cwd, disabled);
236
+ if (!commit) return null;
237
+ ctx.log("deny", { rule: "commit-secrets" });
238
+ return commit;
239
+ }
240
+ async function preToolUse(input, ctx) {
241
+ const { disabled, adjudicator } = parseSettings("guard", guardSettings, ctx.settings);
242
+ const toolInput = input.tool_input ?? {};
243
+ const verdict = evaluate(
244
+ { tool: input.tool_name ?? "", input: toolInput },
245
+ { root: ctx.root, disabled }
246
+ );
247
+ if (verdict)
248
+ ctx.log(verdict.decision, {
249
+ rule: verdict.rule,
250
+ tool: input.tool_name,
251
+ overridden: verdict.overridden
252
+ });
253
+ if (verdict?.decision === "deny") return { kind: "deny", reason: verdict.reason };
254
+ const command = typeof toolInput.command === "string" ? toolInput.command : "";
255
+ const cwd = typeof input.cwd === "string" ? input.cwd : ctx.root;
256
+ const commit = commitDeny(input, verdict, command, cwd, disabled, ctx);
257
+ if (commit) return commit;
258
+ if (verdict?.decision === "warn") {
259
+ const filePath = typeof toolInput.file_path === "string" ? toolInput.file_path : null;
260
+ const call = { tool: input.tool_name ?? "", command, filePath, cwd };
261
+ return resolveWarn(verdict, call, adjudicator, ctx);
262
+ }
263
+ return { kind: "none" };
264
+ }
265
+ var runtime = {
266
+ hooks: { PreToolUse: preToolUse }
267
+ };
268
+ export {
269
+ runtime
270
+ };
271
+ //# sourceMappingURL=runtime-ZGGF6RVA.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/modules/guard/adjudicator.ts", "../../src/modules/guard/commit-scan.ts", "../../src/modules/guard/rules.ts", "../../src/modules/guard/runtime.ts"],
4
+ "sourcesContent": ["// Optional Jev adjudicator for the guard's ambiguous (warn) cases, mirroring jev-kit's airlock:\n// deterministic rules run first and only the genuinely ambiguous calls are sent to Jev \u2014 the real\n// TypeSafe typed-decision model, which returns a calibrated choice among allow/warn/deny. Fail-open\n// throughout: a null answer leaves the deterministic verdict untouched.\nimport { decideChoice, type JevCall } from '@cli/shared/jev';\nimport type { Verdict } from './rules';\n\nexport type AdjudicatorMode = 'off' | 'shadow' | 'enforce';\n\nexport interface AdjudicatorSettings extends JevCall {\n mode: AdjudicatorMode;\n /** A deny is honoured only at or above this confidence (jev-kit uses 0.8). */\n denyConfidence: number;\n}\n\nexport interface AdjCall {\n tool: string;\n /** Bash command, when the call is a shell command. */\n command?: string;\n /** File path only \u2014 never the file's contents, which may hold secrets. */\n filePath?: string | null;\n cwd: string;\n}\n\nexport interface AdjVerdict {\n decision: 'allow' | 'warn' | 'deny';\n confidence: number;\n}\n\nconst CRITERIA: Record<AdjVerdict['decision'], string> = {\n allow: 'The call is safe in this context; let it run silently.',\n warn: 'Let it run but surface a caution to the agent; there is some risk.',\n deny: 'Block it: real, avoidable risk to the repository or to credentials.',\n};\n\n/** The situation described to Jev \u2014 deliberately no file contents. */\nfunction state(call: AdjCall, ruleVerdict: Verdict): string {\n return JSON.stringify({\n tool: call.tool,\n command: call.command,\n file: call.filePath ?? undefined,\n cwd: call.cwd,\n flagged_rule: ruleVerdict.rule,\n rule_reason: ruleVerdict.reason,\n });\n}\n\n/**\n * Ask Jev to judge one ambiguous call. Returns its typed verdict, or null on any failure so the\n * caller keeps the deterministic verdict (fail-open). Never throws.\n */\nexport async function adjudicate(\n call: AdjCall,\n ruleVerdict: Verdict,\n settings: AdjudicatorSettings,\n apiKey: string,\n fetchImpl: typeof fetch = fetch,\n): Promise<AdjVerdict | null> {\n const answer = await decideChoice(\n settings,\n state(call, ruleVerdict),\n 'A deterministic rule flagged this coding-agent tool call as ambiguous. Decide what to do.',\n CRITERIA,\n apiKey,\n fetchImpl,\n );\n return answer\n ? { decision: answer.choice as AdjVerdict['decision'], confidence: answer.confidence }\n : null;\n}\n\n/**\n * Fold Jev's verdict into the deterministic warn verdict under `enforce`: a confident deny blocks,\n * an allow clears the warning, anything else (including a null/fail-open result) keeps the warn.\n */\nexport function resolveEnforced(\n adj: AdjVerdict | null,\n denyConfidence: number,\n): 'deny' | 'warn' | 'allow' {\n if (adj === null) return 'warn';\n if (adj.decision === 'deny' && adj.confidence >= denyConfidence) return 'deny';\n if (adj.decision === 'allow') return 'allow';\n return 'warn';\n}\n", "import { spawnSync } from 'node:child_process';\nimport { findSecrets } from '@yandecode/core';\n\n/** Secrets in lines a `git commit` would record, as \"rule (preview) in file\". */\nexport function secretsInPendingCommit(\n cwd: string,\n includeUnstaged: boolean,\n timeoutMs: number,\n): string[] {\n const diffArgs = includeUnstaged\n ? ['diff', 'HEAD', '-U0', '--no-color']\n : ['diff', '--cached', '-U0', '--no-color'];\n const run = spawnSync('git', diffArgs, {\n cwd,\n encoding: 'utf8',\n timeout: timeoutMs,\n maxBuffer: 32 * 1024 * 1024,\n });\n // No HEAD yet (first commit) makes `diff HEAD` fail; fall back to the index.\n const diff =\n run.status === 0\n ? run.stdout\n : spawnSync('git', ['diff', '--cached', '-U0', '--no-color'], {\n cwd,\n encoding: 'utf8',\n timeout: timeoutMs,\n }).stdout;\n const found: string[] = [];\n let file = '';\n for (const line of diff.split('\\n')) {\n if (line.startsWith('+++ ')) file = line.replace(/^\\+\\+\\+ (b\\/)?/, '');\n else if (line.startsWith('+') && !line.startsWith('+++')) {\n for (const hit of findSecrets(line.slice(1)))\n found.push(`${hit.rule} (${hit.preview}) in ${file}`);\n }\n }\n return [...new Set(found)];\n}\n", "import { basename } from 'node:path';\nimport { findSecrets } from '@yandecode/core';\n\nexport interface GuardInput {\n tool: string;\n input: Record<string, unknown>;\n}\n\nexport interface GuardOptions {\n root: string;\n /** Rule ids turned off in yandecode.json \u2192 guard.disabled. */\n disabled: readonly string[];\n}\n\nexport interface Verdict {\n decision: 'deny' | 'warn' | 'allow';\n rule: string;\n reason?: string;\n /** Present when a deny was overridden with `# guard-ok: <reason>`. */\n overridden?: string;\n}\n\ninterface Rule {\n id: string;\n decision: 'deny' | 'warn';\n /** Returns a reason when the rule fires. */\n check: (call: ParsedCall) => string | null;\n}\n\ninterface ParsedCall {\n tool: string;\n /** Raw command (Bash) \u2014 used for secret detection. */\n command: string;\n /** Command with quoted text blanked and split into simple commands. */\n segments: string[];\n filePath: string | null;\n content: string;\n}\n\nconst OVERRIDE = /(?:#\\s*|\\[)guard-ok:\\s*([^\\]\\n]+?)\\s*\\]?\\s*$/m;\nconst OVERRIDE_HINT =\n 'If the user explicitly asked for this, re-run it with `# guard-ok: <reason>` appended to the command.';\n\nconst CREDENTIAL_FILE =\n /^(\\.env(\\..+)?|id_(rsa|dsa|ecdsa|ed25519)|.+\\.(pem|key|p12|pfx|keystore)|\\.netrc|\\.git-credentials|\\.pgpass|credentials(\\.json)?)$/;\nconst CREDENTIAL_TEMPLATE = /\\.(example|sample|template|dist|defaults)$/;\nconst READERS = /^(cat|less|more|head|tail|bat|xxd|strings|od|nl|source|\\.)\\b/;\n\nfunction isCredentialFile(path: string): boolean {\n const name = basename(path);\n return CREDENTIAL_FILE.test(name) && !CREDENTIAL_TEMPLATE.test(name);\n}\n\nfunction parse(call: GuardInput): ParsedCall {\n const command = typeof call.input.command === 'string' ? call.input.command : '';\n const bare = command.replace(/'[^']*'|\"(?:\\\\.|[^\"\\\\])*\"/g, (quoted) =>\n /^\"\\$\\{?HOME\\}?\"$/.test(quoted) ? '$HOME' : \"''\",\n );\n const filePath =\n typeof call.input.file_path === 'string'\n ? call.input.file_path\n : typeof call.input.notebook_path === 'string'\n ? call.input.notebook_path\n : null;\n const content = ['content', 'new_string', 'new_source']\n .map((k) => call.input[k])\n .filter((v): v is string => typeof v === 'string')\n .join('\\n');\n const segments = bare\n .replace(/#.*$/gm, '')\n .split(/&&|\\|\\||;|\\||\\n/)\n .map((s) => s.trim())\n .filter(Boolean);\n return { tool: call.tool, command, segments, filePath, content };\n}\n\nconst anySegment = (call: ParsedCall, test: (segment: string) => boolean): boolean =>\n call.tool === 'Bash' && call.segments.some(test);\n\nconst RM_RECURSIVE_FORCE =\n /^rm\\s+(-\\w*r\\w*f\\w*|-\\w*f\\w*r\\w*|(-\\w+\\s+)*--recursive\\s+--force|-r\\s+-f|-f\\s+-r)\\b/;\nconst RM_CRITICAL_TARGET = /\\s(\\/|\\/\\*|~|~\\/|~\\/\\*|\\$HOME|\\$HOME\\/\\*?|\\.|\\.\\.|\\*)\\s*$/;\n\nconst RULES: readonly Rule[] = [\n {\n id: 'secrets-in-command',\n decision: 'deny',\n check: (call) => {\n if (call.tool !== 'Bash') return null;\n const hits = findSecrets(call.command);\n return hits.length > 0\n ? `The command contains a credential (${hits.map((h) => `${h.rule} ${h.preview}`).join(', ')}); it would be stored in the transcript and shell history. Read it from an environment variable instead.`\n : null;\n },\n },\n {\n id: 'secrets-in-content',\n decision: 'deny',\n check: (call) => {\n if (!call.content) return null;\n const hits = findSecrets(call.content);\n return hits.length > 0\n ? `The new content contains a credential (${hits.map((h) => `${h.rule} ${h.preview}`).join(', ')}). Load it from the environment or a secret manager instead of writing it to ${call.filePath ?? 'a file'}.`\n : null;\n },\n },\n {\n id: 'credential-file',\n decision: 'deny',\n check: (call) => {\n if (call.tool === 'Read' && call.filePath && isCredentialFile(call.filePath)) {\n return `${basename(call.filePath)} holds credentials; reading it copies them into the conversation. Ask the user for the specific non-secret value you need, or read the template (e.g. .env.example).`;\n }\n const reader = call.segments.find(\n (s) => READERS.test(s) && s.split(/\\s+/).slice(1).some(isCredentialFile),\n );\n return reader ? `\\`${reader}\\` would print credentials into the conversation.` : null;\n },\n },\n {\n id: 'sudo',\n decision: 'deny',\n check: (call) =>\n anySegment(call, (s) => /^(sudo|doas)\\b/.test(s))\n ? 'Privilege escalation from the agent is blocked. Ask the user to run it themselves (they can type `! <command>`).'\n : null,\n },\n {\n id: 'destructive-rm',\n decision: 'deny',\n check: (call) =>\n anySegment(call, (s) => RM_RECURSIVE_FORCE.test(s) && RM_CRITICAL_TARGET.test(s))\n ? 'Recursive forced delete of the filesystem root, the home directory or the whole working directory.'\n : null,\n },\n {\n id: 'disk',\n decision: 'deny',\n check: (call) =>\n anySegment(call, (s) => /^mkfs(\\.\\w+)?\\b|^dd\\b.*\\bof=\\/dev\\/|>\\s*\\/dev\\/(sd|nvme|hd)/.test(s))\n ? 'Writes directly to a block device or formats a filesystem.'\n : null,\n },\n {\n id: 'force-push',\n decision: 'deny',\n check: (call) =>\n anySegment(\n call,\n (s) =>\n /^git\\s+push\\b/.test(s) &&\n /\\s(--force(?!-with-lease)|-f)\\b/.test(s) &&\n /\\b(main|master)\\b|\\s\\+/.test(s),\n )\n ? 'Force-pushing to main/master rewrites shared history.'\n : null,\n },\n {\n id: 'force-push',\n decision: 'warn',\n check: (call) =>\n anySegment(call, (s) => /^git\\s+push\\b/.test(s) && /\\s(--force(?!-with-lease)|-f)\\b/.test(s))\n ? 'Force push without --force-with-lease can overwrite collaborators\u2019 commits; prefer --force-with-lease.'\n : null,\n },\n {\n id: 'history-rewrite',\n decision: 'warn',\n check: (call) =>\n anySegment(call, (s) =>\n /^git\\s+(reset\\s+--hard|clean\\s+-\\w*f|checkout\\s+--\\s+\\.|restore\\s+\\.)/.test(s),\n )\n ? 'This discards uncommitted work irreversibly; make sure the user wants that (git stash keeps a copy).'\n : null,\n },\n {\n id: 'credential-file',\n decision: 'warn',\n check: (call) =>\n (call.tool === 'Edit' || call.tool === 'Write' || call.tool === 'MultiEdit') &&\n call.filePath &&\n isCredentialFile(call.filePath)\n ? `Editing ${basename(call.filePath)}, a credentials file: do not echo its values back into the conversation.`\n : null,\n },\n];\n\n/**\n * Deterministic verdict for one tool call (ADR-022): the first deny wins, else the first warn,\n * else null. A deny can be overridden by the agent with `# guard-ok: <reason>` (logged).\n */\nexport function evaluate(call: GuardInput, options: GuardOptions): Verdict | null {\n const parsed = parse(call);\n const active = RULES.filter((r) => !options.disabled.includes(r.id));\n for (const decision of ['deny', 'warn'] as const) {\n for (const rule of active.filter((r) => r.decision === decision)) {\n const reason = rule.check(parsed);\n if (reason === null) continue;\n const override = OVERRIDE.exec(parsed.command)?.[1];\n if (decision === 'deny' && override)\n return { decision: 'allow', rule: rule.id, overridden: override };\n return {\n decision,\n rule: rule.id,\n reason: decision === 'deny' ? `${reason} ${OVERRIDE_HINT}` : reason,\n };\n }\n }\n return null;\n}\n", "import type { HookInput, HookResult, ModuleContext, ModuleRuntime } from '@cli/modules/contract';\nimport { parseSettings } from '@cli/modules/host';\nimport { adjudicate, resolveEnforced, type AdjudicatorSettings } from './adjudicator';\nimport { secretsInPendingCommit } from './commit-scan';\nimport { guardSettings } from './definition';\nimport { evaluate, type Verdict } from './rules';\n\nconst COMMIT = /(^|[;&|]\\s*)git\\s+(-C\\s+\\S+\\s+)?commit\\b/m;\n\nfunction commitVerdict(\n command: string,\n cwd: string,\n disabled: readonly string[],\n): HookResult | null {\n if (disabled.includes('commit-secrets') || !COMMIT.test(command)) return null;\n const all = /\\scommit\\b[^;&|]*\\s(-a|--all|-\\w*a\\w*)\\b/.test(command);\n const found = secretsInPendingCommit(cwd, all, 800);\n if (found.length === 0) return null;\n return {\n kind: 'deny',\n reason: `The commit would record credentials: ${found.join('; ')}. Remove them from the change (and rotate them if they were ever pushed). If they are test fixtures the user approved, re-run with \\`# guard-ok: <reason>\\`.`,\n };\n}\n\nconst warnContext = (verdict: Verdict, note = ''): HookResult => ({\n kind: 'context',\n text: `yandecode guard (${verdict.rule}): ${verdict.reason!}${note}`,\n});\n\n/**\n * A warn verdict is where Jev earns its keep. Off (or no API key) keeps the plain caution; shadow\n * asks Jev and logs its opinion but never changes the outcome; enforce acts on a confident deny or\n * a clear allow. Any Jev failure falls back to the caution (fail-open).\n */\nasync function resolveWarn(\n verdict: Verdict,\n call: { tool: string; command: string; filePath: string | null; cwd: string },\n adj: AdjudicatorSettings,\n ctx: ModuleContext,\n): Promise<HookResult> {\n const apiKey = process.env.OPENROUTER_API_KEY;\n if (adj.mode === 'off' || !apiKey) return warnContext(verdict);\n const opinion = await adjudicate(call, verdict, adj, apiKey);\n ctx.log('adjudicated', {\n rule: verdict.rule,\n tool: call.tool,\n mode: adj.mode,\n decision: opinion?.decision ?? 'unavailable',\n confidence: opinion?.confidence,\n });\n if (adj.mode === 'shadow') return warnContext(verdict);\n const enforced = resolveEnforced(opinion, adj.denyConfidence);\n if (enforced === 'deny')\n return {\n kind: 'deny',\n reason: `${verdict.reason!} Jev judged this too risky (confidence ${opinion!.confidence.toFixed(2)}). If you meant to do this, re-run with \\`# guard-ok: <reason>\\`.`,\n };\n if (enforced === 'allow') return { kind: 'none' };\n return warnContext(verdict);\n}\n\n/** Scans a `git commit` for staged secrets (only when no rule already overrode the call). */\nfunction commitDeny(\n input: HookInput,\n verdict: Verdict | null,\n command: string,\n cwd: string,\n disabled: readonly string[],\n ctx: ModuleContext,\n): HookResult | null {\n if (input.tool_name !== 'Bash' || verdict?.overridden !== undefined) return null;\n const commit = commitVerdict(command, cwd, disabled);\n if (!commit) return null;\n ctx.log('deny', { rule: 'commit-secrets' });\n return commit;\n}\n\nasync function preToolUse(input: HookInput, ctx: ModuleContext): Promise<HookResult> {\n const { disabled, adjudicator } = parseSettings('guard', guardSettings, ctx.settings);\n const toolInput = input.tool_input ?? {};\n const verdict = evaluate(\n { tool: input.tool_name ?? '', input: toolInput },\n { root: ctx.root, disabled },\n );\n if (verdict)\n ctx.log(verdict.decision, {\n rule: verdict.rule,\n tool: input.tool_name,\n overridden: verdict.overridden,\n });\n if (verdict?.decision === 'deny') return { kind: 'deny', reason: verdict.reason! };\n const command = typeof toolInput.command === 'string' ? toolInput.command : '';\n const cwd = typeof input.cwd === 'string' ? input.cwd : ctx.root;\n const commit = commitDeny(input, verdict, command, cwd, disabled, ctx);\n if (commit) return commit;\n if (verdict?.decision === 'warn') {\n const filePath = typeof toolInput.file_path === 'string' ? toolInput.file_path : null;\n const call = { tool: input.tool_name ?? '', command, filePath, cwd };\n return resolveWarn(verdict, call, adjudicator, ctx);\n }\n return { kind: 'none' };\n}\n\nexport const runtime: ModuleRuntime = {\n hooks: { PreToolUse: preToolUse },\n};\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -0,0 +1,38 @@
1
+ import { createRequire as __yandecodeCreateRequire } from 'node:module';
2
+ const require = __yandecodeCreateRequire(import.meta.url);
3
+ import {
4
+ readManifest
5
+ } from "./chunk-DWD37AI2.js";
6
+ import {
7
+ VERSION
8
+ } from "./chunk-PUWSEWX3.js";
9
+ import {
10
+ enabledModules,
11
+ requireWorkspace
12
+ } from "./chunk-QCQC73WX.js";
13
+ import "./chunk-7L6DD2VD.js";
14
+ import "./chunk-Y2MIXROU.js";
15
+
16
+ // packages/cli/src/commands/status.ts
17
+ function runStatus(cwd, io) {
18
+ const ws = requireWorkspace(cwd);
19
+ const modules = enabledModules(ws);
20
+ const manifest = readManifest(ws.paths.managedManifest);
21
+ const lines = [
22
+ `yandecode ${VERSION}`,
23
+ `project ${ws.root}`,
24
+ `modules ${modules.map((m) => m.id).join(", ") || "(none)"}`,
25
+ `tools ${modules.flatMap((m) => (m.tools ?? []).map((t) => t.name)).join(", ") || "-"}`,
26
+ `hooks ${[...new Set(modules.flatMap((m) => m.hooks.map((h) => h.event)))].join(", ") || "-"}`,
27
+ `integration ${manifest ? `applied by ${manifest.version}, ${manifest.files.length} managed file(s)` : 'not applied (run "yandecode update")'}`
28
+ ];
29
+ if (manifest && manifest.version !== VERSION)
30
+ lines.push(' \u2192 installed version differs: run "yandecode update"');
31
+ io.out(`${lines.join("\n")}
32
+ `);
33
+ return 0;
34
+ }
35
+ export {
36
+ runStatus
37
+ };
38
+ //# sourceMappingURL=status-SPIESL4F.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/commands/status.ts"],
4
+ "sourcesContent": ["import type { Io } from '@cli/io';\nimport { readManifest } from '@cli/integration/manifest';\nimport { enabledModules, requireWorkspace } from '@cli/modules/host';\nimport { VERSION } from '@cli/version';\n\nexport function runStatus(cwd: string, io: Io): number {\n const ws = requireWorkspace(cwd);\n const modules = enabledModules(ws);\n const manifest = readManifest(ws.paths.managedManifest);\n const lines = [\n `yandecode ${VERSION}`,\n `project ${ws.root}`,\n `modules ${modules.map((m) => m.id).join(', ') || '(none)'}`,\n `tools ${modules.flatMap((m) => (m.tools ?? []).map((t) => t.name)).join(', ') || '-'}`,\n `hooks ${[...new Set(modules.flatMap((m) => m.hooks.map((h) => h.event)))].join(', ') || '-'}`,\n `integration ${manifest ? `applied by ${manifest.version}, ${manifest.files.length} managed file(s)` : 'not applied (run \"yandecode update\")'}`,\n ];\n if (manifest && manifest.version !== VERSION)\n lines.push(' \u2192 installed version differs: run \"yandecode update\"');\n io.out(`${lines.join('\\n')}\\n`);\n return 0;\n}\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;AAKO,SAAS,UAAU,KAAa,IAAgB;AACrD,QAAM,KAAK,iBAAiB,GAAG;AAC/B,QAAM,UAAU,eAAe,EAAE;AACjC,QAAM,WAAW,aAAa,GAAG,MAAM,eAAe;AACtD,QAAM,QAAQ;AAAA,IACZ,aAAa,OAAO;AAAA,IACpB,cAAc,GAAG,IAAI;AAAA,IACrB,cAAc,QAAQ,IAAI,CAAC,MAAM,EAAE,EAAE,EAAE,KAAK,IAAI,KAAK,QAAQ;AAAA,IAC7D,cAAc,QAAQ,QAAQ,CAAC,OAAO,EAAE,SAAS,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,EAAE,KAAK,IAAI,KAAK,GAAG;AAAA,IAC1F,cAAc,CAAC,GAAG,IAAI,IAAI,QAAQ,QAAQ,CAAC,MAAM,EAAE,MAAM,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,IAAI,KAAK,GAAG;AAAA,IACjG,eAAe,WAAW,cAAc,SAAS,OAAO,KAAK,SAAS,MAAM,MAAM,qBAAqB,sCAAsC;AAAA,EAC/I;AACA,MAAI,YAAY,SAAS,YAAY;AACnC,UAAM,KAAK,4DAAuD;AACpE,KAAG,IAAI,GAAG,MAAM,KAAK,IAAI,CAAC;AAAA,CAAI;AAC9B,SAAO;AACT;",
6
+ "names": []
7
+ }
@@ -0,0 +1,54 @@
1
+ import { createRequire as __yandecodeCreateRequire } from 'node:module';
2
+ const require = __yandecodeCreateRequire(import.meta.url);
3
+ import {
4
+ applyIntegration,
5
+ removeGitignoreEntry,
6
+ resolveLauncher
7
+ } from "./chunk-KVBKQXTU.js";
8
+ import "./chunk-L2DDIZPI.js";
9
+ import "./chunk-DWD37AI2.js";
10
+ import "./chunk-PUWSEWX3.js";
11
+ import {
12
+ requireWorkspace
13
+ } from "./chunk-QCQC73WX.js";
14
+ import "./chunk-7L6DD2VD.js";
15
+ import {
16
+ writeFileAtomic
17
+ } from "./chunk-Y2MIXROU.js";
18
+
19
+ // packages/cli/src/commands/uninstall.ts
20
+ import { existsSync, readFileSync, rmSync, unlinkSync } from "node:fs";
21
+ import { join } from "node:path";
22
+ function runUninstall(cwd, flags, io, deps = {}) {
23
+ const ws = requireWorkspace(cwd);
24
+ const report = applyIntegration({
25
+ root: ws.root,
26
+ modules: [],
27
+ launcher: deps.launcher ?? resolveLauncher()
28
+ });
29
+ for (const path of report.removed) io.out(` removed ${path}
30
+ `);
31
+ for (const path of report.keptEdited) io.out(` left ${path} (edited by you)
32
+ `);
33
+ const gitignore = join(ws.root, ".gitignore");
34
+ if (existsSync(gitignore)) {
35
+ writeFileAtomic(
36
+ gitignore,
37
+ removeGitignoreEntry(readFileSync(gitignore, "utf8"), ".yandecode/")
38
+ );
39
+ }
40
+ unlinkSync(ws.paths.configFile);
41
+ if (flags.purge) {
42
+ rmSync(ws.paths.yandecodeDir, { recursive: true, force: true });
43
+ io.out(" purged .yandecode/\n");
44
+ } else if (existsSync(ws.paths.managedManifest)) {
45
+ unlinkSync(ws.paths.managedManifest);
46
+ io.out(" kept .yandecode/ (indexes, memories); pass --purge to delete it\n");
47
+ }
48
+ io.out("YandeCode removed from this project.\n");
49
+ return 0;
50
+ }
51
+ export {
52
+ runUninstall
53
+ };
54
+ //# sourceMappingURL=uninstall-J2OWCX4A.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/commands/uninstall.ts"],
4
+ "sourcesContent": ["import { existsSync, readFileSync, rmSync, unlinkSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { writeFileAtomic } from '@yandecode/core';\nimport { applyIntegration } from '@cli/integration/apply';\nimport { removeGitignoreEntry } from '@cli/integration/gitignore';\nimport type { Io } from '@cli/io';\nimport { resolveLauncher } from '@cli/launcher';\nimport { requireWorkspace } from '@cli/modules/host';\nimport type { SetupDeps } from './setup';\n\n/**\n * Removes everything yandecode added to the project (files it manages and did not see edited,\n * hooks, MCP entry, CLAUDE.md block, .gitignore entry, config). Indexes and memories stay in\n * .yandecode/ unless --purge.\n */\nexport function runUninstall(\n cwd: string,\n flags: { purge?: boolean },\n io: Io,\n deps: SetupDeps = {},\n): number {\n const ws = requireWorkspace(cwd);\n const report = applyIntegration({\n root: ws.root,\n modules: [],\n launcher: deps.launcher ?? resolveLauncher(),\n });\n for (const path of report.removed) io.out(` removed ${path}\\n`);\n for (const path of report.keptEdited) io.out(` left ${path} (edited by you)\\n`);\n\n const gitignore = join(ws.root, '.gitignore');\n if (existsSync(gitignore)) {\n writeFileAtomic(\n gitignore,\n removeGitignoreEntry(readFileSync(gitignore, 'utf8'), '.yandecode/'),\n );\n }\n unlinkSync(ws.paths.configFile);\n if (flags.purge) {\n rmSync(ws.paths.yandecodeDir, { recursive: true, force: true });\n io.out(' purged .yandecode/\\n');\n } else if (existsSync(ws.paths.managedManifest)) {\n unlinkSync(ws.paths.managedManifest);\n io.out(' kept .yandecode/ (indexes, memories); pass --purge to delete it\\n');\n }\n io.out('YandeCode removed from this project.\\n');\n return 0;\n}\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;;AAAA,SAAS,YAAY,cAAc,QAAQ,kBAAkB;AAC7D,SAAS,YAAY;AAcd,SAAS,aACd,KACA,OACA,IACA,OAAkB,CAAC,GACX;AACR,QAAM,KAAK,iBAAiB,GAAG;AAC/B,QAAM,SAAS,iBAAiB;AAAA,IAC9B,MAAM,GAAG;AAAA,IACT,SAAS,CAAC;AAAA,IACV,UAAU,KAAK,YAAY,gBAAgB;AAAA,EAC7C,CAAC;AACD,aAAW,QAAQ,OAAO,QAAS,IAAG,IAAI,aAAa,IAAI;AAAA,CAAI;AAC/D,aAAW,QAAQ,OAAO,WAAY,IAAG,IAAI,UAAU,IAAI;AAAA,CAAoB;AAE/E,QAAM,YAAY,KAAK,GAAG,MAAM,YAAY;AAC5C,MAAI,WAAW,SAAS,GAAG;AACzB;AAAA,MACE;AAAA,MACA,qBAAqB,aAAa,WAAW,MAAM,GAAG,aAAa;AAAA,IACrE;AAAA,EACF;AACA,aAAW,GAAG,MAAM,UAAU;AAC9B,MAAI,MAAM,OAAO;AACf,WAAO,GAAG,MAAM,cAAc,EAAE,WAAW,MAAM,OAAO,KAAK,CAAC;AAC9D,OAAG,IAAI,wBAAwB;AAAA,EACjC,WAAW,WAAW,GAAG,MAAM,eAAe,GAAG;AAC/C,eAAW,GAAG,MAAM,eAAe;AACnC,OAAG,IAAI,qEAAqE;AAAA,EAC9E;AACA,KAAG,IAAI,wCAAwC;AAC/C,SAAO;AACT;",
6
+ "names": []
7
+ }
@@ -0,0 +1,34 @@
1
+ import { createRequire as __yandecodeCreateRequire } from 'node:module';
2
+ const require = __yandecodeCreateRequire(import.meta.url);
3
+ import {
4
+ printApplyReport,
5
+ saveSelectionAndApply
6
+ } from "./chunk-VKVJGBNJ.js";
7
+ import "./chunk-KVBKQXTU.js";
8
+ import "./chunk-L2DDIZPI.js";
9
+ import "./chunk-DWD37AI2.js";
10
+ import "./chunk-PUWSEWX3.js";
11
+ import {
12
+ requireWorkspace
13
+ } from "./chunk-QCQC73WX.js";
14
+ import "./chunk-7L6DD2VD.js";
15
+ import "./chunk-Y2MIXROU.js";
16
+
17
+ // packages/cli/src/commands/update.ts
18
+ function runUpdate(cwd, flags, io, deps = {}) {
19
+ const ws = requireWorkspace(cwd);
20
+ const { config, added, report } = saveSelectionAndApply(
21
+ ws.root,
22
+ ws.config.modules,
23
+ deps,
24
+ flags.force ? { force: true } : {}
25
+ );
26
+ io.out(`yandecode.json is at version ${config.version}
27
+ `);
28
+ printApplyReport(io, config.modules, added, report);
29
+ return 0;
30
+ }
31
+ export {
32
+ runUpdate
33
+ };
34
+ //# sourceMappingURL=update-OX5MZYQY.js.map