0sec-cli 0.15.0 → 0.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (209) hide show
  1. package/0sec.js +322 -0
  2. package/README.md +63 -52
  3. package/attacks/data-exfiltration/pii-leakage.yaml +27 -0
  4. package/attacks/encoding-bypass/base64-encoding.yaml +24 -0
  5. package/attacks/jailbreak/dan-roleplay.yaml +27 -0
  6. package/attacks/jailbreak/hypothetical-scenario.yaml +25 -0
  7. package/attacks/jailbreak/multilingual-bypass.yaml +22 -0
  8. package/attacks/output-manipulation/harmful-content.yaml +25 -0
  9. package/attacks/prompt-injection/context-manipulation.yaml +32 -0
  10. package/attacks/prompt-injection/direct-injection.yaml +28 -0
  11. package/attacks/prompt-injection/indirect-injection.yaml +33 -0
  12. package/attacks/system-prompt-extraction/direct-ask.yaml +30 -0
  13. package/attacks/system-prompt-extraction/markdown-exfil.yaml +26 -0
  14. package/attacks/tool-misuse/ssrf-via-tools.yaml +27 -0
  15. package/chunks/adapt-loop-ECQG7454.js +18 -0
  16. package/chunks/adgraph-JLGA6RYI.js +54 -0
  17. package/chunks/agent/skills/frameworks/entra-id.yaml +63 -0
  18. package/chunks/agent/skills/frameworks/graphql-introspection.yaml +116 -0
  19. package/chunks/agent/skills/frameworks/nextjs.yaml +82 -0
  20. package/chunks/agent/skills/frameworks/python-web.yaml +85 -0
  21. package/chunks/agent/skills/frameworks/supabase.yaml +83 -0
  22. package/chunks/agent/skills/frameworks/wordpress-deep.yaml +122 -0
  23. package/chunks/agent/skills/techniques/ad-attack-paths.yaml +57 -0
  24. package/chunks/agent/skills/techniques/advisory-disclosure.yaml +59 -0
  25. package/chunks/agent/skills/techniques/assumption-mining.yaml +53 -0
  26. package/chunks/agent/skills/techniques/blind-exploitation.yaml +143 -0
  27. package/chunks/agent/skills/techniques/crypto-misuse.yaml +88 -0
  28. package/chunks/agent/skills/techniques/cve-poc-adaptation.yaml +82 -0
  29. package/chunks/agent/skills/techniques/entra-attack-paths.yaml +55 -0
  30. package/chunks/agent/skills/techniques/http-conformance-diff.yaml +48 -0
  31. package/chunks/agent/skills/techniques/jwt-attacks.yaml +137 -0
  32. package/chunks/agent/skills/techniques/kernel-weaponization.yaml +53 -0
  33. package/chunks/agent/skills/techniques/llm-excessive-agency.yaml +55 -0
  34. package/chunks/agent/skills/techniques/llm-insecure-output-handling.yaml +56 -0
  35. package/chunks/agent/skills/techniques/llm-prompt-injection.yaml +54 -0
  36. package/chunks/agent/skills/techniques/llm-prompt-layer-write.yaml +68 -0
  37. package/chunks/agent/skills/techniques/llm-rag-poisoning.yaml +57 -0
  38. package/chunks/agent/skills/techniques/llm-safety-eval.yaml +51 -0
  39. package/chunks/agent/skills/techniques/npm-ecosystem.yaml +51 -0
  40. package/chunks/agent/skills/techniques/poc-verification.yaml +55 -0
  41. package/chunks/agent/skills/techniques/race-condition.yaml +122 -0
  42. package/chunks/agent/skills/techniques/scoped-fix.yaml +49 -0
  43. package/chunks/agent/skills/techniques/seedless-depth-review.yaml +59 -0
  44. package/chunks/agent/skills/techniques/spec-differential.yaml +48 -0
  45. package/chunks/agent/skills/techniques/variant-hunting.yaml +55 -0
  46. package/chunks/agent/skills/vulnerabilities/cardano-eutxo-validators.yaml +72 -0
  47. package/chunks/agent/skills/vulnerabilities/command-injection.yaml +99 -0
  48. package/chunks/agent/skills/vulnerabilities/deserialization-chains.yaml +106 -0
  49. package/chunks/agent/skills/vulnerabilities/native-memory-safety.yaml +93 -0
  50. package/chunks/agent/skills/vulnerabilities/path-traversal.yaml +78 -0
  51. package/chunks/agent/skills/vulnerabilities/prototype-pollution.yaml +132 -0
  52. package/chunks/agent/skills/vulnerabilities/request-smuggling.yaml +129 -0
  53. package/chunks/agent/skills/vulnerabilities/sqli-advanced.yaml +102 -0
  54. package/chunks/agent/skills/vulnerabilities/ssrf-bypass.yaml +84 -0
  55. package/chunks/agent/skills/vulnerabilities/ssti-exploitation.yaml +112 -0
  56. package/chunks/agent/skills/vulnerabilities/structural-sqli.yaml +91 -0
  57. package/chunks/appsec-catalog-CBWHGTEL.js +24 -0
  58. package/chunks/artifact-scraper-GJEZMOHF.js +34 -0
  59. package/chunks/assumption-mining-BVMMUZHB.js +79 -0
  60. package/chunks/chunk-2CJ776PV.js +2430 -0
  61. package/chunks/chunk-2RMLOJVB.js +47 -0
  62. package/chunks/chunk-2SANI5RH.js +4728 -0
  63. package/chunks/chunk-3MOLBTLS.js +953 -0
  64. package/chunks/chunk-3QFDYBZQ.js +5108 -0
  65. package/chunks/chunk-47TQJWDH.js +3729 -0
  66. package/chunks/chunk-4Y4KQJXE.js +600 -0
  67. package/chunks/chunk-53G27VPS.js +136 -0
  68. package/chunks/chunk-57ZENEX2.js +169 -0
  69. package/chunks/chunk-5G3ZXFBW.js +182 -0
  70. package/chunks/chunk-6LKRLK2R.js +542 -0
  71. package/chunks/chunk-7DQEV5QI.js +287 -0
  72. package/chunks/chunk-A6CLR72I.js +235 -0
  73. package/chunks/chunk-BKZFDZ23.js +361 -0
  74. package/chunks/chunk-CLHCDHP4.js +471 -0
  75. package/chunks/chunk-D6S3IIPG.js +518 -0
  76. package/chunks/chunk-DN25OQQA.js +1070 -0
  77. package/chunks/chunk-DW5UWPFY.js +275 -0
  78. package/chunks/chunk-F3WBKITT.js +687 -0
  79. package/chunks/chunk-H2FFLZNK.js +3 -0
  80. package/chunks/chunk-H44E2CRN.js +193 -0
  81. package/chunks/chunk-HDWV7PGI.js +596 -0
  82. package/chunks/chunk-HE7LCA7G.js +381 -0
  83. package/chunks/chunk-HT6P7RY3.js +2597 -0
  84. package/chunks/chunk-IOL7D5YV.js +515 -0
  85. package/chunks/chunk-IORC6MQX.js +72828 -0
  86. package/chunks/chunk-IR537GON.js +49 -0
  87. package/chunks/chunk-K26SZ37E.js +5735 -0
  88. package/chunks/chunk-KKGE5RQE.js +1094 -0
  89. package/chunks/chunk-KLTNTE2Z.js +121 -0
  90. package/chunks/chunk-KTQDLNSR.js +1732 -0
  91. package/chunks/chunk-LOHTE223.js +2572 -0
  92. package/chunks/chunk-LP3HHYQU.js +245 -0
  93. package/chunks/chunk-MMLDQR4H.js +852 -0
  94. package/chunks/chunk-MYVT64FN.js +16 -0
  95. package/chunks/chunk-O462Y7P2.js +33019 -0
  96. package/chunks/chunk-OEFNRYI2.js +150 -0
  97. package/chunks/chunk-P6WKNFWX.js +1968 -0
  98. package/chunks/chunk-QI233I24.js +333 -0
  99. package/chunks/chunk-QJQKHO7G.js +917 -0
  100. package/chunks/chunk-QKICO43A.js +808 -0
  101. package/chunks/chunk-QOKTUOU2.js +102 -0
  102. package/chunks/chunk-RDZYQQLW.js +596 -0
  103. package/chunks/chunk-RJWOYEOG.js +271 -0
  104. package/chunks/chunk-RRMJC3ZE.js +105 -0
  105. package/chunks/chunk-RWONANDA.js +973 -0
  106. package/chunks/chunk-SAFFWQW4.js +5921 -0
  107. package/chunks/chunk-SF4KZ4O3.js +502 -0
  108. package/chunks/chunk-SNKTC4BP.js +1422 -0
  109. package/chunks/chunk-SOG2U7B3.js +662 -0
  110. package/chunks/chunk-SZJCPG2I.js +110 -0
  111. package/chunks/chunk-UJ4IK5PO.js +2010 -0
  112. package/chunks/chunk-UM3ZNQIM.js +9329 -0
  113. package/chunks/chunk-VGRDNSHA.js +3249 -0
  114. package/chunks/chunk-VQG4FT5D.js +685 -0
  115. package/chunks/chunk-WKNNZVJS.js +2798 -0
  116. package/chunks/chunk-WU6AFRAZ.js +1167 -0
  117. package/chunks/chunk-WVTBZEQO.js +1531 -0
  118. package/chunks/chunk-YLMN3N25.js +4054 -0
  119. package/chunks/commands-U3AMV5ZU.js +16795 -0
  120. package/chunks/corpus-v1.json +403 -0
  121. package/chunks/cost-ledger-ZCKMBJEN.js +13 -0
  122. package/chunks/data/appsec-archetypes.json +102 -0
  123. package/chunks/data/chromium-archetypes.json +204 -0
  124. package/chunks/data/freebsd-archetypes.json +171 -0
  125. package/chunks/data/kernel-archetypes.json +611 -0
  126. package/chunks/db-26NGQFKO.js +16 -0
  127. package/chunks/disclose-A6AEIEDA.js +132 -0
  128. package/chunks/dist-FDKALV4R.js +2772 -0
  129. package/chunks/dist-GL66KMUX.js +74 -0
  130. package/chunks/dist-JR67XKYO.js +159 -0
  131. package/chunks/eval-runner-DDLE5RQ3.js +27 -0
  132. package/chunks/example-manifest.json +95 -0
  133. package/chunks/exploit-agent-XP23ISN7.js +98 -0
  134. package/chunks/exploit-autoclimb-E6T7RRSC.js +81 -0
  135. package/chunks/exploit-climb-2FAUP6XU.js +358 -0
  136. package/chunks/fix-IG7LYXH3.js +12 -0
  137. package/chunks/github-issues-MJ6OYOOU.js +157 -0
  138. package/chunks/harness-HWOYFKFY.js +22 -0
  139. package/chunks/http-conformance-DU66MZIU.js +11 -0
  140. package/chunks/http-sender-GWH2IYEA.js +10 -0
  141. package/chunks/hunt-scan-XPELSPQQ.js +38 -0
  142. package/chunks/identity-6ZAIIWOR.js +191 -0
  143. package/chunks/kernel-primitive-TENE3R7T.js +44 -0
  144. package/chunks/kernel-vm-runner-4F6QSNFY.js +62 -0
  145. package/chunks/memsafety-scan-J7SECV5W.js +16 -0
  146. package/chunks/native-loop-NTONUDP7.js +54 -0
  147. package/chunks/npm-detectors-KB5Y5ZFX.js +69 -0
  148. package/chunks/npm-dynamic-discovery-AHROOZDB.js +13 -0
  149. package/chunks/orchestrate-ZUWAUWBC.js +62 -0
  150. package/chunks/pipeline-FCARFZU3.js +14 -0
  151. package/chunks/pre-recon-cve-66EB6G4M.js +351 -0
  152. package/chunks/prepare-MYY743TK.js +13 -0
  153. package/chunks/process-3Q7QJIOZ.js +13 -0
  154. package/chunks/replay-runner-RRR4E2A7.js +39 -0
  155. package/chunks/run-ESNN4V5W.js +32632 -0
  156. package/chunks/runtime-62ZQAH7H.js +43 -0
  157. package/chunks/runtime-J7PLXZNM.js +12 -0
  158. package/chunks/scan-stream-FHI2FYZE.js +96 -0
  159. package/chunks/scope-BI7BF4ZY.js +18 -0
  160. package/chunks/session-store-BCFQYDCE.js +28 -0
  161. package/chunks/source-files-PWRQR6LY.js +12 -0
  162. package/chunks/specdrift-WCLH6TTQ.js +19 -0
  163. package/chunks/variant-candidates-6KM6F6MD.js +13 -0
  164. package/chunks/web-recon-prepass-DPVCBRZA.js +1148 -0
  165. package/dashboard/assets/0sec-icon-66SreztZ.gif +0 -0
  166. package/dashboard/assets/bot-yILPnRgD.js +1 -0
  167. package/dashboard/assets/chevron-down-BeDJ-Vka.js +1 -0
  168. package/dashboard/assets/circle-alert-BEnMBMT-.js +1 -0
  169. package/dashboard/assets/client-DRYsuOGl.js +9 -0
  170. package/dashboard/assets/copy-Bi5vzoF9.js +1 -0
  171. package/dashboard/assets/desktop-CXTQonNm.js +32 -0
  172. package/dashboard/assets/desktop-NOekk4QS.css +1 -0
  173. package/dashboard/assets/dist-CmX-h7a4.js +1 -0
  174. package/dashboard/assets/dist-DAwYQmf_.js +45 -0
  175. package/dashboard/assets/findings-page-CACW9nw2.js +5 -0
  176. package/dashboard/assets/format-PoISqsES.js +1 -0
  177. package/dashboard/assets/geist-cyrillic-ext-wght-normal-DjL33-gN.woff2 +0 -0
  178. package/dashboard/assets/geist-cyrillic-wght-normal-BEAKL7Jp.woff2 +0 -0
  179. package/dashboard/assets/geist-latin-ext-wght-normal-DC-KSUi6.woff2 +0 -0
  180. package/dashboard/assets/geist-latin-wght-normal-BgDaEnEv.woff2 +0 -0
  181. package/dashboard/assets/geist-vietnamese-wght-normal-6IgcOCM7.woff2 +0 -0
  182. package/dashboard/assets/ibm-plex-mono-cyrillic-400-normal-BSMlKf0J.woff2 +0 -0
  183. package/dashboard/assets/ibm-plex-mono-cyrillic-400-normal-CEL4l2ZJ.woff +0 -0
  184. package/dashboard/assets/ibm-plex-mono-cyrillic-ext-400-normal-DMdlQ8Kv.woff +0 -0
  185. package/dashboard/assets/ibm-plex-mono-cyrillic-ext-400-normal-xuaO2J-f.woff2 +0 -0
  186. package/dashboard/assets/ibm-plex-mono-latin-400-normal-CvHOgSBP.woff +0 -0
  187. package/dashboard/assets/ibm-plex-mono-latin-400-normal-DMJ8VG8y.woff2 +0 -0
  188. package/dashboard/assets/ibm-plex-mono-latin-ext-400-normal-BmRBH3aV.woff2 +0 -0
  189. package/dashboard/assets/ibm-plex-mono-latin-ext-400-normal-D3D2R8hC.woff +0 -0
  190. package/dashboard/assets/ibm-plex-mono-vietnamese-400-normal-BulugwFq.woff2 +0 -0
  191. package/dashboard/assets/ibm-plex-mono-vietnamese-400-normal-DDuiU_S-.woff +0 -0
  192. package/dashboard/assets/jsx-runtime-C7oxC63R.js +1 -0
  193. package/dashboard/assets/live-page-DrgQqQK5.js +1 -0
  194. package/dashboard/assets/meta-tile-CcskIV_o.js +1 -0
  195. package/dashboard/assets/operations-BKE8T-vY.css +2 -0
  196. package/dashboard/assets/operations-D8nUP5_m.js +4 -0
  197. package/dashboard/assets/operations-app-CQQhG54n.js +2 -0
  198. package/dashboard/assets/overview-page-DTGS8dPo.js +1 -0
  199. package/dashboard/assets/page-header-MFVvEtZW.js +1 -0
  200. package/dashboard/assets/play-Dwo-9xt6.js +1 -0
  201. package/dashboard/assets/scans-page-ChVtq8Us.js +1 -0
  202. package/dashboard/assets/search-CiooTLck.js +1 -0
  203. package/dashboard/assets/siren-CCBwTSuk.js +1 -0
  204. package/dashboard/assets/table-BYS-nIVA.js +1 -0
  205. package/dashboard/assets/tabs-DivxbhQy.js +1 -0
  206. package/dashboard/desktop.html +21 -0
  207. package/dashboard/index.html +15 -0
  208. package/package.json +30 -18
  209. package/bin/0sec.cjs +0 -361
@@ -0,0 +1,662 @@
1
+ #!/usr/bin/env node
2
+ import { createRequire as __0secCreateRequire } from "node:module";
3
+ const require = __0secCreateRequire(import.meta.url);
4
+ import {
5
+ homeStateDir
6
+ } from "./chunk-KKGE5RQE.js";
7
+
8
+ // packages/core/dist/agent/journal/types.js
9
+ var JOURNAL_SCHEMA_VERSION = 1;
10
+ var DEFAULT_JOURNAL_SIDECAR_THRESHOLD_BYTES = 32 * 1024;
11
+
12
+ // packages/core/dist/agent/journal/migrate.js
13
+ function migrateJournalEntry(raw) {
14
+ if (!raw || typeof raw !== "object") {
15
+ throw new Error("Invalid journal entry: expected object");
16
+ }
17
+ const entry = raw;
18
+ if (entry.schemaVersion === JOURNAL_SCHEMA_VERSION) {
19
+ return raw;
20
+ }
21
+ throw new Error(`Unsupported journal entry schema version: ${String(entry.schemaVersion)}`);
22
+ }
23
+
24
+ // packages/core/dist/agent/journal/rehydrate.js
25
+ function emptyState() {
26
+ return {
27
+ runId: null,
28
+ lastSeq: -1,
29
+ toolSteps: [],
30
+ hypotheses: [],
31
+ findings: [],
32
+ notes: [],
33
+ decisions: [],
34
+ done: false,
35
+ summary: ""
36
+ };
37
+ }
38
+ function orderEntries(entries) {
39
+ const seqOf = (entry) => {
40
+ const seq = entry?.seq;
41
+ return typeof seq === "number" && Number.isFinite(seq) ? seq : Number.POSITIVE_INFINITY;
42
+ };
43
+ return entries.map((entry, index) => ({ entry, index })).sort((a, b) => {
44
+ const sa = seqOf(a.entry);
45
+ const sb = seqOf(b.entry);
46
+ if (sa !== sb)
47
+ return sa - sb;
48
+ return a.index - b.index;
49
+ }).map(({ entry }) => entry);
50
+ }
51
+ function isPlainObject(value) {
52
+ return typeof value === "object" && value !== null && !Array.isArray(value);
53
+ }
54
+ function rehydrateContext(entries) {
55
+ const state = emptyState();
56
+ if (!Array.isArray(entries) || entries.length === 0)
57
+ return state;
58
+ const ordered = orderEntries(entries);
59
+ const callsByCallId = /* @__PURE__ */ new Map();
60
+ const hypothesisByStatement = /* @__PURE__ */ new Map();
61
+ for (const entry of ordered) {
62
+ if (!entry || typeof entry !== "object" || typeof entry.kind !== "string") {
63
+ continue;
64
+ }
65
+ if (typeof entry.runId === "string" && state.runId === null) {
66
+ state.runId = entry.runId;
67
+ }
68
+ if (typeof entry.seq === "number" && entry.seq > state.lastSeq) {
69
+ state.lastSeq = entry.seq;
70
+ }
71
+ switch (entry.kind) {
72
+ case "tool_call": {
73
+ const e = entry;
74
+ if (typeof e.tool !== "string")
75
+ break;
76
+ const step = {
77
+ tool: e.tool,
78
+ ...e.arguments !== void 0 ? { arguments: e.arguments } : {},
79
+ ...typeof e.turn === "number" ? { turn: e.turn } : {},
80
+ ...e.callId ? { callId: e.callId } : {}
81
+ };
82
+ state.toolSteps.push(step);
83
+ if (e.callId)
84
+ callsByCallId.set(e.callId, step);
85
+ break;
86
+ }
87
+ case "tool_result": {
88
+ const e = entry;
89
+ if (typeof e.tool !== "string")
90
+ break;
91
+ const result = {
92
+ ok: e.ok === true,
93
+ ...e.output !== void 0 ? { output: e.output } : {},
94
+ ...typeof e.error === "string" ? { error: e.error } : {}
95
+ };
96
+ let target;
97
+ if (e.callId && callsByCallId.has(e.callId)) {
98
+ target = callsByCallId.get(e.callId);
99
+ } else {
100
+ for (let i = state.toolSteps.length - 1; i >= 0; i -= 1) {
101
+ const candidate = state.toolSteps[i];
102
+ if (candidate.tool === e.tool && candidate.result === void 0) {
103
+ target = candidate;
104
+ break;
105
+ }
106
+ }
107
+ }
108
+ if (target) {
109
+ target.result = result;
110
+ } else {
111
+ state.toolSteps.push({
112
+ tool: e.tool,
113
+ ...typeof e.turn === "number" ? { turn: e.turn } : {},
114
+ ...e.callId ? { callId: e.callId } : {},
115
+ result
116
+ });
117
+ }
118
+ break;
119
+ }
120
+ case "hypothesis": {
121
+ const e = entry;
122
+ if (typeof e.statement !== "string")
123
+ break;
124
+ const existing = hypothesisByStatement.get(e.statement);
125
+ const merged = {
126
+ statement: e.statement,
127
+ ...e.rationale !== void 0 ? { rationale: e.rationale } : existing?.rationale ? { rationale: existing.rationale } : {},
128
+ ...typeof e.confidence === "number" ? { confidence: e.confidence } : existing?.confidence !== void 0 ? { confidence: existing.confidence } : {},
129
+ status: e.status ?? existing?.status ?? "open"
130
+ };
131
+ hypothesisByStatement.set(e.statement, merged);
132
+ break;
133
+ }
134
+ case "finding": {
135
+ const e = entry;
136
+ if (isPlainObject(e.finding))
137
+ state.findings.push(e.finding);
138
+ break;
139
+ }
140
+ case "observation": {
141
+ const e = entry;
142
+ if (typeof e.summary === "string" && e.summary.trim())
143
+ state.notes.push(e.summary);
144
+ break;
145
+ }
146
+ case "note": {
147
+ const e = entry;
148
+ if (typeof e.text === "string" && e.text.trim())
149
+ state.notes.push(e.text);
150
+ break;
151
+ }
152
+ case "decision": {
153
+ const e = entry;
154
+ if (typeof e.decision === "string" && e.decision.trim())
155
+ state.decisions.push(e.decision);
156
+ break;
157
+ }
158
+ case "done": {
159
+ const e = entry;
160
+ state.done = true;
161
+ if (typeof e.summary === "string")
162
+ state.summary = e.summary;
163
+ break;
164
+ }
165
+ default:
166
+ break;
167
+ }
168
+ }
169
+ const seen = /* @__PURE__ */ new Set();
170
+ for (const entry of ordered) {
171
+ if (entry?.kind !== "hypothesis")
172
+ continue;
173
+ const statement = entry.statement;
174
+ if (typeof statement !== "string" || seen.has(statement))
175
+ continue;
176
+ seen.add(statement);
177
+ const merged = hypothesisByStatement.get(statement);
178
+ if (merged)
179
+ state.hypotheses.push(merged);
180
+ }
181
+ return state;
182
+ }
183
+
184
+ // packages/core/dist/agent/journal/seed.js
185
+ var MAX_OUTPUT_CHARS = 1200;
186
+ function clip(text, max) {
187
+ if (text.length <= max)
188
+ return text;
189
+ return text.slice(0, max - 1) + "\u2026";
190
+ }
191
+ function renderValue(value) {
192
+ if (value === void 0 || value === null)
193
+ return "";
194
+ if (typeof value === "string")
195
+ return value;
196
+ try {
197
+ return JSON.stringify(value);
198
+ } catch {
199
+ return String(value);
200
+ }
201
+ }
202
+ function renderToolStep(step, index) {
203
+ const turn = typeof step.turn === "number" ? ` (turn ${step.turn})` : "";
204
+ const args = step.arguments !== void 0 ? ` ${clip(renderValue(step.arguments), 400)}` : "";
205
+ const lines = [`${index + 1}. ${step.tool}${turn}:${args}`];
206
+ if (step.result) {
207
+ if (step.result.ok) {
208
+ const out = clip(renderValue(step.result.output ?? ""), MAX_OUTPUT_CHARS);
209
+ lines.push(` \u2192 ok${out ? `: ${out}` : ""}`);
210
+ } else {
211
+ lines.push(` \u2192 error: ${clip(step.result.error ?? "unknown", 400)}`);
212
+ }
213
+ } else {
214
+ lines.push(" \u2192 (no result recorded)");
215
+ }
216
+ return lines.join("\n");
217
+ }
218
+ function renderSeedMessages(state) {
219
+ const hasProgress = state.toolSteps.length > 0 || state.hypotheses.length > 0 || state.findings.length > 0 || state.notes.length > 0 || state.decisions.length > 0 || state.done || state.summary.trim().length > 0;
220
+ if (!hasProgress)
221
+ return [];
222
+ const sections = [
223
+ "[Execution journal \u2014 prior progress on this run, rehydrated from disk]"
224
+ ];
225
+ if (state.toolSteps.length > 0) {
226
+ sections.push("## Tool steps so far\n" + state.toolSteps.map((step, i) => renderToolStep(step, i)).join("\n"));
227
+ }
228
+ if (state.hypotheses.length > 0) {
229
+ sections.push("## Hypotheses\n" + state.hypotheses.map((h) => {
230
+ const conf = typeof h.confidence === "number" ? ` (confidence ${h.confidence})` : "";
231
+ const rationale = h.rationale ? ` \u2014 ${h.rationale}` : "";
232
+ return `- [${h.status}] ${h.statement}${conf}${rationale}`;
233
+ }).join("\n"));
234
+ }
235
+ if (state.findings.length > 0) {
236
+ sections.push("## Findings recorded\n" + state.findings.map((f, i) => `${i + 1}. ${clip(renderValue(f), MAX_OUTPUT_CHARS)}`).join("\n"));
237
+ }
238
+ if (state.decisions.length > 0) {
239
+ sections.push("## Decisions\n" + state.decisions.map((d) => `- ${d}`).join("\n"));
240
+ }
241
+ if (state.notes.length > 0) {
242
+ sections.push("## Notes\n" + state.notes.map((n) => `- ${n}`).join("\n"));
243
+ }
244
+ if (state.done && state.summary.trim()) {
245
+ sections.push(`## Prior run closed
246
+ ${state.summary}`);
247
+ }
248
+ sections.push("Continue from this state. Use your tools \u2014 do not repeat steps already completed above.");
249
+ return [
250
+ {
251
+ role: "user",
252
+ content: [{ type: "text", text: sections.join("\n\n") }]
253
+ }
254
+ ];
255
+ }
256
+
257
+ // packages/core/dist/agent/journal/writer.js
258
+ import { closeSync, copyFileSync, createReadStream, existsSync, mkdirSync, openSync, readFileSync, renameSync, statSync, writeSync, fsyncSync } from "node:fs";
259
+ import { readFile } from "node:fs/promises";
260
+ import { createHash, randomUUID } from "node:crypto";
261
+ import { dirname, join, resolve, sep } from "node:path";
262
+ function defaultJournalRootDir() {
263
+ return join(homeStateDir(), "runs");
264
+ }
265
+ function resolveJournalPaths(options) {
266
+ const runDir = options.runDir ?? join(options.rootDir ?? defaultJournalRootDir(), options.runId);
267
+ return {
268
+ runDir,
269
+ journalPath: join(runDir, "journal.jsonl"),
270
+ artifactsDir: join(runDir, "artifacts")
271
+ };
272
+ }
273
+ function branchJournal(options) {
274
+ const { runId, fromEntry, label, rootDir } = options;
275
+ const effectiveRootDir = rootDir ?? defaultJournalRootDir();
276
+ const srcPaths = resolveJournalPaths({ runId, rootDir: effectiveRootDir });
277
+ if (!existsSync(srcPaths.journalPath)) {
278
+ throw new Error(`Source journal not found: ${srcPaths.journalPath}`);
279
+ }
280
+ const allEntries = loadJournalSync({ runId, rootDir: effectiveRootDir });
281
+ if (allEntries.length === 0) {
282
+ throw new Error(`Source journal is empty: ${srcPaths.journalPath}`);
283
+ }
284
+ if (fromEntry < 0 || fromEntry >= allEntries.length) {
285
+ throw new Error(`fromEntry ${fromEntry} is out of range; journal has ${allEntries.length} entries (valid: 0..${allEntries.length - 1})`);
286
+ }
287
+ const suffix = label ? `-${label}` : "";
288
+ const newRunId = `${runId}-branch${suffix}-${randomUUID().slice(0, 8)}`;
289
+ const dstPaths = resolveJournalPaths({ runId: newRunId, rootDir: effectiveRootDir });
290
+ mkdirSync(dstPaths.runDir, { recursive: true, mode: 448 });
291
+ mkdirSync(dstPaths.artifactsDir, { recursive: true, mode: 448 });
292
+ const entriesToCopy = allEntries.slice(0, fromEntry + 1);
293
+ const rewrittenEntries = entriesToCopy.map((entry) => ({
294
+ ...entry,
295
+ runId: newRunId
296
+ }));
297
+ const lines = rewrittenEntries.map((entry) => JSON.stringify(entry)).join("\n") + "\n";
298
+ const fd = openSync(dstPaths.journalPath, "w", 384);
299
+ try {
300
+ writeSync(fd, Buffer.from(lines, "utf8"));
301
+ fsyncSync(fd);
302
+ } finally {
303
+ closeSync(fd);
304
+ }
305
+ const refsToCopy = /* @__PURE__ */ new Set();
306
+ for (const entry of entriesToCopy) {
307
+ if (!entry.artifacts)
308
+ continue;
309
+ for (const artifact of entry.artifacts) {
310
+ if (artifact.kind === "ref") {
311
+ refsToCopy.add(artifact.ref);
312
+ }
313
+ }
314
+ }
315
+ let artifactsCopied = 0;
316
+ for (const ref of refsToCopy) {
317
+ const srcPath = join(srcPaths.runDir, ref);
318
+ const dstPath = join(dstPaths.runDir, ref);
319
+ if (existsSync(srcPath)) {
320
+ mkdirSync(dirname(dstPath), { recursive: true, mode: 448 });
321
+ copyFileSync(srcPath, dstPath);
322
+ artifactsCopied += 1;
323
+ }
324
+ }
325
+ fsyncDir(dirname(dstPaths.runDir));
326
+ return {
327
+ newRunId,
328
+ paths: dstPaths,
329
+ entriesCopied: entriesToCopy.length,
330
+ artifactsCopied
331
+ };
332
+ }
333
+ function createJournalWriter(options) {
334
+ return new FileJournalWriter(options);
335
+ }
336
+ function loadJournal(pathOrOptions, pathOptions) {
337
+ if (typeof pathOrOptions === "string") {
338
+ return loadJournalFromPath(pathOrOptions, pathOptions);
339
+ }
340
+ return loadJournalSync(pathOrOptions);
341
+ }
342
+ async function* streamJournal(path, options = {}) {
343
+ if (!existsSync(path))
344
+ return;
345
+ const migrate = options.migrate ?? migrateJournalEntry;
346
+ const runDir = options.runDir ?? dirname(path);
347
+ const stream = createReadStream(path, { encoding: "utf8" });
348
+ let buffer = "";
349
+ let lineNumber = 0;
350
+ try {
351
+ for await (const chunk of stream) {
352
+ buffer += String(chunk);
353
+ let newline = buffer.indexOf("\n");
354
+ while (newline !== -1) {
355
+ const line = buffer.slice(0, newline);
356
+ buffer = buffer.slice(newline + 1);
357
+ lineNumber += 1;
358
+ const entry = parseCompleteJournalLine(line, lineNumber, migrate);
359
+ if (entry) {
360
+ yield options.preserveRefs ? entry : await rehydrateEntryArtifacts(entry, runDir);
361
+ }
362
+ newline = buffer.indexOf("\n");
363
+ }
364
+ }
365
+ } catch (err) {
366
+ const code = err?.code;
367
+ if (code === "ENOENT" && lineNumber === 0 && !buffer)
368
+ return;
369
+ throw err;
370
+ }
371
+ if (!buffer.trim())
372
+ return;
373
+ try {
374
+ const entry = migrate(JSON.parse(buffer));
375
+ yield options.preserveRefs ? entry : await rehydrateEntryArtifacts(entry, runDir);
376
+ } catch {
377
+ }
378
+ }
379
+ function loadJournalSync(options) {
380
+ const paths = resolveJournalPaths(options);
381
+ if (!existsSync(paths.journalPath))
382
+ return [];
383
+ const text = readFileSync(paths.journalPath, "utf8");
384
+ return parseJournalText(text, options.migrate ?? migrateJournalEntry);
385
+ }
386
+ async function loadJournalFromPath(path, options = {}) {
387
+ const entries = [];
388
+ for await (const entry of streamJournal(path, options)) {
389
+ entries.push(entry);
390
+ }
391
+ return entries;
392
+ }
393
+ function parseJournalText(text, migrate) {
394
+ const lines = text.split("\n");
395
+ const entries = [];
396
+ for (let index = 0; index < lines.length; index += 1) {
397
+ const line = lines[index];
398
+ if (!line.trim())
399
+ continue;
400
+ try {
401
+ entries.push(migrate(JSON.parse(line)));
402
+ } catch (err) {
403
+ const isTrailingLine = lines.slice(index + 1).every((rest) => rest.trim() === "");
404
+ const lineWasTerminated = index < lines.length - 1;
405
+ if (isTrailingLine && !lineWasTerminated)
406
+ break;
407
+ const msg = err instanceof Error ? err.message : String(err);
408
+ throw new Error(`Invalid journal line ${index + 1}: ${msg}`);
409
+ }
410
+ }
411
+ return entries;
412
+ }
413
+ function parseCompleteJournalLine(line, lineNumber, migrate) {
414
+ if (!line.trim())
415
+ return void 0;
416
+ try {
417
+ return migrate(JSON.parse(line));
418
+ } catch (err) {
419
+ const msg = err instanceof Error ? err.message : String(err);
420
+ throw new Error(`Invalid journal line ${lineNumber}: ${msg}`);
421
+ }
422
+ }
423
+ async function rehydrateEntryArtifacts(entry, runDir) {
424
+ const artifacts = entry.artifacts;
425
+ if (!artifacts || artifacts.length === 0)
426
+ return entry;
427
+ const resolved = await Promise.all(artifacts.map((artifact) => artifact.kind === "ref" ? rehydrateRefArtifact(artifact, runDir) : artifact));
428
+ return { ...entry, artifacts: resolved };
429
+ }
430
+ async function rehydrateRefArtifact(artifact, runDir) {
431
+ const sidecarPath = resolveSidecarPath(runDir, artifact.ref);
432
+ let bytes;
433
+ try {
434
+ bytes = await readFile(sidecarPath);
435
+ } catch (err) {
436
+ const code = err?.code;
437
+ if (code === "ENOENT") {
438
+ throw new Error(`Journal sidecar artifact missing: ${artifact.ref}`);
439
+ }
440
+ throw err;
441
+ }
442
+ const encoding = artifact.mediaType && !artifact.mediaType.startsWith("text/") && !artifact.mediaType.includes("json") ? "base64" : "utf8";
443
+ const inline = {
444
+ kind: "inline",
445
+ ...artifact.name ? { name: artifact.name } : {},
446
+ ...artifact.mediaType ? { mediaType: artifact.mediaType } : {},
447
+ content: encoding === "base64" ? bytes.toString("base64") : bytes.toString("utf8"),
448
+ encoding,
449
+ sha256: artifact.sha256,
450
+ size: artifact.size
451
+ };
452
+ return inline;
453
+ }
454
+ function resolveSidecarPath(runDir, ref) {
455
+ const root = resolve(runDir);
456
+ const resolved = resolve(root, ref);
457
+ if (resolved !== root && !resolved.startsWith(`${root}${sep}`)) {
458
+ throw new Error(`Journal artifact ref escapes run directory: ${ref}`);
459
+ }
460
+ return resolved;
461
+ }
462
+ var FileJournalWriter = class {
463
+ paths;
464
+ runId;
465
+ sidecarThresholdBytes;
466
+ now;
467
+ idFactory;
468
+ /** Next monotonic seq to assign. Seeded from any pre-existing journal so
469
+ * resumed / branched runs continue the numbering rather than restarting. */
470
+ nextSeq;
471
+ constructor(options) {
472
+ this.runId = options.runId;
473
+ this.paths = resolveJournalPaths(options);
474
+ this.sidecarThresholdBytes = options.sidecarThresholdBytes ?? DEFAULT_JOURNAL_SIDECAR_THRESHOLD_BYTES;
475
+ this.now = options.now ?? (() => /* @__PURE__ */ new Date());
476
+ this.idFactory = options.idFactory ?? randomUUID;
477
+ mkdirSync(this.paths.runDir, { recursive: true, mode: 448 });
478
+ mkdirSync(this.paths.artifactsDir, { recursive: true, mode: 448 });
479
+ fsyncDir(dirname(this.paths.runDir));
480
+ this.nextSeq = seedNextSeq(this.paths.journalPath);
481
+ }
482
+ append(input) {
483
+ const id = input.id ?? this.idFactory();
484
+ const timestamp = input.timestamp ?? this.now().toISOString();
485
+ const artifacts = input.artifacts ? materializeArtifacts(this.paths, input.artifacts, this.sidecarThresholdBytes) : void 0;
486
+ const seq = input.seq ?? this.nextSeq;
487
+ this.nextSeq = Math.max(this.nextSeq, seq) + 1;
488
+ const { artifacts: _inputArtifacts, id: _inputId, timestamp: _inputTimestamp, seq: _inputSeq, ...rest } = input;
489
+ const entry = {
490
+ schemaVersion: JOURNAL_SCHEMA_VERSION,
491
+ id,
492
+ runId: this.runId,
493
+ seq,
494
+ timestamp,
495
+ ...rest,
496
+ ...artifacts && artifacts.length > 0 ? { artifacts } : {}
497
+ };
498
+ atomicAppendJsonLine(this.paths.journalPath, entry);
499
+ return entry;
500
+ }
501
+ load() {
502
+ return loadJournal({ runId: this.runId, runDir: this.paths.runDir });
503
+ }
504
+ };
505
+ function seedNextSeq(journalPath) {
506
+ if (!existsSync(journalPath))
507
+ return 0;
508
+ let text;
509
+ try {
510
+ text = readFileSync(journalPath, "utf8");
511
+ } catch {
512
+ return 0;
513
+ }
514
+ const lines = text.split("\n").filter((line) => line.trim() !== "");
515
+ if (lines.length === 0)
516
+ return 0;
517
+ let maxSeq = -1;
518
+ let sawSeq = false;
519
+ for (const line of lines) {
520
+ try {
521
+ const parsed = JSON.parse(line);
522
+ if (typeof parsed.seq === "number" && Number.isFinite(parsed.seq)) {
523
+ sawSeq = true;
524
+ if (parsed.seq > maxSeq)
525
+ maxSeq = parsed.seq;
526
+ }
527
+ } catch {
528
+ }
529
+ }
530
+ return sawSeq ? maxSeq + 1 : lines.length;
531
+ }
532
+ function materializeArtifacts(paths, artifacts, thresholdBytes) {
533
+ return artifacts.map((artifact) => {
534
+ const bytes = artifact.content instanceof Uint8Array ? Buffer.from(artifact.content) : Buffer.from(artifact.content, "utf8");
535
+ const sha256 = createHash("sha256").update(bytes).digest("hex");
536
+ const size = bytes.byteLength;
537
+ if (artifact.forceSidecar || size > thresholdBytes) {
538
+ const ext = sanitizeExtension(artifact.ext ?? inferExtension(artifact));
539
+ const filename = `${sha256}.${ext}`;
540
+ const absPath = join(paths.artifactsDir, filename);
541
+ atomicWriteFile(absPath, bytes);
542
+ const ref = {
543
+ kind: "ref",
544
+ ...artifact.name ? { name: artifact.name } : {},
545
+ ...artifact.mediaType ? { mediaType: artifact.mediaType } : {},
546
+ ref: `artifacts/${filename}`,
547
+ sha256,
548
+ size
549
+ };
550
+ return ref;
551
+ }
552
+ const binary = artifact.content instanceof Uint8Array;
553
+ const inline = {
554
+ kind: "inline",
555
+ ...artifact.name ? { name: artifact.name } : {},
556
+ ...artifact.mediaType ? { mediaType: artifact.mediaType } : {},
557
+ content: binary ? bytes.toString("base64") : bytes.toString("utf8"),
558
+ encoding: binary ? "base64" : "utf8",
559
+ sha256,
560
+ size
561
+ };
562
+ return inline;
563
+ });
564
+ }
565
+ function inferExtension(artifact) {
566
+ if (artifact.mediaType?.includes("json"))
567
+ return "json";
568
+ if (artifact.mediaType?.startsWith("text/"))
569
+ return "txt";
570
+ return typeof artifact.content === "string" ? "txt" : "bin";
571
+ }
572
+ function sanitizeExtension(ext) {
573
+ const cleaned = ext.replace(/^\.+/, "").replace(/[^A-Za-z0-9_-]/g, "").slice(0, 16);
574
+ return cleaned || "bin";
575
+ }
576
+ var LINUX_PIPE_BUF = 4096;
577
+ function atomicAppendJsonLine(path, entry) {
578
+ mkdirSync(dirname(path), { recursive: true, mode: 448 });
579
+ const line = JSON.stringify(entry) + "\n";
580
+ const bytes = Buffer.from(line, "utf8");
581
+ if (bytes.byteLength > LINUX_PIPE_BUF) {
582
+ process.emitWarning(`journal line ${bytes.byteLength}B exceeds PIPE_BUF (${LINUX_PIPE_BUF}B); concurrent writers may interleave. Consider forcing the artifact to a sidecar.`, { code: "0SEC_JOURNAL_LINE_TOO_LARGE", type: "Warning" });
583
+ }
584
+ const fd = openSync(path, "a", 384);
585
+ try {
586
+ writeSync(fd, bytes);
587
+ fsyncSync(fd);
588
+ } finally {
589
+ closeSync(fd);
590
+ }
591
+ }
592
+ function atomicWriteFile(path, data) {
593
+ const dir = dirname(path);
594
+ mkdirSync(dir, { recursive: true, mode: 448 });
595
+ const tmp = join(dir, `.${Date.now()}-${randomUUID()}.tmp`);
596
+ const bytes = typeof data === "string" ? Buffer.from(data, "utf8") : Buffer.from(data);
597
+ const fd = openSync(tmp, "w", 384);
598
+ try {
599
+ writeSync(fd, bytes);
600
+ fsyncSync(fd);
601
+ } finally {
602
+ closeSync(fd);
603
+ }
604
+ renameSync(tmp, path);
605
+ fsyncDir(dir);
606
+ }
607
+ function fsyncDir(dir) {
608
+ try {
609
+ if (!existsSync(dir) || !statSync(dir).isDirectory())
610
+ return;
611
+ const fd = openSync(dir, "r");
612
+ try {
613
+ fsyncSync(fd);
614
+ } finally {
615
+ closeSync(fd);
616
+ }
617
+ } catch {
618
+ }
619
+ }
620
+
621
+ // packages/core/dist/agent/journal/credential-shared.js
622
+ function buildCredentialSharedEntry(record) {
623
+ const sourceTarget = record.sourceTarget.trim();
624
+ const destTarget = record.destTarget.trim();
625
+ const credentialKind = record.credentialKind.trim();
626
+ const originatingFindingId = record.originatingFindingId.trim();
627
+ if (!sourceTarget)
628
+ throw new Error("credential_shared: sourceTarget is required");
629
+ if (!destTarget)
630
+ throw new Error("credential_shared: destTarget is required");
631
+ if (!credentialKind)
632
+ throw new Error("credential_shared: credentialKind is required");
633
+ if (!originatingFindingId)
634
+ throw new Error("credential_shared: originatingFindingId is required");
635
+ return {
636
+ kind: "credential_shared",
637
+ sourceTarget,
638
+ destTarget,
639
+ credentialKind,
640
+ originatingFindingId,
641
+ ...record.rationale ? { rationale: record.rationale } : {},
642
+ ...record.turn !== void 0 ? { turn: record.turn } : {}
643
+ };
644
+ }
645
+ function appendCredentialShared(sink, record) {
646
+ sink.append(buildCredentialSharedEntry(record));
647
+ }
648
+
649
+ export {
650
+ JOURNAL_SCHEMA_VERSION,
651
+ DEFAULT_JOURNAL_SIDECAR_THRESHOLD_BYTES,
652
+ migrateJournalEntry,
653
+ appendCredentialShared,
654
+ rehydrateContext,
655
+ renderSeedMessages,
656
+ defaultJournalRootDir,
657
+ resolveJournalPaths,
658
+ branchJournal,
659
+ createJournalWriter,
660
+ loadJournal,
661
+ streamJournal
662
+ };