@hasna/instructions 0.5.6 → 0.6.1

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 (230) hide show
  1. package/README.md +89 -21
  2. package/dist/chunks/apply-sfzja1f3.js +22 -0
  3. package/dist/chunks/apply-ynfn1av7.js +23 -0
  4. package/dist/chunks/index-1hpwskwd.js +12702 -0
  5. package/dist/chunks/index-35z65jsa.js +198 -0
  6. package/dist/chunks/index-85n5wnd8.js +625 -0
  7. package/dist/chunks/index-9p9gn7gh.js +627 -0
  8. package/dist/chunks/index-axhwg61p.js +523 -0
  9. package/dist/chunks/index-bsan4c16.js +48 -0
  10. package/dist/chunks/index-e9epbsvs.js +521 -0
  11. package/dist/chunks/index-ma2xmp6c.js +14 -0
  12. package/dist/chunks/index-nnwp92tk.js +19 -0
  13. package/dist/chunks/index-pkscjnj5.js +118 -0
  14. package/dist/chunks/index-v7dkb384.js +7248 -0
  15. package/dist/chunks/local-0d8qrc92.js +693 -0
  16. package/dist/chunks/local-a9nen65z.js +694 -0
  17. package/dist/chunks/package-manager-guard-x70xrwk2.js +391 -0
  18. package/dist/chunks/redact-hnq4sc4r.js +16 -0
  19. package/dist/chunks/sync-m46fc257.js +33 -0
  20. package/dist/chunks/sync-vy1yjvs6.js +34 -0
  21. package/dist/chunks/template-02wjvv05.js +16 -0
  22. package/dist/chunks/template-ke972qqe.js +16 -0
  23. package/dist/cli/index.js +775 -14212
  24. package/dist/data/config-store.d.ts +63 -34
  25. package/dist/data/config-store.d.ts.map +1 -1
  26. package/dist/db/database.d.ts +3 -5
  27. package/dist/db/database.d.ts.map +1 -1
  28. package/dist/db/local.d.ts +38 -0
  29. package/dist/db/local.d.ts.map +1 -0
  30. package/dist/generated/storage-kit/backend.d.ts +4 -4
  31. package/dist/generated/storage-kit/backend.d.ts.map +1 -1
  32. package/dist/generated/storage-kit/index.d.ts +1 -1
  33. package/dist/generated/storage-kit/index.d.ts.map +1 -1
  34. package/dist/generated/storage-kit/migrations.d.ts +21 -0
  35. package/dist/generated/storage-kit/migrations.d.ts.map +1 -1
  36. package/dist/generated/storage-kit/pool.d.ts +2 -5
  37. package/dist/generated/storage-kit/pool.d.ts.map +1 -1
  38. package/dist/index.d.ts +6 -3
  39. package/dist/index.d.ts.map +1 -1
  40. package/dist/index.js +13030 -10744
  41. package/dist/lib/app-home.d.ts +9 -0
  42. package/dist/lib/app-home.d.ts.map +1 -1
  43. package/dist/lib/client-types.d.ts +130 -0
  44. package/dist/lib/client-types.d.ts.map +1 -0
  45. package/dist/lib/ids.d.ts +4 -0
  46. package/dist/lib/ids.d.ts.map +1 -0
  47. package/dist/lib/instruction-graph.d.ts.map +1 -1
  48. package/dist/lib/local-opt-in.d.ts +82 -0
  49. package/dist/lib/local-opt-in.d.ts.map +1 -0
  50. package/dist/lib/project-context.d.ts +14 -14
  51. package/dist/lib/project-context.d.ts.map +1 -1
  52. package/dist/lib/project-dashboard-standard.d.ts +1 -1
  53. package/dist/lib/project-dashboard-standard.d.ts.map +1 -1
  54. package/dist/lib/session-render-state.d.ts +9 -0
  55. package/dist/lib/session-render-state.d.ts.map +1 -1
  56. package/dist/lib/session-render.d.ts +3 -0
  57. package/dist/lib/session-render.d.ts.map +1 -1
  58. package/dist/lib/transport-resolver.d.ts +80 -0
  59. package/dist/lib/transport-resolver.d.ts.map +1 -0
  60. package/dist/mcp/index.d.ts.map +1 -1
  61. package/dist/mcp/index.js +76 -8232
  62. package/dist/mcp/server.d.ts.map +1 -1
  63. package/dist/sdk/index.d.ts +22 -0
  64. package/dist/sdk/index.d.ts.map +1 -0
  65. package/dist/sdk/index.js +1042 -0
  66. package/dist/sdk/resolve.d.ts +82 -0
  67. package/dist/sdk/resolve.d.ts.map +1 -0
  68. package/dist/sdk/v1.generated.d.ts +288 -0
  69. package/dist/sdk/v1.generated.d.ts.map +1 -0
  70. package/dist/server/cloud.d.ts.map +1 -1
  71. package/dist/server/index.d.ts.map +1 -1
  72. package/dist/server/index.js +7327 -7242
  73. package/dist/status.d.ts +12 -2
  74. package/dist/status.d.ts.map +1 -1
  75. package/package.json +20 -16
  76. package/dashboard/README.md +0 -37
  77. package/dist/cli/add-duplicate-target.test.d.ts +0 -2
  78. package/dist/cli/add-duplicate-target.test.d.ts.map +0 -1
  79. package/dist/cli/add-reference-update.test.d.ts +0 -2
  80. package/dist/cli/add-reference-update.test.d.ts.map +0 -1
  81. package/dist/cli/apply-unchanged-snapshot-bloat.test.d.ts +0 -2
  82. package/dist/cli/apply-unchanged-snapshot-bloat.test.d.ts.map +0 -1
  83. package/dist/cli/doctor-reference-duplicates.test.d.ts +0 -2
  84. package/dist/cli/doctor-reference-duplicates.test.d.ts.map +0 -1
  85. package/dist/cli/output.test.d.ts +0 -2
  86. package/dist/cli/output.test.d.ts.map +0 -1
  87. package/dist/cli/profile-binding.test.d.ts +0 -2
  88. package/dist/cli/profile-binding.test.d.ts.map +0 -1
  89. package/dist/cli/profile-reads.test.d.ts +0 -2
  90. package/dist/cli/profile-reads.test.d.ts.map +0 -1
  91. package/dist/cli/profile-update.test.d.ts +0 -2
  92. package/dist/cli/profile-update.test.d.ts.map +0 -1
  93. package/dist/cli/project-context.test.d.ts +0 -2
  94. package/dist/cli/project-context.test.d.ts.map +0 -1
  95. package/dist/cli/raw-store-root.test.d.ts +0 -2
  96. package/dist/cli/raw-store-root.test.d.ts.map +0 -1
  97. package/dist/cli/session-apply-managed-input-bound.test.d.ts +0 -2
  98. package/dist/cli/session-apply-managed-input-bound.test.d.ts.map +0 -1
  99. package/dist/cli/session.test.d.ts +0 -2
  100. package/dist/cli/session.test.d.ts.map +0 -1
  101. package/dist/cli/station-profile.test.d.ts +0 -2
  102. package/dist/cli/station-profile.test.d.ts.map +0 -1
  103. package/dist/data/config-store.test.d.ts +0 -2
  104. package/dist/data/config-store.test.d.ts.map +0 -1
  105. package/dist/db/configs.test.d.ts +0 -2
  106. package/dist/db/configs.test.d.ts.map +0 -1
  107. package/dist/db/database.test.d.ts +0 -2
  108. package/dist/db/database.test.d.ts.map +0 -1
  109. package/dist/db/machines.test.d.ts +0 -2
  110. package/dist/db/machines.test.d.ts.map +0 -1
  111. package/dist/db/profile-assets.test.d.ts +0 -2
  112. package/dist/db/profile-assets.test.d.ts.map +0 -1
  113. package/dist/db/profile-config-bindings.test.d.ts +0 -2
  114. package/dist/db/profile-config-bindings.test.d.ts.map +0 -1
  115. package/dist/db/profiles.test.d.ts +0 -2
  116. package/dist/db/profiles.test.d.ts.map +0 -1
  117. package/dist/db/snapshots.test.d.ts +0 -2
  118. package/dist/db/snapshots.test.d.ts.map +0 -1
  119. package/dist/lib/app-home.test.d.ts +0 -2
  120. package/dist/lib/app-home.test.d.ts.map +0 -1
  121. package/dist/lib/apply-batch.test.d.ts +0 -2
  122. package/dist/lib/apply-batch.test.d.ts.map +0 -1
  123. package/dist/lib/apply-dry-run-verdict.test.d.ts +0 -2
  124. package/dist/lib/apply-dry-run-verdict.test.d.ts.map +0 -1
  125. package/dist/lib/apply-secret-placeholder-guard.test.d.ts +0 -2
  126. package/dist/lib/apply-secret-placeholder-guard.test.d.ts.map +0 -1
  127. package/dist/lib/apply-text-format-credential-guard.test.d.ts +0 -2
  128. package/dist/lib/apply-text-format-credential-guard.test.d.ts.map +0 -1
  129. package/dist/lib/apply.test.d.ts +0 -2
  130. package/dist/lib/apply.test.d.ts.map +0 -1
  131. package/dist/lib/asset-plan.test.d.ts +0 -2
  132. package/dist/lib/asset-plan.test.d.ts.map +0 -1
  133. package/dist/lib/codewith-shared-todos-storage-standard.test.d.ts +0 -2
  134. package/dist/lib/codewith-shared-todos-storage-standard.test.d.ts.map +0 -1
  135. package/dist/lib/compact-output.test.d.ts +0 -2
  136. package/dist/lib/compact-output.test.d.ts.map +0 -1
  137. package/dist/lib/config-target-identity.test.d.ts +0 -2
  138. package/dist/lib/config-target-identity.test.d.ts.map +0 -1
  139. package/dist/lib/cursor-authority.test.d.ts +0 -2
  140. package/dist/lib/cursor-authority.test.d.ts.map +0 -1
  141. package/dist/lib/dangerous-operation-guard-standard.test.d.ts +0 -2
  142. package/dist/lib/dangerous-operation-guard-standard.test.d.ts.map +0 -1
  143. package/dist/lib/diff-redaction.test.d.ts +0 -2
  144. package/dist/lib/diff-redaction.test.d.ts.map +0 -1
  145. package/dist/lib/export-import.test.d.ts +0 -2
  146. package/dist/lib/export-import.test.d.ts.map +0 -1
  147. package/dist/lib/global-agent-rules-render-integration.test.d.ts +0 -2
  148. package/dist/lib/global-agent-rules-render-integration.test.d.ts.map +0 -1
  149. package/dist/lib/global-agent-rules-standard.test.d.ts +0 -2
  150. package/dist/lib/global-agent-rules-standard.test.d.ts.map +0 -1
  151. package/dist/lib/global-agent-rules-stored-content.test.d.ts +0 -2
  152. package/dist/lib/global-agent-rules-stored-content.test.d.ts.map +0 -1
  153. package/dist/lib/global-source-coverage.test.d.ts +0 -2
  154. package/dist/lib/global-source-coverage.test.d.ts.map +0 -1
  155. package/dist/lib/instruction-graph-apply.test.d.ts +0 -2
  156. package/dist/lib/instruction-graph-apply.test.d.ts.map +0 -1
  157. package/dist/lib/instruction-graph.test.d.ts +0 -2
  158. package/dist/lib/instruction-graph.test.d.ts.map +0 -1
  159. package/dist/lib/machine.test.d.ts +0 -2
  160. package/dist/lib/machine.test.d.ts.map +0 -1
  161. package/dist/lib/managed-skill-runtimes.test.d.ts +0 -2
  162. package/dist/lib/managed-skill-runtimes.test.d.ts.map +0 -1
  163. package/dist/lib/package-manager-guard.test.d.ts +0 -2
  164. package/dist/lib/package-manager-guard.test.d.ts.map +0 -1
  165. package/dist/lib/project-context-prepared-file.test.d.ts +0 -2
  166. package/dist/lib/project-context-prepared-file.test.d.ts.map +0 -1
  167. package/dist/lib/project-context.test.d.ts +0 -2
  168. package/dist/lib/project-context.test.d.ts.map +0 -1
  169. package/dist/lib/project-dashboard-standard.test.d.ts +0 -2
  170. package/dist/lib/project-dashboard-standard.test.d.ts.map +0 -1
  171. package/dist/lib/provider-assets-adapters.test.d.ts +0 -2
  172. package/dist/lib/provider-assets-adapters.test.d.ts.map +0 -1
  173. package/dist/lib/provider-context.test.d.ts +0 -2
  174. package/dist/lib/provider-context.test.d.ts.map +0 -1
  175. package/dist/lib/provider-version-adapters.test.d.ts +0 -2
  176. package/dist/lib/provider-version-adapters.test.d.ts.map +0 -1
  177. package/dist/lib/redact.test.d.ts +0 -2
  178. package/dist/lib/redact.test.d.ts.map +0 -1
  179. package/dist/lib/retired-storage-mode.d.ts +0 -8
  180. package/dist/lib/retired-storage-mode.d.ts.map +0 -1
  181. package/dist/lib/session-apply.test.d.ts +0 -2
  182. package/dist/lib/session-apply.test.d.ts.map +0 -1
  183. package/dist/lib/session-authority.test.d.ts +0 -2
  184. package/dist/lib/session-authority.test.d.ts.map +0 -1
  185. package/dist/lib/session-render-managed-output-bound.test.d.ts +0 -2
  186. package/dist/lib/session-render-managed-output-bound.test.d.ts.map +0 -1
  187. package/dist/lib/session-render-ownership.test.d.ts +0 -2
  188. package/dist/lib/session-render-ownership.test.d.ts.map +0 -1
  189. package/dist/lib/session-render-rule-currency-floor.test.d.ts +0 -2
  190. package/dist/lib/session-render-rule-currency-floor.test.d.ts.map +0 -1
  191. package/dist/lib/session-render-silent-source-drop.test.d.ts +0 -2
  192. package/dist/lib/session-render-silent-source-drop.test.d.ts.map +0 -1
  193. package/dist/lib/session-render-state.test.d.ts +0 -2
  194. package/dist/lib/session-render-state.test.d.ts.map +0 -1
  195. package/dist/lib/session-render.test.d.ts +0 -2
  196. package/dist/lib/session-render.test.d.ts.map +0 -1
  197. package/dist/lib/station-profile.test.d.ts +0 -2
  198. package/dist/lib/station-profile.test.d.ts.map +0 -1
  199. package/dist/lib/sync-dir.test.d.ts +0 -2
  200. package/dist/lib/sync-dir.test.d.ts.map +0 -1
  201. package/dist/lib/sync-dry-run-unchanged.test.d.ts +0 -2
  202. package/dist/lib/sync-dry-run-unchanged.test.d.ts.map +0 -1
  203. package/dist/lib/sync-known.test.d.ts +0 -2
  204. package/dist/lib/sync-known.test.d.ts.map +0 -1
  205. package/dist/lib/sync.test.d.ts +0 -2
  206. package/dist/lib/sync.test.d.ts.map +0 -1
  207. package/dist/lib/template.test.d.ts +0 -2
  208. package/dist/lib/template.test.d.ts.map +0 -1
  209. package/dist/lib/transforms.test.d.ts +0 -2
  210. package/dist/lib/transforms.test.d.ts.map +0 -1
  211. package/dist/mcp/create-config-target-guard.test.d.ts +0 -2
  212. package/dist/mcp/create-config-target-guard.test.d.ts.map +0 -1
  213. package/dist/mcp/early-args.test.d.ts +0 -2
  214. package/dist/mcp/early-args.test.d.ts.map +0 -1
  215. package/dist/mcp/http.test.d.ts +0 -2
  216. package/dist/mcp/http.test.d.ts.map +0 -1
  217. package/dist/mcp/mcp.test.d.ts +0 -2
  218. package/dist/mcp/mcp.test.d.ts.map +0 -1
  219. package/dist/server/cloud-auth.test.d.ts +0 -2
  220. package/dist/server/cloud-auth.test.d.ts.map +0 -1
  221. package/dist/server/cloud.test.d.ts +0 -2
  222. package/dist/server/cloud.test.d.ts.map +0 -1
  223. package/dist/server/early-args.test.d.ts +0 -2
  224. package/dist/server/early-args.test.d.ts.map +0 -1
  225. package/dist/server/profile-contract.test.d.ts +0 -2
  226. package/dist/server/profile-contract.test.d.ts.map +0 -1
  227. package/dist/status.test.d.ts +0 -2
  228. package/dist/status.test.d.ts.map +0 -1
  229. package/dist/storage/cloud-store.test.d.ts +0 -2
  230. package/dist/storage/cloud-store.test.d.ts.map +0 -1
@@ -0,0 +1,627 @@
1
+ // @bun
2
+ import {
3
+ applyConfigsWithReport,
4
+ expandPath,
5
+ getConfigHome,
6
+ normalizeTargetPath
7
+ } from "./index-axhwg61p.js";
8
+ import {
9
+ applyTransform,
10
+ detectMachineContext,
11
+ isRetiredOrUnsupportedConfigAgent,
12
+ resolveConfigStore,
13
+ retiredOrUnsupportedAgentReason,
14
+ templateizeMachineContent
15
+ } from "./index-v7dkb384.js";
16
+ import {
17
+ isSecretVarName,
18
+ redactContent,
19
+ redactFormatForTarget
20
+ } from "./index-35z65jsa.js";
21
+
22
+ // src/lib/sync.ts
23
+ import { existsSync as existsSync2, readdirSync as readdirSync2, readFileSync as readFileSync2 } from "fs";
24
+ import { basename, extname, join as join2 } from "path";
25
+
26
+ // src/lib/sync-dir.ts
27
+ import { existsSync, readdirSync, readFileSync, statSync } from "fs";
28
+ import { join, relative } from "path";
29
+ import { homedir } from "os";
30
+ var SKIP = [".db", ".db-shm", ".db-wal", ".log", ".lock", ".DS_Store", "node_modules", ".git"];
31
+ function shouldSkip(p) {
32
+ return SKIP.some((s) => p.includes(s));
33
+ }
34
+ async function syncFromDir(dir, opts = {}) {
35
+ const store = opts.store ?? resolveConfigStore();
36
+ const absDir = expandPath(dir);
37
+ if (!existsSync(absDir))
38
+ return { added: 0, updated: 0, unchanged: 0, skipped: [`Not found: ${absDir}`] };
39
+ const files = opts.recursive !== false ? walkDir(absDir) : readdirSync(absDir).map((f) => join(absDir, f)).filter((f) => statSync(f).isFile());
40
+ const result = { added: 0, updated: 0, unchanged: 0, skipped: [] };
41
+ const home = homedir();
42
+ const allConfigs = await store.listConfigs();
43
+ for (const file of files) {
44
+ if (shouldSkip(file)) {
45
+ result.skipped.push(file);
46
+ continue;
47
+ }
48
+ try {
49
+ const content = readFileSync(file, "utf-8");
50
+ if (content.length > 500000) {
51
+ result.skipped.push(file + " (too large)");
52
+ continue;
53
+ }
54
+ const targetPath = file.replace(home, "~");
55
+ const redacted = redactContent(content, redactFormatForTarget(targetPath, detectFormat(file)));
56
+ const existing = allConfigs.find((c) => c.target_path === targetPath);
57
+ if (!existing) {
58
+ if (!opts.dryRun)
59
+ await store.createConfig({ name: relative(absDir, file), category: detectCategory(file), agent: detectAgent(file), target_path: targetPath, format: detectFormat(file), content: redacted.content });
60
+ result.added++;
61
+ } else if (existing.content !== redacted.content) {
62
+ if (!opts.dryRun)
63
+ await store.updateConfig(existing.id, { content: redacted.content });
64
+ result.updated++;
65
+ } else {
66
+ result.unchanged++;
67
+ }
68
+ } catch {
69
+ result.skipped.push(file);
70
+ }
71
+ }
72
+ return result;
73
+ }
74
+ async function syncToDir(dir, opts = {}) {
75
+ const store = opts.store ?? resolveConfigStore();
76
+ const home = homedir();
77
+ const absDir = expandPath(dir);
78
+ const normalized = dir.startsWith("~/") ? dir : absDir.replace(home, "~");
79
+ const configs = (await store.listConfigs()).filter((c) => c.target_path && (c.target_path.startsWith(normalized) || c.target_path.startsWith(absDir)));
80
+ const result = { added: 0, updated: 0, unchanged: 0, skipped: [] };
81
+ for (const config of configs) {
82
+ if (config.kind === "reference")
83
+ continue;
84
+ try {
85
+ const report = await applyConfigsWithReport([config], { dryRun: opts.dryRun, store });
86
+ result.skipped.push(...report.skipped.map((entry) => `${entry.path} (${entry.owner})`));
87
+ if (report.failures.length > 0)
88
+ throw new Error(report.failures[0].message);
89
+ for (const applied of report.results) {
90
+ applied.changed ? result.updated++ : result.unchanged++;
91
+ }
92
+ } catch {
93
+ result.skipped.push(config.target_path || config.id);
94
+ }
95
+ }
96
+ return result;
97
+ }
98
+ function walkDir(dir, files = []) {
99
+ for (const entry of readdirSync(dir, { withFileTypes: true })) {
100
+ const full = join(dir, entry.name);
101
+ if (shouldSkip(full))
102
+ continue;
103
+ if (entry.isDirectory())
104
+ walkDir(full, files);
105
+ else if (entry.isFile())
106
+ files.push(full);
107
+ }
108
+ return files;
109
+ }
110
+
111
+ // src/lib/sync.ts
112
+ var CLAUDE_PROMPT_OUTPUTS = [
113
+ { agent: "codex", target_path: "~/.codex/AGENTS.md", transform: "codex-flat" },
114
+ { agent: "codewith", target_path: "~/.codewith/CODEWITH.md", transform: "codex-flat" },
115
+ { agent: "opencode", target_path: "~/.config/opencode/AGENTS.md", transform: "opencode-flat" },
116
+ { agent: "aicopilot", target_path: "~/.config/aicopilot/AICOPILOT.md", transform: "codex-flat" },
117
+ { agent: "antigravity", target_path: "~/.gemini/GEMINI.md", transform: "codex-flat" },
118
+ { agent: "cursor", target_path: "~/.cursor/rules/claude.mdc", transform: "cursor-mdc" },
119
+ { agent: "qwen", target_path: "~/.qwen/QWEN.md", transform: "codex-flat" }
120
+ ];
121
+ function claudeRuleOutputs(fileName) {
122
+ const stem = basename(fileName, extname(fileName));
123
+ return [
124
+ { agent: "cursor", target_path: `~/.cursor/rules/${stem}.mdc`, transform: "cursor-mdc" }
125
+ ];
126
+ }
127
+ function normalizeOutputs(outputs) {
128
+ return outputs ?? [];
129
+ }
130
+ function outputsEqual(a, b) {
131
+ return JSON.stringify(normalizeOutputs(a)) === JSON.stringify(normalizeOutputs(b));
132
+ }
133
+ var UNGUARDED_LOCAL_ENV_HELPER = '. "$HOME/.local/bin/env"';
134
+ var GUARDED_LOCAL_ENV_HELPER = '[ -r "$HOME/.local/bin/env" ] && . "$HOME/.local/bin/env"';
135
+ function normalizeKnownConfigSource(known, content) {
136
+ if (known.name !== "bash-profile")
137
+ return content;
138
+ return content.split(`
139
+ `).map((line) => line === UNGUARDED_LOCAL_ENV_HELPER ? GUARDED_LOCAL_ENV_HELPER : line).join(`
140
+ `);
141
+ }
142
+ function outputOwnerIdsByTarget(configs) {
143
+ const owners = new Map;
144
+ for (const config of configs) {
145
+ for (const output of config.outputs) {
146
+ const targetPath = normalizeTargetPath(output.target_path);
147
+ const existing = owners.get(targetPath) ?? new Set;
148
+ existing.add(config.id);
149
+ owners.set(targetPath, existing);
150
+ }
151
+ }
152
+ return owners;
153
+ }
154
+ function isGeneratedOutputTarget(config, owners) {
155
+ if (!config.target_path)
156
+ return false;
157
+ const ownerIds = owners.get(normalizeTargetPath(config.target_path));
158
+ return !!ownerIds && !ownerIds.has(config.id);
159
+ }
160
+ function hasClaudePromptSource() {
161
+ return existsSync2(expandPath("~/.claude/CLAUDE.md"));
162
+ }
163
+ function hasClaudeRuleSourceForCursorTarget(targetPath) {
164
+ const absoluteTargetPath = expandPath(targetPath);
165
+ const absolutePrefix = expandPath("~/.cursor/rules");
166
+ if (!absoluteTargetPath.startsWith(`${absolutePrefix}/`) || !absoluteTargetPath.endsWith(".mdc"))
167
+ return false;
168
+ const stem = basename(absoluteTargetPath, ".mdc");
169
+ return existsSync2(expandPath(`~/.claude/rules/${stem}.md`)) || existsSync2(expandPath(`~/.claude/rules/${stem}.mdc`));
170
+ }
171
+ function isKnownGeneratedTargetPath(targetPath) {
172
+ const normalizedTargetPath = normalizeTargetPath(targetPath);
173
+ const promptTargets = new Set(CLAUDE_PROMPT_OUTPUTS.map((output) => normalizeTargetPath(output.target_path)));
174
+ if (promptTargets.has(normalizedTargetPath))
175
+ return hasClaudePromptSource();
176
+ return hasClaudeRuleSourceForCursorTarget(targetPath);
177
+ }
178
+ var KNOWN_CONFIGS = [
179
+ { path: "~/.claude/CLAUDE.md", name: "claude-claude-md", category: "rules", agent: "claude", format: "markdown", outputs: CLAUDE_PROMPT_OUTPUTS },
180
+ { path: "~/.claude/settings.json", name: "claude-settings", category: "agent", agent: "claude", format: "json" },
181
+ { path: "~/.claude/settings.local.json", name: "claude-settings-local", category: "agent", agent: "claude", format: "json" },
182
+ { path: "~/.claude/keybindings.json", name: "claude-keybindings", category: "agent", agent: "claude", format: "json", optional: true },
183
+ { path: "~/.claude/rules", name: "claude-rules", category: "rules", agent: "claude", rulesDir: "~/.claude/rules", rulesExtensions: [".md", ".mdc"] },
184
+ { path: "~/.codex/config.toml", name: "codex-config", category: "agent", agent: "codex", format: "toml" },
185
+ { path: "~/.codex/AGENTS.md", name: "codex-agents-md", category: "rules", agent: "codex", format: "markdown" },
186
+ { path: "~/.config/opencode/AGENTS.md", name: "opencode-agents-md", category: "rules", agent: "opencode", format: "markdown", optional: true },
187
+ { path: "~/.config/opencode/opencode.json", name: "opencode-config", category: "mcp", agent: "opencode", format: "json", optional: true, description: "OpenCode config (includes Skills MCP server entries)" },
188
+ { path: "~/.cursor/rules", name: "cursor-rules", category: "rules", agent: "cursor", rulesDir: "~/.cursor/rules", rulesExtensions: [".md", ".mdc"] },
189
+ { path: "~/.cursor/mcp.json", name: "cursor-mcp", category: "mcp", agent: "cursor", format: "json", optional: true, description: "Cursor MCP config (includes Skills MCP server entries)" },
190
+ { path: "~/.codewith/CODEWITH.md", name: "codewith-codewith-md", category: "rules", agent: "codewith", format: "markdown", optional: true },
191
+ { path: "~/.codewith/config.toml", name: "codewith-config", category: "mcp", agent: "codewith", format: "toml", optional: true, description: "codewith config (Codex fork, includes Skills MCP server entries)" },
192
+ { path: "~/.config/aicopilot/AICOPILOT.md", name: "aicopilot-aicopilot-md", category: "rules", agent: "aicopilot", format: "markdown", optional: true },
193
+ { path: "~/.config/aicopilot/aicopilot.json", name: "aicopilot-config", category: "mcp", agent: "aicopilot", format: "json", optional: true, description: "AI Copilot config (includes instructions and MCP server entries)" },
194
+ { path: "~/.gemini/GEMINI.md", name: "antigravity-global-rules", category: "rules", agent: "antigravity", format: "markdown", optional: true, description: "Google Antigravity global rules file" },
195
+ { path: "~/.gemini/config/mcp_config.json", name: "antigravity-global-mcp", category: "mcp", agent: "antigravity", format: "json", optional: true, description: "Google Antigravity global MCP server entries" },
196
+ { path: "~/.qwen/QWEN.md", name: "qwen-qwen-md", category: "rules", agent: "qwen", format: "markdown", optional: true, description: "Qwen Code global instructional context" },
197
+ { path: "~/.qwen/settings.json", name: "qwen-settings", category: "agent", agent: "qwen", format: "json", optional: true, description: "Qwen Code settings.json, including native hooks" },
198
+ { path: "~/.claude.json", name: "claude-json", category: "mcp", agent: "claude", format: "json", description: "Claude Code global config (includes MCP server entries)" },
199
+ { path: "~/.zshrc", name: "zshrc", category: "shell", agent: "zsh" },
200
+ { path: "~/.zprofile", name: "zprofile", category: "shell", agent: "zsh", optional: true },
201
+ { path: "~/.bashrc", name: "bashrc", category: "shell", agent: "zsh", optional: true },
202
+ { path: "~/.bash_profile", name: "bash-profile", category: "shell", agent: "zsh", optional: true },
203
+ { path: "~/.gitconfig", name: "gitconfig", category: "git", agent: "git", format: "ini" },
204
+ { path: "~/.gitignore_global", name: "gitignore-global", category: "git", agent: "git", optional: true },
205
+ { path: "~/.npmrc", name: "npmrc", category: "tools", agent: "npm", format: "ini" },
206
+ { path: "~/.bunfig.toml", name: "bunfig", category: "tools", agent: "global", format: "toml", optional: true }
207
+ ];
208
+ var PROJECT_CONFIG_FILES = [
209
+ { file: "CLAUDE.md", category: "rules", agent: "claude", format: "markdown" },
210
+ { file: ".claude/settings.json", category: "agent", agent: "claude", format: "json" },
211
+ { file: ".claude/settings.local.json", category: "agent", agent: "claude", format: "json" },
212
+ { file: ".mcp.json", category: "mcp", agent: "claude", format: "json" },
213
+ { file: "AGENTS.md", category: "rules", agent: "codex", format: "markdown" },
214
+ { file: ".codex/AGENTS.md", category: "rules", agent: "codex", format: "markdown" },
215
+ { file: ".opencode/AGENTS.md", category: "rules", agent: "opencode", format: "markdown" },
216
+ { file: "CODEWITH.md", category: "rules", agent: "codewith", format: "markdown" },
217
+ { file: ".codewith/CODEWITH.md", category: "rules", agent: "codewith", format: "markdown" },
218
+ { file: ".aicopilot/AICOPILOT.md", category: "rules", agent: "aicopilot", format: "markdown" },
219
+ { file: "AICOPILOT.md", category: "rules", agent: "aicopilot", format: "markdown" },
220
+ { file: ".cursor/mcp.json", category: "mcp", agent: "cursor", format: "json" },
221
+ { file: ".github/copilot-instructions.md", category: "rules", agent: "copilot", format: "markdown" },
222
+ { file: "QWEN.md", category: "rules", agent: "qwen", format: "markdown" },
223
+ { file: ".agents/mcp_config.json", category: "mcp", agent: "antigravity", format: "json" },
224
+ { file: ".qwen/settings.json", category: "agent", agent: "qwen", format: "json" }
225
+ ];
226
+ async function syncProject(opts) {
227
+ const store = opts.store ?? resolveConfigStore();
228
+ const absDir = expandPath(opts.projectDir);
229
+ const projectName = absDir.split("/").pop() || "project";
230
+ const result = { added: 0, updated: 0, unchanged: 0, skipped: [] };
231
+ const allConfigs = await store.listConfigs();
232
+ const machine = detectMachineContext();
233
+ for (const pf of PROJECT_CONFIG_FILES) {
234
+ const abs = join2(absDir, pf.file);
235
+ if (!existsSync2(abs))
236
+ continue;
237
+ try {
238
+ const rawContent = readFileSync2(abs, "utf-8");
239
+ if (rawContent.length > 500000) {
240
+ result.skipped.push(pf.file);
241
+ continue;
242
+ }
243
+ const redacted = redactContent(rawContent, pf.format);
244
+ const machineAware = templateizeMachineContent(redacted.content, machine);
245
+ const content = machineAware.content;
246
+ const isTemplate = redacted.isTemplate || machineAware.changed;
247
+ const name = `${projectName}/${pf.file}`;
248
+ const targetPath = abs.startsWith(getConfigHome()) ? abs.replace(getConfigHome(), "~") : abs;
249
+ const slug = name.toLowerCase().replace(/[^a-z0-9]+/g, "-");
250
+ const existing = allConfigs.find((c) => c.target_path === targetPath || c.slug === slug);
251
+ if (!existing) {
252
+ if (!opts.dryRun)
253
+ await store.createConfig({ name, category: pf.category, agent: pf.agent, format: pf.format, content, target_path: targetPath, is_template: isTemplate });
254
+ result.added++;
255
+ } else if (existing.content !== content) {
256
+ if (!opts.dryRun)
257
+ await store.updateConfig(existing.id, { content, is_template: isTemplate });
258
+ result.updated++;
259
+ } else {
260
+ result.unchanged++;
261
+ }
262
+ } catch {
263
+ result.skipped.push(pf.file);
264
+ }
265
+ }
266
+ for (const ruleDir of [
267
+ { dir: join2(absDir, ".claude", "rules"), agent: "claude", namePrefix: "rules" },
268
+ { dir: join2(absDir, ".agents", "rules"), agent: "antigravity", namePrefix: "antigravity-rules" },
269
+ { dir: join2(absDir, ".cursor", "rules"), agent: "cursor", namePrefix: "cursor-rules" },
270
+ { dir: join2(absDir, ".github", "instructions"), agent: "copilot", namePrefix: "copilot-instructions" },
271
+ { dir: join2(absDir, ".devin", "rules"), agent: "devin", namePrefix: "devin-rules" },
272
+ { dir: join2(absDir, ".windsurf", "rules"), agent: "windsurf-legacy", namePrefix: "windsurf-rules" },
273
+ { dir: join2(absDir, ".clinerules"), agent: "cline", namePrefix: "cline-rules" }
274
+ ]) {
275
+ if (!existsSync2(ruleDir.dir))
276
+ continue;
277
+ const mdFiles = readdirSync2(ruleDir.dir).filter((f) => f.endsWith(".md") || f.endsWith(".mdc"));
278
+ for (const f of mdFiles) {
279
+ const abs = join2(ruleDir.dir, f);
280
+ const raw = readFileSync2(abs, "utf-8");
281
+ const redacted = redactContent(raw, "markdown");
282
+ const machineAware = templateizeMachineContent(redacted.content, machine);
283
+ const content = machineAware.content;
284
+ const isTemplate = redacted.isTemplate || machineAware.changed;
285
+ const name = `${projectName}/${ruleDir.namePrefix}/${f}`;
286
+ const targetPath = abs.startsWith(getConfigHome()) ? abs.replace(getConfigHome(), "~") : abs;
287
+ const slug = name.toLowerCase().replace(/[^a-z0-9]+/g, "-");
288
+ const existing = allConfigs.find((c) => c.target_path === targetPath || c.slug === slug);
289
+ if (!existing) {
290
+ if (!opts.dryRun)
291
+ await store.createConfig({ name, category: "rules", agent: ruleDir.agent, format: "markdown", content, target_path: targetPath, is_template: isTemplate });
292
+ result.added++;
293
+ } else if (existing.content !== content) {
294
+ if (!opts.dryRun)
295
+ await store.updateConfig(existing.id, { content, is_template: isTemplate });
296
+ result.updated++;
297
+ } else {
298
+ result.unchanged++;
299
+ }
300
+ }
301
+ }
302
+ return result;
303
+ }
304
+ async function syncKnown(opts = {}) {
305
+ const store = opts.store ?? resolveConfigStore();
306
+ const result = { added: 0, updated: 0, unchanged: 0, skipped: [] };
307
+ const home = getConfigHome();
308
+ const machine = detectMachineContext();
309
+ let targets = KNOWN_CONFIGS;
310
+ if (opts.agent)
311
+ targets = targets.filter((k) => k.agent === opts.agent);
312
+ if (opts.category)
313
+ targets = targets.filter((k) => k.category === opts.category);
314
+ const allConfigs = await store.listConfigs();
315
+ const existingOutputOwners = outputOwnerIdsByTarget(allConfigs);
316
+ for (const known of targets) {
317
+ if (known.rulesDir) {
318
+ const absDir = expandPath(known.rulesDir);
319
+ if (!existsSync2(absDir)) {
320
+ result.skipped.push(known.rulesDir);
321
+ continue;
322
+ }
323
+ const extensions = known.rulesExtensions ?? [".md", ".mdc"];
324
+ const ruleFiles = readdirSync2(absDir).filter((f) => extensions.some((ext) => f.endsWith(ext)));
325
+ for (const f of ruleFiles) {
326
+ const abs2 = join2(absDir, f);
327
+ const targetPath = abs2.replace(home, "~");
328
+ if (existingOutputOwners.has(normalizeTargetPath(targetPath)) || isKnownGeneratedTargetPath(targetPath)) {
329
+ result.skipped.push(`${targetPath} (generated output)`);
330
+ continue;
331
+ }
332
+ const raw = readFileSync2(abs2, "utf-8");
333
+ const redacted = redactContent(raw, "markdown");
334
+ const machineAware = templateizeMachineContent(redacted.content, machine);
335
+ const content = machineAware.content;
336
+ const isTemplate = redacted.isTemplate || machineAware.changed;
337
+ const name = `${known.name}-${f}`;
338
+ const slug = name.toLowerCase().replace(/[^a-z0-9]+/g, "-");
339
+ const existing = allConfigs.find((c) => c.target_path === targetPath || c.slug === slug);
340
+ const outputs = known.agent === "claude" ? claudeRuleOutputs(f) : known.outputs;
341
+ if (!existing) {
342
+ if (!opts.dryRun)
343
+ await store.createConfig({ name, category: known.category, agent: known.agent, format: "markdown", content, target_path: targetPath, is_template: isTemplate, outputs });
344
+ result.added++;
345
+ } else if (existing.content !== content) {
346
+ if (!opts.dryRun)
347
+ await store.updateConfig(existing.id, { content, is_template: isTemplate, outputs });
348
+ result.updated++;
349
+ } else if (!outputsEqual(existing.outputs, outputs)) {
350
+ if (!opts.dryRun)
351
+ await store.updateConfig(existing.id, { outputs });
352
+ result.updated++;
353
+ } else {
354
+ result.unchanged++;
355
+ }
356
+ }
357
+ continue;
358
+ }
359
+ const abs = expandPath(known.path);
360
+ if (!existsSync2(abs)) {
361
+ result.skipped.push(known.path);
362
+ continue;
363
+ }
364
+ try {
365
+ const rawContent = normalizeKnownConfigSource(known, readFileSync2(abs, "utf-8"));
366
+ if (rawContent.length > 500000) {
367
+ result.skipped.push(known.path + " (too large)");
368
+ continue;
369
+ }
370
+ const fmt = known.format ?? detectFormat(abs);
371
+ const redacted = redactContent(rawContent, redactFormatForTarget(abs, fmt));
372
+ const machineAware = templateizeMachineContent(redacted.content, machine);
373
+ const content = machineAware.content;
374
+ const isTemplate = redacted.isTemplate || machineAware.changed;
375
+ const targetPath = abs.replace(home, "~");
376
+ if (existingOutputOwners.has(normalizeTargetPath(targetPath)) || isKnownGeneratedTargetPath(targetPath)) {
377
+ result.skipped.push(`${targetPath} (generated output)`);
378
+ continue;
379
+ }
380
+ const existing = allConfigs.find((c) => c.target_path === targetPath || c.slug === known.name);
381
+ if (!existing) {
382
+ if (!opts.dryRun) {
383
+ await store.createConfig({
384
+ name: known.name,
385
+ category: known.category,
386
+ agent: known.agent,
387
+ format: fmt,
388
+ content,
389
+ target_path: known.kind === "reference" ? null : targetPath,
390
+ kind: known.kind ?? "file",
391
+ description: known.description,
392
+ is_template: isTemplate,
393
+ outputs: known.outputs
394
+ });
395
+ }
396
+ result.added++;
397
+ } else if (existing.content !== content) {
398
+ if (!opts.dryRun)
399
+ await store.updateConfig(existing.id, { content, is_template: isTemplate, outputs: known.outputs });
400
+ result.updated++;
401
+ } else if (!outputsEqual(existing.outputs, known.outputs)) {
402
+ if (!opts.dryRun)
403
+ await store.updateConfig(existing.id, { outputs: known.outputs });
404
+ result.updated++;
405
+ } else {
406
+ result.unchanged++;
407
+ }
408
+ } catch {
409
+ result.skipped.push(known.path);
410
+ }
411
+ }
412
+ return result;
413
+ }
414
+ async function syncToDisk(opts = {}) {
415
+ const store = opts.store ?? resolveConfigStore();
416
+ const result = { added: 0, updated: 0, unchanged: 0, skipped: [] };
417
+ const allFileConfigs = await store.listConfigs({ kind: "file", ...opts.category ? { category: opts.category } : {} });
418
+ const outputOwners = outputOwnerIdsByTarget(allFileConfigs);
419
+ let configs = allFileConfigs.filter((config) => {
420
+ return !isGeneratedOutputTarget(config, outputOwners);
421
+ }).filter((config) => {
422
+ if (!opts.agent)
423
+ return true;
424
+ return config.agent === opts.agent || config.outputs.some((output) => output.agent === opts.agent);
425
+ });
426
+ for (const config of configs) {
427
+ if (!config.target_path && config.outputs.length === 0)
428
+ continue;
429
+ if (isRetiredOrUnsupportedConfigAgent(config.agent)) {
430
+ result.skipped.push(`${config.slug} (${retiredOrUnsupportedAgentReason(config.agent)})`);
431
+ continue;
432
+ }
433
+ try {
434
+ const report = await applyConfigsWithReport([config], {
435
+ dryRun: opts.dryRun,
436
+ store,
437
+ outputAgent: opts.agent
438
+ });
439
+ result.skipped.push(...report.skipped.map((entry) => `${entry.path} (${entry.owner})`));
440
+ if (report.failures.length > 0)
441
+ throw new Error(report.failures[0].message);
442
+ for (const applied of report.results) {
443
+ applied.changed ? result.updated++ : result.unchanged++;
444
+ }
445
+ } catch {
446
+ result.skipped.push(config.target_path ?? config.id);
447
+ }
448
+ }
449
+ return result;
450
+ }
451
+ var CERTAIN_PLACEHOLDER_RE = /\{\{[A-Za-z_][A-Za-z0-9_]*\}\}/g;
452
+ var ASSIGNED_PLACEHOLDER_RE = /[=:]\s*(["']?)(\$\{([A-Za-z_][A-Za-z0-9_]*)\}|\$([A-Z][A-Z0-9_]*)|%([A-Za-z_][A-Za-z0-9_]*)%)\1\s*,?\s*$/;
453
+ function redactionPlaceholders(storedLine) {
454
+ const found = [...storedLine.match(CERTAIN_PLACEHOLDER_RE) ?? []];
455
+ const assigned = storedLine.match(ASSIGNED_PLACEHOLDER_RE);
456
+ if (assigned) {
457
+ const name = assigned[3] ?? assigned[4] ?? assigned[5];
458
+ if (name && isSecretVarName(name))
459
+ found.push(assigned[2]);
460
+ }
461
+ return found;
462
+ }
463
+ function storedPlaceholderIsLiteralOnDisk(storedLine, diskLine) {
464
+ return redactionPlaceholders(storedLine).some((p) => !diskLine.includes(p));
465
+ }
466
+ function buildDiff(expectedContent, targetPath, storedFormat, showSecrets) {
467
+ const path = expandPath(targetPath);
468
+ if (!existsSync2(path))
469
+ return `(file not found on disk: ${path})`;
470
+ const diskContent = readFileSync2(path, "utf-8");
471
+ if (diskContent === expectedContent)
472
+ return "(no diff \u2014 identical)";
473
+ const format = redactFormatForTarget(targetPath, storedFormat);
474
+ const stored = expectedContent.split(`
475
+ `);
476
+ const disk = diskContent.split(`
477
+ `);
478
+ const { content: redactedDiskContent, redacted } = showSecrets ? { content: diskContent, redacted: [] } : redactContent(diskContent, format);
479
+ const redactedDisk = redactedDiskContent.split(`
480
+ `);
481
+ const reasonByLine = new Map;
482
+ for (const r of redacted)
483
+ if (!reasonByLine.has(r.line))
484
+ reasonByLine.set(r.line, r.reason);
485
+ const lines = [`--- stored (DB)`, `+++ disk (${path})`];
486
+ const maxLen = Math.max(stored.length, disk.length);
487
+ for (let i = 0;i < maxLen; i++) {
488
+ const lineNo = i + 1;
489
+ const s = stored[i];
490
+ const dk = disk[i];
491
+ if (s === dk) {
492
+ if (s !== undefined)
493
+ lines.push(` ${s}`);
494
+ continue;
495
+ }
496
+ if (showSecrets || dk === undefined) {
497
+ if (s !== undefined)
498
+ lines.push(`-${s}`);
499
+ if (dk !== undefined)
500
+ lines.push(`+${dk}`);
501
+ continue;
502
+ }
503
+ const structural = s !== undefined && storedPlaceholderIsLiteralOnDisk(s, dk);
504
+ const patterned = reasonByLine.has(lineNo);
505
+ if (!structural && !patterned) {
506
+ if (s !== undefined)
507
+ lines.push(`-${s}`);
508
+ lines.push(`+${dk}`);
509
+ continue;
510
+ }
511
+ if (structural) {
512
+ const placeholder = redactionPlaceholders(s).find((p) => !dk.includes(p)) ?? "a placeholder";
513
+ lines.push(`~line ${lineNo} differs: stored \`${s}\`, disk holds a literal value for ${placeholder} \u2014 redacted (use --show-secrets on a TTY to reveal)`);
514
+ continue;
515
+ }
516
+ const safe = redactedDisk[i] ?? "";
517
+ const reason = reasonByLine.get(lineNo);
518
+ if (s !== undefined && safe === s) {
519
+ lines.push(`~line ${lineNo} differs: stored \`${s}\`, disk holds a literal value (${reason}) \u2014 redacted (use --show-secrets on a TTY to reveal)`);
520
+ } else {
521
+ if (s !== undefined)
522
+ lines.push(`-${s}`);
523
+ lines.push(`+${safe}`);
524
+ lines.push(`~line ${lineNo}: disk value redacted (${reason}) \u2014 use --show-secrets on a TTY to reveal`);
525
+ }
526
+ }
527
+ return lines.join(`
528
+ `);
529
+ }
530
+ async function diffConfig(config, opts = {}) {
531
+ if (!config.target_path && config.outputs.length === 0)
532
+ return "(reference \u2014 no target path)";
533
+ const diffs = [];
534
+ const store = opts.store ?? resolveConfigStore();
535
+ const contextConfigs = config.outputs.length > 0 || config.target_path ? await store.listConfigs() : [config];
536
+ if (isGeneratedOutputTarget(config, outputOwnerIdsByTarget(contextConfigs))) {
537
+ return "(generated output \u2014 managed by fan-out)";
538
+ }
539
+ const showSecrets = opts.showSecrets ?? false;
540
+ if (config.target_path) {
541
+ const diff = buildDiff(config.content, config.target_path, config.format, showSecrets);
542
+ if (!diff.includes("no diff"))
543
+ diffs.push(diff);
544
+ }
545
+ if (config.outputs.length > 0) {
546
+ for (const output of config.outputs) {
547
+ const expected = applyTransform(config, output, { configs: contextConfigs });
548
+ const diff = buildDiff(expected, output.target_path, detectFormat(output.target_path), showSecrets);
549
+ if (!diff.includes("no diff"))
550
+ diffs.push(diff);
551
+ }
552
+ }
553
+ return diffs.length > 0 ? diffs.join(`
554
+
555
+ `) : "(no diff \u2014 identical)";
556
+ }
557
+ function detectCategory(filePath) {
558
+ const p = filePath.toLowerCase().replace(getConfigHome(), "~");
559
+ if (p.includes("/.claude/rules/") || p.includes("/.cursor/rules/") || p.includes("/.agents/rules/") || p.endsWith("claude.md") || p.endsWith("agents.md") || p.endsWith("codewith.md") || p.endsWith("aicopilot.md") || p.endsWith("/.gemini/gemini.md") || p.endsWith(".mdc"))
560
+ return "rules";
561
+ if (p.includes(".mcp.json") || p.includes("mcp"))
562
+ return "mcp";
563
+ if (p.includes("/.claude/") || p.includes("/.codex/") || p.includes("/.antigravity/") || p.includes("/.agents/") || p.includes("/.cursor/") || p.includes("/.config/opencode/") || p.includes("/.codewith/") || p.includes("/.config/aicopilot/") || p.includes("/.qwen/"))
564
+ return "agent";
565
+ if (p.includes(".zshrc") || p.includes(".zprofile") || p.includes(".bashrc") || p.includes(".bash_profile"))
566
+ return "shell";
567
+ if (p.includes(".gitconfig") || p.includes(".gitignore"))
568
+ return "git";
569
+ if (p.includes(".npmrc") || p.includes("tsconfig") || p.includes("bunfig"))
570
+ return "tools";
571
+ if (p.includes(".secrets"))
572
+ return "secrets_schema";
573
+ return "tools";
574
+ }
575
+ function detectAgent(filePath) {
576
+ const p = filePath.toLowerCase().replace(getConfigHome(), "~");
577
+ if (p.includes("/.github/instructions/") || p.endsWith("/.github/copilot-instructions.md"))
578
+ return "copilot";
579
+ if (p.includes("/.devin/rules/"))
580
+ return "devin";
581
+ if (p.includes("/.windsurf/rules/"))
582
+ return "windsurf-legacy";
583
+ if (p.includes("/.clinerules/"))
584
+ return "cline";
585
+ if (p.endsWith("/.gemini/gemini.md") || p.endsWith("/.gemini/config/mcp_config.json"))
586
+ return "antigravity";
587
+ if (p.includes("/.agents/rules/") || p.endsWith("/.agents/mcp_config.json"))
588
+ return "antigravity";
589
+ if (p.includes("/.claude/") || p.endsWith("claude.md"))
590
+ return "claude";
591
+ if (p.includes("/.config/opencode/"))
592
+ return "opencode";
593
+ if (p.includes("/.cursor/") || p.endsWith(".mdc"))
594
+ return "cursor";
595
+ if (p.includes("/.codewith/") || p.endsWith("codewith.md"))
596
+ return "codewith";
597
+ if (p.includes("/.config/aicopilot/"))
598
+ return "aicopilot";
599
+ if (p.includes("/.qwen/"))
600
+ return "qwen";
601
+ if (p.includes("/.antigravity/"))
602
+ return "antigravity";
603
+ if (p.includes("/.codex/") || p.endsWith("agents.md"))
604
+ return "codex";
605
+ if (p.includes(".zshrc") || p.includes(".zprofile") || p.includes(".bashrc"))
606
+ return "zsh";
607
+ if (p.includes(".gitconfig") || p.includes(".gitignore"))
608
+ return "git";
609
+ if (p.includes(".npmrc"))
610
+ return "npm";
611
+ return "global";
612
+ }
613
+ function detectFormat(filePath) {
614
+ const ext = extname(filePath).toLowerCase();
615
+ if (ext === ".json")
616
+ return "json";
617
+ if (ext === ".toml")
618
+ return "toml";
619
+ if (ext === ".yaml" || ext === ".yml")
620
+ return "yaml";
621
+ if (ext === ".md" || ext === ".mdc" || ext === ".markdown")
622
+ return "markdown";
623
+ if (ext === ".ini" || ext === ".cfg")
624
+ return "ini";
625
+ return "text";
626
+ }
627
+ export { CLAUDE_PROMPT_OUTPUTS, KNOWN_CONFIGS, PROJECT_CONFIG_FILES, syncProject, syncKnown, syncToDisk, diffConfig, detectCategory, detectAgent, detectFormat, syncFromDir, syncToDir };