@tacuchi/agent-workflow-cli 21.8.0 → 21.9.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 (60) hide show
  1. package/dist/adapters/git-cli.js +217 -0
  2. package/dist/adapters/git-cli.js.map +1 -1
  3. package/dist/application/flow/flow-service.js +7 -0
  4. package/dist/application/flow/flow-service.js.map +1 -1
  5. package/dist/application/flow/internal-actions.js +5 -0
  6. package/dist/application/flow/internal-actions.js.map +1 -1
  7. package/dist/application/history-table.js +37 -0
  8. package/dist/application/history-table.js.map +1 -1
  9. package/dist/application/local-proposal.js +37 -0
  10. package/dist/application/local-proposal.js.map +1 -1
  11. package/dist/application/retirement/apply.js +448 -0
  12. package/dist/application/retirement/apply.js.map +1 -0
  13. package/dist/application/retirement/attribution.js +395 -0
  14. package/dist/application/retirement/attribution.js.map +1 -0
  15. package/dist/application/retirement/graph.js +196 -0
  16. package/dist/application/retirement/graph.js.map +1 -0
  17. package/dist/application/retirement/history-events.js +158 -0
  18. package/dist/application/retirement/history-events.js.map +1 -0
  19. package/dist/application/retirement/journal.js +113 -0
  20. package/dist/application/retirement/journal.js.map +1 -0
  21. package/dist/application/retirement/prepare.js +233 -0
  22. package/dist/application/retirement/prepare.js.map +1 -0
  23. package/dist/application/retirement/preview.js +101 -0
  24. package/dist/application/retirement/preview.js.map +1 -0
  25. package/dist/application/retirement/resolve.js +356 -0
  26. package/dist/application/retirement/resolve.js.map +1 -0
  27. package/dist/application/session-create-service.js +103 -12
  28. package/dist/application/session-create-service.js.map +1 -1
  29. package/dist/application/session-custody-recorder.js +137 -0
  30. package/dist/application/session-custody-recorder.js.map +1 -0
  31. package/dist/application/session-custody-service.js +171 -0
  32. package/dist/application/session-custody-service.js.map +1 -0
  33. package/dist/application/status-service.js +5 -0
  34. package/dist/application/status-service.js.map +1 -1
  35. package/dist/application/workline-index-service.js +31 -0
  36. package/dist/application/workline-index-service.js.map +1 -1
  37. package/dist/application/worktree-service.js +47 -1
  38. package/dist/application/worktree-service.js.map +1 -1
  39. package/dist/cli/commands/index.js +6 -0
  40. package/dist/cli/commands/index.js.map +1 -1
  41. package/dist/cli/commands/retirement.js +137 -0
  42. package/dist/cli/commands/retirement.js.map +1 -0
  43. package/dist/cli/commands/session-create.js +4 -1
  44. package/dist/cli/commands/session-create.js.map +1 -1
  45. package/dist/cli/help-groups.js +4 -0
  46. package/dist/cli/help-groups.js.map +1 -1
  47. package/dist/domain/flow/authority.js +8 -0
  48. package/dist/domain/flow/authority.js.map +1 -1
  49. package/dist/domain/retirement/proposal.js +83 -0
  50. package/dist/domain/retirement/proposal.js.map +1 -0
  51. package/dist/domain/retirement/selector.js +109 -0
  52. package/dist/domain/retirement/selector.js.map +1 -0
  53. package/dist/domain/session/custody.js +176 -0
  54. package/dist/domain/session/custody.js.map +1 -0
  55. package/dist/domain/workline-node.js +56 -0
  56. package/dist/domain/workline-node.js.map +1 -0
  57. package/package.json +1 -1
  58. package/skills/w/commands/discard.md +49 -0
  59. package/skills/w/commands/reset.md +50 -0
  60. package/skills/w/context/MANIFEST.json +147 -139
@@ -0,0 +1,356 @@
1
+ /**
2
+ * From "what did they name" to "exactly which nodes come out", or a refusal.
3
+ *
4
+ * Everything here is read-only and every refusal is actionable: a destructive
5
+ * command that answers "no" without saying which candidates it saw, or which edge
6
+ * it could not prove, forces the person to guess — and guessing is what the whole
7
+ * design exists to prevent. So each rejection carries its code, the candidates and
8
+ * the one next move.
9
+ *
10
+ * The two modes ask genuinely different questions and share only the graph:
11
+ *
12
+ * - **discard** asks "what does this node OWN, transitively and exclusively?"
13
+ * Anything reachable through a provable edge comes out with it; a node that also
14
+ * belongs to something outside the closure stops the whole operation.
15
+ * - **reset** asks "which single INCOMPLETE session is this, and what did it
16
+ * receive?" It never cascades: work that descends from what the session produced
17
+ * would be orphaned, so its presence is a refusal rather than a wider closure.
18
+ */
19
+ import { selectorText } from "../../domain/retirement/selector.js";
20
+ import { formatNodeId, } from "../../domain/workline-node.js";
21
+ /**
22
+ * The node a selector names, or the candidates that make it ambiguous.
23
+ *
24
+ * A bare number is the only form that can be ambiguous by construction, and it is
25
+ * accepted at all because typing `plan:` in front of the number every time is
26
+ * ceremony when only one node answers. The moment two do, the ambiguity is the
27
+ * answer.
28
+ */
29
+ export function resolveTarget(graph, selector) {
30
+ const matches = candidatesFor(graph, selector);
31
+ if (matches.length === 1 && matches[0] !== undefined)
32
+ return { ok: true, node: matches[0] };
33
+ if (matches.length === 0) {
34
+ return {
35
+ ok: false,
36
+ rejection: {
37
+ code: "TARGET_NOT_FOUND",
38
+ message: `no existe ningún nodo que coincida con '${selectorText(selector)}'`,
39
+ candidates: [],
40
+ action: "revisá `aw status` y reintentá con una identidad existente",
41
+ },
42
+ };
43
+ }
44
+ return {
45
+ ok: false,
46
+ rejection: {
47
+ code: "TARGET_AMBIGUOUS",
48
+ message: `'${selectorText(selector)}' coincide con ${matches.length} nodos`,
49
+ candidates: matches.map((n) => formatNodeId(n.id)),
50
+ action: "reintentá con la forma explícita: spec:<NNN>, plan:<PPP>, quick:<NNN> o session:<carpeta>",
51
+ },
52
+ };
53
+ }
54
+ function candidatesFor(graph, selector) {
55
+ switch (selector.form) {
56
+ case "path":
57
+ return graph.all().filter((n) => n.path === selector.path);
58
+ case "folder":
59
+ return graph
60
+ .all()
61
+ .filter((n) => n.kind === "session" && n.session?.folder === selector.folder);
62
+ case "qualified":
63
+ return selector.kind === "quick"
64
+ ? quickCandidates(graph, selector.key)
65
+ : graph.all().filter((n) => n.kind === selector.kind && matchesKey(n, selector.key));
66
+ case "bare":
67
+ return graph.all().filter((n) => matchesKey(n, selector.key));
68
+ }
69
+ }
70
+ /**
71
+ * `quick:<NNN>` addresses a SESSION whose flow was the quick one.
72
+ *
73
+ * A quick has no document of its own, so it is not a node kind — it is a session
74
+ * with a type. Keeping it out of the graph's vocabulary and in the selector's is
75
+ * what stops the graph from having a fourth kind that owns nothing.
76
+ */
77
+ function quickCandidates(graph, key) {
78
+ return graph
79
+ .all()
80
+ .filter((n) => n.kind === "session" && n.session?.type === "quick" && matchesKey(n, key));
81
+ }
82
+ /** A session answers to its number as well as to its folder; a doc only to its number. */
83
+ function matchesKey(node, key) {
84
+ if (node.kind !== "session")
85
+ return node.id.key === key;
86
+ const folder = node.session?.folder ?? node.id.key;
87
+ return folder === key || folder.startsWith(`${key}-`) || folder.startsWith(`session${key}-`);
88
+ }
89
+ /**
90
+ * Everything a discard takes with it, or the reason it takes nothing.
91
+ *
92
+ * The walk only ever follows PROVABLE edges, and it checks two things about each
93
+ * node it reaches: that its own custody can still say what it owns, and that
94
+ * nothing outside the closure descends from it. The second check is what makes
95
+ * "exclusive ownership" a computed fact — a session that belongs to two plans is
96
+ * not a descendant of either, it is shared work, and the operation stops.
97
+ */
98
+ export function resolveDiscardClosure(graph, target) {
99
+ const walked = walkDescendants(graph, target);
100
+ if ("rejection" in walked)
101
+ return { ok: false, rejection: walked.rejection };
102
+ const shared = sharedConsumer(graph, walked.collected);
103
+ if (shared !== null)
104
+ return { ok: false, rejection: shared };
105
+ const missing = missingEvidence([...walked.collected.values()].map((e) => e.node));
106
+ if (missing !== null)
107
+ return { ok: false, rejection: missing };
108
+ return {
109
+ ok: true,
110
+ closure: { mode: "discard", target, entries: removalOrder([...walked.collected.values()]) },
111
+ };
112
+ }
113
+ /**
114
+ * The breadth-first walk down the provable edges, or the first edge that stops it.
115
+ *
116
+ * Separated from the checks that follow it because the two ask different
117
+ * questions: this one is "what hangs off the target", and the ones after it are
118
+ * "may we take all of that". Reading them together is what made a single function
119
+ * hard to hold in the head.
120
+ */
121
+ function walkDescendants(graph, target) {
122
+ const collected = new Map();
123
+ collected.set(formatNodeId(target.id), { node: target, reason: "target" });
124
+ const pending = [target.id];
125
+ const seen = new Set();
126
+ while (pending.length > 0) {
127
+ const current = pending.shift();
128
+ const key = formatNodeId(current);
129
+ if (seen.has(key))
130
+ continue;
131
+ seen.add(key);
132
+ // An edge nobody can prove cannot be followed AND cannot be ignored: the node
133
+ // on its other end may or may not belong here, and both answers are guesses.
134
+ const unprovable = graph.unprovableInto(current);
135
+ if (unprovable.length > 0)
136
+ return { rejection: unprovableEdges(key, unprovable) };
137
+ const rejection = collectChildren(graph, current, collected, pending);
138
+ if (rejection !== null)
139
+ return { rejection };
140
+ }
141
+ return { collected };
142
+ }
143
+ /** One node's children into the closure, or the cycle that has no removal order. */
144
+ function collectChildren(graph, parent, collected, pending) {
145
+ const parentKey = formatNodeId(parent);
146
+ for (const edge of graph.childrenOf(parent)) {
147
+ const child = graph.get(edge.from);
148
+ if (child === undefined)
149
+ continue;
150
+ const childKey = formatNodeId(child.id);
151
+ if (childKey === parentKey)
152
+ return cyclic(childKey);
153
+ if (!collected.has(childKey)) {
154
+ collected.set(childKey, {
155
+ node: child,
156
+ reason: child.kind === "session" ? "internal-session" : "descendant",
157
+ });
158
+ }
159
+ pending.push(child.id);
160
+ }
161
+ return null;
162
+ }
163
+ function unprovableEdges(key, edges) {
164
+ return {
165
+ code: "EVIDENCE_MISSING",
166
+ message: `'${key}' tiene descendientes cuya procedencia no se puede probar`,
167
+ candidates: edges.map((e) => `${formatNodeId(e.from)} (${e.evidence})`),
168
+ action: "esas sesiones nacieron sin custodia: retirálas individualmente por su carpeta, o dejá el objetivo como está",
169
+ };
170
+ }
171
+ /**
172
+ * A node inside the closure that something OUTSIDE also descends from.
173
+ *
174
+ * Counted over the closure's own members rather than over the target alone,
175
+ * because the sharing that matters can be two levels down: a session that hangs
176
+ * off both the plan being discarded and another one is not the target's to delete,
177
+ * even though the target never mentions it.
178
+ */
179
+ function sharedConsumer(graph, collected) {
180
+ for (const { node } of collected.values()) {
181
+ for (const edge of graph.parentsOf(node.id)) {
182
+ if (collected.has(formatNodeId(edge.to)))
183
+ continue;
184
+ // A parent outside the closure is normal for the TARGET itself — that is
185
+ // what it hangs from. It is only sharing when the node came in as a
186
+ // descendant, because then two things own it.
187
+ const entry = collected.get(formatNodeId(node.id));
188
+ if (entry?.reason === "target")
189
+ continue;
190
+ return {
191
+ code: "SHARED_CONSUMER",
192
+ message: `'${formatNodeId(node.id)}' también pertenece a '${formatNodeId(edge.to)}', fuera del alcance`,
193
+ candidates: [formatNodeId(node.id), formatNodeId(edge.to)],
194
+ action: "el alcance no es de propiedad exclusiva: retirá primero el consumidor compartido o elegí un objetivo más chico",
195
+ };
196
+ }
197
+ }
198
+ return null;
199
+ }
200
+ /** A session in the closure whose custody cannot say what it owns. */
201
+ function missingEvidence(nodes) {
202
+ for (const node of nodes) {
203
+ const gap = node.session?.custody_gap ?? null;
204
+ if (gap === null)
205
+ continue;
206
+ return {
207
+ code: "EVIDENCE_MISSING",
208
+ message: `'${formatNodeId(node.id)}' no tiene una custodia reconstruible: ${gap}`,
209
+ candidates: [formatNodeId(node.id)],
210
+ action: "sin baseline no se puede probar qué le pertenece: cerrá o retirá esa sesión a mano antes de retirar el objetivo",
211
+ };
212
+ }
213
+ return null;
214
+ }
215
+ function cyclic(key) {
216
+ return {
217
+ code: "CYCLIC_PROVENANCE",
218
+ message: `la procedencia de '${key}' se cierra sobre sí misma`,
219
+ candidates: [key],
220
+ action: "corregí la procedencia declarada antes de retirar: un ciclo no tiene orden de retiro",
221
+ };
222
+ }
223
+ /**
224
+ * Sessions first, then documents, deepest first.
225
+ *
226
+ * Removal order is material — it is in the seal — because a document removed
227
+ * before the sessions that point at it leaves, for as long as the operation runs,
228
+ * a session whose provenance resolves to nothing.
229
+ */
230
+ function removalOrder(entries) {
231
+ const rank = (entry) => {
232
+ if (entry.node.kind === "session")
233
+ return 0;
234
+ if (entry.reason === "target")
235
+ return 2;
236
+ return 1;
237
+ };
238
+ return [...entries].sort((a, b) => {
239
+ const byRank = rank(a) - rank(b);
240
+ if (byRank !== 0)
241
+ return byRank;
242
+ return formatNodeId(a.node.id) < formatNodeId(b.node.id) ? -1 : 1;
243
+ });
244
+ }
245
+ /**
246
+ * The single incomplete session a reset target names.
247
+ *
248
+ * A session can be named directly; a document names one only when exactly one of
249
+ * its sessions is incomplete. Both roads end in the same requirement, and the
250
+ * assumption behind it is explicit in the spec: a FINISHED session does not become
251
+ * resettable by being selected.
252
+ */
253
+ export function resolveResetSession(graph, target) {
254
+ if (target.kind === "session") {
255
+ const facts = target.session;
256
+ if (facts === null)
257
+ return { ok: false, rejection: noIncomplete(formatNodeId(target.id)) };
258
+ if (facts.completion === "converged") {
259
+ return {
260
+ ok: false,
261
+ rejection: {
262
+ code: "RESET_SESSION_CONVERGED",
263
+ message: `la sesión '${facts.folder}' ya convergió: no es una sesión incompleta`,
264
+ candidates: [facts.folder],
265
+ action: "para retirarla junto con lo que produjo usá `aw discard`; `reset` sólo vuelve atrás lo inconcluso",
266
+ },
267
+ };
268
+ }
269
+ if (facts.completion === "unknown") {
270
+ return {
271
+ ok: false,
272
+ rejection: {
273
+ code: "EVIDENCE_MISSING",
274
+ message: `no se puede probar hasta dónde llegó '${facts.folder}': ${facts.custody_gap ?? "sin evidencia"}`,
275
+ candidates: [facts.folder],
276
+ action: "es una sesión legacy: no hay baseline que restaurar, y reset no lo inventa",
277
+ },
278
+ };
279
+ }
280
+ return { ok: true, node: target };
281
+ }
282
+ const sessions = graph.sessionsOf(target.id);
283
+ const incomplete = sessions.filter((s) => s.session?.completion === "incomplete");
284
+ if (incomplete.length === 1 && incomplete[0] !== undefined) {
285
+ return resolveResetSession(graph, incomplete[0]);
286
+ }
287
+ if (incomplete.length === 0) {
288
+ return { ok: false, rejection: noIncomplete(formatNodeId(target.id), sessions) };
289
+ }
290
+ return {
291
+ ok: false,
292
+ rejection: {
293
+ code: "RESET_AMBIGUOUS_SESSION",
294
+ message: `'${formatNodeId(target.id)}' tiene ${incomplete.length} sesiones incompletas`,
295
+ candidates: incomplete.map((s) => s.session?.folder ?? formatNodeId(s.id)),
296
+ action: "nombrá la sesión exacta con session:<carpeta>",
297
+ },
298
+ };
299
+ }
300
+ function noIncomplete(target, seen = []) {
301
+ return {
302
+ code: "RESET_NO_INCOMPLETE_SESSION",
303
+ message: `'${target}' no resuelve a ninguna sesión incompleta`,
304
+ candidates: seen.map((s) => `${s.session?.folder ?? formatNodeId(s.id)} (${s.session?.completion ?? "?"})`),
305
+ action: "reset necesita una sesión que no haya convergido; revisá `aw status --detail`",
306
+ };
307
+ }
308
+ /**
309
+ * What a reset takes out: the session, plus the documents it BORN.
310
+ *
311
+ * It stops at one level on purpose. A document this session created that already
312
+ * has work of its own is not something a reset may remove — that work would be
313
+ * orphaned — so its presence is a refusal, which is the same rule discard applies
314
+ * to shared ownership, read from the other direction.
315
+ */
316
+ export function resolveResetClosure(graph, session) {
317
+ const entries = [
318
+ { node: session, reason: "target" },
319
+ ];
320
+ const custody = session.session?.custody ?? null;
321
+ if (custody === null) {
322
+ return {
323
+ ok: false,
324
+ rejection: {
325
+ code: "EVIDENCE_MISSING",
326
+ message: `'${formatNodeId(session.id)}' no tiene custodia: no hay salidas ni entradas que probar`,
327
+ candidates: [formatNodeId(session.id)],
328
+ action: "es una sesión legacy: retirala a mano o usá discard sobre su carpeta",
329
+ },
330
+ };
331
+ }
332
+ for (const artifact of custody.artifacts) {
333
+ if (artifact.role !== "output")
334
+ continue;
335
+ const node = graph.all().find((n) => n.path === artifact.path);
336
+ if (node === undefined)
337
+ continue;
338
+ const others = graph
339
+ .childrenOf(node.id)
340
+ .filter((e) => formatNodeId(e.from) !== formatNodeId(session.id));
341
+ if (others.length > 0) {
342
+ return {
343
+ ok: false,
344
+ rejection: {
345
+ code: "SHARED_CONSUMER",
346
+ message: `'${artifact.path}' ya tiene trabajo que depende de él`,
347
+ candidates: others.map((e) => formatNodeId(e.from)),
348
+ action: "retirá primero ese trabajo, o usá discard sobre el documento si querés llevártelo todo",
349
+ },
350
+ };
351
+ }
352
+ entries.push({ node, reason: "descendant" });
353
+ }
354
+ return { ok: true, closure: { mode: "reset", target: session, entries: removalOrder(entries) } };
355
+ }
356
+ //# sourceMappingURL=resolve.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolve.js","sourceRoot":"","sources":["../../../src/application/retirement/resolve.ts"],"names":[],"mappings":"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"}
@@ -1,7 +1,12 @@
1
1
  import { join } from "node:path";
2
+ import { checkSafeRelativePath } from "../domain/safe-path.js";
3
+ import { nodeFromDocPath } from "../domain/workline-node.js";
4
+ import { localDateIso } from "./dates.js";
5
+ import { maxHistoryNumber } from "./history-table.js";
2
6
  import { withCwdLock } from "./lock-service.js";
3
7
  import { canonicalArtifactPath } from "./session-artifacts.js";
4
8
  import { bindContextToSession, readBindingRegistry } from "./session-binding-service.js";
9
+ import { baselineOf, birthCustody, custodyPath, writeCustody } from "./session-custody-service.js";
5
10
  import { renderSessionMarkdown } from "./templates/session.js";
6
11
  const VALID_TYPES = ["research", "refine", "exec", "quick"];
7
12
  export async function runSessionCreate(fs, paths, input) {
@@ -9,7 +14,14 @@ export async function runSessionCreate(fs, paths, input) {
9
14
  if ("error" in validated)
10
15
  return validated;
11
16
  const { type, name, objetivo } = validated;
12
- const folderInfo = await claimSessionFolder(fs, paths, name, input.contextId);
17
+ // Baselines are read BEFORE the claim so the bytes sealed are the ones that
18
+ // existed before this session could touch anything, and a declared input that
19
+ // cannot be read fails the creation instead of producing a custody that
20
+ // pretends to know what it received.
21
+ const baselines = await readBaselines(fs, paths, input.inputs ?? []);
22
+ if ("error" in baselines)
23
+ return baselines;
24
+ const folderInfo = await claimSessionFolder(fs, paths, name, input.contextId, baselines.artifacts);
13
25
  if ("error" in folderInfo)
14
26
  return folderInfo;
15
27
  const sessionPath = folderInfo.sessionPath;
@@ -28,11 +40,47 @@ export async function runSessionCreate(fs, paths, input) {
28
40
  folder: folderInfo.folder,
29
41
  path: sessionPath,
30
42
  session_path: sessionFilePath,
43
+ custody_path: folderInfo.custodyPath,
44
+ inputs: baselines.artifacts.map((a) => a.path),
31
45
  };
32
46
  if (origin && origin.length > 0)
33
47
  record.origin = origin;
34
48
  return { sessionCreate: record };
35
49
  }
50
+ /**
51
+ * The sealed previous state of every declared input, or the refusal.
52
+ *
53
+ * The path guard is the workspace's own (`checkSafeRelativePath`), the same one
54
+ * every other write boundary uses: a second, hand-rolled version of "is this
55
+ * relative" is how two boundaries end up disagreeing about which paths are
56
+ * allowed. A repeated input is collapsed rather than sealed twice — the baseline
57
+ * of a path is one fact.
58
+ */
59
+ async function readBaselines(fs, paths, inputs) {
60
+ const artifacts = [];
61
+ const root = paths.workspaceDir();
62
+ for (const raw of inputs) {
63
+ const safe = checkSafeRelativePath(raw);
64
+ if (!safe.ok) {
65
+ return {
66
+ error: `--input '${raw}' tiene que ser una ruta relativa al workspace: ${safe.why}`,
67
+ code: "INVALID_INPUT",
68
+ };
69
+ }
70
+ if (artifacts.some((a) => a.path === safe.path))
71
+ continue;
72
+ try {
73
+ artifacts.push(await baselineOf(fs, root, safe.path));
74
+ }
75
+ catch (err) {
76
+ return {
77
+ error: `no se pudo sellar el estado previo de '${safe.path}': ${err instanceof Error ? err.message : String(err)}`,
78
+ code: "CUSTODY_BASELINE_UNREADABLE",
79
+ };
80
+ }
81
+ }
82
+ return { artifacts };
83
+ }
36
84
  function validateInput(input) {
37
85
  const type = input.type?.trim().toLowerCase();
38
86
  if (!type) {
@@ -56,11 +104,17 @@ function validateInput(input) {
56
104
  return { type: type, name, objetivo };
57
105
  }
58
106
  /**
59
- * Claim number + folder + conversation association under ONE lock: two
107
+ * Claim number + folder + custody + conversation association under ONE lock: two
60
108
  * concurrent creations must not read the same counter and race for the same
61
- * `NNN`, and the new line must belong to its conversation the moment it exists.
109
+ * `NNN`, and the new line must belong to its conversation and hold its sealed
110
+ * baseline — the moment it exists.
111
+ *
112
+ * The custody is written INSIDE the critical section for the same reason the
113
+ * number is minted there: a session that becomes visible before its baseline is
114
+ * sealed is a session another process can start driving, and the first mutation
115
+ * would then land against a custody nobody had written yet.
62
116
  */
63
- async function claimSessionFolder(fs, paths, name, contextId) {
117
+ async function claimSessionFolder(fs, paths, name, contextId, artifacts) {
64
118
  const id = contextId?.trim() ?? "";
65
119
  const result = await withCwdLock(fs, paths, async () => {
66
120
  // Fail before creating anything when the registry cannot be read: a session
@@ -82,30 +136,67 @@ async function claimSessionFolder(fs, paths, name, contextId) {
82
136
  // `NNN-` prefix is assigned here. A descriptor that already carries a leading
83
137
  // `NNN-` is normalized away first so the prefix can't double up.
84
138
  const descriptor = name.replace(/^\d{3}-/, "");
85
- const number = await nextSessionNumber(fs, sessionsDir);
139
+ const number = await nextSessionNumber(fs, paths, sessionsDir);
86
140
  const folder = `${number}-${descriptor}`;
87
141
  const sessionPath = join(sessionsDir, folder);
88
142
  if (await fs.exists(sessionPath)) {
89
143
  return { ok: false, failure: { error: `Ya existe ${sessionPath}` } };
90
144
  }
91
145
  await fs.mkdirp(sessionPath);
146
+ await writeCustody(fs, sessionPath, birthCustody({
147
+ subject: { kind: "session", key: folder },
148
+ subjectPath: sessionPath,
149
+ parents: parentsOf(artifacts),
150
+ artifacts,
151
+ created: localDateIso(new Date()),
152
+ }));
92
153
  if (id.length > 0)
93
154
  await bindContextToSession(fs, paths, id, folder);
94
- return { ok: true, info: { folder, number, sessionPath } };
155
+ return {
156
+ ok: true,
157
+ info: { folder, number, sessionPath, custodyPath: custodyPath(sessionPath) },
158
+ };
95
159
  });
96
160
  if ("error" in result)
97
161
  return { error: result.error, code: "LOCK_BUSY" };
98
162
  return result.ok ? result.info : result.failure;
99
163
  }
100
164
  /**
101
- * Next global session number: scan `.workflow/sessions/` for any entry whose name
102
- * starts with a 3-digit code and return max+1, zero-padded. Type-agnostic — one
103
- * sequence for every session regardless of kind. Legacy `sessionNNN-…` folders
104
- * (no leading digit) don't match and are ignored, so the new sequence starts fresh.
165
+ * The typed parents a set of declared inputs implies.
166
+ *
167
+ * An input is the document the run works ON, so the document IS its parent — and
168
+ * the edge is provable, because the path was declared by the caller and its
169
+ * identity is fixed by the workspace layout. An input that names no spec or plan
170
+ * (a checkpoint, a loose file) contributes no parent rather than a guessed one.
171
+ */
172
+ function parentsOf(artifacts) {
173
+ const parents = [];
174
+ for (const artifact of artifacts) {
175
+ const node = nodeFromDocPath(artifact.path);
176
+ if (node === null)
177
+ continue;
178
+ if (parents.some((p) => p.kind === node.kind && p.key === node.key))
179
+ continue;
180
+ parents.push(node);
181
+ }
182
+ return parents;
183
+ }
184
+ /**
185
+ * Next global session number: the maximum of what the sessions folder holds and
186
+ * what `HISTORY.md` remembers, plus one, zero-padded. Type-agnostic — one
187
+ * sequence for every session regardless of kind.
188
+ *
189
+ * HISTORY is read as well as the folder because a RETIRED session leaves no
190
+ * folder behind: scanning live directories alone would hand `119` to a new
191
+ * session after the old `119` was discarded, and the two would then share a row
192
+ * key, a unit branch and a `--code`. Numbering is monotonic even across
193
+ * deletions — an identity is spent once. Legacy `sessionNNN-…` folders carry no
194
+ * leading digit and are ignored by the folder half, while the history half still
195
+ * recognizes their rows.
105
196
  */
106
- async function nextSessionNumber(fs, sessionsDir) {
197
+ async function nextSessionNumber(fs, paths, sessionsDir) {
107
198
  const entries = await fs.list(sessionsDir);
108
- let max = 0;
199
+ let max = await maxHistoryNumber(fs, paths.cwdHistoryFile());
109
200
  for (const entry of entries) {
110
201
  const m = entry.name.match(/^(\d{3})/);
111
202
  if (m?.[1])
@@ -1 +1 @@
1
- {"version":3,"file":"session-create-service.js","sourceRoot":"","sources":["../../src/application/session-create-service.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"session-create-service.js","sourceRoot":"","sources":["../../src/application/session-create-service.ts"],"names":[],"mappings":"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"}