contextos-agents 1.7.0 → 2.0.0-beta.3

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 (313) hide show
  1. package/.agents/AGENTS.md +16 -50
  2. package/.agents/adapters/aider/export.js +117 -99
  3. package/.agents/adapters/claude/export.js +68 -26
  4. package/.agents/adapters/copilot/export.js +90 -53
  5. package/.agents/adapters/cursor/export.js +100 -104
  6. package/.agents/adapters/drift-detector.js +196 -0
  7. package/.agents/adapters/gemini/export.js +76 -45
  8. package/.agents/adapters/pure-compiler.js +443 -0
  9. package/.agents/adapters/zed/export.js +104 -96
  10. package/.agents/compiled/registry.v2.json +504 -0
  11. package/.agents/compiled/registry.v2.sha256 +1 -0
  12. package/.agents/compiler/manifest-compiler.js +963 -0
  13. package/.agents/compiler/vendor/yaml.LICENSE.txt +13 -0
  14. package/.agents/compiler/vendor/yaml.SBOM.json +6 -0
  15. package/.agents/compiler/vendor/yaml.js +139 -0
  16. package/.agents/core/profiles/init.yaml +25 -0
  17. package/.agents/core/skills/context-manager/skill.yaml +3 -5
  18. package/.agents/core/skills/context-os/SKILL.md +3 -6
  19. package/.agents/core/skills/context-os/skill.yaml +3 -8
  20. package/.agents/core/skills/engineering-workflow/skill.yaml +1 -7
  21. package/.agents/core/skills/gemini-precision/skill.yaml +1 -6
  22. package/.agents/core/skills/gstack-roles/skill.yaml +3 -6
  23. package/.agents/core/skills/ponytail-mindset/skill.yaml +1 -7
  24. package/.agents/core/skills/security/skill.yaml +15 -3
  25. package/.agents/ctx.js +537 -112
  26. package/.agents/customization-dx.js +282 -0
  27. package/.agents/doctor.js +855 -66
  28. package/.agents/filesystem/index.js +71 -0
  29. package/.agents/filesystem/journaled-transaction.js +451 -0
  30. package/.agents/filesystem/lockfile-v2.js +275 -0
  31. package/.agents/filesystem/platform-hardening.js +222 -0
  32. package/.agents/filesystem/project-lock.js +218 -0
  33. package/.agents/filesystem/safe-path.js +256 -0
  34. package/.agents/generated/claude/skills/context-os/SKILL.md +1 -1
  35. package/.agents/generated/gemini/skills/context-os/SKILL.md +2 -2
  36. package/.agents/plugins/contextos/plugin.json +1 -1
  37. package/.agents/plugins.js +278 -64
  38. package/.agents/profiles.js +486 -51
  39. package/.agents/resolver/canonical-resolver.js +1348 -0
  40. package/.agents/resolver.js +50 -534
  41. package/.agents/rules/rule-catalog.js +525 -0
  42. package/.agents/schemas/attestation.review.v1.json +111 -0
  43. package/.agents/schemas/attestation.verification.v1.json +85 -0
  44. package/.agents/schemas/lockfile.v2.schema.json +134 -0
  45. package/.agents/schemas/profile.v2.schema.json +114 -0
  46. package/.agents/schemas/runtime.thread.v1.json +192 -0
  47. package/.agents/schemas/skill.manifest.v2.json +177 -0
  48. package/.agents/schemas/verification.spec.v1.json +39 -0
  49. package/.agents/schemas/workspace.graph.schema.json +106 -0
  50. package/.agents/skills-index.json +6 -166
  51. package/.agents/stats.js +9 -9
  52. package/.agents/transaction-core/event-store.js +288 -0
  53. package/.agents/transaction-core/idempotency.js +129 -0
  54. package/.agents/transaction-core/ipc-lock.js +311 -0
  55. package/.agents/transaction-core/plugin-supply-chain-bundle.js +436 -0
  56. package/.agents/validate.js +44 -1
  57. package/.agents/watch.js +354 -102
  58. package/.agents/workspace/workspace-graph.js +778 -0
  59. package/README.md +59 -387
  60. package/benchmarks/v2/analysis/statistics.js +140 -0
  61. package/benchmarks/v2/analysis/stats.js +69 -0
  62. package/benchmarks/v2/arms/arm-definitions.js +79 -0
  63. package/benchmarks/v2/dataset.schema.json +34 -0
  64. package/benchmarks/v2/evaluators/index.js +25 -0
  65. package/benchmarks/v2/evaluators/verified-success.js +116 -0
  66. package/benchmarks/v2/harness/runner.js +88 -0
  67. package/benchmarks/v2/pilot-tasks.json +392 -0
  68. package/bin/commands/recover.js +88 -0
  69. package/bin/commands/update.js +80 -17
  70. package/bin/commands.js +62 -25
  71. package/bin/index.js +138 -81
  72. package/bin/lib/lockfile.js +5 -3
  73. package/bin/lib/safe-writer.js +34 -3
  74. package/package.json +87 -72
  75. package/registry.json +2 -2
  76. package/registry.v2.schema.json +86 -0
  77. package/.agents/core/profiles/backend.yaml +0 -47
  78. package/.agents/core/profiles/enterprise.yaml +0 -46
  79. package/.agents/core/profiles/frontend.yaml +0 -46
  80. package/.agents/core/profiles/hackathon.yaml +0 -45
  81. package/.agents/core/profiles/mvp.yaml +0 -44
  82. package/.agents/core/profiles/startup.yaml +0 -48
  83. package/.agents/core/skills/adapters/EXAMPLES.md +0 -19
  84. package/.agents/core/skills/adapters/SKILL.md +0 -105
  85. package/.agents/core/skills/adapters/TROUBLESHOOTING.md +0 -7
  86. package/.agents/core/skills/adapters/VALIDATION.json +0 -12
  87. package/.agents/core/skills/adapters/skill.yaml +0 -16
  88. package/.agents/core/skills/architecture-diagrams/SKILL.md +0 -108
  89. package/.agents/core/skills/architecture-diagrams/VALIDATION.json +0 -12
  90. package/.agents/core/skills/architecture-diagrams/skill.yaml +0 -12
  91. package/.agents/core/skills/brutalist-design/SKILL.md +0 -150
  92. package/.agents/core/skills/brutalist-design/VALIDATION.json +0 -12
  93. package/.agents/core/skills/brutalist-design/skill.yaml +0 -12
  94. package/.agents/core/skills/database/EXAMPLES.md +0 -74
  95. package/.agents/core/skills/database/SKILL.md +0 -101
  96. package/.agents/core/skills/database/TROUBLESHOOTING.md +0 -18
  97. package/.agents/core/skills/database/VALIDATION.json +0 -11
  98. package/.agents/core/skills/database/skill.yaml +0 -31
  99. package/.agents/core/skills/ddd/EXAMPLES.md +0 -42
  100. package/.agents/core/skills/ddd/SKILL.md +0 -247
  101. package/.agents/core/skills/ddd/TROUBLESHOOTING.md +0 -19
  102. package/.agents/core/skills/ddd/VALIDATION.json +0 -12
  103. package/.agents/core/skills/ddd/ddd.md +0 -178
  104. package/.agents/core/skills/ddd/skill.yaml +0 -17
  105. package/.agents/core/skills/decisions/EXAMPLES.md +0 -35
  106. package/.agents/core/skills/decisions/SKILL.md +0 -90
  107. package/.agents/core/skills/decisions/TROUBLESHOOTING.md +0 -13
  108. package/.agents/core/skills/decisions/VALIDATION.json +0 -12
  109. package/.agents/core/skills/decisions/skill.yaml +0 -16
  110. package/.agents/core/skills/docker/EXAMPLES.md +0 -56
  111. package/.agents/core/skills/docker/SKILL.md +0 -63
  112. package/.agents/core/skills/docker/TROUBLESHOOTING.md +0 -18
  113. package/.agents/core/skills/docker/VALIDATION.json +0 -11
  114. package/.agents/core/skills/docker/skill.yaml +0 -29
  115. package/.agents/core/skills/fastapi/EXAMPLES.md +0 -36
  116. package/.agents/core/skills/fastapi/SKILL.md +0 -148
  117. package/.agents/core/skills/fastapi/TROUBLESHOOTING.md +0 -19
  118. package/.agents/core/skills/fastapi/VALIDATION.json +0 -12
  119. package/.agents/core/skills/fastapi/fastapi.md +0 -112
  120. package/.agents/core/skills/fastapi/skill.yaml +0 -17
  121. package/.agents/core/skills/generators/EXAMPLES.md +0 -19
  122. package/.agents/core/skills/generators/SKILL.md +0 -112
  123. package/.agents/core/skills/generators/TROUBLESHOOTING.md +0 -7
  124. package/.agents/core/skills/generators/VALIDATION.json +0 -12
  125. package/.agents/core/skills/generators/skill.yaml +0 -25
  126. package/.agents/core/skills/generators/templates/API.md +0 -77
  127. package/.agents/core/skills/generators/templates/ARCHITECTURE.md +0 -70
  128. package/.agents/core/skills/generators/templates/DATABASE.md +0 -42
  129. package/.agents/core/skills/generators/templates/DECISION.md +0 -46
  130. package/.agents/core/skills/generators/templates/PRD.md +0 -67
  131. package/.agents/core/skills/generators/templates/PROJECT_GRAPH.md +0 -56
  132. package/.agents/core/skills/generators/templates/ROADMAP.md +0 -51
  133. package/.agents/core/skills/generators/templates/TASKS.md +0 -43
  134. package/.agents/core/skills/generators/templates/UI.md +0 -73
  135. package/.agents/core/skills/graphify/EXAMPLES.md +0 -73
  136. package/.agents/core/skills/graphify/SKILL.md +0 -130
  137. package/.agents/core/skills/graphify/VALIDATION.json +0 -12
  138. package/.agents/core/skills/graphify/skill.yaml +0 -18
  139. package/.agents/core/skills/impeccable-design/EXAMPLES.md +0 -26
  140. package/.agents/core/skills/impeccable-design/SKILL.md +0 -201
  141. package/.agents/core/skills/impeccable-design/TROUBLESHOOTING.md +0 -19
  142. package/.agents/core/skills/impeccable-design/VALIDATION.json +0 -12
  143. package/.agents/core/skills/impeccable-design/skill.yaml +0 -20
  144. package/.agents/core/skills/interview-me/SKILL.md +0 -97
  145. package/.agents/core/skills/interview-me/VALIDATION.json +0 -12
  146. package/.agents/core/skills/interview-me/skill.yaml +0 -12
  147. package/.agents/core/skills/microservices/EXAMPLES.md +0 -38
  148. package/.agents/core/skills/microservices/SKILL.md +0 -164
  149. package/.agents/core/skills/microservices/TROUBLESHOOTING.md +0 -19
  150. package/.agents/core/skills/microservices/VALIDATION.json +0 -12
  151. package/.agents/core/skills/microservices/microservices.md +0 -119
  152. package/.agents/core/skills/microservices/skill.yaml +0 -17
  153. package/.agents/core/skills/minimalist-design/SKILL.md +0 -113
  154. package/.agents/core/skills/minimalist-design/VALIDATION.json +0 -12
  155. package/.agents/core/skills/minimalist-design/skill.yaml +0 -12
  156. package/.agents/core/skills/nestjs/EXAMPLES.md +0 -40
  157. package/.agents/core/skills/nestjs/SKILL.md +0 -139
  158. package/.agents/core/skills/nestjs/TROUBLESHOOTING.md +0 -19
  159. package/.agents/core/skills/nestjs/VALIDATION.json +0 -12
  160. package/.agents/core/skills/nestjs/nestjs.md +0 -103
  161. package/.agents/core/skills/nestjs/skill.yaml +0 -17
  162. package/.agents/core/skills/nextjs/EXAMPLES.md +0 -40
  163. package/.agents/core/skills/nextjs/SKILL.md +0 -163
  164. package/.agents/core/skills/nextjs/TROUBLESHOOTING.md +0 -19
  165. package/.agents/core/skills/nextjs/VALIDATION.json +0 -12
  166. package/.agents/core/skills/nextjs/nextjs.md +0 -67
  167. package/.agents/core/skills/nextjs/skill.yaml +0 -17
  168. package/.agents/core/skills/node/EXAMPLES.md +0 -80
  169. package/.agents/core/skills/node/SKILL.md +0 -128
  170. package/.agents/core/skills/node/TROUBLESHOOTING.md +0 -19
  171. package/.agents/core/skills/node/VALIDATION.json +0 -12
  172. package/.agents/core/skills/node/node.md +0 -87
  173. package/.agents/core/skills/node/skill.yaml +0 -17
  174. package/.agents/core/skills/performance/EXAMPLES.md +0 -30
  175. package/.agents/core/skills/performance/SKILL.md +0 -75
  176. package/.agents/core/skills/performance/TROUBLESHOOTING.md +0 -19
  177. package/.agents/core/skills/performance/VALIDATION.json +0 -12
  178. package/.agents/core/skills/performance/performance.md +0 -52
  179. package/.agents/core/skills/performance/skill.yaml +0 -17
  180. package/.agents/core/skills/react/EXAMPLES.md +0 -79
  181. package/.agents/core/skills/react/SKILL.md +0 -132
  182. package/.agents/core/skills/react/TROUBLESHOOTING.md +0 -19
  183. package/.agents/core/skills/react/VALIDATION.json +0 -12
  184. package/.agents/core/skills/react/react.md +0 -93
  185. package/.agents/core/skills/react/skill.yaml +0 -17
  186. package/.agents/core/skills/react-best-practices/SKILL.md +0 -155
  187. package/.agents/core/skills/react-best-practices/VALIDATION.json +0 -12
  188. package/.agents/core/skills/react-best-practices/skill.yaml +0 -14
  189. package/.agents/core/skills/redesign-audit/SKILL.md +0 -117
  190. package/.agents/core/skills/redesign-audit/VALIDATION.json +0 -12
  191. package/.agents/core/skills/redesign-audit/skill.yaml +0 -12
  192. package/.agents/core/skills/soft-design/SKILL.md +0 -108
  193. package/.agents/core/skills/soft-design/VALIDATION.json +0 -12
  194. package/.agents/core/skills/soft-design/skill.yaml +0 -12
  195. package/.agents/core/skills/state-management/EXAMPLES.md +0 -56
  196. package/.agents/core/skills/state-management/SKILL.md +0 -48
  197. package/.agents/core/skills/state-management/TROUBLESHOOTING.md +0 -18
  198. package/.agents/core/skills/state-management/VALIDATION.json +0 -11
  199. package/.agents/core/skills/state-management/skill.yaml +0 -28
  200. package/.agents/core/skills/subagent-orchestrator/SKILL.md +0 -117
  201. package/.agents/core/skills/subagent-orchestrator/VALIDATION.json +0 -12
  202. package/.agents/core/skills/subagent-orchestrator/skill.yaml +0 -12
  203. package/.agents/core/skills/system-design/EXAMPLES.md +0 -75
  204. package/.agents/core/skills/system-design/SKILL.md +0 -419
  205. package/.agents/core/skills/system-design/TROUBLESHOOTING.md +0 -19
  206. package/.agents/core/skills/system-design/VALIDATION.json +0 -12
  207. package/.agents/core/skills/system-design/skill.yaml +0 -20
  208. package/.agents/core/skills/system-design/system-design.md +0 -112
  209. package/.agents/core/skills/testing/EXAMPLES.md +0 -71
  210. package/.agents/core/skills/testing/SKILL.md +0 -70
  211. package/.agents/core/skills/testing/TROUBLESHOOTING.md +0 -18
  212. package/.agents/core/skills/testing/VALIDATION.json +0 -11
  213. package/.agents/core/skills/testing/skill.yaml +0 -32
  214. package/.agents/core/skills/typescript/EXAMPLES.md +0 -64
  215. package/.agents/core/skills/typescript/SKILL.md +0 -112
  216. package/.agents/core/skills/typescript/TROUBLESHOOTING.md +0 -19
  217. package/.agents/core/skills/typescript/VALIDATION.json +0 -12
  218. package/.agents/core/skills/typescript/skill.yaml +0 -17
  219. package/.agents/core/skills/typescript/typescript.md +0 -71
  220. package/.agents/core/skills/ui-design/EXAMPLES.md +0 -21
  221. package/.agents/core/skills/ui-design/SKILL.md +0 -124
  222. package/.agents/core/skills/ui-design/TROUBLESHOOTING.md +0 -19
  223. package/.agents/core/skills/ui-design/VALIDATION.json +0 -12
  224. package/.agents/core/skills/ui-design/skill.yaml +0 -17
  225. package/.agents/core/skills/ui-design/ui.md +0 -88
  226. package/.agents/core/skills/ui-ux-pro/EXAMPLES.md +0 -62
  227. package/.agents/core/skills/ui-ux-pro/SKILL.md +0 -375
  228. package/.agents/core/skills/ui-ux-pro/TROUBLESHOOTING.md +0 -19
  229. package/.agents/core/skills/ui-ux-pro/VALIDATION.json +0 -12
  230. package/.agents/core/skills/ui-ux-pro/skill.yaml +0 -19
  231. package/.agents/core/skills/ux-design/EXAMPLES.md +0 -36
  232. package/.agents/core/skills/ux-design/SKILL.md +0 -116
  233. package/.agents/core/skills/ux-design/TROUBLESHOOTING.md +0 -19
  234. package/.agents/core/skills/ux-design/VALIDATION.json +0 -12
  235. package/.agents/core/skills/ux-design/skill.yaml +0 -17
  236. package/.agents/core/skills/ux-design/ux.md +0 -80
  237. package/.agents/core/skills/vercel-optimize/SKILL.md +0 -83
  238. package/.agents/core/skills/vercel-optimize/VALIDATION.json +0 -12
  239. package/.agents/core/skills/vercel-optimize/scripts/collect-signals.mjs +0 -131
  240. package/.agents/core/skills/vercel-optimize/scripts/gate-investigations.mjs +0 -142
  241. package/.agents/core/skills/vercel-optimize/scripts/merge-signals.mjs +0 -143
  242. package/.agents/core/skills/vercel-optimize/scripts/scan-codebase.mjs +0 -174
  243. package/.agents/core/skills/vercel-optimize/skill.yaml +0 -18
  244. package/.agents/core/skills/web-accessibility/EXAMPLES.md +0 -39
  245. package/.agents/core/skills/web-accessibility/SKILL.md +0 -170
  246. package/.agents/core/skills/web-accessibility/TROUBLESHOOTING.md +0 -19
  247. package/.agents/core/skills/web-accessibility/VALIDATION.json +0 -12
  248. package/.agents/core/skills/web-accessibility/accessibility.md +0 -63
  249. package/.agents/core/skills/web-accessibility/skill.yaml +0 -17
  250. package/.agents/generated/claude/skills/adapters/SKILL.md +0 -126
  251. package/.agents/generated/claude/skills/architecture-diagrams/SKILL.md +0 -101
  252. package/.agents/generated/claude/skills/brutalist-design/SKILL.md +0 -145
  253. package/.agents/generated/claude/skills/database/SKILL.md +0 -191
  254. package/.agents/generated/claude/skills/ddd/SKILL.md +0 -305
  255. package/.agents/generated/claude/skills/decisions/SKILL.md +0 -134
  256. package/.agents/generated/claude/skills/docker/SKILL.md +0 -135
  257. package/.agents/generated/claude/skills/fastapi/SKILL.md +0 -200
  258. package/.agents/generated/claude/skills/generators/SKILL.md +0 -133
  259. package/.agents/generated/claude/skills/graphify/SKILL.md +0 -198
  260. package/.agents/generated/claude/skills/impeccable-design/SKILL.md +0 -241
  261. package/.agents/generated/claude/skills/interview-me/SKILL.md +0 -90
  262. package/.agents/generated/claude/skills/microservices/SKILL.md +0 -218
  263. package/.agents/generated/claude/skills/minimalist-design/SKILL.md +0 -108
  264. package/.agents/generated/claude/skills/nestjs/SKILL.md +0 -195
  265. package/.agents/generated/claude/skills/nextjs/SKILL.md +0 -219
  266. package/.agents/generated/claude/skills/node/SKILL.md +0 -224
  267. package/.agents/generated/claude/skills/performance/SKILL.md +0 -121
  268. package/.agents/generated/claude/skills/react/SKILL.md +0 -227
  269. package/.agents/generated/claude/skills/react-best-practices/SKILL.md +0 -146
  270. package/.agents/generated/claude/skills/redesign-audit/SKILL.md +0 -112
  271. package/.agents/generated/claude/skills/soft-design/SKILL.md +0 -103
  272. package/.agents/generated/claude/skills/state-management/SKILL.md +0 -120
  273. package/.agents/generated/claude/skills/subagent-orchestrator/SKILL.md +0 -110
  274. package/.agents/generated/claude/skills/system-design/SKILL.md +0 -507
  275. package/.agents/generated/claude/skills/testing/SKILL.md +0 -157
  276. package/.agents/generated/claude/skills/typescript/SKILL.md +0 -192
  277. package/.agents/generated/claude/skills/ui-design/SKILL.md +0 -161
  278. package/.agents/generated/claude/skills/ui-ux-pro/SKILL.md +0 -451
  279. package/.agents/generated/claude/skills/ux-design/SKILL.md +0 -168
  280. package/.agents/generated/claude/skills/vercel-optimize/SKILL.md +0 -76
  281. package/.agents/generated/claude/skills/web-accessibility/SKILL.md +0 -225
  282. package/.agents/generated/gemini/skills/adapters/SKILL.md +0 -135
  283. package/.agents/generated/gemini/skills/architecture-diagrams/SKILL.md +0 -107
  284. package/.agents/generated/gemini/skills/brutalist-design/SKILL.md +0 -151
  285. package/.agents/generated/gemini/skills/database/SKILL.md +0 -200
  286. package/.agents/generated/gemini/skills/ddd/SKILL.md +0 -314
  287. package/.agents/generated/gemini/skills/decisions/SKILL.md +0 -143
  288. package/.agents/generated/gemini/skills/docker/SKILL.md +0 -144
  289. package/.agents/generated/gemini/skills/fastapi/SKILL.md +0 -209
  290. package/.agents/generated/gemini/skills/generators/SKILL.md +0 -142
  291. package/.agents/generated/gemini/skills/graphify/SKILL.md +0 -205
  292. package/.agents/generated/gemini/skills/impeccable-design/SKILL.md +0 -250
  293. package/.agents/generated/gemini/skills/interview-me/SKILL.md +0 -96
  294. package/.agents/generated/gemini/skills/microservices/SKILL.md +0 -227
  295. package/.agents/generated/gemini/skills/minimalist-design/SKILL.md +0 -114
  296. package/.agents/generated/gemini/skills/nestjs/SKILL.md +0 -204
  297. package/.agents/generated/gemini/skills/nextjs/SKILL.md +0 -298
  298. package/.agents/generated/gemini/skills/node/SKILL.md +0 -323
  299. package/.agents/generated/gemini/skills/performance/SKILL.md +0 -185
  300. package/.agents/generated/gemini/skills/react/SKILL.md +0 -332
  301. package/.agents/generated/gemini/skills/react-best-practices/SKILL.md +0 -152
  302. package/.agents/generated/gemini/skills/redesign-audit/SKILL.md +0 -118
  303. package/.agents/generated/gemini/skills/soft-design/SKILL.md +0 -109
  304. package/.agents/generated/gemini/skills/state-management/SKILL.md +0 -129
  305. package/.agents/generated/gemini/skills/subagent-orchestrator/SKILL.md +0 -116
  306. package/.agents/generated/gemini/skills/system-design/SKILL.md +0 -631
  307. package/.agents/generated/gemini/skills/testing/SKILL.md +0 -166
  308. package/.agents/generated/gemini/skills/typescript/SKILL.md +0 -275
  309. package/.agents/generated/gemini/skills/ui-design/SKILL.md +0 -170
  310. package/.agents/generated/gemini/skills/ui-ux-pro/SKILL.md +0 -460
  311. package/.agents/generated/gemini/skills/ux-design/SKILL.md +0 -177
  312. package/.agents/generated/gemini/skills/vercel-optimize/SKILL.md +0 -82
  313. package/.agents/generated/gemini/skills/web-accessibility/SKILL.md +0 -300
@@ -0,0 +1,71 @@
1
+ /**
2
+ * .agents/filesystem/index.js
3
+ * ContextOS Filesystem Safety & Transaction Barrel
4
+ */
5
+
6
+ const {
7
+ resolveManagedPath,
8
+ toPosix,
9
+ isReservedDeviceName,
10
+ SafePathError,
11
+ ERROR_CODES: SAFE_PATH_ERRORS,
12
+ WINDOWS_RESERVED_NAMES,
13
+ } = require('./safe-path.js');
14
+
15
+ const {
16
+ ProjectMutationLock,
17
+ ProjectLockError,
18
+ ERROR_CODES: LOCK_ERRORS,
19
+ isPidAlive,
20
+ } = require('./project-lock.js');
21
+
22
+ const {
23
+ LockfileV2Manager,
24
+ computeExactHash,
25
+ computeSemanticHash,
26
+ LockfileV2Error,
27
+ ERROR_CODES: LOCKFILE_ERRORS,
28
+ DEFAULT_LOCKFILE_SUBPATH,
29
+ } = require('./lockfile-v2.js');
30
+
31
+ const {
32
+ JournaledTransaction,
33
+ TX_STATES,
34
+ ERROR_CODES: TX_ERRORS,
35
+ TransactionError,
36
+ safeRenameSync,
37
+ } = require('./journaled-transaction.js');
38
+
39
+ module.exports = {
40
+ // Safe Paths
41
+ resolveManagedPath,
42
+ toPosix,
43
+ isReservedDeviceName,
44
+ SafePathError,
45
+ SAFE_PATH_ERRORS,
46
+ WINDOWS_RESERVED_NAMES,
47
+
48
+ // Project Locks
49
+ ProjectMutationLock,
50
+ ProjectLockError,
51
+ LOCK_ERRORS,
52
+ isPidAlive,
53
+
54
+ // Lockfile v2
55
+ LockfileV2Manager,
56
+ computeExactHash,
57
+ computeSemanticHash,
58
+ LockfileV2Error,
59
+ LOCKFILE_ERRORS,
60
+ DEFAULT_LOCKFILE_SUBPATH,
61
+
62
+ // Transactions
63
+ JournaledTransaction,
64
+ TX_STATES,
65
+ TX_ERRORS,
66
+ TransactionError,
67
+ safeRenameSync,
68
+
69
+ // Platform Hardening
70
+ ...require('./platform-hardening.js'),
71
+ };
@@ -0,0 +1,451 @@
1
+ /**
2
+ * .agents/filesystem/journaled-transaction.js
3
+ * ContextOS Journaled Recoverable File Transactions
4
+ *
5
+ * Implements crash-resilient multi-file mutation protocol:
6
+ * - State machine: PLANNED -> PREPARED -> APPLYING -> COMMITTED
7
+ * - Failure handling: APPLYING -> ROLLING_BACK -> ROLLED_BACK
8
+ * - Crash recovery: incomplete journals trigger RECOVERY_REQUIRED
9
+ * - Precondition checks (expectedBeforeHash) prevent clobbering concurrent user edits
10
+ * - Transient Windows locking backoff retry (EACCES, EPERM, EBUSY)
11
+ * - Zero direct-write fallback: atomicity or complete rollback
12
+ */
13
+
14
+ const fs = require('fs');
15
+ const path = require('path');
16
+ const crypto = require('crypto');
17
+ const { resolveManagedPath, toPosix } = require('./safe-path.js');
18
+ const { computeExactHash } = require('./lockfile-v2.js');
19
+ const { isNetworkOrUNCPath } = require('./platform-hardening.js');
20
+
21
+ const TX_BASE_SUBPATH = path.join('.agents', '.contextos', 'transactions');
22
+
23
+ const TX_STATES = {
24
+ PLANNED: 'PLANNED',
25
+ PREPARED: 'PREPARED',
26
+ APPLYING: 'APPLYING',
27
+ COMMITTED: 'COMMITTED',
28
+ ROLLING_BACK: 'ROLLING_BACK',
29
+ ROLLED_BACK: 'ROLLED_BACK',
30
+ RECOVERY_REQUIRED: 'RECOVERY_REQUIRED',
31
+ };
32
+
33
+ const ERROR_CODES = {
34
+ PRECONDITION_FAILED: 'CTX_TX_PRECONDITION_FAILED',
35
+ APPLY_FAILED: 'CTX_TX_APPLY_FAILED',
36
+ ROLLBACK_FAILED: 'CTX_TX_ROLLBACK_FAILED',
37
+ RECOVERY_REQUIRED: 'CTX_TX_RECOVERY_REQUIRED',
38
+ INVALID_STATE: 'CTX_TX_INVALID_STATE',
39
+ UNSUPPORTED: 'UNSUPPORTED',
40
+ };
41
+
42
+ class TransactionError extends Error {
43
+ constructor(code, message, details = {}) {
44
+ super(message);
45
+ this.name = 'TransactionError';
46
+ this.code = code;
47
+ this.details = details;
48
+ }
49
+ }
50
+
51
+ /**
52
+ * Windows-aware atomic rename with bounded retry for transient locks.
53
+ */
54
+ function safeRenameSync(sourcePath, targetPath, maxRetries = 3, delays = [10, 50, 150]) {
55
+ const targetDir = path.dirname(targetPath);
56
+ if (!fs.existsSync(targetDir)) {
57
+ fs.mkdirSync(targetDir, { recursive: true });
58
+ }
59
+
60
+ let lastError = null;
61
+ for (let attempt = 0; attempt <= maxRetries; attempt++) {
62
+ try {
63
+ fs.renameSync(sourcePath, targetPath);
64
+ return;
65
+ } catch (err) {
66
+ lastError = err;
67
+ const isTransient = err.code === 'EPERM' || err.code === 'EBUSY' || err.code === 'EACCES';
68
+ if (isTransient && attempt < maxRetries) {
69
+ const waitMs = delays[attempt] || 50;
70
+ try {
71
+ Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, waitMs);
72
+ } catch {
73
+ const start = Date.now();
74
+ while (Date.now() - start < waitMs) {}
75
+ }
76
+ } else {
77
+ break;
78
+ }
79
+ }
80
+ }
81
+ throw lastError;
82
+ }
83
+
84
+ class JournaledTransaction {
85
+ constructor(projectRoot, txId = null) {
86
+ this.projectRoot = path.resolve(projectRoot);
87
+ this.txId = txId || `tx-${Date.now()}-${crypto.randomBytes(4).toString('hex')}`;
88
+ this.txDir = path.resolve(this.projectRoot, TX_BASE_SUBPATH, this.txId);
89
+ this.journalPath = path.join(this.txDir, 'journal.json');
90
+ this.stagingDir = path.join(this.txDir, 'staging');
91
+ this.backupDir = path.join(this.txDir, 'backup');
92
+
93
+ this.state = TX_STATES.PLANNED;
94
+ this.operations = [];
95
+ this.appliedOperations = [];
96
+ this.createdAt = new Date().toISOString();
97
+ }
98
+
99
+ /**
100
+ * Plans a write or replace operation.
101
+ */
102
+ stageWrite(relativePath, content, options = {}) {
103
+ if (this.state !== TX_STATES.PLANNED) {
104
+ throw new TransactionError(
105
+ ERROR_CODES.INVALID_STATE,
106
+ `Cannot stage operations in state '${this.state}' (must be PLANNED)`
107
+ );
108
+ }
109
+
110
+ const { resolvedPath, relativePosixPath } = resolveManagedPath(this.projectRoot, relativePath);
111
+ const buf = Buffer.isBuffer(content) ? content : Buffer.from(String(content), 'utf8');
112
+ const afterHash = computeExactHash(buf);
113
+
114
+ this.operations.push({
115
+ type: 'write',
116
+ relativePath: relativePosixPath,
117
+ resolvedPath,
118
+ content: buf,
119
+ afterHash,
120
+ expectedBeforeHash: options.expectedBeforeHash || null,
121
+ mode: options.mode || 420,
122
+ });
123
+ }
124
+
125
+ /**
126
+ * Plans a delete operation.
127
+ */
128
+ stageDelete(relativePath, options = {}) {
129
+ if (this.state !== TX_STATES.PLANNED) {
130
+ throw new TransactionError(
131
+ ERROR_CODES.INVALID_STATE,
132
+ `Cannot stage operations in state '${this.state}' (must be PLANNED)`
133
+ );
134
+ }
135
+
136
+ const { resolvedPath, relativePosixPath } = resolveManagedPath(this.projectRoot, relativePath);
137
+
138
+ this.operations.push({
139
+ type: 'delete',
140
+ relativePath: relativePosixPath,
141
+ resolvedPath,
142
+ expectedBeforeHash: options.expectedBeforeHash || null,
143
+ });
144
+ }
145
+
146
+ /**
147
+ * Plans an empty directory deletion operation.
148
+ */
149
+ stageDeleteDir(relativePath, options = {}) {
150
+ if (this.state !== TX_STATES.PLANNED) {
151
+ throw new TransactionError(
152
+ ERROR_CODES.INVALID_STATE,
153
+ `Cannot stage operations in state '${this.state}' (must be PLANNED)`
154
+ );
155
+ }
156
+
157
+ const { resolvedPath, relativePosixPath } = resolveManagedPath(this.projectRoot, relativePath);
158
+
159
+ this.operations.push({
160
+ type: 'deleteDir',
161
+ relativePath: relativePosixPath,
162
+ resolvedPath,
163
+ });
164
+ }
165
+
166
+ /**
167
+ * Writes the journal and staged files to disk.
168
+ */
169
+ prepare() {
170
+ if (this.state !== TX_STATES.PLANNED) {
171
+ throw new TransactionError(
172
+ ERROR_CODES.INVALID_STATE,
173
+ `Cannot prepare transaction from state '${this.state}'`
174
+ );
175
+ }
176
+
177
+ fs.mkdirSync(this.stagingDir, { recursive: true });
178
+ fs.mkdirSync(this.backupDir, { recursive: true });
179
+
180
+ // Write staged files
181
+ for (let i = 0; i < this.operations.length; i++) {
182
+ const op = this.operations[i];
183
+ if (op.type === 'write') {
184
+ const stagedFilePath = path.join(this.stagingDir, `${i}-${path.basename(op.relativePath)}`);
185
+ fs.writeFileSync(stagedFilePath, op.content);
186
+ op.stagedFilePath = stagedFilePath;
187
+ }
188
+ }
189
+
190
+ this.state = TX_STATES.PREPARED;
191
+ this.saveJournal();
192
+ return this;
193
+ }
194
+
195
+ /**
196
+ * Executes the transaction, modifying disk files.
197
+ */
198
+ commit() {
199
+ if (this.state === TX_STATES.PLANNED) {
200
+ this.prepare();
201
+ }
202
+
203
+ if (this.state !== TX_STATES.PREPARED) {
204
+ throw new TransactionError(
205
+ ERROR_CODES.INVALID_STATE,
206
+ `Cannot commit transaction in state '${this.state}'`
207
+ );
208
+ }
209
+
210
+ this.state = TX_STATES.APPLYING;
211
+ this.saveJournal();
212
+
213
+ // 1. Verify all preconditions before touching any file
214
+ for (const op of this.operations) {
215
+ if (op.expectedBeforeHash) {
216
+ if (fs.existsSync(op.resolvedPath)) {
217
+ const currentBuf = fs.readFileSync(op.resolvedPath);
218
+ const currentHash = computeExactHash(currentBuf);
219
+ if (currentHash !== op.expectedBeforeHash) {
220
+ this.rollback();
221
+ throw new TransactionError(
222
+ ERROR_CODES.PRECONDITION_FAILED,
223
+ `Precondition hash mismatch for '${op.relativePath}': expected ${op.expectedBeforeHash}, found ${currentHash}`,
224
+ { relativePath: op.relativePath, expected: op.expectedBeforeHash, actual: currentHash }
225
+ );
226
+ }
227
+ } else if (op.expectedBeforeHash !== 'NONE') {
228
+ this.rollback();
229
+ throw new TransactionError(
230
+ ERROR_CODES.PRECONDITION_FAILED,
231
+ `Precondition failed: target file '${op.relativePath}' does not exist on disk`,
232
+ { relativePath: op.relativePath }
233
+ );
234
+ }
235
+ }
236
+ }
237
+
238
+ // 2. Apply operations sequentially with backups
239
+ try {
240
+ for (let i = 0; i < this.operations.length; i++) {
241
+ const op = this.operations[i];
242
+ const backupFilePath = path.join(this.backupDir, `${i}-${path.basename(op.relativePath)}`);
243
+
244
+ if (fs.existsSync(op.resolvedPath)) {
245
+ if (op.type !== 'deleteDir') {
246
+ fs.copyFileSync(op.resolvedPath, backupFilePath);
247
+ op.backupFilePath = backupFilePath;
248
+ }
249
+ op.hadExisting = true;
250
+ } else {
251
+ op.hadExisting = false;
252
+ }
253
+
254
+ if (op.type === 'write') {
255
+ safeRenameSync(op.stagedFilePath, op.resolvedPath);
256
+ } else if (op.type === 'delete') {
257
+ if (fs.existsSync(op.resolvedPath)) {
258
+ fs.unlinkSync(op.resolvedPath);
259
+ }
260
+ } else if (op.type === 'deleteDir') {
261
+ if (fs.existsSync(op.resolvedPath)) {
262
+ try {
263
+ fs.rmdirSync(op.resolvedPath);
264
+ } catch (err) {
265
+ // Gracefully ignore ENOTEMPTY or ENOENT as per W3.3 safety requirements
266
+ if (err.code !== 'ENOTEMPTY' && err.code !== 'ENOENT' && err.code !== 'EEXIST') {
267
+ throw err;
268
+ }
269
+ }
270
+ }
271
+ }
272
+
273
+ this.appliedOperations.push(op);
274
+ }
275
+ } catch (applyErr) {
276
+ // Automatic reverse-order rollback on failure
277
+ this.rollback();
278
+ throw new TransactionError(
279
+ ERROR_CODES.APPLY_FAILED,
280
+ `Transaction apply failed: ${applyErr.message}. All modifications rolled back successfully.`,
281
+ { originalError: applyErr.message }
282
+ );
283
+ }
284
+
285
+ this.state = TX_STATES.COMMITTED;
286
+ this.completedAt = new Date().toISOString();
287
+ this.saveJournal();
288
+
289
+ // Clean up temporary transaction staging/backups upon clean commit
290
+ this.cleanup();
291
+
292
+ return {
293
+ txId: this.txId,
294
+ status: 'COMMITTED',
295
+ appliedCount: this.appliedOperations.length,
296
+ };
297
+ }
298
+
299
+ /**
300
+ * Rolls back applied modifications in reverse order.
301
+ */
302
+ rollback() {
303
+ this.state = TX_STATES.ROLLING_BACK;
304
+ this.saveJournal();
305
+
306
+ let rollbackError = null;
307
+ const toRevert = [...this.appliedOperations].reverse();
308
+
309
+ for (const op of toRevert) {
310
+ try {
311
+ if (op.hadExisting && op.backupFilePath && fs.existsSync(op.backupFilePath)) {
312
+ safeRenameSync(op.backupFilePath, op.resolvedPath);
313
+ } else if (op.hadExisting && op.type === 'deleteDir') {
314
+ if (!fs.existsSync(op.resolvedPath)) {
315
+ fs.mkdirSync(op.resolvedPath, { recursive: true });
316
+ }
317
+ } else if (!op.hadExisting && fs.existsSync(op.resolvedPath)) {
318
+ // File or dir was newly created by this tx, remove it
319
+ if (op.type === 'write' || op.type === 'delete') {
320
+ fs.unlinkSync(op.resolvedPath);
321
+ } else if (op.type === 'deleteDir') {
322
+ // If we didn't have existing deleteDir, but we somehow created it? That's not a thing, but just in case
323
+ fs.rmdirSync(op.resolvedPath);
324
+ }
325
+ }
326
+ } catch (err) {
327
+ rollbackError = err;
328
+ }
329
+ }
330
+
331
+ if (rollbackError) {
332
+ this.state = TX_STATES.RECOVERY_REQUIRED;
333
+ this.saveJournal();
334
+ throw new TransactionError(
335
+ ERROR_CODES.ROLLBACK_FAILED,
336
+ `Rollback failed: ${rollbackError.message}. Manual recovery required for tx '${this.txId}'`,
337
+ { txId: this.txId, originalError: rollbackError.message }
338
+ );
339
+ }
340
+
341
+ this.state = TX_STATES.ROLLED_BACK;
342
+ this.saveJournal();
343
+ this.cleanup();
344
+
345
+ return { txId: this.txId, status: 'ROLLED_BACK' };
346
+ }
347
+
348
+ saveJournal() {
349
+ if (!fs.existsSync(this.txDir)) {
350
+ fs.mkdirSync(this.txDir, { recursive: true });
351
+ }
352
+
353
+ const journalData = {
354
+ txId: this.txId,
355
+ state: this.state,
356
+ createdAt: this.createdAt,
357
+ updatedAt: new Date().toISOString(),
358
+ completedAt: this.completedAt || null,
359
+ operations: this.operations.map(o => ({
360
+ type: o.type,
361
+ relativePath: o.relativePath,
362
+ afterHash: o.afterHash,
363
+ expectedBeforeHash: o.expectedBeforeHash,
364
+ hadExisting: o.hadExisting,
365
+ stagedFilePath: o.stagedFilePath || null,
366
+ backupFilePath: o.backupFilePath || null,
367
+ })),
368
+ };
369
+
370
+ fs.writeFileSync(this.journalPath, JSON.stringify(journalData, null, 2), 'utf8');
371
+ }
372
+
373
+ cleanup() {
374
+ try {
375
+ if (fs.existsSync(this.stagingDir)) {
376
+ fs.rmSync(this.stagingDir, { recursive: true, force: true });
377
+ }
378
+ if (fs.existsSync(this.backupDir)) {
379
+ fs.rmSync(this.backupDir, { recursive: true, force: true });
380
+ }
381
+ } catch {
382
+ // Best effort cleanup of completed transactions
383
+ }
384
+ }
385
+
386
+ /**
387
+ * Inspects pending or broken transactions across the project.
388
+ */
389
+ static listPending(projectRoot) {
390
+ const baseDir = path.resolve(projectRoot, TX_BASE_SUBPATH);
391
+ if (!fs.existsSync(baseDir)) return [];
392
+
393
+ const entries = fs.readdirSync(baseDir, { withFileTypes: true });
394
+ const pending = [];
395
+
396
+ for (const ent of entries) {
397
+ if (ent.isDirectory()) {
398
+ const jPath = path.join(baseDir, ent.name, 'journal.json');
399
+ if (fs.existsSync(jPath)) {
400
+ try {
401
+ const data = JSON.parse(fs.readFileSync(jPath, 'utf8'));
402
+ const st = data.state || data.status;
403
+ if (st === TX_STATES.APPLYING || st === TX_STATES.ROLLING_BACK || st === TX_STATES.RECOVERY_REQUIRED || st === TX_STATES.PREPARED) {
404
+ pending.push(data);
405
+ }
406
+ } catch {
407
+ pending.push({ txId: ent.name, state: TX_STATES.RECOVERY_REQUIRED, error: 'Unparseable journal' });
408
+ }
409
+ }
410
+ }
411
+ }
412
+
413
+ return pending;
414
+ }
415
+
416
+ /**
417
+ * Loads a transaction from an existing journal.json.
418
+ */
419
+ static load(projectRoot, txId) {
420
+ const tx = new JournaledTransaction(projectRoot, txId);
421
+ if (!fs.existsSync(tx.journalPath)) {
422
+ throw new Error(`Transaction ${txId} not found`);
423
+ }
424
+
425
+ const data = JSON.parse(fs.readFileSync(tx.journalPath, 'utf8'));
426
+ tx.state = data.state;
427
+ tx.createdAt = data.createdAt;
428
+ tx.completedAt = data.completedAt;
429
+
430
+ tx.operations = data.operations.map(o => ({
431
+ type: o.type,
432
+ relativePath: o.relativePath,
433
+ resolvedPath: resolveManagedPath(projectRoot, o.relativePath).resolvedPath,
434
+ afterHash: o.afterHash,
435
+ expectedBeforeHash: o.expectedBeforeHash,
436
+ hadExisting: o.hadExisting,
437
+ stagedFilePath: o.stagedFilePath,
438
+ backupFilePath: o.backupFilePath,
439
+ }));
440
+
441
+ return tx;
442
+ }
443
+ }
444
+
445
+ module.exports = {
446
+ JournaledTransaction,
447
+ TX_STATES,
448
+ ERROR_CODES,
449
+ TransactionError,
450
+ safeRenameSync,
451
+ };