@tacuchi/agent-workflow-cli 21.10.1 → 21.12.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/application/dev-bootstrap-dsn-service.js +45 -35
- package/dist/application/dev-bootstrap-dsn-service.js.map +1 -1
- package/dist/application/docs-canon-service.js +68 -0
- package/dist/application/docs-canon-service.js.map +1 -0
- package/dist/application/dsn-reader-service.js +53 -2
- package/dist/application/dsn-reader-service.js.map +1 -1
- package/dist/application/flow/advance.js +132 -18
- package/dist/application/flow/advance.js.map +1 -1
- package/dist/application/flow/flow-service.js +100 -2
- package/dist/application/flow/flow-service.js.map +1 -1
- package/dist/application/flow/internal-drive.js +16 -13
- package/dist/application/flow/internal-drive.js.map +1 -1
- package/dist/application/flow/run-state-service.js +236 -5
- package/dist/application/flow/run-state-service.js.map +1 -1
- package/dist/application/flow/submit.js +90 -35
- package/dist/application/flow/submit.js.map +1 -1
- package/dist/application/mcp-dbhub-launcher.js +193 -34
- package/dist/application/mcp-dbhub-launcher.js.map +1 -1
- package/dist/application/mcp-doctor-service.js +13 -4
- package/dist/application/mcp-doctor-service.js.map +1 -1
- package/dist/application/mcp-test-connection-service.js +5 -11
- package/dist/application/mcp-test-connection-service.js.map +1 -1
- package/dist/application/paths-service.js +17 -0
- package/dist/application/paths-service.js.map +1 -1
- package/dist/application/session-narrative.js +7 -3
- package/dist/application/session-narrative.js.map +1 -1
- package/dist/application/session-resolver.js +12 -2
- package/dist/application/session-resolver.js.map +1 -1
- package/dist/application/session-resume-service.js +7 -0
- package/dist/application/session-resume-service.js.map +1 -1
- package/dist/application/visibility-doctor-service.js +89 -49
- package/dist/application/visibility-doctor-service.js.map +1 -1
- package/dist/application/workspace-migrate/apply.js +57 -0
- package/dist/application/workspace-migrate/apply.js.map +1 -0
- package/dist/application/workspace-migrate/markers.js +177 -0
- package/dist/application/workspace-migrate/markers.js.map +1 -0
- package/dist/application/workspace-migrate/plan.js +171 -0
- package/dist/application/workspace-migrate/plan.js.map +1 -0
- package/dist/application/workspace-migrate/preview.js +111 -0
- package/dist/application/workspace-migrate/preview.js.map +1 -0
- package/dist/cli/commands/flow.js +52 -5
- package/dist/cli/commands/flow.js.map +1 -1
- package/dist/cli/commands/unknown-flags.js +51 -0
- package/dist/cli/commands/unknown-flags.js.map +1 -0
- package/dist/cli/commands/visibility.js +105 -16
- package/dist/cli/commands/visibility.js.map +1 -1
- package/dist/cli/commands/workspace-migrate.js +70 -0
- package/dist/cli/commands/workspace-migrate.js.map +1 -0
- package/dist/domain/capability/effects.js +13 -0
- package/dist/domain/capability/effects.js.map +1 -1
- package/dist/domain/flow/answer.js +105 -0
- package/dist/domain/flow/answer.js.map +1 -1
- package/dist/domain/flow/run-state.js +215 -11
- package/dist/domain/flow/run-state.js.map +1 -1
- package/package.json +1 -1
- package/skills/w/loops/CHASSIS.md +5 -7
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What a hub with a legacy session series needs before it can be operated with
|
|
3
|
+
* the same commands as a new one — derived without writing a byte.
|
|
4
|
+
*
|
|
5
|
+
* Three things are broken in such a hub, and none of them announces itself:
|
|
6
|
+
* the project block wears markers of an older namespace and the CLI silently
|
|
7
|
+
* reads a second, empty one it appended itself; the sessions the record calls
|
|
8
|
+
* closed have no `.closed` sentinel on disk, so they show up as active forever;
|
|
9
|
+
* and the numbers of the legacy series live only in folder names, so they
|
|
10
|
+
* vanish from the record the day somebody archives the folders.
|
|
11
|
+
*
|
|
12
|
+
* This is a PUNCTUAL, explicit operation and not a reconciliation some other
|
|
13
|
+
* command performs on the side: it decides what to do by comparing two sources
|
|
14
|
+
* that may disagree, and a disagreement is answered by refusing to touch that
|
|
15
|
+
* session — never by picking the more convenient of the two.
|
|
16
|
+
*/
|
|
17
|
+
import { join } from "node:path";
|
|
18
|
+
import { readHistoryRows } from "../history-table.js";
|
|
19
|
+
import { resolveWorkspaceRootFrom } from "../paths-service.js";
|
|
20
|
+
import { CLOSED_MARKER, buildSessionEntry, listSessionFolders, nextSessionCorrelative, parseSessionFolder, sessionNumericCode, sessionsSharingNumber, } from "../session-resolver.js";
|
|
21
|
+
import { planHubMarkers, readHubFiles, } from "./markers.js";
|
|
22
|
+
/** How many writes the plan holds. Zero means the workspace is already current. */
|
|
23
|
+
export function pendingChanges(plan) {
|
|
24
|
+
return plan.markers.length + plan.sentinels.length + plan.rows.length;
|
|
25
|
+
}
|
|
26
|
+
export async function planWorkspaceMigration(fs, paths) {
|
|
27
|
+
const workspace = await resolveWorkspaceRootFrom(fs, paths);
|
|
28
|
+
const markers = planMarkers(await readHubFiles(fs, workspace), paths.blockMarkers());
|
|
29
|
+
const recorded = await readRecord(fs, paths);
|
|
30
|
+
const sentinels = [];
|
|
31
|
+
const rows = [];
|
|
32
|
+
const conflicts = [...markers.conflicts];
|
|
33
|
+
const legacy = [];
|
|
34
|
+
for (const folder of await listSessionFolders(fs, paths.cwdSessionsDir())) {
|
|
35
|
+
const number = legacyNumber(folder.name);
|
|
36
|
+
if (number === null)
|
|
37
|
+
continue; // current-model folder: nothing legacy about it
|
|
38
|
+
legacy.push(folder.name);
|
|
39
|
+
const outcome = await planSession(fs, paths, folder, number, recorded.get(number));
|
|
40
|
+
if (outcome.kind === "sentinel")
|
|
41
|
+
sentinels.push(outcome.seed);
|
|
42
|
+
if (outcome.kind === "row")
|
|
43
|
+
rows.push(outcome.seed);
|
|
44
|
+
if (outcome.kind === "conflict")
|
|
45
|
+
conflicts.push(outcome.conflict);
|
|
46
|
+
}
|
|
47
|
+
return {
|
|
48
|
+
workspace,
|
|
49
|
+
markers: markers.rewrites,
|
|
50
|
+
sentinels,
|
|
51
|
+
rows,
|
|
52
|
+
conflicts,
|
|
53
|
+
legacy,
|
|
54
|
+
next_correlative: await nextSessionCorrelative(fs, paths),
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
function planMarkers(hubs, current) {
|
|
58
|
+
const rewrites = [];
|
|
59
|
+
const conflicts = [];
|
|
60
|
+
for (const hub of hubs) {
|
|
61
|
+
const outcome = planHubMarkers(hub.path, hub.text, current);
|
|
62
|
+
if (outcome.kind === "rewrite")
|
|
63
|
+
rewrites.push(outcome.rewrite);
|
|
64
|
+
if (outcome.kind === "refused") {
|
|
65
|
+
conflicts.push({
|
|
66
|
+
subject: hub.path,
|
|
67
|
+
reason: outcome.refusal.reason,
|
|
68
|
+
detail: outcome.refusal.detail,
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return { rewrites, conflicts };
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* What one legacy session needs, given what the record says about its number.
|
|
76
|
+
*
|
|
77
|
+
* The rule that makes seeding a sentinel safe is the LAYOUT: a `sessionNNN-`
|
|
78
|
+
* folder predates the sentinel model entirely, so the file's absence there is
|
|
79
|
+
* the absence of the model and not a statement about the session. In a
|
|
80
|
+
* current-model folder that same absence MEANS active — `session-resume
|
|
81
|
+
* --reopen` produces exactly it, on purpose — and writing the sentinel back
|
|
82
|
+
* would re-close a session somebody had just reopened. That is why this walks
|
|
83
|
+
* the legacy series and nothing else.
|
|
84
|
+
*/
|
|
85
|
+
async function planSession(fs, paths, folder, number, row) {
|
|
86
|
+
// The record is indexed by number, so a number two folders answer to has ONE
|
|
87
|
+
// row for TWO sessions: whichever we wrote, we would be writing about the
|
|
88
|
+
// other one too.
|
|
89
|
+
const sharing = await sessionsSharingNumber(fs, paths, folder.name);
|
|
90
|
+
if (sharing.length > 1) {
|
|
91
|
+
const folders = sharing.map((candidate) => candidate.folder).join(", ");
|
|
92
|
+
return conflictOf(folder.name, "numero_compartido", `el número ${number} lo comparten ${sharing.length} carpetas (${folders}) y el registro se indexa por número: renombrá la legacy al modelo actual (\`NNN-<slug>\`) y reintentá`);
|
|
93
|
+
}
|
|
94
|
+
const entry = await buildSessionEntry(fs, folder.path, folder.name);
|
|
95
|
+
if (row === undefined) {
|
|
96
|
+
return {
|
|
97
|
+
kind: "row",
|
|
98
|
+
seed: {
|
|
99
|
+
folder: folder.name,
|
|
100
|
+
code: entry.code ?? folder.name,
|
|
101
|
+
name: entry.name,
|
|
102
|
+
state: entry.state,
|
|
103
|
+
date: entry.date ?? null,
|
|
104
|
+
},
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
const recorded = recordedState(row.state);
|
|
108
|
+
if (recorded === null) {
|
|
109
|
+
return conflictOf(folder.name, "estado_ilegible", `la fila del histórico dice '${row.state}', que no es ni 'active' ni 'closed': corregila a mano y reintentá`);
|
|
110
|
+
}
|
|
111
|
+
if (recorded === entry.state)
|
|
112
|
+
return { kind: "coherente" };
|
|
113
|
+
if (recorded === "active") {
|
|
114
|
+
return conflictOf(folder.name, "estado_divergente", "el histórico la da por activa y la carpeta ya tiene su centinela `.closed`: cuál de las dos quedó atrás no se adivina");
|
|
115
|
+
}
|
|
116
|
+
return {
|
|
117
|
+
kind: "sentinel",
|
|
118
|
+
seed: { folder: folder.name, path: folder.path, date: row.date },
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
function conflictOf(subject, reason, detail) {
|
|
122
|
+
return { kind: "conflict", conflict: { subject, reason, detail } };
|
|
123
|
+
}
|
|
124
|
+
/** Where the sentinel of a session goes. */
|
|
125
|
+
export function sentinelPath(seed) {
|
|
126
|
+
return join(seed.path, CLOSED_MARKER);
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* The record, indexed by NUMBER — the key it is actually written with.
|
|
130
|
+
*
|
|
131
|
+
* Compared as numbers and not as strings for the same reason the upsert does
|
|
132
|
+
* it: `47` and `047` are one session, and `100` is not `1000`.
|
|
133
|
+
*/
|
|
134
|
+
async function readRecord(fs, paths) {
|
|
135
|
+
const path = paths.cwdHistoryFile();
|
|
136
|
+
const byNumber = new Map();
|
|
137
|
+
if (!(await fs.exists(path)))
|
|
138
|
+
return byNumber;
|
|
139
|
+
for (const row of readHistoryRows(await fs.readText(path))) {
|
|
140
|
+
// The SAME reading of "what number does this carry" the resolver and the
|
|
141
|
+
// correlative use: `session047-x`, `047-x` and a bare `047` are one session.
|
|
142
|
+
const digits = sessionNumericCode(row.key);
|
|
143
|
+
if (digits !== null)
|
|
144
|
+
byNumber.set(Number.parseInt(digits, 10), row);
|
|
145
|
+
}
|
|
146
|
+
return byNumber;
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* The number a LEGACY folder carries, or `null` when the folder is not one.
|
|
150
|
+
*
|
|
151
|
+
* `parseSessionFolder` is the canonical reading of a folder's identity and it
|
|
152
|
+
* answers this without another regex: for the current model it hands back the
|
|
153
|
+
* WHOLE folder name as the code, and only the `sessionNNN-<slug>` layout splits
|
|
154
|
+
* a number off.
|
|
155
|
+
*/
|
|
156
|
+
function legacyNumber(folder) {
|
|
157
|
+
const { code } = parseSessionFolder(folder);
|
|
158
|
+
if (code === null || code === folder)
|
|
159
|
+
return null;
|
|
160
|
+
const parsed = Number.parseInt(code, 10);
|
|
161
|
+
return Number.isNaN(parsed) ? null : parsed;
|
|
162
|
+
}
|
|
163
|
+
function recordedState(cell) {
|
|
164
|
+
const value = cell.trim().toLowerCase();
|
|
165
|
+
if (value === "closed")
|
|
166
|
+
return "closed";
|
|
167
|
+
if (value === "active")
|
|
168
|
+
return "active";
|
|
169
|
+
return null;
|
|
170
|
+
}
|
|
171
|
+
//# sourceMappingURL=plan.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plan.js","sourceRoot":"","sources":["../../../src/application/workspace-migrate/plan.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAGjC,OAAO,EAAmB,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAGvE,OAAO,EAAE,wBAAwB,EAAE,MAAM,qBAAqB,CAAC;AAC/D,OAAO,EACL,aAAa,EACb,iBAAiB,EACjB,kBAAkB,EAClB,sBAAsB,EACtB,kBAAkB,EAClB,kBAAkB,EAClB,qBAAqB,GACtB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAGL,cAAc,EACd,YAAY,GACb,MAAM,cAAc,CAAC;AA+CtB,mFAAmF;AACnF,MAAM,UAAU,cAAc,CAAC,IAA4B;IACzD,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC;AACxE,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAC1C,EAAkB,EAClB,KAAmB;IAEnB,MAAM,SAAS,GAAG,MAAM,wBAAwB,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC;IAC5D,MAAM,OAAO,GAAG,WAAW,CAAC,MAAM,YAAY,CAAC,EAAE,EAAE,SAAS,CAAC,EAAE,KAAK,CAAC,YAAY,EAAE,CAAC,CAAC;IACrF,MAAM,QAAQ,GAAG,MAAM,UAAU,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC;IAE7C,MAAM,SAAS,GAAmB,EAAE,CAAC;IACrC,MAAM,IAAI,GAAc,EAAE,CAAC;IAC3B,MAAM,SAAS,GAAwB,CAAC,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC;IAC9D,MAAM,MAAM,GAAa,EAAE,CAAC;IAE5B,KAAK,MAAM,MAAM,IAAI,MAAM,kBAAkB,CAAC,EAAE,EAAE,KAAK,CAAC,cAAc,EAAE,CAAC,EAAE,CAAC;QAC1E,MAAM,MAAM,GAAG,YAAY,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QACzC,IAAI,MAAM,KAAK,IAAI;YAAE,SAAS,CAAC,gDAAgD;QAC/E,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QACzB,MAAM,OAAO,GAAG,MAAM,WAAW,CAAC,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC;QACnF,IAAI,OAAO,CAAC,IAAI,KAAK,UAAU;YAAE,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QAC9D,IAAI,OAAO,CAAC,IAAI,KAAK,KAAK;YAAE,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QACpD,IAAI,OAAO,CAAC,IAAI,KAAK,UAAU;YAAE,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IACpE,CAAC;IAED,OAAO;QACL,SAAS;QACT,OAAO,EAAE,OAAO,CAAC,QAAQ;QACzB,SAAS;QACT,IAAI;QACJ,SAAS;QACT,MAAM;QACN,gBAAgB,EAAE,MAAM,sBAAsB,CAAC,EAAE,EAAE,KAAK,CAAC;KAC1D,CAAC;AACJ,CAAC;AAED,SAAS,WAAW,CAClB,IAA+C,EAC/C,OAA4B;IAE5B,MAAM,QAAQ,GAAuB,EAAE,CAAC;IACxC,MAAM,SAAS,GAAwB,EAAE,CAAC;IAC1C,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,MAAM,OAAO,GAAG,cAAc,CAAC,GAAG,CAAC,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QAC5D,IAAI,OAAO,CAAC,IAAI,KAAK,SAAS;YAAE,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QAC/D,IAAI,OAAO,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;YAC/B,SAAS,CAAC,IAAI,CAAC;gBACb,OAAO,EAAE,GAAG,CAAC,IAAI;gBACjB,MAAM,EAAE,OAAO,CAAC,OAAO,CAAC,MAAM;gBAC9B,MAAM,EAAE,OAAO,CAAC,OAAO,CAAC,MAAM;aAC/B,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IACD,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC;AACjC,CAAC;AAQD;;;;;;;;;;GAUG;AACH,KAAK,UAAU,WAAW,CACxB,EAAkB,EAClB,KAAmB,EACnB,MAAsC,EACtC,MAAc,EACd,GAA2B;IAE3B,6EAA6E;IAC7E,0EAA0E;IAC1E,iBAAiB;IACjB,MAAM,OAAO,GAAG,MAAM,qBAAqB,CAAC,EAAE,EAAE,KAAK,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC;IACpE,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACvB,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACxE,OAAO,UAAU,CACf,MAAM,CAAC,IAAI,EACX,mBAAmB,EACnB,aAAa,MAAM,iBAAiB,OAAO,CAAC,MAAM,cAAc,OAAO,wGAAwG,CAChL,CAAC;IACJ,CAAC;IAED,MAAM,KAAK,GAAG,MAAM,iBAAiB,CAAC,EAAE,EAAE,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC;IACpE,IAAI,GAAG,KAAK,SAAS,EAAE,CAAC;QACtB,OAAO;YACL,IAAI,EAAE,KAAK;YACX,IAAI,EAAE;gBACJ,MAAM,EAAE,MAAM,CAAC,IAAI;gBACnB,IAAI,EAAE,KAAK,CAAC,IAAI,IAAI,MAAM,CAAC,IAAI;gBAC/B,IAAI,EAAE,KAAK,CAAC,IAAI;gBAChB,KAAK,EAAE,KAAK,CAAC,KAAK;gBAClB,IAAI,EAAE,KAAK,CAAC,IAAI,IAAI,IAAI;aACzB;SACF,CAAC;IACJ,CAAC;IAED,MAAM,QAAQ,GAAG,aAAa,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IAC1C,IAAI,QAAQ,KAAK,IAAI,EAAE,CAAC;QACtB,OAAO,UAAU,CACf,MAAM,CAAC,IAAI,EACX,iBAAiB,EACjB,+BAA+B,GAAG,CAAC,KAAK,oEAAoE,CAC7G,CAAC;IACJ,CAAC;IACD,IAAI,QAAQ,KAAK,KAAK,CAAC,KAAK;QAAE,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC;IAC3D,IAAI,QAAQ,KAAK,QAAQ,EAAE,CAAC;QAC1B,OAAO,UAAU,CACf,MAAM,CAAC,IAAI,EACX,mBAAmB,EACnB,uHAAuH,CACxH,CAAC;IACJ,CAAC;IACD,OAAO;QACL,IAAI,EAAE,UAAU;QAChB,IAAI,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE;KACjE,CAAC;AACJ,CAAC;AAED,SAAS,UAAU,CAAC,OAAe,EAAE,MAAsB,EAAE,MAAc;IACzE,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,QAAQ,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,CAAC;AACrE,CAAC;AAED,4CAA4C;AAC5C,MAAM,UAAU,YAAY,CAAC,IAAkB;IAC7C,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,aAAa,CAAC,CAAC;AACxC,CAAC;AAED;;;;;GAKG;AACH,KAAK,UAAU,UAAU,CACvB,EAAkB,EAClB,KAAmB;IAEnB,MAAM,IAAI,GAAG,KAAK,CAAC,cAAc,EAAE,CAAC;IACpC,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAsB,CAAC;IAC/C,IAAI,CAAC,CAAC,MAAM,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QAAE,OAAO,QAAQ,CAAC;IAC9C,KAAK,MAAM,GAAG,IAAI,eAAe,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC;QAC3D,yEAAyE;QACzE,6EAA6E;QAC7E,MAAM,MAAM,GAAG,kBAAkB,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAC3C,IAAI,MAAM,KAAK,IAAI;YAAE,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,EAAE,EAAE,CAAC,EAAE,GAAG,CAAC,CAAC;IACtE,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED;;;;;;;GAOG;AACH,SAAS,YAAY,CAAC,MAAc;IAClC,MAAM,EAAE,IAAI,EAAE,GAAG,kBAAkB,CAAC,MAAM,CAAC,CAAC;IAC5C,IAAI,IAAI,KAAK,IAAI,IAAI,IAAI,KAAK,MAAM;QAAE,OAAO,IAAI,CAAC;IAClD,MAAM,MAAM,GAAG,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;IACzC,OAAO,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC;AAC9C,CAAC;AAED,SAAS,aAAa,CAAC,IAAY;IACjC,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IACxC,IAAI,KAAK,KAAK,QAAQ;QAAE,OAAO,QAAQ,CAAC;IACxC,IAAI,KAAK,KAAK,QAAQ;QAAE,OAAO,QAAQ,CAAC;IACxC,OAAO,IAAI,CAAC;AACd,CAAC"}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The projection of the plan a caller gets to see — and the same one, in prose,
|
|
3
|
+
* that a person reads before approving it.
|
|
4
|
+
*
|
|
5
|
+
* The rewritten bytes of each hub file stay OUT of it: the payload is what the
|
|
6
|
+
* migration will do, not the file it will produce, and a JSON consumer that had
|
|
7
|
+
* to diff two whole documents to learn "the markers get renamed" would be
|
|
8
|
+
* reading an implementation detail as if it were the answer.
|
|
9
|
+
*/
|
|
10
|
+
import { relpath } from "../paths.js";
|
|
11
|
+
import { pendingChanges } from "./plan.js";
|
|
12
|
+
export function migrationPreview(plan) {
|
|
13
|
+
return {
|
|
14
|
+
workspace: plan.workspace,
|
|
15
|
+
markers: plan.markers.map((hub) => ({
|
|
16
|
+
file: relpath(hub.path, plan.workspace),
|
|
17
|
+
from: hub.from,
|
|
18
|
+
to: hub.to,
|
|
19
|
+
drops_duplicate: hub.drops_duplicate,
|
|
20
|
+
})),
|
|
21
|
+
sentinels: plan.sentinels.map((seed) => ({ folder: seed.folder, date: seed.date })),
|
|
22
|
+
rows: plan.rows.map((seed) => ({
|
|
23
|
+
folder: seed.folder,
|
|
24
|
+
state: seed.state,
|
|
25
|
+
date: seed.date,
|
|
26
|
+
})),
|
|
27
|
+
conflicts: plan.conflicts.map((conflict) => ({
|
|
28
|
+
...conflict,
|
|
29
|
+
subject: relpath(conflict.subject, plan.workspace),
|
|
30
|
+
})),
|
|
31
|
+
legacy: plan.legacy,
|
|
32
|
+
next_correlative: plan.next_correlative,
|
|
33
|
+
pending: pendingChanges(plan),
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
export function renderMigrationPreview(preview) {
|
|
37
|
+
const lines = [
|
|
38
|
+
`Workspace: ${preview.workspace}`,
|
|
39
|
+
`Serie legacy: ${countOf(preview.legacy.length, "carpeta", "carpetas")} · próximo correlativo: ${preview.next_correlative}`,
|
|
40
|
+
];
|
|
41
|
+
if (preview.markers.length > 0) {
|
|
42
|
+
lines.push("", "Marcadores del bloque de proyecto:");
|
|
43
|
+
for (const marker of preview.markers) {
|
|
44
|
+
const duplicate = marker.drops_duplicate
|
|
45
|
+
? " (y elimina el bloque vacío que el CLI había agregado aparte)"
|
|
46
|
+
: "";
|
|
47
|
+
lines.push(` ${marker.file} — ${marker.from} → ${marker.to}${duplicate}`);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
if (preview.sentinels.length > 0) {
|
|
51
|
+
lines.push("", "Centinelas de cierre a sembrar, con la fecha del histórico:");
|
|
52
|
+
for (const sentinel of preview.sentinels) {
|
|
53
|
+
lines.push(` ${sentinel.folder} — cerrada el ${sentinel.date || "(fila sin fecha)"}`);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
if (preview.rows.length > 0) {
|
|
57
|
+
lines.push("", "Filas a reservar en el histórico, para que el número no se reasigne:");
|
|
58
|
+
for (const row of preview.rows) {
|
|
59
|
+
lines.push(` ${row.folder} — ${row.state}, ${dateNote(row.date)}`);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
if (preview.pending === 0) {
|
|
63
|
+
lines.push("", "Nada que migrar: el workspace ya opera con el modelo actual.");
|
|
64
|
+
}
|
|
65
|
+
lines.push(...conflictLines(preview.conflicts));
|
|
66
|
+
if (preview.pending > 0) {
|
|
67
|
+
lines.push("", "Para aplicarlo:", " aw workspace-migrate --apply");
|
|
68
|
+
}
|
|
69
|
+
return lines.join("\n");
|
|
70
|
+
}
|
|
71
|
+
export function renderMigrationApplied(applied) {
|
|
72
|
+
const lines = [`Workspace migrado: ${applied.workspace}`];
|
|
73
|
+
if (applied.markers_renamed.length > 0) {
|
|
74
|
+
const files = applied.markers_renamed.map((path) => relpath(path, applied.workspace));
|
|
75
|
+
lines.push(`Marcadores renombrados: ${files.join(", ")}`);
|
|
76
|
+
}
|
|
77
|
+
if (applied.duplicates_dropped.length > 0) {
|
|
78
|
+
const files = applied.duplicates_dropped.map((path) => relpath(path, applied.workspace));
|
|
79
|
+
lines.push(`Bloques duplicados eliminados: ${files.join(", ")}`);
|
|
80
|
+
}
|
|
81
|
+
if (applied.sentinels_seeded.length > 0) {
|
|
82
|
+
lines.push(`Centinelas sembrados: ${applied.sentinels_seeded.join(", ")}`);
|
|
83
|
+
}
|
|
84
|
+
if (applied.rows_seeded.length > 0) {
|
|
85
|
+
lines.push(`Filas reservadas: ${applied.rows_seeded.join(", ")}`);
|
|
86
|
+
}
|
|
87
|
+
if (applied.rows_dated_today.length > 0) {
|
|
88
|
+
lines.push(`Sin fecha declarada — su fila nació con la de hoy: ${applied.rows_dated_today.join(", ")}`);
|
|
89
|
+
}
|
|
90
|
+
if (lines.length === 1)
|
|
91
|
+
lines.push("No había nada que migrar.");
|
|
92
|
+
lines.push(`Próximo correlativo: ${applied.next_correlative}`);
|
|
93
|
+
lines.push(...conflictLines(applied.conflicts));
|
|
94
|
+
return lines.join("\n");
|
|
95
|
+
}
|
|
96
|
+
function conflictLines(conflicts) {
|
|
97
|
+
if (conflicts.length === 0)
|
|
98
|
+
return [];
|
|
99
|
+
const lines = ["", "Sin tocar, porque el histórico y el disco no dicen lo mismo:"];
|
|
100
|
+
for (const conflict of conflicts) {
|
|
101
|
+
lines.push(` ${conflict.subject} [${conflict.reason}] — ${conflict.detail}`);
|
|
102
|
+
}
|
|
103
|
+
return lines;
|
|
104
|
+
}
|
|
105
|
+
function dateNote(date) {
|
|
106
|
+
return date === null ? "sin fecha declarada: la fila nace con la de hoy" : date;
|
|
107
|
+
}
|
|
108
|
+
function countOf(total, singular, plural) {
|
|
109
|
+
return `${total} ${total === 1 ? singular : plural}`;
|
|
110
|
+
}
|
|
111
|
+
//# sourceMappingURL=preview.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"preview.js","sourceRoot":"","sources":["../../../src/application/workspace-migrate/preview.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { WORKLINE_FLOWS } from "../../application/capability/compose.js";
|
|
2
2
|
import { isHarnessId } from "../../application/dev-only-services.js";
|
|
3
|
-
import { advanceFlow } from "../../application/flow/flow-service.js";
|
|
3
|
+
import { advanceFlow, recoverFlowBoundary, } from "../../application/flow/flow-service.js";
|
|
4
4
|
import { internalActionExecutor } from "../../application/flow/internal-actions.js";
|
|
5
5
|
import { submitFlow } from "../../application/flow/submit.js";
|
|
6
6
|
import { renderDirectiveHuman } from "../../domain/flow/directive.js";
|
|
@@ -15,16 +15,53 @@ import { fail, failSemantic, failSessionResolution } from "../render.js";
|
|
|
15
15
|
* `advance` applies every consecutive transition the CLI owns and returns the
|
|
16
16
|
* first boundary it does not; `submit` (the second verb) brings an answer, a
|
|
17
17
|
* choice or an approval back and is delivered by the phases that own the
|
|
18
|
-
* boundaries.
|
|
18
|
+
* boundaries. `recover` is the third and the only one that is not part of a
|
|
19
|
+
* walk: it gives a boundary that ran out of attempts a way back to being
|
|
20
|
+
* answerable, which until it existed meant editing the run's state by hand.
|
|
19
21
|
*
|
|
20
22
|
* The directive travels with `ok: true` plus its outcome — with `ok: false` the
|
|
21
23
|
* host never calls `renderHuman`, and a boundary the person cannot see is a
|
|
22
24
|
* boundary that did not happen.
|
|
23
25
|
*/
|
|
24
|
-
const VERBS = ["advance", "submit"];
|
|
26
|
+
const VERBS = ["advance", "submit", "recover"];
|
|
27
|
+
/**
|
|
28
|
+
* The answer envelope, published where an executor can read it WITHOUT running a
|
|
29
|
+
* journey.
|
|
30
|
+
*
|
|
31
|
+
* The contract itself lives in `domain/flow/answer.ts` and is enforced there;
|
|
32
|
+
* this is its documentation, and until now it existed nowhere else. The cost of
|
|
33
|
+
* that was measured: one host opened eleven throwaway sessions whose declared
|
|
34
|
+
* objective was to discover this shape, and a second host, independently,
|
|
35
|
+
* repeated its wrong guess. A contract only a failed attempt can teach is a
|
|
36
|
+
* contract that charges every executor the same tuition.
|
|
37
|
+
*
|
|
38
|
+
* Kept beside the command rather than in the doctrine bundle because the bundle's
|
|
39
|
+
* context budget is frozen and this is reference material: it is read when
|
|
40
|
+
* somebody is composing an answer, not on every run.
|
|
41
|
+
*/
|
|
42
|
+
const ENVELOPE = [
|
|
43
|
+
"Sobre de `submit` — un único objeto JSON por stdin, con sus campos en el NIVEL SUPERIOR:",
|
|
44
|
+
"",
|
|
45
|
+
" siempre input_digest: el `state_digest` de la directiva que contestás — la directiva lo rotula `continuidad:` y el sobre lo llama `input_digest`; es el mismo valor.",
|
|
46
|
+
"",
|
|
47
|
+
" execution outcome: completed | needs_input | blocked | failed | cancelled",
|
|
48
|
+
" invocation: {program, args[], target, input} — el OBJETO idéntico al que la directiva selló; si cambia el programa, un argumento, el target o el input, se rechaza.",
|
|
49
|
+
" validations: [{id, passed, detail}] — un ítem por CADA evidencia que la directiva exige, con `passed: true` y `detail` no vacío: ahí va la salida real de la herramienta, no una afirmación sobre ella.",
|
|
50
|
+
" effects: {planned[], approved[], applied[]} — el registro de clases de efecto, no una lista.",
|
|
51
|
+
" output: opcional — {value, reference: {id, revision, digest, locator}, completeness} o null.",
|
|
52
|
+
"",
|
|
53
|
+
" semantic signals[]: solo identificadores del vocabulario que esa frontera declara · decisions: objeto con al menos una clave. Alcanza con uno de los dos.",
|
|
54
|
+
" artifacts: [{path, content}] — obligatorio cuando la frontera propone efectos locales, rechazado cuando no propone ninguno.",
|
|
55
|
+
"",
|
|
56
|
+
" human choice: la etiqueta literal de una de las alternativas que la directiva emitió.",
|
|
57
|
+
"",
|
|
58
|
+
" authorization --approval <digest> con el digest que la directiva nombra en `siguiente:` — NO es el state_digest · choice: opcional, y con `Cerrar` o `Compactar` no se pide aprobación.",
|
|
59
|
+
].join("\n");
|
|
25
60
|
export const flowCommand = {
|
|
26
61
|
name: "flow",
|
|
27
|
-
describe: `Avanza un recorrido de Workline hasta su primera frontera no determinista y devuelve su directiva. Verbos: ${VERBS.join(" | ")}. La respuesta de submit entra por stdin como JSON y la aprobación de efecto viaja aparte en --approval. Usage: aw flow advance --session <código> [--flow <flow> --adopt]
|
|
62
|
+
describe: `Avanza un recorrido de Workline hasta su primera frontera no determinista y devuelve su directiva. Verbos: ${VERBS.join(" | ")}. La respuesta de submit entra por stdin como JSON y la aprobación de efecto viaja aparte en --approval. recover le devuelve los intentos a la frontera agotada vigente conservando todo lo aplicado, y se niega si esa frontera ya ejerció efectos. Usage: aw flow advance --session <código> [--flow <flow> --adopt] · aw flow recover --session <código> [--transition <id>].
|
|
63
|
+
|
|
64
|
+
${ENVELOPE}`,
|
|
28
65
|
async execute(args, ctx) {
|
|
29
66
|
const requestedHost = args.values.get("host");
|
|
30
67
|
if (requestedHost !== undefined && !isHarnessId(requestedHost)) {
|
|
@@ -32,7 +69,7 @@ export const flowCommand = {
|
|
|
32
69
|
}
|
|
33
70
|
const verb = args.rest[0];
|
|
34
71
|
if (verb === undefined || !VERBS.includes(verb)) {
|
|
35
|
-
return fail("ARGS_INVALID", `uso: aw flow ${VERBS.join(" | ")} --session <código> [--flow <flow> --adopt] [--approval <digest>]`);
|
|
72
|
+
return fail("ARGS_INVALID", `uso: aw flow ${VERBS.join(" | ")} --session <código> [--flow <flow> --adopt] [--approval <digest>] [--transition <id>]`);
|
|
36
73
|
}
|
|
37
74
|
const flow = args.values.get("flow");
|
|
38
75
|
if (flow !== undefined && !WORKLINE_FLOWS.includes(flow)) {
|
|
@@ -47,6 +84,16 @@ export const flowCommand = {
|
|
|
47
84
|
...(named.code !== undefined ? { code: named.code } : {}),
|
|
48
85
|
...(contextId !== undefined ? { contextId } : {}),
|
|
49
86
|
};
|
|
87
|
+
// Before the executor, and without stdin: recovery is not a walk. It returns
|
|
88
|
+
// the boundary to an answerable state and stops there, so whatever runs next
|
|
89
|
+
// is decided by whoever answers it — never by the command that unblocked it.
|
|
90
|
+
if (verb === "recover") {
|
|
91
|
+
const transition = args.values.get("transition");
|
|
92
|
+
return project(await recoverFlowBoundary(ctx.fs, ctx.paths, {
|
|
93
|
+
...session,
|
|
94
|
+
...(transition !== undefined ? { transition } : {}),
|
|
95
|
+
}));
|
|
96
|
+
}
|
|
50
97
|
// Only `submit` reads stdin: an `advance` that waited on a pipe would hang a
|
|
51
98
|
// caller that has nothing to send yet — the same split `capability` makes
|
|
52
99
|
// between `prepare` and the stages that carry content.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"flow.js","sourceRoot":"","sources":["../../../src/cli/commands/flow.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,EAAE,WAAW,EAAE,MAAM,wCAAwC,CAAC;AACrE,OAAO,
|
|
1
|
+
{"version":3,"file":"flow.js","sourceRoot":"","sources":["../../../src/cli/commands/flow.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Flags every command tolerates because the RUNTIME reads them, not the
|
|
3
|
+
* command: namespace resolution, output projection and help. `-h` never gets
|
|
4
|
+
* this far (main.ts prints help before dispatching) and is listed anyway, so
|
|
5
|
+
* the set answers for itself instead of relying on the caller's order.
|
|
6
|
+
*/
|
|
7
|
+
const RUNTIME_FLAGS = new Set([
|
|
8
|
+
"namespace",
|
|
9
|
+
"format",
|
|
10
|
+
"json",
|
|
11
|
+
"detail",
|
|
12
|
+
"help",
|
|
13
|
+
"version",
|
|
14
|
+
"h",
|
|
15
|
+
]);
|
|
16
|
+
/**
|
|
17
|
+
* Every flag the invocation carried, whichever map the parser routed it to.
|
|
18
|
+
*
|
|
19
|
+
* A flag with a value lands in `values` (or `valuesMulti`), a bare one in
|
|
20
|
+
* `flags` as `--name`; reading only one of the three is how an unknown flag
|
|
21
|
+
* stays invisible depending on whether the caller gave it a value.
|
|
22
|
+
*/
|
|
23
|
+
function passedFlags(args) {
|
|
24
|
+
const names = new Set();
|
|
25
|
+
for (const name of args.values.keys())
|
|
26
|
+
names.add(name);
|
|
27
|
+
for (const name of args.valuesMulti.keys())
|
|
28
|
+
names.add(name);
|
|
29
|
+
for (const token of args.flags)
|
|
30
|
+
names.add(token.replace(/^--?/, ""));
|
|
31
|
+
return [...names];
|
|
32
|
+
}
|
|
33
|
+
export function reviewFlags(args, contract) {
|
|
34
|
+
const known = new Set(contract.known);
|
|
35
|
+
const retired = new Set(contract.retired ?? []);
|
|
36
|
+
const review = { unknown: [], retired: [] };
|
|
37
|
+
for (const name of passedFlags(args)) {
|
|
38
|
+
if (known.has(name) || RUNTIME_FLAGS.has(name))
|
|
39
|
+
continue;
|
|
40
|
+
(retired.has(name) ? review.retired : review.unknown).push(`--${name}`);
|
|
41
|
+
}
|
|
42
|
+
review.unknown.sort();
|
|
43
|
+
review.retired.sort();
|
|
44
|
+
return review;
|
|
45
|
+
}
|
|
46
|
+
/** The refusal message, naming what the command does accept. */
|
|
47
|
+
export function unknownFlagMessage(review, contract) {
|
|
48
|
+
const accepted = [...contract.known].sort().map((name) => `--${name}`);
|
|
49
|
+
return `${review.unknown.join(", ")} no ${review.unknown.length === 1 ? "es un flag" : "son flags"} de este comando; acepta ${accepted.join(", ")}`;
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=unknown-flags.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"unknown-flags.js","sourceRoot":"","sources":["../../../src/cli/commands/unknown-flags.ts"],"names":[],"mappings":"AA0BA;;;;;GAKG;AACH,MAAM,aAAa,GAAwB,IAAI,GAAG,CAAC;IACjD,WAAW;IACX,QAAQ;IACR,MAAM;IACN,QAAQ;IACR,MAAM;IACN,SAAS;IACT,GAAG;CACJ,CAAC,CAAC;AASH;;;;;;GAMG;AACH,SAAS,WAAW,CAAC,IAAgB;IACnC,MAAM,KAAK,GAAG,IAAI,GAAG,EAAU,CAAC;IAChC,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE;QAAE,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IACvD,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE;QAAE,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAC5D,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,KAAK;QAAE,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,CAAC;IACrE,OAAO,CAAC,GAAG,KAAK,CAAC,CAAC;AACpB,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,IAAgB,EAAE,QAAsB;IAClE,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IACtC,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC;IAChD,MAAM,MAAM,GAAe,EAAE,OAAO,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;IACxD,KAAK,MAAM,IAAI,IAAI,WAAW,CAAC,IAAI,CAAC,EAAE,CAAC;QACrC,IAAI,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC;YAAE,SAAS;QACzD,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC;IAC1E,CAAC;IACD,MAAM,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;IACtB,MAAM,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;IACtB,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,gEAAgE;AAChE,MAAM,UAAU,kBAAkB,CAAC,MAAkB,EAAE,QAAsB;IAC3E,MAAM,QAAQ,GAAG,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC;IACvE,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,MAAM,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,WAAW,4BAA4B,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;AACtJ,CAAC"}
|
|
@@ -1,14 +1,26 @@
|
|
|
1
|
-
import { runVisibilityDoctor } from "../../application/visibility-doctor-service.js";
|
|
1
|
+
import { runVisibilityDoctor, } from "../../application/visibility-doctor-service.js";
|
|
2
2
|
import { fail } from "../render.js";
|
|
3
3
|
export const visibilityCommand = {
|
|
4
4
|
name: "visibility",
|
|
5
|
-
describe: "Inspector de visibilidad multi-root del hub. Subcomandos: doctor [--workspace dir] [--global]
|
|
5
|
+
describe: "Inspector de visibilidad multi-root del hub. Subcomandos: doctor [--workspace dir] [--global] " +
|
|
6
|
+
"[--format human|json] [--detail].",
|
|
6
7
|
async execute(args, ctx) {
|
|
7
8
|
const subcommand = args.rest[0];
|
|
8
9
|
if (subcommand === "doctor")
|
|
9
10
|
return runDoctorSub(args, ctx);
|
|
10
11
|
return fail("INVALID_INPUT", "visibility requiere subcomando: doctor");
|
|
11
12
|
},
|
|
13
|
+
/**
|
|
14
|
+
* The human projection of the SAME result the JSON carries: one line per host
|
|
15
|
+
* with its verdict and the file(s) the verdict was read from, plus the paths
|
|
16
|
+
* that are missing or left over. It re-derives nothing.
|
|
17
|
+
*/
|
|
18
|
+
renderHuman(result, context) {
|
|
19
|
+
const data = result.data;
|
|
20
|
+
if (data === undefined)
|
|
21
|
+
return "";
|
|
22
|
+
return renderDoctor(data, context.detail);
|
|
23
|
+
},
|
|
12
24
|
};
|
|
13
25
|
async function runDoctorSub(args, ctx) {
|
|
14
26
|
const workspace = args.values.get("workspace");
|
|
@@ -18,19 +30,96 @@ async function runDoctorSub(args, ctx) {
|
|
|
18
30
|
});
|
|
19
31
|
const totalReports = data.reports.length + data.global_reports.length;
|
|
20
32
|
const okCount = data.summary.ok;
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
33
|
+
if (okCount === totalReports)
|
|
34
|
+
return { ok: true, data, exitCode: 0 };
|
|
35
|
+
// Drift stays `ok:false` (exit 1 is the contract scripts already gate on), and
|
|
36
|
+
// the host renders `ok:false` ONLY through the failure projection — so the
|
|
37
|
+
// report travels in `action`, or `--format human` would print a bare count in
|
|
38
|
+
// exactly the case the person needs the per-host diagnosis.
|
|
39
|
+
return fail("VISIBILITY_DRIFT", `${totalReports - okCount}/${totalReports} reports con drift (ver data.reports/global_reports)`, {
|
|
40
|
+
...data,
|
|
41
|
+
// `--detail` is read HERE and not in the renderer because the failure
|
|
42
|
+
// projection never reaches `renderHuman` — and detail is precisely what
|
|
43
|
+
// the person asked for in the only case that prints this text.
|
|
44
|
+
action: `revisá el drift host por host:\n\n${renderDoctor(data, args.flags.has("--detail"))}`,
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
const STATUS_MARK = {
|
|
48
|
+
ok: "✓",
|
|
49
|
+
"missing-paths": "✗",
|
|
50
|
+
"extra-paths": "✗",
|
|
51
|
+
"no-settings": "✗",
|
|
52
|
+
"no-project-block": "✗",
|
|
53
|
+
"global-pollution": "✗",
|
|
54
|
+
};
|
|
55
|
+
/**
|
|
56
|
+
* Statuses whose `detail` only restates the line it would sit under: `ok` is the
|
|
57
|
+
* line itself, and missing/extra already print the paths one by one. Every other
|
|
58
|
+
* status prints no list, so its `detail` is the only thing that explains it.
|
|
59
|
+
*/
|
|
60
|
+
const REDUNDANT_DETAIL = new Set([
|
|
61
|
+
"ok",
|
|
62
|
+
"missing-paths",
|
|
63
|
+
"extra-paths",
|
|
64
|
+
]);
|
|
65
|
+
const STATUS_WIDTH = Math.max(...Object.keys(STATUS_MARK).map((s) => s.length));
|
|
66
|
+
function renderDoctor(data, detail) {
|
|
67
|
+
const lines = [`Visibilidad multi-root · ${data.workspace_dir}`, ""];
|
|
68
|
+
lines.push(...renderScope("workspace", data.reports, detail));
|
|
69
|
+
if (data.global_reports.length > 0) {
|
|
70
|
+
lines.push("", ...renderScope("global", data.global_reports, detail));
|
|
71
|
+
}
|
|
72
|
+
const total = data.reports.length + data.global_reports.length;
|
|
73
|
+
lines.push("", `${data.summary.ok}/${total} host(s) sin drift`);
|
|
74
|
+
lines.push(...renderFixes([...data.reports, ...data.global_reports]));
|
|
75
|
+
return `${lines.join("\n").trimEnd()}\n`;
|
|
76
|
+
}
|
|
77
|
+
function renderScope(title, reports, detail) {
|
|
78
|
+
if (reports.length === 0)
|
|
79
|
+
return [];
|
|
80
|
+
const hostWidth = Math.max(...reports.map((r) => r.host.length));
|
|
81
|
+
const lines = [title];
|
|
82
|
+
for (const report of reports) {
|
|
83
|
+
const head = `${report.host.padEnd(hostWidth)} ${report.status.padEnd(STATUS_WIDTH)}`;
|
|
84
|
+
// The file(s) the verdict was actually read from — never a hardcoded name.
|
|
85
|
+
lines.push(` ${STATUS_MARK[report.status]} ${head} ${report.targets.join(" + ")}`);
|
|
86
|
+
if (report.missing.length > 0)
|
|
87
|
+
lines.push(` faltan: ${report.missing.join(", ")}`);
|
|
88
|
+
if (report.extra.length > 0)
|
|
89
|
+
lines.push(` sobran: ${report.extra.join(", ")}`);
|
|
90
|
+
if (report.detail !== undefined && (detail || !REDUNDANT_DETAIL.has(report.status))) {
|
|
91
|
+
lines.push(` ${report.detail}`);
|
|
92
|
+
}
|
|
93
|
+
if (detail && report.declared_paths.length > 0) {
|
|
94
|
+
lines.push(` declarados: ${report.declared_paths.join(", ")}`);
|
|
95
|
+
lines.push(` registrados: ${report.registered_paths.join(", ") || "(ninguno)"}`);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
return lines;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* One command per kind of drift present — never advice for drift nobody has.
|
|
102
|
+
*
|
|
103
|
+
* The trigger is the LIST, not the status: `status` reports only the most severe
|
|
104
|
+
* drift, so a host with paths missing AND left over would otherwise print
|
|
105
|
+
* `sobran:` above and no command to remove them.
|
|
106
|
+
*/
|
|
107
|
+
function renderFixes(reports) {
|
|
108
|
+
const fixes = [];
|
|
109
|
+
if (reports.some((r) => r.missing.length > 0)) {
|
|
110
|
+
fixes.push(" aw attach-multiroot --from-sources registra las fuentes que faltan");
|
|
111
|
+
}
|
|
112
|
+
// Global leftovers are the hub's own sources leaking into ~/: a different
|
|
113
|
+
// command, and `--path` on the workspace scope would not touch them.
|
|
114
|
+
if (reports.some((r) => r.scope === "workspace" && r.extra.length > 0)) {
|
|
115
|
+
fixes.push(" aw detach-multiroot --path <dir> quita las rutas que sobran");
|
|
116
|
+
}
|
|
117
|
+
if (reports.some((r) => r.status === "global-pollution")) {
|
|
118
|
+
fixes.push(" aw detach-multiroot --global --from-sources limpia el scope global");
|
|
119
|
+
}
|
|
120
|
+
if (reports.some((r) => r.status === "no-project-block")) {
|
|
121
|
+
fixes.push(" aw workspace-init --source <alias>:<path> declara las fuentes del workspace");
|
|
122
|
+
}
|
|
123
|
+
return fixes.length === 0 ? [] : ["", "Para corregir:", ...fixes];
|
|
35
124
|
}
|
|
36
125
|
//# sourceMappingURL=visibility.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"visibility.js","sourceRoot":"","sources":["../../../src/cli/commands/visibility.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"visibility.js","sourceRoot":"","sources":["../../../src/cli/commands/visibility.ts"],"names":[],"mappings":"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"}
|