@tacuchi/agent-workflow-cli 21.8.0 → 21.10.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.
- package/dist/adapters/git-cli.js +217 -0
- package/dist/adapters/git-cli.js.map +1 -1
- package/dist/application/check-branch-service.js +48 -20
- package/dist/application/check-branch-service.js.map +1 -1
- package/dist/application/dev-only-services.js +53 -4
- package/dist/application/dev-only-services.js.map +1 -1
- package/dist/application/flow/advance.js +10 -3
- package/dist/application/flow/advance.js.map +1 -1
- package/dist/application/flow/flow-service.js +7 -0
- package/dist/application/flow/flow-service.js.map +1 -1
- package/dist/application/flow/internal-actions.js +74 -3
- package/dist/application/flow/internal-actions.js.map +1 -1
- package/dist/application/flow/internal-drive.js +1 -0
- package/dist/application/flow/internal-drive.js.map +1 -1
- package/dist/application/flow/run-projection.js +10 -4
- package/dist/application/flow/run-projection.js.map +1 -1
- package/dist/application/flow/submit.js +164 -15
- package/dist/application/flow/submit.js.map +1 -1
- package/dist/application/history-table.js +37 -0
- package/dist/application/history-table.js.map +1 -1
- package/dist/application/hook-branch-check.js +17 -0
- package/dist/application/hook-branch-check.js.map +1 -1
- package/dist/application/local-proposal.js +37 -0
- package/dist/application/local-proposal.js.map +1 -1
- package/dist/application/resume-service.js +1 -0
- package/dist/application/resume-service.js.map +1 -1
- package/dist/application/retirement/apply.js +448 -0
- package/dist/application/retirement/apply.js.map +1 -0
- package/dist/application/retirement/attribution.js +395 -0
- package/dist/application/retirement/attribution.js.map +1 -0
- package/dist/application/retirement/graph.js +196 -0
- package/dist/application/retirement/graph.js.map +1 -0
- package/dist/application/retirement/history-events.js +158 -0
- package/dist/application/retirement/history-events.js.map +1 -0
- package/dist/application/retirement/journal.js +113 -0
- package/dist/application/retirement/journal.js.map +1 -0
- package/dist/application/retirement/prepare.js +233 -0
- package/dist/application/retirement/prepare.js.map +1 -0
- package/dist/application/retirement/preview.js +101 -0
- package/dist/application/retirement/preview.js.map +1 -0
- package/dist/application/retirement/resolve.js +356 -0
- package/dist/application/retirement/resolve.js.map +1 -0
- package/dist/application/session-close-service.js +108 -14
- package/dist/application/session-close-service.js.map +1 -1
- package/dist/application/session-create-service.js +103 -12
- package/dist/application/session-create-service.js.map +1 -1
- package/dist/application/session-custody-recorder.js +137 -0
- package/dist/application/session-custody-recorder.js.map +1 -0
- package/dist/application/session-custody-service.js +171 -0
- package/dist/application/session-custody-service.js.map +1 -0
- package/dist/application/session-resolver.js +21 -0
- package/dist/application/session-resolver.js.map +1 -1
- package/dist/application/status-service.js +5 -0
- package/dist/application/status-service.js.map +1 -1
- package/dist/application/workline-index-service.js +31 -0
- package/dist/application/workline-index-service.js.map +1 -1
- package/dist/application/worktree-service.js +247 -34
- package/dist/application/worktree-service.js.map +1 -1
- package/dist/cli/commands/check-branch.js +9 -5
- package/dist/cli/commands/check-branch.js.map +1 -1
- package/dist/cli/commands/dev-only.js +21 -2
- package/dist/cli/commands/dev-only.js.map +1 -1
- package/dist/cli/commands/flow.js +6 -2
- package/dist/cli/commands/flow.js.map +1 -1
- package/dist/cli/commands/index.js +6 -0
- package/dist/cli/commands/index.js.map +1 -1
- package/dist/cli/commands/retirement.js +137 -0
- package/dist/cli/commands/retirement.js.map +1 -0
- package/dist/cli/commands/session-close.js +12 -1
- package/dist/cli/commands/session-close.js.map +1 -1
- package/dist/cli/commands/session-create.js +4 -1
- package/dist/cli/commands/session-create.js.map +1 -1
- package/dist/cli/commands/sources.js +8 -4
- package/dist/cli/commands/sources.js.map +1 -1
- package/dist/cli/commands/worktree.js +14 -7
- package/dist/cli/commands/worktree.js.map +1 -1
- package/dist/cli/help-groups.js +4 -0
- package/dist/cli/help-groups.js.map +1 -1
- package/dist/cli/parser.js +26 -0
- package/dist/cli/parser.js.map +1 -1
- package/dist/domain/flow/answer.js +72 -4
- package/dist/domain/flow/answer.js.map +1 -1
- package/dist/domain/flow/authority.js +219 -47
- package/dist/domain/flow/authority.js.map +1 -1
- package/dist/domain/flow/rules.js +8 -1
- package/dist/domain/flow/rules.js.map +1 -1
- package/dist/domain/flow/run-state.js +34 -1
- package/dist/domain/flow/run-state.js.map +1 -1
- package/dist/domain/reservation.js +33 -0
- package/dist/domain/reservation.js.map +1 -0
- package/dist/domain/retirement/proposal.js +83 -0
- package/dist/domain/retirement/proposal.js.map +1 -0
- package/dist/domain/retirement/selector.js +109 -0
- package/dist/domain/retirement/selector.js.map +1 -0
- package/dist/domain/session/custody.js +176 -0
- package/dist/domain/session/custody.js.map +1 -0
- package/dist/domain/workline-node.js +56 -0
- package/dist/domain/workline-node.js.map +1 -0
- package/package.json +1 -1
- package/skills/w/commands/discard.md +49 -0
- package/skills/w/commands/reset.md +50 -0
- package/skills/w/context/MANIFEST.json +147 -139
- package/skills/w/loops/CODE-POLICIES.md +9 -9
- package/skills/w/loops/plan-exec-loop/LOOP.md +23 -13
- package/skills/w/loops/plan-new-loop/LOOP.md +1 -1
- package/skills/w/modules/PLAN-INPUT.md +1 -1
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The one durable Workline trace a retirement leaves: an append-only row.
|
|
3
|
+
*
|
|
4
|
+
* It is a SECOND table in `HISTORY.md`, under its own heading, and never the
|
|
5
|
+
* session table. The session table is an upsert keyed by session — exactly the
|
|
6
|
+
* wrong shape here, because the session it would key on no longer exists and
|
|
7
|
+
* because a terminal event must never be rewritten. So this ledger only ever
|
|
8
|
+
* grows, and its key is the operation's own digest.
|
|
9
|
+
*
|
|
10
|
+
* That key is what makes the same approval, retried, recognize itself instead of
|
|
11
|
+
* appending a second row for one operation. It is also the re-entry signal for a
|
|
12
|
+
* retirement with no git side at all: with no ref to compare, the presence of this
|
|
13
|
+
* row IS the answer to "did the commit point pass".
|
|
14
|
+
*/
|
|
15
|
+
import { formatNodeId } from "../../domain/workline-node.js";
|
|
16
|
+
import { localDateIso } from "../dates.js";
|
|
17
|
+
import { ensureHistoryFile } from "../history-table.js";
|
|
18
|
+
const HEADING = "## Retiros";
|
|
19
|
+
const TABLE_HEADER = "| Operación | Fecha | Comando | Objetivo | Resultado |\n" +
|
|
20
|
+
"|-----------|-------|---------|----------|-----------|";
|
|
21
|
+
/** Short enough to read, long enough to identify: the digest's first 12 chars. */
|
|
22
|
+
function key(digest) {
|
|
23
|
+
return digest.slice(0, 12);
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* The row a successful retirement adds, derived from the sealed proposal.
|
|
27
|
+
*
|
|
28
|
+
* Every cell comes from the object that was authorized: the command, the target,
|
|
29
|
+
* what disappeared or was restored, and what happened in git. A row assembled from
|
|
30
|
+
* a later reading of the workspace could describe something the person never
|
|
31
|
+
* approved.
|
|
32
|
+
*/
|
|
33
|
+
export function eventOf(proposal, now = new Date()) {
|
|
34
|
+
const git = proposal.publication === null
|
|
35
|
+
? "sin efectos git"
|
|
36
|
+
: `${proposal.reverts.length} revert(s) en ${proposal.publication.ref} → árbol ${proposal.publication.expected_tree.slice(0, 12)}${proposal.reverts.some((r) => r.published)
|
|
37
|
+
? " · publicación remota pendiente y externa"
|
|
38
|
+
: ""}`;
|
|
39
|
+
return {
|
|
40
|
+
operation: key(proposal.digest),
|
|
41
|
+
date: localDateIso(now),
|
|
42
|
+
command: proposal.event.command,
|
|
43
|
+
target: formatNodeId(proposal.target),
|
|
44
|
+
result: `${proposal.event.summary} · ${git}`,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Every terminal event the ledger holds, oldest first.
|
|
49
|
+
*
|
|
50
|
+
* Read for the projections, and kept strictly apart from `status.discarded`, which
|
|
51
|
+
* means something else entirely: items a session DEFERRED or EXCLUDED from its
|
|
52
|
+
* scope. Folding a retirement into that list would make "discarded" mean two
|
|
53
|
+
* different things on the same board — one of them recoverable and one of them not.
|
|
54
|
+
*/
|
|
55
|
+
export async function readEvents(fs, paths) {
|
|
56
|
+
const path = paths.cwdHistoryFile();
|
|
57
|
+
if (!(await fs.exists(path)))
|
|
58
|
+
return [];
|
|
59
|
+
let text;
|
|
60
|
+
try {
|
|
61
|
+
text = await fs.readText(path);
|
|
62
|
+
}
|
|
63
|
+
catch {
|
|
64
|
+
return [];
|
|
65
|
+
}
|
|
66
|
+
const out = [];
|
|
67
|
+
let inTable = false;
|
|
68
|
+
for (const line of text.split("\n")) {
|
|
69
|
+
const trimmed = line.trim();
|
|
70
|
+
if (trimmed === HEADING) {
|
|
71
|
+
inTable = true;
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
if (!inTable)
|
|
75
|
+
continue;
|
|
76
|
+
if (trimmed.startsWith("#"))
|
|
77
|
+
break;
|
|
78
|
+
const event = rowOf(trimmed);
|
|
79
|
+
if (event !== null)
|
|
80
|
+
out.push(event);
|
|
81
|
+
}
|
|
82
|
+
return out;
|
|
83
|
+
}
|
|
84
|
+
/** One data row of the ledger; `null` for the header, the separator or a non-row. */
|
|
85
|
+
function rowOf(line) {
|
|
86
|
+
if (!line.startsWith("|"))
|
|
87
|
+
return null;
|
|
88
|
+
// `| a | b | c | d | e |` splits into ["", a, b, c, d, e, ""].
|
|
89
|
+
const cells = line.split("|").map((c) => c.trim());
|
|
90
|
+
if (cells.length < 7)
|
|
91
|
+
return null;
|
|
92
|
+
const [, operation, date, command, target, result] = cells;
|
|
93
|
+
if (operation === "Operación" || /^[-:]+$/.test(operation))
|
|
94
|
+
return null;
|
|
95
|
+
return { operation, date, command, target, result };
|
|
96
|
+
}
|
|
97
|
+
/** Whether this operation's row is already there — the idempotence check. */
|
|
98
|
+
export async function hasEvent(fs, paths, digest) {
|
|
99
|
+
const path = paths.cwdHistoryFile();
|
|
100
|
+
if (!(await fs.exists(path)))
|
|
101
|
+
return false;
|
|
102
|
+
try {
|
|
103
|
+
return (await fs.readText(path)).includes(`| ${key(digest)} |`);
|
|
104
|
+
}
|
|
105
|
+
catch {
|
|
106
|
+
return false;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Append the row, once.
|
|
111
|
+
*
|
|
112
|
+
* Idempotent by the digest, and append-only by construction: it inserts at the end
|
|
113
|
+
* of its own table and rewrites nothing above it, so no previous row — of either
|
|
114
|
+
* table — can be lost by a retirement.
|
|
115
|
+
*/
|
|
116
|
+
export async function appendEvent(fs, paths, event) {
|
|
117
|
+
const path = paths.cwdHistoryFile();
|
|
118
|
+
await ensureHistoryFile(fs, path);
|
|
119
|
+
const text = await fs.readText(path);
|
|
120
|
+
if (text.includes(`| ${event.operation} |`))
|
|
121
|
+
return { appended: false };
|
|
122
|
+
const row = `| ${event.operation} | ${event.date} | ${event.command} | ${event.target} | ${event.result} |`;
|
|
123
|
+
if (!text.includes(HEADING)) {
|
|
124
|
+
const base = text.endsWith("\n") ? text : `${text}\n`;
|
|
125
|
+
await fs.writeText(path, `${base}\n${HEADING}\n\n${TABLE_HEADER}\n${row}\n`);
|
|
126
|
+
return { appended: true };
|
|
127
|
+
}
|
|
128
|
+
// The table already exists: the row goes at the END of it, and everything else
|
|
129
|
+
// in the file is copied through untouched.
|
|
130
|
+
const lines = text.split("\n");
|
|
131
|
+
const last = lastRowIndex(lines);
|
|
132
|
+
if (last === -1) {
|
|
133
|
+
const base = text.endsWith("\n") ? text : `${text}\n`;
|
|
134
|
+
await fs.writeText(path, `${base}${TABLE_HEADER}\n${row}\n`);
|
|
135
|
+
return { appended: true };
|
|
136
|
+
}
|
|
137
|
+
lines.splice(last + 1, 0, row);
|
|
138
|
+
await fs.writeText(path, lines.join("\n"));
|
|
139
|
+
return { appended: true };
|
|
140
|
+
}
|
|
141
|
+
/** Index of the last row of the retirements table; `-1` when it has none yet. */
|
|
142
|
+
function lastRowIndex(lines) {
|
|
143
|
+
let last = -1;
|
|
144
|
+
let inTable = false;
|
|
145
|
+
for (let i = 0; i < lines.length; i++) {
|
|
146
|
+
const line = (lines[i] ?? "").trim();
|
|
147
|
+
if (line === HEADING)
|
|
148
|
+
inTable = true;
|
|
149
|
+
else if (!inTable)
|
|
150
|
+
continue;
|
|
151
|
+
else if (line.startsWith("|"))
|
|
152
|
+
last = i;
|
|
153
|
+
else if (line.startsWith("#"))
|
|
154
|
+
break;
|
|
155
|
+
}
|
|
156
|
+
return last;
|
|
157
|
+
}
|
|
158
|
+
//# sourceMappingURL=history-events.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"history-events.js","sourceRoot":"","sources":["../../../src/application/retirement/history-events.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The journal: the only thing that exists between "nothing happened" and "it is
|
|
3
|
+
* done".
|
|
4
|
+
*
|
|
5
|
+
* A retirement deletes session folders, so its own record cannot live inside one —
|
|
6
|
+
* the operation would erase the evidence it needs to finish itself. It lives under
|
|
7
|
+
* `.workflow/.retirement/`, outside everything the operation is allowed to remove,
|
|
8
|
+
* and it disappears when the operation converges.
|
|
9
|
+
*
|
|
10
|
+
* What it exists for is a single question a re-entering process has to answer:
|
|
11
|
+
* **which side of the commit point is the world on?** And the answer is never "how
|
|
12
|
+
* far did the previous process think it got" — that reading died with the process.
|
|
13
|
+
* The answer is the REF: at the prepared tip means committed, still at the expected
|
|
14
|
+
* old value means nothing was published. So the journal carries the two values that
|
|
15
|
+
* make the question answerable, and the phase it records is a hint for a human, not
|
|
16
|
+
* the decision.
|
|
17
|
+
*
|
|
18
|
+
* While a journal exists, the operation is neither a success nor a failure: it is
|
|
19
|
+
* IN FLIGHT, and every Workline surface that projects state has to say so rather
|
|
20
|
+
* than describe a half-retired workspace as if it were finished.
|
|
21
|
+
*/
|
|
22
|
+
import { join } from "node:path";
|
|
23
|
+
/** Directory the journals live in — outside every deletable session. */
|
|
24
|
+
export const JOURNAL_DIR = ".retirement";
|
|
25
|
+
export const JOURNAL_VERSION = 1;
|
|
26
|
+
export function journalDir(paths) {
|
|
27
|
+
return join(paths.cwdRoot(), JOURNAL_DIR);
|
|
28
|
+
}
|
|
29
|
+
export function journalPath(paths, digest) {
|
|
30
|
+
return join(journalDir(paths), `${digest}.json`);
|
|
31
|
+
}
|
|
32
|
+
export function quarantinePath(paths, digest) {
|
|
33
|
+
return join(journalDir(paths), `${digest}.quarantine`);
|
|
34
|
+
}
|
|
35
|
+
export function openJournal(input) {
|
|
36
|
+
return {
|
|
37
|
+
version: JOURNAL_VERSION,
|
|
38
|
+
digest: input.proposal.digest,
|
|
39
|
+
phase: "prepared",
|
|
40
|
+
opened: input.opened,
|
|
41
|
+
proposal: input.proposal,
|
|
42
|
+
quarantine: input.quarantine,
|
|
43
|
+
private_refs: [],
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
export async function writeJournal(fs, paths, journal) {
|
|
47
|
+
await fs.mkdirp(journalDir(paths));
|
|
48
|
+
await fs.writeText(journalPath(paths, journal.digest), `${JSON.stringify(journal, null, 2)}\n`);
|
|
49
|
+
}
|
|
50
|
+
export async function dropJournal(fs, paths, digest) {
|
|
51
|
+
await fs.remove(journalPath(paths, digest));
|
|
52
|
+
}
|
|
53
|
+
export async function readJournal(fs, paths, digest) {
|
|
54
|
+
const path = journalPath(paths, digest);
|
|
55
|
+
if (!(await fs.exists(path)))
|
|
56
|
+
return { status: "absent" };
|
|
57
|
+
return parseJournal(fs, path);
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Every journal in flight right now.
|
|
61
|
+
*
|
|
62
|
+
* Read by the surfaces that project state, because a workspace with a journal is
|
|
63
|
+
* not a workspace anybody can describe yet: one of its sessions may be gone from
|
|
64
|
+
* disk while its row is not written, or a ref may have moved while the filesystem
|
|
65
|
+
* has not caught up. Reporting the pending operation is what turns that window
|
|
66
|
+
* from a lie into a visible state.
|
|
67
|
+
*/
|
|
68
|
+
export async function listPendingJournals(fs, paths) {
|
|
69
|
+
const dir = journalDir(paths);
|
|
70
|
+
if (!(await fs.exists(dir)))
|
|
71
|
+
return { journals: [], unreadable: [] };
|
|
72
|
+
const journals = [];
|
|
73
|
+
const unreadable = [];
|
|
74
|
+
for (const entry of await fs.list(dir)) {
|
|
75
|
+
if (entry.type !== "file" || !entry.name.endsWith(".json"))
|
|
76
|
+
continue;
|
|
77
|
+
const read = await parseJournal(fs, entry.path);
|
|
78
|
+
if (read.status === "present")
|
|
79
|
+
journals.push(read.journal);
|
|
80
|
+
else if (read.status === "unreadable")
|
|
81
|
+
unreadable.push({ path: entry.path, reason: read.reason });
|
|
82
|
+
}
|
|
83
|
+
return { journals, unreadable };
|
|
84
|
+
}
|
|
85
|
+
async function parseJournal(fs, path) {
|
|
86
|
+
let parsed;
|
|
87
|
+
try {
|
|
88
|
+
parsed = JSON.parse(await fs.readText(path));
|
|
89
|
+
}
|
|
90
|
+
catch (err) {
|
|
91
|
+
return {
|
|
92
|
+
status: "unreadable",
|
|
93
|
+
reason: `no se pudo leer el journal de retiro ${path}: ${err instanceof Error ? err.message : String(err)}`,
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
if (!isJournal(parsed)) {
|
|
97
|
+
return { status: "unreadable", reason: `${path} no tiene la forma de un journal de retiro` };
|
|
98
|
+
}
|
|
99
|
+
return { status: "present", journal: parsed };
|
|
100
|
+
}
|
|
101
|
+
function isJournal(value) {
|
|
102
|
+
if (value === null || typeof value !== "object")
|
|
103
|
+
return false;
|
|
104
|
+
const j = value;
|
|
105
|
+
return (typeof j.version === "number" &&
|
|
106
|
+
typeof j.digest === "string" &&
|
|
107
|
+
typeof j.phase === "string" &&
|
|
108
|
+
typeof j.quarantine === "string" &&
|
|
109
|
+
Array.isArray(j.private_refs) &&
|
|
110
|
+
j.proposal !== null &&
|
|
111
|
+
typeof j.proposal === "object");
|
|
112
|
+
}
|
|
113
|
+
//# sourceMappingURL=journal.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"journal.js","sourceRoot":"","sources":["../../../src/application/retirement/journal.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAKjC,wEAAwE;AACxE,MAAM,CAAC,MAAM,WAAW,GAAG,aAAa,CAAC;AAmCzC,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,CAAC;AAEjC,MAAM,UAAU,UAAU,CAAC,KAAmB;IAC5C,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,EAAE,WAAW,CAAC,CAAC;AAC5C,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,KAAmB,EAAE,MAAc;IAC7D,OAAO,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,GAAG,MAAM,OAAO,CAAC,CAAC;AACnD,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,KAAmB,EAAE,MAAc;IAChE,OAAO,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,GAAG,MAAM,aAAa,CAAC,CAAC;AACzD,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,KAI3B;IACC,OAAO;QACL,OAAO,EAAE,eAAe;QACxB,MAAM,EAAE,KAAK,CAAC,QAAQ,CAAC,MAAM;QAC7B,KAAK,EAAE,UAAU;QACjB,MAAM,EAAE,KAAK,CAAC,MAAM;QACpB,QAAQ,EAAE,KAAK,CAAC,QAAQ;QACxB,UAAU,EAAE,KAAK,CAAC,UAAU;QAC5B,YAAY,EAAE,EAAE;KACjB,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,EAAkB,EAClB,KAAmB,EACnB,OAA0B;IAE1B,MAAM,EAAE,CAAC,MAAM,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC;IACnC,MAAM,EAAE,CAAC,SAAS,CAAC,WAAW,CAAC,KAAK,EAAE,OAAO,CAAC,MAAM,CAAC,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;AAClG,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,EAAkB,EAClB,KAAmB,EACnB,MAAc;IAEd,MAAM,EAAE,CAAC,MAAM,CAAC,WAAW,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC;AAC9C,CAAC;AAOD,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,EAAkB,EAClB,KAAmB,EACnB,MAAc;IAEd,MAAM,IAAI,GAAG,WAAW,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;IACxC,IAAI,CAAC,CAAC,MAAM,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC;IAC1D,OAAO,YAAY,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;AAChC,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,EAAkB,EAClB,KAAmB;IAEnB,MAAM,GAAG,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC;IAC9B,IAAI,CAAC,CAAC,MAAM,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QAAE,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,UAAU,EAAE,EAAE,EAAE,CAAC;IACrE,MAAM,QAAQ,GAAwB,EAAE,CAAC;IACzC,MAAM,UAAU,GAA4C,EAAE,CAAC;IAC/D,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;QACvC,IAAI,KAAK,CAAC,IAAI,KAAK,MAAM,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC;YAAE,SAAS;QACrE,MAAM,IAAI,GAAG,MAAM,YAAY,CAAC,EAAE,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;QAChD,IAAI,IAAI,CAAC,MAAM,KAAK,SAAS;YAAE,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;aACtD,IAAI,IAAI,CAAC,MAAM,KAAK,YAAY;YACnC,UAAU,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;IAC/D,CAAC;IACD,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,CAAC;AAClC,CAAC;AAED,KAAK,UAAU,YAAY,CAAC,EAAkB,EAAE,IAAY;IAC1D,IAAI,MAAe,CAAC;IACpB,IAAI,CAAC;QACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC;IAC/C,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO;YACL,MAAM,EAAE,YAAY;YACpB,MAAM,EAAE,wCAAwC,IAAI,KAAK,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE;SAC5G,CAAC;IACJ,CAAC;IACD,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,CAAC;QACvB,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,GAAG,IAAI,4CAA4C,EAAE,CAAC;IAC/F,CAAC;IACD,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC;AAChD,CAAC;AAED,SAAS,SAAS,CAAC,KAAc;IAC/B,IAAI,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IAC9D,MAAM,CAAC,GAAG,KAAgC,CAAC;IAC3C,OAAO,CACL,OAAO,CAAC,CAAC,OAAO,KAAK,QAAQ;QAC7B,OAAO,CAAC,CAAC,MAAM,KAAK,QAAQ;QAC5B,OAAO,CAAC,CAAC,KAAK,KAAK,QAAQ;QAC3B,OAAO,CAAC,CAAC,UAAU,KAAK,QAAQ;QAChC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,YAAY,CAAC;QAC7B,CAAC,CAAC,QAAQ,KAAK,IAAI;QACnB,OAAO,CAAC,CAAC,QAAQ,KAAK,QAAQ,CAC/B,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `prepare`: everything a retirement would do, sealed, having changed nothing.
|
|
3
|
+
*
|
|
4
|
+
* It writes no session, no journal, no file and no ref. That is not an
|
|
5
|
+
* optimization — it is what makes the preview safe to run on the wrong target,
|
|
6
|
+
* which is exactly what somebody about to delete work needs to be able to do.
|
|
7
|
+
*
|
|
8
|
+
* The whole answer comes out of ONE object. The preview a person reads, the digest
|
|
9
|
+
* they approve and the effects `apply` performs are three views of the same record,
|
|
10
|
+
* so "what I was shown" and "what will happen" cannot drift apart into two
|
|
11
|
+
* descriptions that disagree.
|
|
12
|
+
*/
|
|
13
|
+
import { tmpdir } from "node:os";
|
|
14
|
+
import { join } from "node:path";
|
|
15
|
+
import { sealRetirementProposal, } from "../../domain/retirement/proposal.js";
|
|
16
|
+
import { parseTargetSelector, selectorText } from "../../domain/retirement/selector.js";
|
|
17
|
+
import { baselineDigest } from "../../domain/session/custody.js";
|
|
18
|
+
import { formatNodeId } from "../../domain/workline-node.js";
|
|
19
|
+
import { semanticDigest } from "../semantic-operation/protocol.js";
|
|
20
|
+
import { readBindingRegistry } from "../session-binding-service.js";
|
|
21
|
+
import { attributeGitEffects } from "./attribution.js";
|
|
22
|
+
import { buildRetirementGraph } from "./graph.js";
|
|
23
|
+
import { resolveDiscardClosure, resolveResetClosure, resolveResetSession, resolveTarget, } from "./resolve.js";
|
|
24
|
+
export async function prepareRetirement(deps, input) {
|
|
25
|
+
const parsed = parseTargetSelector(input.target);
|
|
26
|
+
if (!parsed.ok) {
|
|
27
|
+
return {
|
|
28
|
+
ok: false,
|
|
29
|
+
rejection: {
|
|
30
|
+
code: "TARGET_NOT_FOUND",
|
|
31
|
+
message: parsed.problem.message,
|
|
32
|
+
candidates: [],
|
|
33
|
+
action: parsed.problem.action,
|
|
34
|
+
},
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
const { graph } = await buildRetirementGraph(deps);
|
|
38
|
+
const found = resolveTarget(graph, parsed.selector);
|
|
39
|
+
if (!found.ok)
|
|
40
|
+
return { ok: false, rejection: found.rejection };
|
|
41
|
+
const closure = input.mode === "discard"
|
|
42
|
+
? resolveDiscardClosure(graph, found.node)
|
|
43
|
+
: await resetClosure(graph, found.node);
|
|
44
|
+
if (!closure.ok)
|
|
45
|
+
return { ok: false, rejection: closure.rejection };
|
|
46
|
+
return buildProposal(deps, closure.closure, selectorText(parsed.selector));
|
|
47
|
+
}
|
|
48
|
+
function resetClosure(graph, target) {
|
|
49
|
+
const session = resolveResetSession(graph, target);
|
|
50
|
+
if (!session.ok)
|
|
51
|
+
return { ok: false, rejection: session.rejection };
|
|
52
|
+
return resolveResetClosure(graph, session.node);
|
|
53
|
+
}
|
|
54
|
+
async function buildProposal(deps, closure, targetText) {
|
|
55
|
+
const readSet = [];
|
|
56
|
+
const deletes = [];
|
|
57
|
+
const restores = [];
|
|
58
|
+
const units = [];
|
|
59
|
+
const blocks = [];
|
|
60
|
+
const dirty = [];
|
|
61
|
+
const reverts = [];
|
|
62
|
+
const publications = [];
|
|
63
|
+
const restored = new Set();
|
|
64
|
+
for (const entry of closure.entries) {
|
|
65
|
+
if (entry.node.kind === "session") {
|
|
66
|
+
await collectSession(deps, entry.node, {
|
|
67
|
+
mode: closure.mode,
|
|
68
|
+
deletes,
|
|
69
|
+
restores,
|
|
70
|
+
restored,
|
|
71
|
+
units,
|
|
72
|
+
dirty,
|
|
73
|
+
reverts,
|
|
74
|
+
publications,
|
|
75
|
+
blocks,
|
|
76
|
+
readSet,
|
|
77
|
+
});
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
// A document in the closure disappears whole. Its digest travels so `apply`
|
|
81
|
+
// can tell "the file I was shown" from "a file somebody edited since" — read
|
|
82
|
+
// ONCE, because two readings of the same file could disagree and then the
|
|
83
|
+
// delete and the compare-and-swap would be checking different things.
|
|
84
|
+
const digest = await digestOf(deps.fs, entry.node.absolute_path);
|
|
85
|
+
deletes.push({ path: entry.node.path, kind: "file", digest });
|
|
86
|
+
readSet.push({ id: `doc:${entry.node.path}`, digest: digest ?? "absent" });
|
|
87
|
+
}
|
|
88
|
+
if (blocks.length > 0) {
|
|
89
|
+
return {
|
|
90
|
+
ok: false,
|
|
91
|
+
rejection: {
|
|
92
|
+
code: "SHARED_CONSUMER",
|
|
93
|
+
message: blocks.map((b) => b.reason).join("; "),
|
|
94
|
+
candidates: blocks.flatMap((b) => b.contested),
|
|
95
|
+
action: blocks[0]?.action ?? "resolvé la atribución compartida y reintentá",
|
|
96
|
+
},
|
|
97
|
+
blocks,
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
// A restore and a delete over the same path would be two instructions for one
|
|
101
|
+
// file. The restore wins: it is the one that knows what should be there.
|
|
102
|
+
const finalDeletes = deletes.filter((d) => !restored.has(d.path));
|
|
103
|
+
const bindings = await bindingsOf(deps, closure, readSet);
|
|
104
|
+
return {
|
|
105
|
+
ok: true,
|
|
106
|
+
proposal: sealRetirementProposal({
|
|
107
|
+
mode: closure.mode,
|
|
108
|
+
target: closure.target.id,
|
|
109
|
+
closure: closure.entries.map((e) => ({ node: e.node.id, path: e.node.path, reason: e.reason })),
|
|
110
|
+
deletes: finalDeletes,
|
|
111
|
+
restores,
|
|
112
|
+
bindings,
|
|
113
|
+
units,
|
|
114
|
+
dirty,
|
|
115
|
+
reverts,
|
|
116
|
+
// More than one would mean two commit points; the attribution refuses that
|
|
117
|
+
// shape upstream, so reaching here with two is impossible by construction.
|
|
118
|
+
publication: publications[0] ?? null,
|
|
119
|
+
event: eventOf(closure, targetText, finalDeletes, restores),
|
|
120
|
+
read_set: readSet,
|
|
121
|
+
}),
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* What one session in the closure contributes.
|
|
126
|
+
*
|
|
127
|
+
* The mode decides only ONE thing here — whether the session's declared inputs go
|
|
128
|
+
* back to their previous bytes — and everything else is identical. A discard that
|
|
129
|
+
* restored inputs would undo work the user asked to keep; a reset that did not
|
|
130
|
+
* would leave the document half-executed. Both modes remove the session folder,
|
|
131
|
+
* its units and its attributable git effects, because those are the session's own
|
|
132
|
+
* either way.
|
|
133
|
+
*/
|
|
134
|
+
async function collectSession(deps, node, collector) {
|
|
135
|
+
const facts = node.session;
|
|
136
|
+
if (facts === null)
|
|
137
|
+
return;
|
|
138
|
+
collector.deletes.push({ path: node.path, kind: "directory", digest: null });
|
|
139
|
+
const custody = facts.custody;
|
|
140
|
+
for (const unit of facts.units) {
|
|
141
|
+
collector.units.push({
|
|
142
|
+
alias: unit.alias,
|
|
143
|
+
session: facts.folder,
|
|
144
|
+
path: unit.path,
|
|
145
|
+
branch: unit.branch,
|
|
146
|
+
// From the custody's own record of that source; empty when a legacy session
|
|
147
|
+
// has a unit but no custody, and then the unit is reported rather than touched.
|
|
148
|
+
repo: custody?.sources.find((s) => s.alias === unit.alias)?.path ?? "",
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
if (custody === null)
|
|
152
|
+
return;
|
|
153
|
+
collector.readSet.push({ id: `custody:${facts.folder}`, digest: custody.digest });
|
|
154
|
+
for (const artifact of custody.artifacts) {
|
|
155
|
+
if (artifact.role === "output") {
|
|
156
|
+
// Born inside the session: it goes, in both modes.
|
|
157
|
+
const absolute = join(deps.paths.workspaceDir(), artifact.path);
|
|
158
|
+
collector.deletes.push({
|
|
159
|
+
path: artifact.path,
|
|
160
|
+
kind: "file",
|
|
161
|
+
digest: await digestOf(deps.fs, absolute),
|
|
162
|
+
});
|
|
163
|
+
continue;
|
|
164
|
+
}
|
|
165
|
+
if (collector.mode !== "reset")
|
|
166
|
+
continue;
|
|
167
|
+
const absolute = join(deps.paths.workspaceDir(), artifact.path);
|
|
168
|
+
collector.restores.push({
|
|
169
|
+
path: artifact.path,
|
|
170
|
+
existed: artifact.before.existed,
|
|
171
|
+
content: artifact.before.content,
|
|
172
|
+
digest: artifact.before.digest,
|
|
173
|
+
current_digest: await digestOf(deps.fs, absolute),
|
|
174
|
+
});
|
|
175
|
+
collector.restored.add(artifact.path);
|
|
176
|
+
}
|
|
177
|
+
const attribution = await attributeGitEffects(deps.git, custody, {
|
|
178
|
+
scratchDir: tmpdir(),
|
|
179
|
+
opId: facts.folder,
|
|
180
|
+
});
|
|
181
|
+
collector.dirty.push(...attribution.dirty);
|
|
182
|
+
collector.reverts.push(...attribution.reverts);
|
|
183
|
+
collector.blocks.push(...attribution.blocks);
|
|
184
|
+
if (attribution.publication !== null)
|
|
185
|
+
collector.publications.push(attribution.publication);
|
|
186
|
+
for (const source of custody.sources) {
|
|
187
|
+
const tree = source.unit_path ?? source.path;
|
|
188
|
+
collector.readSet.push({
|
|
189
|
+
id: `git:${source.alias}/HEAD`,
|
|
190
|
+
digest: (await headOf(deps.git, tree)) ?? "unborn",
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
/** Conversation associations that stop resolving once the closure is gone. */
|
|
195
|
+
async function bindingsOf(deps, closure, readSet) {
|
|
196
|
+
const read = await readBindingRegistry(deps.fs, deps.paths);
|
|
197
|
+
if (!read.ok)
|
|
198
|
+
return [];
|
|
199
|
+
readSet.push({ id: "bindings", digest: semanticDigest(read.registry.bindings) });
|
|
200
|
+
const folders = new Set(closure.entries
|
|
201
|
+
.filter((e) => e.node.kind === "session")
|
|
202
|
+
.map((e) => e.node.session?.folder ?? e.node.id.key));
|
|
203
|
+
return Object.entries(read.registry.bindings)
|
|
204
|
+
.filter(([, folder]) => folders.has(folder))
|
|
205
|
+
.map(([contextHash]) => contextHash)
|
|
206
|
+
.sort();
|
|
207
|
+
}
|
|
208
|
+
function eventOf(closure, targetText, deletes, restores) {
|
|
209
|
+
const summary = closure.mode === "discard"
|
|
210
|
+
? `retirado ${targetText}: ${closure.entries.length} nodos, ${deletes.length} rutas`
|
|
211
|
+
: `restaurado ${restores.length} artefacto(s) y retirada ${formatNodeId(closure.target.id)}`;
|
|
212
|
+
return { command: closure.mode, key: formatNodeId(closure.target.id), summary };
|
|
213
|
+
}
|
|
214
|
+
/** `null` when the path is not there — an absence is a fact, not a failure. */
|
|
215
|
+
async function digestOf(fs, absolute) {
|
|
216
|
+
if (!(await fs.exists(absolute)))
|
|
217
|
+
return null;
|
|
218
|
+
try {
|
|
219
|
+
return baselineDigest(await fs.readText(absolute));
|
|
220
|
+
}
|
|
221
|
+
catch {
|
|
222
|
+
return null;
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
async function headOf(git, tree) {
|
|
226
|
+
try {
|
|
227
|
+
return await git.head(tree);
|
|
228
|
+
}
|
|
229
|
+
catch {
|
|
230
|
+
return null;
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
//# sourceMappingURL=prepare.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prepare.js","sourceRoot":"","sources":["../../../src/application/retirement/prepare.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The preview: the sealed proposal, read out loud.
|
|
3
|
+
*
|
|
4
|
+
* Every line below is DERIVED from the record — nothing is authored here and
|
|
5
|
+
* nothing is looked up again. That is the property the whole authorization rests
|
|
6
|
+
* on: the person reads this, approves the digest, and `apply` performs the same
|
|
7
|
+
* object. A preview assembled from a second reading of the workspace could describe
|
|
8
|
+
* a retirement that differs from the one being approved, and it would be the
|
|
9
|
+
* description a human trusts.
|
|
10
|
+
*
|
|
11
|
+
* The human projection and the JSON are two renderings of one structure for the
|
|
12
|
+
* same reason: a terminal user and an agent host must be able to disagree about
|
|
13
|
+
* formatting and never about scope.
|
|
14
|
+
*/
|
|
15
|
+
import { proposesReverts } from "../../domain/retirement/proposal.js";
|
|
16
|
+
import { formatNodeId } from "../../domain/workline-node.js";
|
|
17
|
+
export function retirementPreview(proposal) {
|
|
18
|
+
return {
|
|
19
|
+
mode: proposal.mode,
|
|
20
|
+
target: formatNodeId(proposal.target),
|
|
21
|
+
digest: proposal.digest,
|
|
22
|
+
disappears: proposal.closure.map((entry) => ({
|
|
23
|
+
node: formatNodeId(entry.node),
|
|
24
|
+
path: entry.path,
|
|
25
|
+
reason: entry.reason,
|
|
26
|
+
})),
|
|
27
|
+
restores: proposal.restores.map((restore) => ({
|
|
28
|
+
path: restore.path,
|
|
29
|
+
to: restore.existed ? "bytes-previos" : "inexistente",
|
|
30
|
+
// What the person most needs to see: the file moved since the baseline was
|
|
31
|
+
// sealed, so restoring it discards whatever happened in between.
|
|
32
|
+
changed_since: restore.current_digest !== restore.digest,
|
|
33
|
+
})),
|
|
34
|
+
local_changes: proposal.dirty.map((change) => ({
|
|
35
|
+
alias: change.alias,
|
|
36
|
+
tree: change.tree,
|
|
37
|
+
paths: change.paths,
|
|
38
|
+
exclusive_unit: change.exclusive_unit,
|
|
39
|
+
})),
|
|
40
|
+
reverts: proposal.reverts.map((revert) => ({
|
|
41
|
+
alias: revert.alias,
|
|
42
|
+
commit: revert.commit,
|
|
43
|
+
ref: revert.ref,
|
|
44
|
+
published: revert.published,
|
|
45
|
+
})),
|
|
46
|
+
publication: proposal.publication === null
|
|
47
|
+
? null
|
|
48
|
+
: {
|
|
49
|
+
alias: proposal.publication.alias,
|
|
50
|
+
ref: proposal.publication.ref,
|
|
51
|
+
expected_old: proposal.publication.expected_old,
|
|
52
|
+
expected_tree: proposal.publication.expected_tree,
|
|
53
|
+
revert_count: proposal.publication.revert_count,
|
|
54
|
+
},
|
|
55
|
+
units: proposal.units.map((unit) => ({
|
|
56
|
+
alias: unit.alias,
|
|
57
|
+
session: unit.session,
|
|
58
|
+
branch: unit.branch,
|
|
59
|
+
})),
|
|
60
|
+
bindings: proposal.bindings.length,
|
|
61
|
+
history_row: `${proposal.event.command} · ${proposal.event.key} · ${proposal.event.summary}`,
|
|
62
|
+
touches_git_history: proposesReverts(proposal),
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* The terminal reading of the same structure.
|
|
67
|
+
*
|
|
68
|
+
* A section with nothing in it is omitted rather than printed empty: a preview
|
|
69
|
+
* that lists "reverts: none" next to five other empty headings buries the two
|
|
70
|
+
* lines that matter, and what matters here is noticing a revert BEFORE approving.
|
|
71
|
+
*/
|
|
72
|
+
export function renderRetirementPreview(preview) {
|
|
73
|
+
const lines = [];
|
|
74
|
+
const verb = preview.mode === "discard" ? "Retirar" : "Restaurar";
|
|
75
|
+
lines.push(`${verb} ${preview.target}`);
|
|
76
|
+
lines.push(`Digest de aprobación: ${preview.digest}`);
|
|
77
|
+
section(lines, "Desaparece", preview.disappears.map((d) => `${d.node} — ${d.path} (${d.reason})`));
|
|
78
|
+
section(lines, "Vuelve atrás", preview.restores.map((r) => `${r.path} → ${r.to}${r.changed_since ? " (cambió desde el baseline)" : ""}`));
|
|
79
|
+
section(lines, "Cambios locales que se descartan", preview.local_changes.map((c) => `${c.alias} (${c.exclusive_unit ? "unidad exclusiva" : "checkout compartido"}): ${c.paths.join(", ")}`));
|
|
80
|
+
section(lines, "Commits que se revierten (nuevo commit, sin reescribir)", preview.reverts.map((r) => `${r.alias} ${r.commit.slice(0, 12)} → ${r.ref}${r.published ? " · publicado: el push queda pendiente y externo" : ""}`));
|
|
81
|
+
if (preview.publication !== null) {
|
|
82
|
+
const p = preview.publication;
|
|
83
|
+
section(lines, "Punto de commit (el único)", [
|
|
84
|
+
`${p.alias} · ${p.ref} · desde ${(p.expected_old ?? "inexistente").slice(0, 12)} · ${p.revert_count} revert(s) hasta el árbol ${p.expected_tree.slice(0, 12)}`,
|
|
85
|
+
]);
|
|
86
|
+
}
|
|
87
|
+
section(lines, "Unidades que se reconcilian", preview.units.map((u) => `${u.alias} · ${u.branch}`));
|
|
88
|
+
if (preview.bindings > 0) {
|
|
89
|
+
section(lines, "Asociaciones de conversación que dejan de resolver", [`${preview.bindings}`]);
|
|
90
|
+
}
|
|
91
|
+
section(lines, "Huella en HISTORY", [preview.history_row]);
|
|
92
|
+
return lines.join("\n");
|
|
93
|
+
}
|
|
94
|
+
function section(lines, title, items) {
|
|
95
|
+
if (items.length === 0)
|
|
96
|
+
return;
|
|
97
|
+
lines.push("", `${title}:`);
|
|
98
|
+
for (const item of items)
|
|
99
|
+
lines.push(` - ${item}`);
|
|
100
|
+
}
|
|
101
|
+
//# sourceMappingURL=preview.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"preview.js","sourceRoot":"","sources":["../../../src/application/retirement/preview.ts"],"names":[],"mappings":"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"}
|