@nanonets/graft 0.24.0 → 0.24.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 (396) hide show
  1. package/dist/ask/ask.d.ts +8 -0
  2. package/dist/ask/ask.d.ts.map +1 -1
  3. package/dist/ask/ask.js +33 -12
  4. package/dist/ask/ask.js.map +1 -1
  5. package/dist/claude/hook-io.d.ts +44 -0
  6. package/dist/claude/hook-io.d.ts.map +1 -0
  7. package/dist/claude/hook-io.js +144 -0
  8. package/dist/claude/hook-io.js.map +1 -0
  9. package/dist/claude/skills-hook-util.d.ts +25 -0
  10. package/dist/claude/skills-hook-util.d.ts.map +1 -0
  11. package/dist/claude/skills-hook-util.js +71 -0
  12. package/dist/claude/skills-hook-util.js.map +1 -0
  13. package/dist/cli-picker.d.ts +24 -0
  14. package/dist/cli-picker.d.ts.map +1 -1
  15. package/dist/cli-picker.js +36 -5
  16. package/dist/cli-picker.js.map +1 -1
  17. package/dist/cli.d.ts.map +1 -1
  18. package/dist/cli.js +278 -29
  19. package/dist/cli.js.map +1 -1
  20. package/dist/cloud/lookup-activity.d.ts +16 -0
  21. package/dist/cloud/lookup-activity.d.ts.map +1 -0
  22. package/dist/cloud/lookup-activity.js +56 -0
  23. package/dist/cloud/lookup-activity.js.map +1 -0
  24. package/dist/cloud/nudge.d.ts.map +1 -1
  25. package/dist/cloud/nudge.js +3 -0
  26. package/dist/cloud/nudge.js.map +1 -1
  27. package/dist/cloud/onboarding.d.ts +237 -0
  28. package/dist/cloud/onboarding.d.ts.map +1 -0
  29. package/dist/cloud/onboarding.js +536 -0
  30. package/dist/cloud/onboarding.js.map +1 -0
  31. package/dist/cloud/pair.d.ts +76 -0
  32. package/dist/cloud/pair.d.ts.map +1 -0
  33. package/dist/cloud/pair.js +249 -0
  34. package/dist/cloud/pair.js.map +1 -0
  35. package/dist/cloud/workspace-sync.d.ts +10 -2
  36. package/dist/cloud/workspace-sync.d.ts.map +1 -1
  37. package/dist/cloud/workspace-sync.js +119 -7
  38. package/dist/cloud/workspace-sync.js.map +1 -1
  39. package/dist/cloud/workspace.d.ts +22 -1
  40. package/dist/cloud/workspace.d.ts.map +1 -1
  41. package/dist/cloud/workspace.js +16 -1
  42. package/dist/cloud/workspace.js.map +1 -1
  43. package/dist/graph/native.d.ts +2 -0
  44. package/dist/graph/native.d.ts.map +1 -1
  45. package/dist/graph/native.js +29 -4
  46. package/dist/graph/native.js.map +1 -1
  47. package/dist/hosts/claude-global.d.ts +14 -0
  48. package/dist/hosts/claude-global.d.ts.map +1 -1
  49. package/dist/hosts/claude-global.js +38 -3
  50. package/dist/hosts/claude-global.js.map +1 -1
  51. package/dist/init/install-record.d.ts +21 -0
  52. package/dist/init/install-record.d.ts.map +1 -0
  53. package/dist/init/install-record.js +144 -0
  54. package/dist/init/install-record.js.map +1 -0
  55. package/dist/init/plain-file.d.ts +11 -0
  56. package/dist/init/plain-file.d.ts.map +1 -0
  57. package/dist/init/plain-file.js +80 -0
  58. package/dist/init/plain-file.js.map +1 -0
  59. package/dist/mcp/brains.d.ts +72 -0
  60. package/dist/mcp/brains.d.ts.map +1 -0
  61. package/dist/mcp/brains.js +220 -0
  62. package/dist/mcp/brains.js.map +1 -0
  63. package/dist/mcp/server.d.ts +3 -1
  64. package/dist/mcp/server.d.ts.map +1 -1
  65. package/dist/mcp/server.js +40 -5
  66. package/dist/mcp/server.js.map +1 -1
  67. package/dist/mcp/tools.d.ts.map +1 -1
  68. package/dist/mcp/tools.js +7 -2
  69. package/dist/mcp/tools.js.map +1 -1
  70. package/dist/notes/cold-start.d.ts +30 -1
  71. package/dist/notes/cold-start.d.ts.map +1 -1
  72. package/dist/notes/cold-start.js +98 -19
  73. package/dist/notes/cold-start.js.map +1 -1
  74. package/dist/notes/every-repo.d.ts +18 -0
  75. package/dist/notes/every-repo.d.ts.map +1 -0
  76. package/dist/notes/every-repo.js +86 -0
  77. package/dist/notes/every-repo.js.map +1 -0
  78. package/dist/notes/guardrails.d.ts +8 -0
  79. package/dist/notes/guardrails.d.ts.map +1 -0
  80. package/dist/notes/guardrails.js +38 -0
  81. package/dist/notes/guardrails.js.map +1 -0
  82. package/dist/notes/lesson-index.d.ts +13 -0
  83. package/dist/notes/lesson-index.d.ts.map +1 -0
  84. package/dist/notes/lesson-index.js +135 -0
  85. package/dist/notes/lesson-index.js.map +1 -0
  86. package/dist/notes/linked-learnings.d.ts +8 -0
  87. package/dist/notes/linked-learnings.d.ts.map +1 -0
  88. package/dist/notes/linked-learnings.js +113 -0
  89. package/dist/notes/linked-learnings.js.map +1 -0
  90. package/dist/notes/replace.d.ts +14 -0
  91. package/dist/notes/replace.d.ts.map +1 -0
  92. package/dist/notes/replace.js +38 -0
  93. package/dist/notes/replace.js.map +1 -0
  94. package/dist/notes/repo-notes-dir.d.ts +2 -0
  95. package/dist/notes/repo-notes-dir.d.ts.map +1 -0
  96. package/dist/notes/repo-notes-dir.js +16 -0
  97. package/dist/notes/repo-notes-dir.js.map +1 -0
  98. package/dist/skills/anchors-cli.d.ts +33 -0
  99. package/dist/skills/anchors-cli.d.ts.map +1 -0
  100. package/dist/skills/anchors-cli.js +274 -0
  101. package/dist/skills/anchors-cli.js.map +1 -0
  102. package/dist/skills/anchors-git.d.ts +29 -0
  103. package/dist/skills/anchors-git.d.ts.map +1 -0
  104. package/dist/skills/anchors-git.js +241 -0
  105. package/dist/skills/anchors-git.js.map +1 -0
  106. package/dist/skills/anchors-wide.d.ts +25 -0
  107. package/dist/skills/anchors-wide.d.ts.map +1 -0
  108. package/dist/skills/anchors-wide.js +481 -0
  109. package/dist/skills/anchors-wide.js.map +1 -0
  110. package/dist/skills/anchors.d.ts +32 -0
  111. package/dist/skills/anchors.d.ts.map +1 -0
  112. package/dist/skills/anchors.js +485 -0
  113. package/dist/skills/anchors.js.map +1 -0
  114. package/dist/skills/check-result.d.ts +26 -0
  115. package/dist/skills/check-result.d.ts.map +1 -0
  116. package/dist/skills/check-result.js +46 -0
  117. package/dist/skills/check-result.js.map +1 -0
  118. package/dist/skills/codex-sandbox.d.ts +6 -0
  119. package/dist/skills/codex-sandbox.d.ts.map +1 -0
  120. package/dist/skills/codex-sandbox.js +55 -0
  121. package/dist/skills/codex-sandbox.js.map +1 -0
  122. package/dist/skills/compile-split.d.ts +57 -0
  123. package/dist/skills/compile-split.d.ts.map +1 -0
  124. package/dist/skills/compile-split.js +532 -0
  125. package/dist/skills/compile-split.js.map +1 -0
  126. package/dist/skills/compile-version.d.ts +37 -0
  127. package/dist/skills/compile-version.d.ts.map +1 -0
  128. package/dist/skills/compile-version.js +56 -0
  129. package/dist/skills/compile-version.js.map +1 -0
  130. package/dist/skills/compile-waits.d.ts +12 -0
  131. package/dist/skills/compile-waits.d.ts.map +1 -0
  132. package/dist/skills/compile-waits.js +52 -0
  133. package/dist/skills/compile-waits.js.map +1 -0
  134. package/dist/skills/compile-words.d.ts +82 -0
  135. package/dist/skills/compile-words.d.ts.map +1 -0
  136. package/dist/skills/compile-words.js +385 -0
  137. package/dist/skills/compile-words.js.map +1 -0
  138. package/dist/skills/compile.d.ts +35 -0
  139. package/dist/skills/compile.d.ts.map +1 -0
  140. package/dist/skills/compile.js +488 -0
  141. package/dist/skills/compile.js.map +1 -0
  142. package/dist/skills/credit-facts.d.ts +8 -0
  143. package/dist/skills/credit-facts.d.ts.map +1 -0
  144. package/dist/skills/credit-facts.js +32 -0
  145. package/dist/skills/credit-facts.js.map +1 -0
  146. package/dist/skills/directive-words.d.ts +11 -0
  147. package/dist/skills/directive-words.d.ts.map +1 -0
  148. package/dist/skills/directive-words.js +33 -0
  149. package/dist/skills/directive-words.js.map +1 -0
  150. package/dist/skills/fidelity.d.ts +42 -0
  151. package/dist/skills/fidelity.d.ts.map +1 -0
  152. package/dist/skills/fidelity.js +138 -0
  153. package/dist/skills/fidelity.js.map +1 -0
  154. package/dist/skills/forget-notice.d.ts +44 -0
  155. package/dist/skills/forget-notice.d.ts.map +1 -0
  156. package/dist/skills/forget-notice.js +131 -0
  157. package/dist/skills/forget-notice.js.map +1 -0
  158. package/dist/skills/found-skill.d.ts +35 -0
  159. package/dist/skills/found-skill.d.ts.map +1 -0
  160. package/dist/skills/found-skill.js +66 -0
  161. package/dist/skills/found-skill.js.map +1 -0
  162. package/dist/skills/front-version.d.ts +12 -0
  163. package/dist/skills/front-version.d.ts.map +1 -0
  164. package/dist/skills/front-version.js +87 -0
  165. package/dist/skills/front-version.js.map +1 -0
  166. package/dist/skills/host-facts.d.ts +51 -0
  167. package/dist/skills/host-facts.d.ts.map +1 -0
  168. package/dist/skills/host-facts.js +134 -0
  169. package/dist/skills/host-facts.js.map +1 -0
  170. package/dist/skills/ledger.d.ts +43 -0
  171. package/dist/skills/ledger.d.ts.map +1 -0
  172. package/dist/skills/ledger.js +336 -0
  173. package/dist/skills/ledger.js.map +1 -0
  174. package/dist/skills/lessons.d.ts +60 -0
  175. package/dist/skills/lessons.d.ts.map +1 -0
  176. package/dist/skills/lessons.js +396 -0
  177. package/dist/skills/lessons.js.map +1 -0
  178. package/dist/skills/offer-answers.d.ts +20 -0
  179. package/dist/skills/offer-answers.d.ts.map +1 -0
  180. package/dist/skills/offer-answers.js +51 -0
  181. package/dist/skills/offer-answers.js.map +1 -0
  182. package/dist/skills/own-folder.d.ts +9 -0
  183. package/dist/skills/own-folder.d.ts.map +1 -0
  184. package/dist/skills/own-folder.js +36 -0
  185. package/dist/skills/own-folder.js.map +1 -0
  186. package/dist/skills/person.d.ts +34 -0
  187. package/dist/skills/person.d.ts.map +1 -0
  188. package/dist/skills/person.js +102 -0
  189. package/dist/skills/person.js.map +1 -0
  190. package/dist/skills/probe-clean.d.ts +9 -0
  191. package/dist/skills/probe-clean.d.ts.map +1 -0
  192. package/dist/skills/probe-clean.js +48 -0
  193. package/dist/skills/probe-clean.js.map +1 -0
  194. package/dist/skills/probes.d.ts +26 -0
  195. package/dist/skills/probes.d.ts.map +1 -0
  196. package/dist/skills/probes.js +225 -0
  197. package/dist/skills/probes.js.map +1 -0
  198. package/dist/skills/recall.d.ts +119 -0
  199. package/dist/skills/recall.d.ts.map +1 -0
  200. package/dist/skills/recall.js +370 -0
  201. package/dist/skills/recall.js.map +1 -0
  202. package/dist/skills/receipts.d.ts +44 -0
  203. package/dist/skills/receipts.d.ts.map +1 -0
  204. package/dist/skills/receipts.js +223 -0
  205. package/dist/skills/receipts.js.map +1 -0
  206. package/dist/skills/run-checkout.d.ts +4 -0
  207. package/dist/skills/run-checkout.d.ts.map +1 -0
  208. package/dist/skills/run-checkout.js +37 -0
  209. package/dist/skills/run-checkout.js.map +1 -0
  210. package/dist/skills/runblock.d.ts +45 -0
  211. package/dist/skills/runblock.d.ts.map +1 -0
  212. package/dist/skills/runblock.js +222 -0
  213. package/dist/skills/runblock.js.map +1 -0
  214. package/dist/skills/save-parse.d.ts +42 -0
  215. package/dist/skills/save-parse.d.ts.map +1 -0
  216. package/dist/skills/save-parse.js +172 -0
  217. package/dist/skills/save-parse.js.map +1 -0
  218. package/dist/skills/save-store.d.ts +12 -0
  219. package/dist/skills/save-store.d.ts.map +1 -0
  220. package/dist/skills/save-store.js +22 -0
  221. package/dist/skills/save-store.js.map +1 -0
  222. package/dist/skills/settings.d.ts +38 -0
  223. package/dist/skills/settings.d.ts.map +1 -0
  224. package/dist/skills/settings.js +133 -0
  225. package/dist/skills/settings.js.map +1 -0
  226. package/dist/skills/skill-diff.d.ts +40 -0
  227. package/dist/skills/skill-diff.d.ts.map +1 -0
  228. package/dist/skills/skill-diff.js +191 -0
  229. package/dist/skills/skill-diff.js.map +1 -0
  230. package/dist/skills/skill-file.d.ts +24 -0
  231. package/dist/skills/skill-file.d.ts.map +1 -0
  232. package/dist/skills/skill-file.js +97 -0
  233. package/dist/skills/skill-file.js.map +1 -0
  234. package/dist/skills/skill-rebuild.d.ts +27 -0
  235. package/dist/skills/skill-rebuild.d.ts.map +1 -0
  236. package/dist/skills/skill-rebuild.js +85 -0
  237. package/dist/skills/skill-rebuild.js.map +1 -0
  238. package/dist/skills/skillmd.d.ts +17 -0
  239. package/dist/skills/skillmd.d.ts.map +1 -0
  240. package/dist/skills/skillmd.js +219 -0
  241. package/dist/skills/skillmd.js.map +1 -0
  242. package/dist/skills/skills.d.ts +2 -0
  243. package/dist/skills/skills.d.ts.map +1 -1
  244. package/dist/skills/skills.js +1 -1
  245. package/dist/skills/skills.js.map +1 -1
  246. package/dist/skills/staleness.d.ts +27 -0
  247. package/dist/skills/staleness.d.ts.map +1 -0
  248. package/dist/skills/staleness.js +178 -0
  249. package/dist/skills/staleness.js.map +1 -0
  250. package/dist/skills/state.d.ts +36 -0
  251. package/dist/skills/state.d.ts.map +1 -0
  252. package/dist/skills/state.js +259 -0
  253. package/dist/skills/state.js.map +1 -0
  254. package/dist/skills/store-fs.d.ts +77 -0
  255. package/dist/skills/store-fs.d.ts.map +1 -0
  256. package/dist/skills/store-fs.js +194 -0
  257. package/dist/skills/store-fs.js.map +1 -0
  258. package/dist/skills/store-held.d.ts +44 -0
  259. package/dist/skills/store-held.d.ts.map +1 -0
  260. package/dist/skills/store-held.js +147 -0
  261. package/dist/skills/store-held.js.map +1 -0
  262. package/dist/skills/store.d.ts +73 -0
  263. package/dist/skills/store.d.ts.map +1 -0
  264. package/dist/skills/store.js +279 -0
  265. package/dist/skills/store.js.map +1 -0
  266. package/dist/skills/validate.d.ts +11 -0
  267. package/dist/skills/validate.d.ts.map +1 -0
  268. package/dist/skills/validate.js +112 -0
  269. package/dist/skills/validate.js.map +1 -0
  270. package/dist/skills/versions-fs.d.ts +45 -0
  271. package/dist/skills/versions-fs.d.ts.map +1 -0
  272. package/dist/skills/versions-fs.js +234 -0
  273. package/dist/skills/versions-fs.js.map +1 -0
  274. package/dist/skills/versions.d.ts +56 -0
  275. package/dist/skills/versions.d.ts.map +1 -0
  276. package/dist/skills/versions.js +351 -0
  277. package/dist/skills/versions.js.map +1 -0
  278. package/dist/trace/checks.d.ts +63 -0
  279. package/dist/trace/checks.d.ts.map +1 -0
  280. package/dist/trace/checks.js +487 -0
  281. package/dist/trace/checks.js.map +1 -0
  282. package/dist/trace/claude.d.ts +124 -0
  283. package/dist/trace/claude.d.ts.map +1 -0
  284. package/dist/trace/claude.js +303 -0
  285. package/dist/trace/claude.js.map +1 -0
  286. package/dist/trace/codex-exec.d.ts +22 -0
  287. package/dist/trace/codex-exec.d.ts.map +1 -0
  288. package/dist/trace/codex-exec.js +129 -0
  289. package/dist/trace/codex-exec.js.map +1 -0
  290. package/dist/trace/codex-meta.d.ts +23 -0
  291. package/dist/trace/codex-meta.d.ts.map +1 -0
  292. package/dist/trace/codex-meta.js +112 -0
  293. package/dist/trace/codex-meta.js.map +1 -0
  294. package/dist/trace/codex.d.ts +33 -0
  295. package/dist/trace/codex.d.ts.map +1 -0
  296. package/dist/trace/codex.js +485 -0
  297. package/dist/trace/codex.js.map +1 -0
  298. package/dist/trace/cursor.d.ts +16 -0
  299. package/dist/trace/cursor.d.ts.map +1 -0
  300. package/dist/trace/cursor.js +133 -0
  301. package/dist/trace/cursor.js.map +1 -0
  302. package/dist/trace/dialect.d.ts +43 -0
  303. package/dist/trace/dialect.d.ts.map +1 -0
  304. package/dist/trace/dialect.js +95 -0
  305. package/dist/trace/dialect.js.map +1 -0
  306. package/dist/trace/epochs.d.ts +10 -0
  307. package/dist/trace/epochs.d.ts.map +1 -0
  308. package/dist/trace/epochs.js +16 -0
  309. package/dist/trace/epochs.js.map +1 -0
  310. package/dist/trace/failure.d.ts +15 -0
  311. package/dist/trace/failure.d.ts.map +1 -0
  312. package/dist/trace/failure.js +69 -0
  313. package/dist/trace/failure.js.map +1 -0
  314. package/dist/trace/gate-file.d.ts +71 -0
  315. package/dist/trace/gate-file.d.ts.map +1 -0
  316. package/dist/trace/gate-file.js +329 -0
  317. package/dist/trace/gate-file.js.map +1 -0
  318. package/dist/trace/guard-fast.d.ts +22 -0
  319. package/dist/trace/guard-fast.d.ts.map +1 -0
  320. package/dist/trace/guard-fast.js +213 -0
  321. package/dist/trace/guard-fast.js.map +1 -0
  322. package/dist/trace/housekeeping.d.ts +5 -0
  323. package/dist/trace/housekeeping.d.ts.map +1 -0
  324. package/dist/trace/housekeeping.js +93 -0
  325. package/dist/trace/housekeeping.js.map +1 -0
  326. package/dist/trace/jobs.d.ts +52 -0
  327. package/dist/trace/jobs.d.ts.map +1 -0
  328. package/dist/trace/jobs.js +182 -0
  329. package/dist/trace/jobs.js.map +1 -0
  330. package/dist/trace/known-repo.d.ts +3 -0
  331. package/dist/trace/known-repo.d.ts.map +1 -0
  332. package/dist/trace/known-repo.js +55 -0
  333. package/dist/trace/known-repo.js.map +1 -0
  334. package/dist/trace/pool.d.ts +40 -0
  335. package/dist/trace/pool.d.ts.map +1 -0
  336. package/dist/trace/pool.js +154 -0
  337. package/dist/trace/pool.js.map +1 -0
  338. package/dist/trace/repairs.d.ts +27 -0
  339. package/dist/trace/repairs.d.ts.map +1 -0
  340. package/dist/trace/repairs.js +303 -0
  341. package/dist/trace/repairs.js.map +1 -0
  342. package/dist/trace/run-calls.d.ts +82 -0
  343. package/dist/trace/run-calls.d.ts.map +1 -0
  344. package/dist/trace/run-calls.js +331 -0
  345. package/dist/trace/run-calls.js.map +1 -0
  346. package/dist/trace/run-join.d.ts +20 -0
  347. package/dist/trace/run-join.d.ts.map +1 -0
  348. package/dist/trace/run-join.js +99 -0
  349. package/dist/trace/run-join.js.map +1 -0
  350. package/dist/trace/run-sheets.d.ts +26 -0
  351. package/dist/trace/run-sheets.d.ts.map +1 -0
  352. package/dist/trace/run-sheets.js +145 -0
  353. package/dist/trace/run-sheets.js.map +1 -0
  354. package/dist/trace/run-turns.d.ts +24 -0
  355. package/dist/trace/run-turns.d.ts.map +1 -0
  356. package/dist/trace/run-turns.js +67 -0
  357. package/dist/trace/run-turns.js.map +1 -0
  358. package/dist/trace/run-verdict.d.ts +24 -0
  359. package/dist/trace/run-verdict.d.ts.map +1 -0
  360. package/dist/trace/run-verdict.js +176 -0
  361. package/dist/trace/run-verdict.js.map +1 -0
  362. package/dist/trace/runs.d.ts +54 -0
  363. package/dist/trace/runs.d.ts.map +1 -0
  364. package/dist/trace/runs.js +501 -0
  365. package/dist/trace/runs.js.map +1 -0
  366. package/dist/trace/skill-session.d.ts +64 -0
  367. package/dist/trace/skill-session.d.ts.map +1 -0
  368. package/dist/trace/skill-session.js +232 -0
  369. package/dist/trace/skill-session.js.map +1 -0
  370. package/dist/trace/tamper.d.ts +12 -0
  371. package/dist/trace/tamper.d.ts.map +1 -0
  372. package/dist/trace/tamper.js +405 -0
  373. package/dist/trace/tamper.js.map +1 -0
  374. package/dist/trace/typed.d.ts +30 -0
  375. package/dist/trace/typed.d.ts.map +1 -0
  376. package/dist/trace/typed.js +132 -0
  377. package/dist/trace/typed.js.map +1 -0
  378. package/dist/trace/wall-state.d.ts +86 -0
  379. package/dist/trace/wall-state.d.ts.map +1 -0
  380. package/dist/trace/wall-state.js +279 -0
  381. package/dist/trace/wall-state.js.map +1 -0
  382. package/dist/trace/walls.d.ts +40 -0
  383. package/dist/trace/walls.d.ts.map +1 -0
  384. package/dist/trace/walls.js +318 -0
  385. package/dist/trace/walls.js.map +1 -0
  386. package/dist/vendor/tree-sitter-swift/LICENSE +21 -0
  387. package/dist/vendor/tree-sitter-swift/node-types.json +30694 -0
  388. package/dist/vendor/tree-sitter-swift/prebuilds/darwin-arm64/tree-sitter-swift.node +0 -0
  389. package/dist/vendor/tree-sitter-swift/prebuilds/darwin-x64/tree-sitter-swift.node +0 -0
  390. package/dist/vendor/tree-sitter-swift/prebuilds/linux-arm64/tree-sitter-swift.node +0 -0
  391. package/dist/vendor/tree-sitter-swift/prebuilds/linux-x64/tree-sitter-swift.node +0 -0
  392. package/dist/vendor/tree-sitter-swift/prebuilds/win32-arm64/tree-sitter-swift.node +0 -0
  393. package/dist/vendor/tree-sitter-swift/prebuilds/win32-x64/tree-sitter-swift.node +0 -0
  394. package/package.json +6 -3
  395. package/scripts/stamp-telemetry-key.mjs +8 -5
  396. package/scripts/vendor-grammars.mjs +35 -0
@@ -0,0 +1,55 @@
1
+ /**
2
+ * 4.17, R21: Codex runs `trail skills add`, `lesson` and `update` as the agent's command, inside its sandbox, where
3
+ * writing `~/.trail` may be refused. Before such a save writes anything, the folders it writes (`skills`, `state`)
4
+ * must each take a file; when one can't, the CLI changes nothing, leaves the receipt unused, and says how the person
5
+ * can run the same command in their own terminal, where the same receipt and transcript decide (1a).
6
+ */
7
+ import { closeSync, constants, openSync, statSync, unlinkSync } from 'node:fs';
8
+ import { randomBytes } from 'node:crypto';
9
+ import { dirname, join } from 'node:path';
10
+ import { trailHome } from '../notes/trail-home.js';
11
+ import { flatLine } from '../notes/flatten.js';
12
+ export const sandboxLine = (command) => `trail · couldn't write ~/.trail from Codex's sandbox. The person can run the same command in their own terminal within 30 minutes: ${flatLine(command, 200)}`;
13
+ /** The folder itself when it is there, else the nearest folder above it that is (where the save would make it). */
14
+ function nearestDir(dir) {
15
+ for (let d = dir, i = 0; i < 8; d = dirname(d), i++) {
16
+ try {
17
+ if (statSync(d).isDirectory())
18
+ return d;
19
+ }
20
+ catch { /* not there yet */ }
21
+ if (dirname(d) === d)
22
+ break;
23
+ }
24
+ return null;
25
+ }
26
+ /** One new file made and removed in the folder: what a sandbox allows, which a permission-bit check can't tell. */
27
+ function takesAFile(dir) {
28
+ const probe = join(dir, `.write-check-${process.pid}-${randomBytes(4).toString('hex')}`);
29
+ try {
30
+ closeSync(openSync(probe, constants.O_WRONLY | constants.O_CREAT | constants.O_EXCL, 0o600));
31
+ }
32
+ catch {
33
+ return false;
34
+ }
35
+ try {
36
+ unlinkSync(probe);
37
+ }
38
+ catch { /* made, so the folder takes a file; a leftover probe is named for its process */ }
39
+ return true;
40
+ }
41
+ /** Whether a save can write `~/.trail/skills` and `~/.trail/state` (or the folder they would be made in). */
42
+ export function trailWritable(env = process.env) {
43
+ const home = trailHome(env);
44
+ return [join(home, 'skills'), join(home, 'state')].every((d) => {
45
+ const at = nearestDir(d);
46
+ return at !== null && takesAFile(at);
47
+ });
48
+ }
49
+ /** The line to print instead of saving, for a save Codex ran where `~/.trail` can't be written; null otherwise. */
50
+ export function codexSandboxRefusal(host, command, env = process.env) {
51
+ if (host !== 'codex')
52
+ return null;
53
+ return trailWritable(env) ? null : sandboxLine(command);
54
+ }
55
+ //# sourceMappingURL=codex-sandbox.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codex-sandbox.js","sourceRoot":"","sources":["../../src/skills/codex-sandbox.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,QAAQ,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAC/E,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACnD,OAAO,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAE/C,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,OAAe,EAAU,EAAE,CACrD,sIAAsI,QAAQ,CAAC,OAAO,EAAE,GAAG,CAAC,EAAE,CAAC;AAEjK,mHAAmH;AACnH,SAAS,UAAU,CAAC,GAAW;IAC7B,KAAK,IAAI,CAAC,GAAG,GAAG,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;QACpD,IAAI,CAAC;YACH,IAAI,QAAQ,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE;gBAAE,OAAO,CAAC,CAAC;QAC1C,CAAC;QAAC,MAAM,CAAC,CAAC,mBAAmB,CAAC,CAAC;QAC/B,IAAI,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC;YAAE,MAAM;IAC9B,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,mHAAmH;AACnH,SAAS,UAAU,CAAC,GAAW;IAC7B,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE,gBAAgB,OAAO,CAAC,GAAG,IAAI,WAAW,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IACzF,IAAI,CAAC;QACH,SAAS,CAAC,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAC,QAAQ,GAAG,SAAS,CAAC,OAAO,GAAG,SAAS,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC;IAC/F,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;IACD,IAAI,CAAC;QACH,UAAU,CAAC,KAAK,CAAC,CAAC;IACpB,CAAC;IAAC,MAAM,CAAC,CAAC,iFAAiF,CAAC,CAAC;IAC7F,OAAO,IAAI,CAAC;AACd,CAAC;AAED,6GAA6G;AAC7G,MAAM,UAAU,aAAa,CAAC,MAAyB,OAAO,CAAC,GAAG;IAChE,MAAM,IAAI,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC;IAC5B,OAAO,CAAC,IAAI,CAAC,IAAI,EAAE,QAAQ,CAAC,EAAE,IAAI,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE;QAC7D,MAAM,EAAE,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC;QACzB,OAAO,EAAE,KAAK,IAAI,IAAI,UAAU,CAAC,EAAE,CAAC,CAAC;IACvC,CAAC,CAAC,CAAC;AACL,CAAC;AAED,mHAAmH;AACnH,MAAM,UAAU,mBAAmB,CAAC,IAAY,EAAE,OAAe,EAAE,MAAyB,OAAO,CAAC,GAAG;IACrG,IAAI,IAAI,KAAK,OAAO;QAAE,OAAO,IAAI,CAAC;IAClC,OAAO,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;AAC1D,CAAC"}
@@ -0,0 +1,57 @@
1
+ import type { CallKind, JobClass, RunCall, RunSheet } from '../trace/types.js';
2
+ export interface Statement {
3
+ /** Word for word what ran (a subshell's leading cds are in `cwd`). */
4
+ text: string;
5
+ /** Repo-relative folder it ran in; null outside the repo or unknown. */
6
+ cwd: string | null;
7
+ kind: CallKind;
8
+ bg: boolean;
9
+ /** It opened a heredoc. */
10
+ heredoc: boolean;
11
+ /** The heredoc bodies it fed, for the risk check of a step ('' when none). */
12
+ body: string;
13
+ /** Why this can't be a step on its own (set only for steps). */
14
+ blocked: string | null;
15
+ /** D58 d: a polling loop, read as the command it polled; compile writes it as the 4.5 wait. */
16
+ wait?: LoopWait;
17
+ }
18
+ /** How a polling loop waited: until CMD prints `token`, until CMD works, or (whileOk) while it still works. */
19
+ export interface LoopWait {
20
+ token: string | null;
21
+ whileOk?: true;
22
+ }
23
+ interface Ctx {
24
+ repoRoot: string;
25
+ home: string;
26
+ job: JobClass | null;
27
+ }
28
+ /**
29
+ * D58 d: a `for`, `while` or `until` loop that tries one command, sleeping between tries, until it works
30
+ * or prints a value: that command and how it waited. Anything else in the loop (a second command, the
31
+ * loop's own variable in the command, an `else`) and it is not a poll: null.
32
+ */
33
+ export declare function pollLoop(text: string): {
34
+ cmd: string;
35
+ wait: LoopWait;
36
+ } | null;
37
+ /** The statements of `cmd`, whose leading cds the fold already read into `cwd`. */
38
+ export declare function statementsOf(cmd: string, cwd: string | null, ctx: Ctx): Statement[];
39
+ /** A sheet whose step calls (and check call) of more than one command are read part by part; `blocked` says why a part refuses. */
40
+ export declare function splitSheet(sheet: RunSheet, ctx: {
41
+ repoRoot: string;
42
+ home: string;
43
+ }): {
44
+ sheet: RunSheet;
45
+ blocked: Map<RunCall, string>;
46
+ waits: Map<RunCall, LoopWait>;
47
+ parts: Map<RunCall, RunCall[]>;
48
+ };
49
+ /**
50
+ * Windows' temp folders, with either slash: the person's `AppData\Local\Temp` (as `C:\` or Git Bash's `/c/`),
51
+ * `Windows\Temp`, `%TEMP%` and `$env:TEMP`. What follows the folder is left to the caller.
52
+ */
53
+ export declare const WIN_TEMP: string;
54
+ /** Where the output went is not what ran: a trailing log into a scratch folder goes (with its `2>&1`), the step stays. */
55
+ export declare function stripScratchLog(text: string): string;
56
+ export {};
57
+ //# sourceMappingURL=compile-split.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compile-split.d.ts","sourceRoot":"","sources":["../../src/skills/compile-split.ts"],"names":[],"mappings":"AAoCA,OAAO,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAO/E,MAAM,WAAW,SAAS;IACxB,sEAAsE;IACtE,IAAI,EAAE,MAAM,CAAC;IACb,wEAAwE;IACxE,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB,IAAI,EAAE,QAAQ,CAAC;IACf,EAAE,EAAE,OAAO,CAAC;IACZ,2BAA2B;IAC3B,OAAO,EAAE,OAAO,CAAC;IACjB,8EAA8E;IAC9E,IAAI,EAAE,MAAM,CAAC;IACb,gEAAgE;IAChE,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,+FAA+F;IAC/F,IAAI,CAAC,EAAE,QAAQ,CAAC;CACjB;AAED,+GAA+G;AAC/G,MAAM,WAAW,QAAQ;IAAG,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,OAAO,CAAC,EAAE,IAAI,CAAA;CAAE;AAElE,UAAU,GAAG;IAAG,QAAQ,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,QAAQ,GAAG,IAAI,CAAA;CAAE;AAgGtE;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,QAAQ,CAAA;CAAE,GAAG,IAAI,CAkE7E;AAED,mFAAmF;AACnF,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI,EAAE,GAAG,EAAE,GAAG,GAAG,SAAS,EAAE,CA8GnF;AA4BD,mIAAmI;AACnI,wBAAgB,UAAU,CAAC,KAAK,EAAE,QAAQ,EAAE,GAAG,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG;IACpF,KAAK,EAAE,QAAQ,CAAC;IAAC,OAAO,EAAE,GAAG,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IAAC,KAAK,EAAE,GAAG,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;IAAC,KAAK,EAAE,GAAG,CAAC,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC;CAC/G,CA4CA;AAKD;;;GAGG;AACH,eAAO,MAAM,QAAQ,QAA4V,CAAC;AAMlX,0HAA0H;AAC1H,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAWpD"}
@@ -0,0 +1,532 @@
1
+ /**
2
+ * One Bash call, as the commands it ran (an addition to design 4.5 step 2).
3
+ *
4
+ * Agents often send a small script in one call: an `echo "=== x ==="` header,
5
+ * a `cd`, a look around, then the commands that matter, one per line or
6
+ * chained with `;` and `&&`. A top-level newline or `;` separates commands,
7
+ * and an `&&` link that only prints or looks can go without changing what
8
+ * the rest does, so such a call is read part by part instead of refused as
9
+ * multi-line. What stays is word for word what ran, so the save gate can
10
+ * still find it (`stepMatches` matches after a newline, `;` or `&&`):
11
+ * - steps chained with `&&` and nothing between them stay one step (design
12
+ * 4.5: `git tag ... && git push ...`); a test that guards a step
13
+ * (`[ -f x ] && ...`, `grep -q`, `command -v`) stays with it;
14
+ * - `cd X` (on its own line, as `cd X || exit 1`, or as `cd X && ...`)
15
+ * moves the folder of what follows, as the shell would;
16
+ * - `set -e`, comments, echo headers and looks are left out;
17
+ * - a step that uses a variable set earlier in the call, or that follows an
18
+ * `export`, `source` or `set -a`, can't run on its own: it refuses the
19
+ * skill, as the whole call did before;
20
+ * - an interpreter heredoc (python3/node/... `- <<EOF`) or a multi-line
21
+ * inline script is work when it writes files or starts programs and a
22
+ * look when it only reads or prints (D51, D58 e): left out either way. A
23
+ * one-line inline script that starts a program is a step. Any other
24
+ * heredoc that is a step (a shell script, `psql <<EOF`) refuses;
25
+ * - a loop that polls one command and sleeps between tries is that command,
26
+ * as a wait (D58 d);
27
+ * - `a &` runs in the background.
28
+ * A failed call is not split (which part failed is unknown), nor one holding
29
+ * anything never saved (sudo, a credential file, Trail itself: the whole
30
+ * skill is refused), and a truncated one only when what it ran holds no step
31
+ * and no heredoc. A call that is one
32
+ * command is left as it is.
33
+ *
34
+ * Pure: no files.
35
+ */
36
+ import { isAbsolute, join, relative, resolve } from 'node:path';
37
+ import { callKind, checkFamilyOf } from '../trace/checks.js';
38
+ import { envPrefix, heredocInterpreter, leadingCds, scriptKind } from '../trace/shell.js';
39
+ import { ASSIGN, OPEN_KW, base, scan, unquote, words } from '../trace/shell-scan.js';
40
+ import { programWords } from '../trace/shell-words.js';
41
+ import { neverSave } from './never-save.js';
42
+ const SETUP = /^(?:export|source|\.|set\s+(?:-\w*a|-o\s+allexport)|umask|nvm\s+use|conda\s+activate|pyenv\s+shell)\b/;
43
+ /** Shell options that change nothing for one command on its own (`set -a` is setup, not one of these). */
44
+ const IGNORED = /^(?:set(?:\s+(?:[-+][b-zA-Z]+|pipefail|errexit|nounset|xtrace|verbose))+|shopt\b.*|setopt\b.*|trap\b.*|unset\b.*|true|:)$/;
45
+ const SHELL = /^(?:ba|z|da|k)?sh$/;
46
+ /** A look that can fail and so guards what follows it in an `&&` chain. */
47
+ const GUARD = /^(?:test|\[\[?|command -v|which|grep -\w*q\w*|git diff --quiet|git diff --exit-code|git rev-parse --verify|git merge-base --is-ancestor|git cat-file -e)(?=\s|$)/;
48
+ /** The folder after `cd target`, repo-relative; null when it leaves the repo or can't be known. */
49
+ function cdTo(cwd, target, vars, ctx) {
50
+ let t = unquote(target ?? '~').replace(/\$\{?([A-Za-z_]\w*)\}?/g, (m, n) => vars.get(n) ?? m);
51
+ t = t.replace(/^(?:~|\$HOME|\$\{HOME\})(?=\/|$)/, ctx.home);
52
+ if (!t || t === '-' || /[$`*?]/.test(t) || (cwd === null && !isAbsolute(t)))
53
+ return null;
54
+ const rel = relative(ctx.repoRoot, resolve(join(ctx.repoRoot, cwd ?? ''), t)).split('\\').join('/');
55
+ // A worktree under the repo is another checkout, not a folder of this one.
56
+ return rel.startsWith('..') || isAbsolute(rel) || /(?:^|\/)\.(?:claude\/)?worktrees(?:\/|$)/.test(rel) ? null : rel;
57
+ }
58
+ /** `$NAME` or `${NAME}` outside single quotes. */
59
+ function usesVar(text, names) {
60
+ const bare = text.replace(/'[^']*'/g, "''");
61
+ for (const m of bare.matchAll(/\$\{?([A-Za-z_]\w*)/g))
62
+ if (names.has(m[1]))
63
+ return m[1];
64
+ return null;
65
+ }
66
+ /**
67
+ * D51, D58 e: an interpreter's heredoc program is a look when it only reads or prints and work when it
68
+ * writes files, starts programs or uses the network: it is left out, never a step (shell.ts `scriptKind`,
69
+ * the fold's reader too). A shell heredoc is a script of commands: a step no one can read, which refuses.
70
+ */
71
+ function heredocKind(head, bodies, job) {
72
+ const w = programWords(head);
73
+ if (SHELL.test(base(w[0] ?? '')))
74
+ return { kind: 'step', step: true };
75
+ const prog = heredocInterpreter(w);
76
+ if (prog)
77
+ return { kind: scriptKind(bodies, prog) === 'look' && callKind(head, job) !== 'work' ? 'look' : 'work', step: false };
78
+ const k = callKind(head, job);
79
+ return { kind: k, step: k === 'step' };
80
+ }
81
+ /** `cd X`, `cd X 2>/dev/null`, `cd X || exit 1`, `cd X || { echo no; exit 1; }`: the target, else undefined. */
82
+ function cdLink(s, l) {
83
+ const w = words(s.slice(l.pieces[0].start, l.pieces[0].end)).filter((x) => !/^\d?>/.test(x) && !/^\/dev\/null$/.test(x));
84
+ if (w[0] !== 'cd' || w.length > 2)
85
+ return null;
86
+ if (l.pieces.length > 1 && (l.pieces[0].sep !== '||' || l.pieces.slice(1).some((p) => callKind(s.slice(p.start, p.end), null) !== 'plumbing')))
87
+ return null;
88
+ return w[1] === undefined ? '~' : w[1];
89
+ }
90
+ /**
91
+ * A plain value: written into later lines, or carried as an env prefix. `$HOME` and `$PATH` stay as they
92
+ * are, and so does a named secret's placeholder (`"${NPM_TOKEN:?set NPM_TOKEN}"`, 4.10).
93
+ */
94
+ const plain = (v) => /^\$\{([A-Za-z_]\w*):\?set \1\}$/.test(unquote(v))
95
+ || /^[\w./:@%+,=~-]*$/.test(unquote(v).replace(/\$(?:\{(?:HOME|PATH)\}|HOME\b|PATH\b)/g, ''));
96
+ /** `$NAME` and `${NAME}` outside single quotes, as their plain values. */
97
+ function writeIn(text, vars) {
98
+ if (!vars.size)
99
+ return text;
100
+ let out = '';
101
+ let single = false;
102
+ let double = false;
103
+ for (let i = 0; i < text.length; i++) {
104
+ const c = text[i];
105
+ if (c === '\\' && !single) {
106
+ out += c + (text[i + 1] ?? '');
107
+ i++;
108
+ continue;
109
+ }
110
+ if (c === "'" && !double)
111
+ single = !single;
112
+ else if (c === '"' && !single)
113
+ double = !double;
114
+ else if (c === '$' && !single) {
115
+ const m = /^\$(?:\{([A-Za-z_]\w*)\}|([A-Za-z_]\w*))/.exec(text.slice(i));
116
+ const v = m ? vars.get(m[1] ?? m[2]) : undefined;
117
+ if (m && v !== undefined) {
118
+ out += v;
119
+ i += m[0].length - 1;
120
+ continue;
121
+ }
122
+ }
123
+ out += c;
124
+ }
125
+ return out;
126
+ }
127
+ /** A `{ ... }` or `( ... )` group, alone or with only redirects and output filters after it: its inside. */
128
+ function groupInside(s, l) {
129
+ const g = l.pieces[0].group;
130
+ if (!g || g.close < 0 || l.pieces[0].bodies.length)
131
+ return null;
132
+ if (!/^\s*(?:\d?>>?&?\s*[^\s&>]\S*(?:\s+|$))*$/.test(s.slice(g.close + 1, l.pieces[0].end)))
133
+ return null;
134
+ const filters = l.pieces.slice(1).every((p) => /^(?:tail|head|grep|cat|sed -n|cut|sort|uniq|wc|tr|tee)\b/.test(s.slice(p.start, p.end).trim()));
135
+ if (!filters || (l.pieces.length > 1 && l.pieces[0].sep !== '|'))
136
+ return null;
137
+ return { inner: s.slice(g.open + 1, g.close), subshell: s[g.open] === '(' };
138
+ }
139
+ const SLEEP = /^sleep\s+\d+(?:\.\d+)?[smh]?$/;
140
+ const NOISE = /^(?:echo|printf|:|true)(?:\s|$)(?![^'"]*>)/;
141
+ const DEV_NULL = /(?:\s+(?:\d?>>?|&>)\s*\/dev\/null|\s+\d?>&\d)+$/;
142
+ /** `[ "$V" = "T" ]`, `[[ $V == T ]]`, `test "$V" != T`: the variable, the test and the value. */
143
+ const COMPARE = /^(?:\[\[?|test)\s+"?\$\{?([A-Za-z_]\w*)\}?"?\s+(==?|!=)\s+(['"]?)([\w.:-]{1,40})\3(?:\s+\]\]?)?$/;
144
+ /** `[ "$(CMD)" = "T" ]` in an until/while header. */
145
+ const COMPARE_SUB = /^(?:\[\[?|test)\s+"\$\(([\s\S]+)\)"\s+(==?|!=)\s+(['"]?)([\w.:-]{1,40})\3(?:\s+\]\]?)?$/;
146
+ /**
147
+ * D58 d: a `for`, `while` or `until` loop that tries one command, sleeping between tries, until it works
148
+ * or prints a value: that command and how it waited. Anything else in the loop (a second command, the
149
+ * loop's own variable in the command, an `else`) and it is not a poll: null.
150
+ */
151
+ export function pollLoop(text) {
152
+ const segs = scan(text, false).segs;
153
+ if (segs.length < 3 || text.slice(segs[segs.length - 1].start, segs[segs.length - 1].end).trim() !== 'done')
154
+ return null;
155
+ // Pipelines, keywords stripped: [text, the separator after it].
156
+ const items = [];
157
+ let pipe = '';
158
+ for (const p of segs) {
159
+ pipe += (pipe ? ' | ' : '') + text.slice(p.start, p.end).trim();
160
+ if (p.sep === '|')
161
+ continue;
162
+ items.push([pipe, p.sep]);
163
+ pipe = '';
164
+ }
165
+ const head = /^(for|while|until)\s+([\s\S]*)$/.exec(items[0][0]);
166
+ if (!head || items[0][1] === '&&' || items[0][1] === '||')
167
+ return null;
168
+ const loopVar = head[1] === 'for' ? /^([A-Za-z_]\w*)\s+in\b/.exec(head[2])?.[1] ?? null : null;
169
+ if (head[1] === 'for' && !loopVar && !/^\(\(/.test(head[2]))
170
+ return null;
171
+ const body = [];
172
+ for (const [t, sep] of items.slice(1, -1)) {
173
+ const x = t.replace(/^(?:do|then)(?:\s+|$)/, '').trim();
174
+ if (x)
175
+ body.push([x, sep]);
176
+ }
177
+ let sleeps = 0;
178
+ const rest = [];
179
+ for (const [x, sep] of body) {
180
+ if (SLEEP.test(x))
181
+ sleeps++;
182
+ else if (/^(?:else|elif)\b/.test(x))
183
+ return null;
184
+ else if (!NOISE.test(x) || sep === '&&' || sep === '||')
185
+ rest.push([x, sep]);
186
+ }
187
+ if (!sleeps)
188
+ return null;
189
+ const isBreak = (x) => x === 'break' || /^\{(?:\s*(?:echo|printf)\b[^;]*;)*\s*break\s*;?\s*\}$/.test(x);
190
+ let cmd = null;
191
+ let wait = null;
192
+ const r = rest.filter(([x]) => x !== 'fi');
193
+ if (head[1] !== 'for') {
194
+ if (r.length)
195
+ return null;
196
+ const cond = head[2].replace(/\s+$/, '');
197
+ const sub = COMPARE_SUB.exec(cond);
198
+ if (sub) {
199
+ if ((head[1] === 'until') !== (sub[2] !== '!='))
200
+ return null;
201
+ [cmd, wait] = [sub[1], { token: sub[4] }];
202
+ }
203
+ else {
204
+ const neg = /^!\s+/.test(cond);
205
+ cmd = cond.replace(/^!\s+/, '');
206
+ wait = (head[1] === 'until') !== neg ? { token: null } : { token: null, whileOk: true };
207
+ }
208
+ }
209
+ else if (r.length === 2 || r.length === 3) {
210
+ // `CMD && break`, `CMD || break`, `if CMD; then break; fi`, or `V=$(CMD)` then a test of $V and a break.
211
+ const [a, b, c] = r;
212
+ const assign = /^([A-Za-z_]\w*)=(?:"\$\(([\s\S]+)\)"|\$\(([\s\S]+)\))$/.exec(a[0]);
213
+ if (assign && c && isBreak(c[0])) {
214
+ const m = COMPARE.exec(b[0].replace(/^if\s+/, ''));
215
+ if (!m || m[1] !== assign[1] || m[2] === '!=' || !(b[1] === '&&' || /^if\s/.test(b[0])))
216
+ return null;
217
+ [cmd, wait] = [assign[2] ?? assign[3], { token: m[4] }];
218
+ }
219
+ else if (!c && isBreak(b[0])) {
220
+ const iff = /^if\s+(!\s+)?([\s\S]+)$/.exec(a[0]);
221
+ if (iff)
222
+ [cmd, wait] = [iff[2], iff[1] ? { token: null, whileOk: true } : { token: null }];
223
+ else if (a[1] === '&&')
224
+ [cmd, wait] = [a[0], { token: null }];
225
+ else if (a[1] === '||')
226
+ [cmd, wait] = [a[0], { token: null, whileOk: true }];
227
+ }
228
+ }
229
+ if (cmd === null || wait === null)
230
+ return null;
231
+ cmd = (wait.token === null ? cmd.replace(DEV_NULL, '') : cmd).trim();
232
+ if (!cmd || /^(?:\[|test\b)/.test(cmd) || scan(cmd).segs.some((p) => p.sep !== '|' && p.sep !== ''))
233
+ return null;
234
+ if (loopVar && usesVar(cmd, new Set([loopVar])))
235
+ return null;
236
+ const k = callKind(cmd, null);
237
+ return k === 'step' || k === 'look' ? { cmd, wait } : null;
238
+ }
239
+ /** The statements of `cmd`, whose leading cds the fold already read into `cwd`. */
240
+ export function statementsOf(cmd, cwd, ctx) {
241
+ const out = [];
242
+ let st = {
243
+ folder: cwd, stack: [], vars: new Map(), local: new Set(),
244
+ env: new Map(), setup: null,
245
+ };
246
+ const copy = () => ({ ...st, stack: [...st.stack], vars: new Map(st.vars), local: new Set(st.local), env: new Map(st.env) });
247
+ const walk = (s) => {
248
+ // Statements end at a newline, `;` or `&`; links at `&&`.
249
+ const statements = [];
250
+ let cur = [];
251
+ let link = [];
252
+ for (const p of scan(s).segs) {
253
+ link.push(p);
254
+ const ends = p.nl || p.sep === ';' || p.sep === '&' || p.sep === '';
255
+ if (ends || p.sep === '&&') {
256
+ cur.push({ start: link[0].start, end: p.end, pieces: link });
257
+ link = [];
258
+ }
259
+ if (ends) {
260
+ statements.push(cur);
261
+ cur = [];
262
+ }
263
+ }
264
+ if (link.length)
265
+ cur.push({ start: link[0].start, end: link[link.length - 1].end, pieces: link });
266
+ if (cur.length)
267
+ statements.push(cur);
268
+ for (const links of statements) {
269
+ const last = links[links.length - 1].pieces;
270
+ const bg = last[last.length - 1].sep === '&';
271
+ // `a && b || c` is `(a && b) || c`: such a statement stays whole.
272
+ const mixed = links.length > 1 && links.some((l) => l.pieces.slice(0, -1).some((p) => p.sep === '||') && cdLink(s, l) === null);
273
+ const units = mixed ? [{ start: links[0].start, end: links[links.length - 1].end, pieces: links.flatMap((l) => l.pieces) }] : links;
274
+ let run = [];
275
+ const emit = (r, poll) => {
276
+ let text = poll ? poll.cmd : s.slice(r[0].l.start, r[r.length - 1].l.end).trim();
277
+ const bodies = r.map((x) => x.bodies).filter(Boolean).join('\n');
278
+ const lead = leadingCds(text);
279
+ const here = lead.cds.reduce((f, c) => cdTo(f, c, st.vars, ctx), st.folder);
280
+ const hd = bodies ? heredocKind(text, bodies, ctx.job) : null;
281
+ const kind = poll ? 'step' : r.length > 1 ? callKind(text, ctx.job) : hd ? hd.kind : r[0].kind;
282
+ let blocked = null;
283
+ if (kind === 'step') {
284
+ text = writeIn(text, st.vars);
285
+ const own = new Set(envPrefix(text).env.map((a) => a.slice(0, a.indexOf('='))));
286
+ const env = [...st.env].filter(([n]) => !own.has(n)).map(([, a]) => a);
287
+ // An env prefix goes on a simple command only: `X=1 if ...` is not shell.
288
+ const compound = OPEN_KW.has(words(text)[0] ?? '') || /^[({!]/.test(text);
289
+ const setup = st.setup ?? (env.length && compound ? `export ${env.join(' ')}` : null);
290
+ if (env.length && !compound)
291
+ text = `${env.join(' ')} ${text}`;
292
+ const v = usesVar(text, new Set([...st.local].filter((n) => !st.vars.has(n))));
293
+ if (hd?.step)
294
+ blocked = 'runs a script written inline (a heredoc)';
295
+ else if (text.includes('\n'))
296
+ blocked = 'runs over more than one line';
297
+ else if (v)
298
+ blocked = `uses $${v}, set on an earlier line`;
299
+ else if (setup)
300
+ blocked = `needs its shell set up first (\`${setup.split('\n')[0].slice(0, 60)}\`)`;
301
+ }
302
+ out.push({ text, cwd: here, kind, bg, heredoc: !!bodies, body: bodies, blocked, ...(poll ? { wait: poll.wait } : {}) });
303
+ };
304
+ const flush = () => {
305
+ // A guard is kept only in front of a step.
306
+ while (run.length && run[run.length - 1].guard) {
307
+ const g = run.pop();
308
+ emit([g]);
309
+ }
310
+ if (run.length)
311
+ emit(run);
312
+ run = [];
313
+ };
314
+ for (const l of units) {
315
+ const head = s.slice(l.start, l.end).trim();
316
+ if (!head || head.startsWith('#'))
317
+ continue;
318
+ const bodies = l.pieces.flatMap((p) => p.bodies.map(([a, b]) => s.slice(a, b))).join('\n');
319
+ const w = words(s.slice(l.pieces[0].start, l.pieces[0].end));
320
+ const group = bodies || mixed ? null : groupInside(s, l);
321
+ if (group) {
322
+ flush();
323
+ const saved = group.subshell ? copy() : null;
324
+ const from = out.length;
325
+ walk(group.inner);
326
+ if (saved)
327
+ st = saved;
328
+ // A block run in the background ran its lines in order: only its last step stays in the background.
329
+ if (bg)
330
+ for (let k = out.length - 1; k >= from; k--)
331
+ if (out[k].kind === 'step') {
332
+ out[k].bg = true;
333
+ break;
334
+ }
335
+ continue;
336
+ }
337
+ // D58 d: a loop that polls one command is that command, as a wait.
338
+ const poll = bodies || l.pieces.length > 1 || !/^(?:for|while|until)\s/.test(head) ? null : pollLoop(head);
339
+ if (poll) {
340
+ flush();
341
+ emit([{ l, kind: 'step', guard: false, bodies }], poll);
342
+ continue;
343
+ }
344
+ const cd = bodies ? null : cdLink(s, l);
345
+ if (cd !== null) {
346
+ flush();
347
+ st.folder = cdTo(st.folder, cd, st.vars, ctx);
348
+ continue;
349
+ }
350
+ if (!bodies && l.pieces.length === 1 && w[0] === 'pushd') {
351
+ flush();
352
+ st.stack.push(st.folder);
353
+ st.folder = cdTo(st.folder, w[1], st.vars, ctx);
354
+ continue;
355
+ }
356
+ if (!bodies && l.pieces.length === 1 && w[0] === 'popd') {
357
+ flush();
358
+ st.folder = st.stack.length ? st.stack.pop() : null;
359
+ continue;
360
+ }
361
+ if (!bodies && IGNORED.test(head))
362
+ continue;
363
+ const assigns = l.pieces.length === 1 && !bodies ? (w[0] === 'export' ? w.slice(1) : w) : [];
364
+ if (assigns.length && assigns.every((x) => ASSIGN.test(x))) {
365
+ flush();
366
+ for (const a0 of assigns) {
367
+ const a = writeIn(a0, st.vars);
368
+ const n = a.slice(0, a.indexOf('='));
369
+ const v = a.slice(a.indexOf('=') + 1);
370
+ st.local.add(n);
371
+ if (plain(v))
372
+ st.vars.set(n, /^\$\{/.test(unquote(v)) ? `"${unquote(v)}"` : unquote(v));
373
+ else
374
+ st.vars.delete(n);
375
+ if (w[0] === 'export') {
376
+ if (plain(v))
377
+ st.env.set(n, a);
378
+ else
379
+ st.setup ??= head;
380
+ }
381
+ }
382
+ continue;
383
+ }
384
+ if (!bodies && SETUP.test(head)) {
385
+ flush();
386
+ st.setup ??= head;
387
+ continue;
388
+ }
389
+ if (w[0] === 'read')
390
+ for (const x of w.slice(1))
391
+ if (/^[A-Za-z_]\w*$/.test(x))
392
+ st.local.add(x);
393
+ const kind = bodies ? heredocKind(head, bodies, ctx.job).kind : callKind(head, ctx.job);
394
+ const guard = kind === 'look' && !bodies && GUARD.test(head);
395
+ if (kind === 'step' || guard) {
396
+ run.push({ l, kind, guard, bodies });
397
+ continue;
398
+ }
399
+ flush();
400
+ emit([{ l, kind, guard, bodies }]);
401
+ }
402
+ flush();
403
+ }
404
+ };
405
+ const s = leadingCds(String(cmd ?? '').replace(/\\\r?\n[ \t]*/g, ' ')).rest;
406
+ if (s)
407
+ walk(s);
408
+ return out;
409
+ }
410
+ /**
411
+ * D58 c: a call over 2,000 characters comes as its top-level pieces (g3's `parts`). Read as one call
412
+ * again, a piece too long to keep (and a pipeline holding one) standing as `:` on a line of its own, so
413
+ * it splits away and is left out like a file edit. Null when a piece held a secret Trail couldn't name:
414
+ * that call refuses whole.
415
+ */
416
+ function fromParts(c) {
417
+ const ps = c.parts ?? [];
418
+ if (ps.some((p) => p.secret === 'refused' || (p.cmd === null && !p.long)))
419
+ return null;
420
+ const long = ps.map((p) => !!p.long);
421
+ // A pipeline with a long piece is gone whole: the rest of it read that piece's output, or fed it.
422
+ for (let i = 0; i < ps.length; i++) {
423
+ if (!long[i])
424
+ continue;
425
+ for (let k = i - 1; k >= 0 && ps[k].sep === '|'; k--)
426
+ long[k] = true;
427
+ for (let k = i; k < ps.length - 1 && ps[k].sep === '|'; k++)
428
+ long[k + 1] = true;
429
+ }
430
+ let text = '';
431
+ ps.forEach((p, i) => {
432
+ text += long[i] ? ':' : p.cmd;
433
+ const apart = long[i] || long[i + 1];
434
+ text += p.sep === '' ? '' : p.sep === ';' || (apart && p.sep !== '|') ? '\n' : p.sep === '&' ? ' &\n' : ` ${p.sep} `;
435
+ });
436
+ const { parts: _parts, ...rest } = c;
437
+ return { ...rest, cmd: text.trim(), truncated: false, multiLine: true };
438
+ }
439
+ /** A sheet whose step calls (and check call) of more than one command are read part by part; `blocked` says why a part refuses. */
440
+ export function splitSheet(sheet, ctx) {
441
+ const blocked = new Map();
442
+ const waits = new Map();
443
+ const parts = new Map();
444
+ const calls = [];
445
+ let checkIndex = sheet.checkIndex;
446
+ const c0 = { ...ctx, job: sheet.job };
447
+ sheet.calls.forEach((orig, i) => {
448
+ const isCheck = i === sheet.checkIndex;
449
+ const c = orig.cmd === null && orig.parts?.length ? fromParts(orig) ?? orig : orig;
450
+ const whole = (x, check) => { if (check)
451
+ checkIndex = calls.length; calls.push(x); parts.set(orig, [x]); };
452
+ if ((c.kind !== 'step' && !isCheck) || c.failed || c.cmd === null)
453
+ return whole(c, isCheck);
454
+ // A call with anything that is never saved (sudo, a credential file, Trail itself) stays whole, so compile refuses it.
455
+ if (neverSave(c.cmd) && !c.multiLine)
456
+ return whole(c, isCheck);
457
+ const st = statementsOf(c.cmd, c.cwd, c0);
458
+ // Code a heredoc writes into a file is not run: only a step's heredoc counts for the risk check.
459
+ if (st.some((x) => neverSave(x.kind === 'step' && x.body ? `${x.text}\n${x.body}` : x.text)))
460
+ return whole(c, isCheck);
461
+ if (!st.length)
462
+ return whole(c, isCheck);
463
+ // One command, as the fold read it: leave it be.
464
+ if (st.length === 1 && st[0].kind === c.kind && !st[0].blocked && !st[0].wait && st[0].cwd === c.cwd && !c.multiLine)
465
+ return whole(c, isCheck);
466
+ if (c.truncated && st.some((x) => x.kind === 'step' || x.heredoc))
467
+ return whole(c, isCheck);
468
+ let ck = -1;
469
+ if (isCheck) {
470
+ const fam = c.check?.family ?? checkFamilyOf(c.cmd, sheet.job);
471
+ for (let k = st.length - 1; k >= 0 && ck < 0; k--)
472
+ if (!st[k].blocked && fam && checkFamilyOf(st[k].text, sheet.job) === fam)
473
+ ck = k;
474
+ if (ck < 0)
475
+ return whole(c, isCheck);
476
+ }
477
+ // A call run in the background: its steps ran in order, so only the last needs to stay in the background.
478
+ const steps = st.filter((x) => x.kind === 'step');
479
+ st.forEach((x, k) => {
480
+ const sub = {
481
+ ...c, cmd: x.text, cwd: x.cwd, kind: x.kind, bg: (c.bg && x === steps[steps.length - 1]) || (x.bg && x.kind === 'step'),
482
+ multiLine: x.text.includes('\n'), truncated: false,
483
+ };
484
+ if (k === ck)
485
+ checkIndex = calls.length;
486
+ else
487
+ delete sub.check;
488
+ if (k !== ck && k !== st.length - 1)
489
+ delete sub.tail;
490
+ if (x.blocked)
491
+ blocked.set(sub, x.blocked);
492
+ if (x.wait && k !== ck)
493
+ waits.set(sub, x.wait);
494
+ calls.push(sub);
495
+ });
496
+ parts.set(orig, calls.slice(calls.length - st.length));
497
+ });
498
+ return { sheet: { ...sheet, calls, checkIndex }, blocked, waits, parts };
499
+ }
500
+ /** `Temp` matched in any case (`[Tt][Ee]…`): Windows paths ignore it. */
501
+ const anyCase = (w) => w.replace(/[a-z]/gi, (c) => `[${c.toUpperCase()}${c.toLowerCase()}]`);
502
+ const SEG = String.raw `[^\\/\s'"\`;|&()<>,]`;
503
+ /**
504
+ * Windows' temp folders, with either slash: the person's `AppData\Local\Temp` (as `C:\` or Git Bash's `/c/`),
505
+ * `Windows\Temp`, `%TEMP%` and `$env:TEMP`. What follows the folder is left to the caller.
506
+ */
507
+ export const WIN_TEMP = String.raw `(?:(?<![\w.~$-])(?:[A-Za-z]:|\/[A-Za-z])[\\/](?:${anyCase('users')}[\\/]${SEG}+[\\/]${anyCase('appdata')}[\\/]${anyCase('local')}[\\/]${anyCase('temp')}|${anyCase('windows')}[\\/]${anyCase('temp')})(?!${SEG})|%${anyCase('t')}${anyCase('e')}?${anyCase('mp')}%|\$${anyCase('env')}:${anyCase('t')}${anyCase('e')}?${anyCase('mp')}(?!\w))`;
508
+ /** A scratch file a step's output went into: `> /tmp/dev.log 2>&1`, `>> "$TMPDIR/x"`, `| tee …/scratchpad/t.log`, `> %TEMP%\x.log`. */
509
+ const SCRATCH_FILE = String.raw `(["']?)(?:(?:\/private)?\/(?:tmp|var\/folders)\/|\$\{?TMPDIR\}?\/?|[^\s'"\`;|&()<>,=]*[\\/]scratchpad[\\/]|${WIN_TEMP}[\\/]?)[^\s'"\`;|&()<>,]*\1`;
510
+ const LOG_TAIL = [new RegExp(String.raw `\s+(?:\d?>>?|&>>?)\s*${SCRATCH_FILE}$`), new RegExp(String.raw `\s*\|\s*tee(?:\s+-a)?\s+${SCRATCH_FILE}$`)];
511
+ /** Where the output went is not what ran: a trailing log into a scratch folder goes (with its `2>&1`), the step stays. */
512
+ export function stripScratchLog(text) {
513
+ let s = text.trimEnd();
514
+ const amp = /(?<![&|>])\s&$/.test(s) ? ' &' : '';
515
+ if (amp)
516
+ s = s.slice(0, -1).trimEnd();
517
+ let cut = false;
518
+ for (let n = 0; n < 6; n++) {
519
+ const bare = s.replace(/\s+\d?>&\d$/, '');
520
+ const re = LOG_TAIL.find((r) => r.test(bare));
521
+ if (re) {
522
+ s = bare.replace(re, '').trimEnd();
523
+ cut = true;
524
+ }
525
+ else if (cut && bare !== s)
526
+ s = bare;
527
+ else
528
+ break;
529
+ }
530
+ return cut && s ? `${s}${amp}` : text;
531
+ }
532
+ //# sourceMappingURL=compile-split.js.map