@tacuchi/agent-workflow-cli 20.22.0 → 20.23.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 +42 -0
- package/dist/adapters/git-cli.js.map +1 -1
- package/dist/application/artifacts-service.js +5 -5
- package/dist/application/artifacts-service.js.map +1 -1
- package/dist/application/checkpoint-service.js +60 -55
- package/dist/application/checkpoint-service.js.map +1 -1
- package/dist/application/checkpoint-write-service.js +61 -66
- package/dist/application/checkpoint-write-service.js.map +1 -1
- package/dist/application/decisiones-service.js +5 -5
- package/dist/application/decisiones-service.js.map +1 -1
- package/dist/application/export-service.js +250 -0
- package/dist/application/export-service.js.map +1 -0
- package/dist/application/fix-git-service.js +244 -0
- package/dist/application/fix-git-service.js.map +1 -0
- package/dist/application/history-update-service.js +35 -24
- package/dist/application/history-update-service.js.map +1 -1
- package/dist/application/lifecycle-target.js +39 -0
- package/dist/application/lifecycle-target.js.map +1 -0
- package/dist/application/parsers/spec-relation.js +80 -0
- package/dist/application/parsers/spec-relation.js.map +1 -0
- package/dist/application/paths-service.js +8 -0
- package/dist/application/paths-service.js.map +1 -1
- package/dist/application/persist-service.js +285 -0
- package/dist/application/persist-service.js.map +1 -0
- package/dist/application/release-data/artifacts.js +17 -21
- package/dist/application/release-data/artifacts.js.map +1 -1
- package/dist/application/resume-service.js +184 -0
- package/dist/application/resume-service.js.map +1 -0
- package/dist/application/semantic-operation/protocol.js +247 -0
- package/dist/application/semantic-operation/protocol.js.map +1 -0
- package/dist/application/semantic-operation/publish.js +80 -0
- package/dist/application/semantic-operation/publish.js.map +1 -0
- package/dist/application/session-binding-service.js +125 -0
- package/dist/application/session-binding-service.js.map +1 -0
- package/dist/application/session-close-service.js +60 -39
- package/dist/application/session-close-service.js.map +1 -1
- package/dist/application/session-create-service.js +45 -19
- package/dist/application/session-create-service.js.map +1 -1
- package/dist/application/session-resolver.js +180 -44
- package/dist/application/session-resolver.js.map +1 -1
- package/dist/application/session-resume-service.js +39 -9
- package/dist/application/session-resume-service.js.map +1 -1
- package/dist/application/sessions-service.js +0 -2
- package/dist/application/sessions-service.js.map +1 -1
- package/dist/application/status-service.js +24 -388
- package/dist/application/status-service.js.map +1 -1
- package/dist/application/tasks-service.js +5 -5
- package/dist/application/tasks-service.js.map +1 -1
- package/dist/application/workline-index-service.js +510 -0
- package/dist/application/workline-index-service.js.map +1 -0
- package/dist/cli/commands/checkpoint-read.js +10 -6
- package/dist/cli/commands/checkpoint-read.js.map +1 -1
- package/dist/cli/commands/checkpoint-write.js +38 -11
- package/dist/cli/commands/checkpoint-write.js.map +1 -1
- package/dist/cli/commands/export.js +117 -0
- package/dist/cli/commands/export.js.map +1 -0
- package/dist/cli/commands/fix-git.js +109 -0
- package/dist/cli/commands/fix-git.js.map +1 -0
- package/dist/cli/commands/generate-launch.js +35 -3
- package/dist/cli/commands/generate-launch.js.map +1 -1
- package/dist/cli/commands/history-update.js +1 -1
- package/dist/cli/commands/history-update.js.map +1 -1
- package/dist/cli/commands/index.js +11 -0
- package/dist/cli/commands/index.js.map +1 -1
- package/dist/cli/commands/persist.js +67 -0
- package/dist/cli/commands/persist.js.map +1 -0
- package/dist/cli/commands/resume-summary.js +14 -3
- package/dist/cli/commands/resume-summary.js.map +1 -1
- package/dist/cli/commands/resume.js +73 -0
- package/dist/cli/commands/resume.js.map +1 -0
- package/dist/cli/commands/session-artifacts.js +12 -11
- package/dist/cli/commands/session-artifacts.js.map +1 -1
- package/dist/cli/commands/session-close.js +8 -7
- package/dist/cli/commands/session-close.js.map +1 -1
- package/dist/cli/commands/session-create.js +5 -1
- package/dist/cli/commands/session-create.js.map +1 -1
- package/dist/cli/commands/session-resume.js +16 -10
- package/dist/cli/commands/session-resume.js.map +1 -1
- package/dist/cli/commands/status.js +66 -2
- package/dist/cli/commands/status.js.map +1 -1
- package/dist/cli/commands/workspace-init.js +21 -2
- package/dist/cli/commands/workspace-init.js.map +1 -1
- package/dist/cli/context-id.js +133 -0
- package/dist/cli/context-id.js.map +1 -0
- package/dist/cli/help-groups.js +16 -1
- package/dist/cli/help-groups.js.map +1 -1
- package/dist/cli/main.js +44 -16
- package/dist/cli/main.js.map +1 -1
- package/dist/cli/output-mode.js +41 -0
- package/dist/cli/output-mode.js.map +1 -0
- package/dist/cli/parser.js +6 -0
- package/dist/cli/parser.js.map +1 -1
- package/dist/cli/registry.js.map +1 -1
- package/dist/cli/render.js +53 -0
- package/dist/cli/render.js.map +1 -1
- package/package.json +1 -1
- package/skills/w/commands/export-diagrams.md +19 -10
- package/skills/w/commands/export-manuals.md +20 -10
- package/skills/w/commands/export-reports.md +20 -11
- package/skills/w/commands/export-scripts.md +20 -10
- package/skills/w/commands/fix-git.md +31 -12
- package/skills/w/commands/generate-launch.md +1 -1
- package/skills/w/commands/persist.md +33 -68
- package/skills/w/commands/resume.md +25 -46
- package/skills/w/commands/status.md +12 -48
- package/skills/w/commands/workspace-init.md +3 -3
- package/skills/w/hooks/README.md +21 -2
- package/skills/w/hooks/hooks.template.json +2 -2
- package/skills/w/roles/git/ROLE.md +7 -8
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
import { firstNonEmptyLine, parseMdSectionBilingual } from "./markdown.js";
|
|
2
|
+
import { findArtifact } from "./session-artifacts.js";
|
|
3
|
+
import { resolveSessionTarget } from "./session-resolver.js";
|
|
4
|
+
import { buildWorklineIndex, } from "./workline-index-service.js";
|
|
5
|
+
export async function runResume(fs, env, paths, input = {}) {
|
|
6
|
+
const index = await buildWorklineIndex(fs, env, paths, {
|
|
7
|
+
...(input.now !== undefined ? { now: input.now } : {}),
|
|
8
|
+
});
|
|
9
|
+
if (input.code !== undefined)
|
|
10
|
+
return await resumeSession(fs, paths, index, input);
|
|
11
|
+
if (input.target !== undefined)
|
|
12
|
+
return resumeTarget(index, input.target);
|
|
13
|
+
return await resumePipeline(fs, index);
|
|
14
|
+
}
|
|
15
|
+
// ── explicit target ──────────────────────────────────────────────────────────
|
|
16
|
+
/**
|
|
17
|
+
* An explicit target wins over the pipeline, and matches by exact path or by
|
|
18
|
+
* document number — **never by slug**, which is how the old survey attached a
|
|
19
|
+
* session to the wrong plan. A number that names both a spec and a plan is a
|
|
20
|
+
* genuine tie, so it comes back as candidates, the same answer the pipeline
|
|
21
|
+
* gives for any other tie.
|
|
22
|
+
*/
|
|
23
|
+
function resumeTarget(index, target) {
|
|
24
|
+
const specs = index.specs.filter((s) => s.file === target || s.number === target);
|
|
25
|
+
const plans = index.plans.filter((p) => p.file === target || p.number === target);
|
|
26
|
+
const matches = [
|
|
27
|
+
...specs.map((s) => specProposal(s, index)),
|
|
28
|
+
...plans.map(planProposal),
|
|
29
|
+
];
|
|
30
|
+
const [first] = matches;
|
|
31
|
+
if (first === undefined) {
|
|
32
|
+
return {
|
|
33
|
+
status: "invalid_target",
|
|
34
|
+
target,
|
|
35
|
+
action: `ningún documento coincide con '${target}': pasá una ruta docs/specs|docs/plans o el número, o usá --code para una sesión`,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
if (matches.length > 1) {
|
|
39
|
+
return {
|
|
40
|
+
status: "candidates",
|
|
41
|
+
candidates: matches,
|
|
42
|
+
action: `'${target}' identifica ${matches.length} documentos: repetí con la ruta completa`,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
return { status: "proposal", via: "explicit", proposal: first };
|
|
46
|
+
}
|
|
47
|
+
async function resumeSession(fs, paths, index, input) {
|
|
48
|
+
// `bind: false` on purpose: this is a read. `sessionReadRequest` would record
|
|
49
|
+
// the conversation→session association, and `resume` must not write.
|
|
50
|
+
const resolution = await resolveSessionTarget(fs, paths, {
|
|
51
|
+
...(input.code !== undefined ? { code: input.code } : {}),
|
|
52
|
+
...(input.contextId !== undefined ? { contextId: input.contextId } : {}),
|
|
53
|
+
allowClosed: true,
|
|
54
|
+
bind: false,
|
|
55
|
+
});
|
|
56
|
+
if (resolution.outcome !== "resolved") {
|
|
57
|
+
return {
|
|
58
|
+
status: "invalid_target",
|
|
59
|
+
target: input.code ?? "",
|
|
60
|
+
action: resolution.action,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
const folder = resolution.session.folder;
|
|
64
|
+
const session = index.sessions.find((s) => s.folder === folder);
|
|
65
|
+
const path = session?.path ?? resolution.session.path;
|
|
66
|
+
return {
|
|
67
|
+
status: "proposal",
|
|
68
|
+
via: "explicit",
|
|
69
|
+
proposal: await sessionProposal(fs, folder, path, session),
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
// ── no target: the documental pipeline ───────────────────────────────────────
|
|
73
|
+
async function resumePipeline(fs, index) {
|
|
74
|
+
const [head] = index.pipeline;
|
|
75
|
+
if (head === undefined) {
|
|
76
|
+
return { status: "idle", action: "no hay trabajo pendiente: el pipeline está vacío" };
|
|
77
|
+
}
|
|
78
|
+
// A tie is priority + progress, never date. Two items that reach here are
|
|
79
|
+
// equally next, and picking one for the user is what this replaces.
|
|
80
|
+
const tied = index.pipeline.filter((item) => item.priority === head.priority && (item.started ?? false) === (head.started ?? false));
|
|
81
|
+
if (tied.length > 1) {
|
|
82
|
+
const candidates = await Promise.all(tied.map((item) => pipelineProposal(fs, index, item)));
|
|
83
|
+
return {
|
|
84
|
+
status: "candidates",
|
|
85
|
+
candidates,
|
|
86
|
+
action: `${tied.length} candidatos con la misma prioridad: elegí uno y volvé a invocar con su ruta`,
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
return { status: "proposal", via: "pipeline", proposal: await pipelineProposal(fs, index, head) };
|
|
90
|
+
}
|
|
91
|
+
async function pipelineProposal(fs, index, item) {
|
|
92
|
+
if (item.kind === "plan-open") {
|
|
93
|
+
const plan = index.plans.find((p) => p.file === item.file);
|
|
94
|
+
if (plan !== undefined)
|
|
95
|
+
return planProposal(plan);
|
|
96
|
+
}
|
|
97
|
+
if (item.kind === "checkpoint-orphan") {
|
|
98
|
+
const session = index.sessions.find((s) => s.folder === item.file);
|
|
99
|
+
if (session !== undefined) {
|
|
100
|
+
return await sessionProposal(fs, session.folder, session.path, session);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
const spec = index.specs.find((s) => s.file === item.file);
|
|
104
|
+
if (spec !== undefined)
|
|
105
|
+
return specProposal(spec, index);
|
|
106
|
+
return {
|
|
107
|
+
kind: item.kind,
|
|
108
|
+
file: item.file,
|
|
109
|
+
number: item.number,
|
|
110
|
+
objective: item.summary,
|
|
111
|
+
progress: "—",
|
|
112
|
+
next: item.summary,
|
|
113
|
+
command: item.command,
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
// ── proposals ────────────────────────────────────────────────────────────────
|
|
117
|
+
function specProposal(spec, index) {
|
|
118
|
+
const planned = index.plans.some((p) => p.spec.status === "resolved" && p.spec.number === spec.number);
|
|
119
|
+
const refine = spec.status !== "ready-for-plan";
|
|
120
|
+
return {
|
|
121
|
+
kind: refine ? "spec-unrefined" : "spec-unplanned",
|
|
122
|
+
file: spec.file,
|
|
123
|
+
number: spec.number,
|
|
124
|
+
objective: `spec ${spec.number}${spec.slug ? ` — ${spec.slug}` : ""}`,
|
|
125
|
+
progress: `status ${spec.status}, ${spec.open_questions} pregunta(s) abierta(s)`,
|
|
126
|
+
next: refine
|
|
127
|
+
? "refinar hasta ready-for-plan"
|
|
128
|
+
: planned
|
|
129
|
+
? "ya tiene plan derivado"
|
|
130
|
+
: "generar su plan",
|
|
131
|
+
command: refine ? `/w:spec-refine ${spec.file}` : `/w:plan-new ${spec.file}`,
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
function planProposal(plan) {
|
|
135
|
+
const [blocked] = plan.blocked_phases;
|
|
136
|
+
const phases = plan.phases_total > 0 ? ` · fases ${plan.phases_validated}/${plan.phases_total}` : "";
|
|
137
|
+
return {
|
|
138
|
+
kind: "plan-open",
|
|
139
|
+
file: plan.file,
|
|
140
|
+
number: plan.number,
|
|
141
|
+
objective: `plan ${plan.number}${plan.slug ? ` — ${plan.slug}` : ""}`,
|
|
142
|
+
progress: `${plan.tasks_done}/${plan.tasks_total} tareas (${plan.progress_pct}%)${phases}`,
|
|
143
|
+
next: describePlanNext(plan, blocked),
|
|
144
|
+
command: `/w:plan-exec ${plan.file}`,
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
function describePlanNext(plan, blocked) {
|
|
148
|
+
if (blocked !== undefined) {
|
|
149
|
+
return `BLOQUEADA F${blocked.number} — ${blocked.blocker ?? "sin motivo declarado"}`;
|
|
150
|
+
}
|
|
151
|
+
if (plan.plan_state === "inconsistent") {
|
|
152
|
+
return "el plan se declara done pero sus contadores no lo respaldan: repararlo a mano";
|
|
153
|
+
}
|
|
154
|
+
if (plan.final_validation_pending)
|
|
155
|
+
return "todo ejecutado: falta la validación final y el cierre";
|
|
156
|
+
return "continuar por la primera fase no validada";
|
|
157
|
+
}
|
|
158
|
+
async function sessionProposal(fs, folder, path, session) {
|
|
159
|
+
const objective = (await readSection(fs, path, "session", "Objective")) ?? session?.summary ?? folder;
|
|
160
|
+
const pending = await readSection(fs, path, "checkpoint", "Pending / Next");
|
|
161
|
+
const completed = await readSection(fs, path, "checkpoint", "Completed");
|
|
162
|
+
return {
|
|
163
|
+
kind: "session",
|
|
164
|
+
file: folder,
|
|
165
|
+
number: session?.code ?? null,
|
|
166
|
+
objective,
|
|
167
|
+
progress: completed === undefined ? "sin checkpoint" : `checkpoint presente: ${completed}`,
|
|
168
|
+
next: pending ?? "el checkpoint no declara trabajo pendiente",
|
|
169
|
+
command: `aw session-resume --code ${folder} --reopen`,
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
async function readSection(fs, sessionPath, artifact, heading) {
|
|
173
|
+
try {
|
|
174
|
+
const file = await findArtifact(sessionPath, artifact, fs);
|
|
175
|
+
if (!file)
|
|
176
|
+
return undefined;
|
|
177
|
+
const section = parseMdSectionBilingual(await fs.readText(file), heading);
|
|
178
|
+
return section === undefined ? undefined : firstNonEmptyLine(section);
|
|
179
|
+
}
|
|
180
|
+
catch {
|
|
181
|
+
return undefined;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
//# sourceMappingURL=resume-service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resume-service.js","sourceRoot":"","sources":["../../src/application/resume-service.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
/**
|
|
3
|
+
* The bounded CLI↔AI handshake shared by every hybrid command.
|
|
4
|
+
*
|
|
5
|
+
* The split is the whole point: the CLI owns inventory, numbering, validation,
|
|
6
|
+
* authorization and writing; the AI owns exactly one semantic step —
|
|
7
|
+
* classification, synthesis or intent — and its answer is data to be validated,
|
|
8
|
+
* never an instruction to be trusted.
|
|
9
|
+
*
|
|
10
|
+
* Three stages, and only the third can touch the filesystem:
|
|
11
|
+
*
|
|
12
|
+
* - `prepare` builds a {@link SemanticRequest}: what was read, where writing is
|
|
13
|
+
* allowed, the limits, and an `input_digest` sealing the state it saw.
|
|
14
|
+
* - `validate` parses the answer against that request and, if it survives,
|
|
15
|
+
* returns a preview plus an `approval_digest` over the exact bytes proposed.
|
|
16
|
+
* - `apply` recomputes the input digest, checks the approval still matches, and
|
|
17
|
+
* only then publishes.
|
|
18
|
+
*
|
|
19
|
+
* Validation is manual (DEC-001: no Zod) and **fail-closed**: anything absent,
|
|
20
|
+
* malformed, stale, oversized or outside the allowlist stops before the first
|
|
21
|
+
* write and comes back with a next action.
|
|
22
|
+
*/
|
|
23
|
+
export const SEMANTIC_PROTOCOL_VERSION = 1;
|
|
24
|
+
/** Stable SHA-256 of a value: object keys sorted so equal state digests equally. */
|
|
25
|
+
export function semanticDigest(value) {
|
|
26
|
+
return createHash("sha256").update(canonicalJson(value), "utf8").digest("hex");
|
|
27
|
+
}
|
|
28
|
+
function canonicalJson(value) {
|
|
29
|
+
if (value === null || typeof value !== "object")
|
|
30
|
+
return JSON.stringify(value) ?? "null";
|
|
31
|
+
if (Array.isArray(value))
|
|
32
|
+
return `[${value.map(canonicalJson).join(",")}]`;
|
|
33
|
+
const entries = Object.entries(value)
|
|
34
|
+
.filter(([, v]) => v !== undefined)
|
|
35
|
+
.sort(([a], [b]) => a.localeCompare(b))
|
|
36
|
+
.map(([k, v]) => `${JSON.stringify(k)}:${canonicalJson(v)}`);
|
|
37
|
+
return `{${entries.join(",")}}`;
|
|
38
|
+
}
|
|
39
|
+
export function buildSemanticRequest(input) {
|
|
40
|
+
const request = {
|
|
41
|
+
version: SEMANTIC_PROTOCOL_VERSION,
|
|
42
|
+
operation: input.operation,
|
|
43
|
+
input_digest: semanticDigest(input.inputs),
|
|
44
|
+
contract: input.contract,
|
|
45
|
+
inventory: input.inventory,
|
|
46
|
+
allowed_destinations: input.allowedDestinations,
|
|
47
|
+
limits: input.limits,
|
|
48
|
+
read_set: input.readSet,
|
|
49
|
+
metrics: { request_bytes: 0, read_set_bytes: input.readSetBytes },
|
|
50
|
+
};
|
|
51
|
+
// Measured after the shape is final, then written back: the number describes
|
|
52
|
+
// the payload actually sent, which is what the spec 009 budgets will consume.
|
|
53
|
+
request.metrics.request_bytes = Buffer.byteLength(JSON.stringify(request), "utf8");
|
|
54
|
+
return request;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Parse and validate an answer against the request that produced it. Every
|
|
58
|
+
* rejection names the problem and a next action; none of them writes.
|
|
59
|
+
*/
|
|
60
|
+
export function parseSemanticResponse(raw, request) {
|
|
61
|
+
const parsed = parseJson(raw);
|
|
62
|
+
if (!parsed.ok)
|
|
63
|
+
return parsed;
|
|
64
|
+
const envelope = parsed.value;
|
|
65
|
+
const header = checkHeader(envelope, request);
|
|
66
|
+
if (header !== null)
|
|
67
|
+
return { ok: false, failure: header };
|
|
68
|
+
const state = envelope.state;
|
|
69
|
+
if (state === "ambiguous" || state === "unsupported") {
|
|
70
|
+
return {
|
|
71
|
+
ok: false,
|
|
72
|
+
failure: {
|
|
73
|
+
code: state === "ambiguous" ? "SEMANTIC_AMBIGUOUS" : "SEMANTIC_UNSUPPORTED",
|
|
74
|
+
message: envelope.reason ?? `la respuesta se declaró '${state}' sin explicar por qué`,
|
|
75
|
+
action: state === "ambiguous"
|
|
76
|
+
? "resolvé la ambigüedad y volvé a responder, o acotá la operación"
|
|
77
|
+
: "la operación no aplica a este contenido: no hay nada que escribir",
|
|
78
|
+
},
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
const artifacts = checkArtifacts(envelope.artifacts, request);
|
|
82
|
+
if (!artifacts.ok)
|
|
83
|
+
return artifacts;
|
|
84
|
+
return {
|
|
85
|
+
ok: true,
|
|
86
|
+
value: {
|
|
87
|
+
version: SEMANTIC_PROTOCOL_VERSION,
|
|
88
|
+
operation: request.operation,
|
|
89
|
+
input_digest: request.input_digest,
|
|
90
|
+
state: "proposed",
|
|
91
|
+
...(isRecord(envelope.decisions) ? { decisions: envelope.decisions } : {}),
|
|
92
|
+
artifacts: artifacts.value,
|
|
93
|
+
},
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
function parseJson(raw) {
|
|
97
|
+
if (raw.trim().length === 0) {
|
|
98
|
+
return {
|
|
99
|
+
ok: false,
|
|
100
|
+
failure: {
|
|
101
|
+
code: "SEMANTIC_RESPONSE_MISSING",
|
|
102
|
+
message: "no llegó respuesta semántica por stdin",
|
|
103
|
+
action: "volvé a invocar pasando el JSON de respuesta por stdin",
|
|
104
|
+
},
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
try {
|
|
108
|
+
return { ok: true, value: JSON.parse(raw) };
|
|
109
|
+
}
|
|
110
|
+
catch {
|
|
111
|
+
return {
|
|
112
|
+
ok: false,
|
|
113
|
+
failure: {
|
|
114
|
+
code: "SEMANTIC_RESPONSE_INVALID",
|
|
115
|
+
message: "la respuesta semántica no es JSON válido",
|
|
116
|
+
action: "reenviá la respuesta como un único objeto JSON completo",
|
|
117
|
+
},
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
function checkHeader(envelope, request) {
|
|
122
|
+
if (!isRecord(envelope)) {
|
|
123
|
+
return invalid("la respuesta no es un objeto JSON");
|
|
124
|
+
}
|
|
125
|
+
if (envelope.version !== SEMANTIC_PROTOCOL_VERSION) {
|
|
126
|
+
return invalid(`versión de protocolo no soportada: ${String(envelope.version)}`);
|
|
127
|
+
}
|
|
128
|
+
if (envelope.operation !== request.operation) {
|
|
129
|
+
return invalid(`la respuesta dice operación '${String(envelope.operation)}' y esta es '${request.operation}'`);
|
|
130
|
+
}
|
|
131
|
+
// The staleness seal: the world moved between prepare and this answer, so the
|
|
132
|
+
// inventory, the numbering and the duplicate check it reasoned over are gone.
|
|
133
|
+
if (envelope.input_digest !== request.input_digest) {
|
|
134
|
+
return {
|
|
135
|
+
code: "SEMANTIC_STALE",
|
|
136
|
+
message: "la respuesta responde a un estado anterior del workspace",
|
|
137
|
+
action: "volvé a correr prepare y respondé sobre el request nuevo",
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
const state = envelope.state;
|
|
141
|
+
if (state !== "proposed" && state !== "ambiguous" && state !== "unsupported") {
|
|
142
|
+
return invalid(`estado desconocido: ${String(state)}`);
|
|
143
|
+
}
|
|
144
|
+
return null;
|
|
145
|
+
}
|
|
146
|
+
function checkArtifacts(raw, request) {
|
|
147
|
+
if (!Array.isArray(raw) || raw.length === 0) {
|
|
148
|
+
return { ok: false, failure: invalid("una respuesta 'proposed' debe traer artifacts") };
|
|
149
|
+
}
|
|
150
|
+
if (raw.length > request.limits.max_artifacts) {
|
|
151
|
+
return {
|
|
152
|
+
ok: false,
|
|
153
|
+
failure: invalid(`${raw.length} artefactos exceden el máximo de ${request.limits.max_artifacts}`),
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
const seen = new Set();
|
|
157
|
+
const out = [];
|
|
158
|
+
for (const entry of raw) {
|
|
159
|
+
if (!isRecord(entry) || typeof entry.path !== "string" || typeof entry.content !== "string") {
|
|
160
|
+
return { ok: false, failure: invalid("cada artefacto necesita 'path' y 'content' de texto") };
|
|
161
|
+
}
|
|
162
|
+
const path = checkPath(entry.path, request.allowed_destinations);
|
|
163
|
+
if (!path.ok)
|
|
164
|
+
return path;
|
|
165
|
+
if (seen.has(path.value)) {
|
|
166
|
+
return { ok: false, failure: invalid(`el artefacto '${path.value}' viene repetido`) };
|
|
167
|
+
}
|
|
168
|
+
const bytes = Buffer.byteLength(entry.content, "utf8");
|
|
169
|
+
if (bytes > request.limits.max_artifact_bytes) {
|
|
170
|
+
return {
|
|
171
|
+
ok: false,
|
|
172
|
+
failure: invalid(`'${path.value}' pesa ${bytes} B y el máximo es ${request.limits.max_artifact_bytes} B`),
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
seen.add(path.value);
|
|
176
|
+
out.push({ path: path.value, content: entry.content });
|
|
177
|
+
}
|
|
178
|
+
return { ok: true, value: out };
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* A destination is only legal if it is workspace-relative and lands INSIDE one
|
|
182
|
+
* of the declared directories. Absolute paths, `..`, backslashes and bare
|
|
183
|
+
* prefix matches (`docs/specs-evil`) are all rejected — the allowlist is the
|
|
184
|
+
* write boundary, so it is checked on normalized segments, never on a string
|
|
185
|
+
* `startsWith`.
|
|
186
|
+
*/
|
|
187
|
+
function checkPath(raw, allowed) {
|
|
188
|
+
const path = raw.trim();
|
|
189
|
+
const reject = (why) => ({
|
|
190
|
+
ok: false,
|
|
191
|
+
failure: {
|
|
192
|
+
code: "SEMANTIC_PATH_REJECTED",
|
|
193
|
+
message: `destino no permitido ('${raw}'): ${why}`,
|
|
194
|
+
action: `escribí solo dentro de: ${allowed.join(", ")}`,
|
|
195
|
+
},
|
|
196
|
+
});
|
|
197
|
+
if (path.length === 0)
|
|
198
|
+
return reject("está vacío");
|
|
199
|
+
if (path.includes("\\"))
|
|
200
|
+
return reject("usa separador de Windows");
|
|
201
|
+
if (path.startsWith("/") || /^[A-Za-z]:/.test(path))
|
|
202
|
+
return reject("es absoluto");
|
|
203
|
+
const segments = path.split("/");
|
|
204
|
+
if (segments.some((s) => s === ".." || s === "." || s.length === 0)) {
|
|
205
|
+
return reject("contiene segmentos relativos o vacíos");
|
|
206
|
+
}
|
|
207
|
+
// A destination is either a directory to write INSIDE (persist, exports) or an
|
|
208
|
+
// exact file already identified as writable (fix-git's conflict set). Both are
|
|
209
|
+
// compared on segments, so `docs/research-evil` never passes as `docs/research`.
|
|
210
|
+
const inside = allowed.some((dest) => {
|
|
211
|
+
const destSegments = dest.split("/").filter((s) => s.length > 0);
|
|
212
|
+
if (segments.length < destSegments.length)
|
|
213
|
+
return false;
|
|
214
|
+
if (!destSegments.every((segment, i) => segments[i] === segment))
|
|
215
|
+
return false;
|
|
216
|
+
return segments.length > destSegments.length || path === dest;
|
|
217
|
+
});
|
|
218
|
+
if (!inside)
|
|
219
|
+
return reject("cae fuera de los destinos declarados");
|
|
220
|
+
return { ok: true, value: path };
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* Seal over the exact artifacts shown to the human. `apply` refuses anything
|
|
224
|
+
* whose digest differs, so what gets approved is what gets written — not a
|
|
225
|
+
* later edit of the same proposal.
|
|
226
|
+
*/
|
|
227
|
+
export function approvalDigest(response) {
|
|
228
|
+
return semanticDigest({
|
|
229
|
+
operation: response.operation,
|
|
230
|
+
input_digest: response.input_digest,
|
|
231
|
+
artifacts: (response.artifacts ?? []).map((a) => ({
|
|
232
|
+
path: a.path,
|
|
233
|
+
content_digest: semanticDigest(a.content),
|
|
234
|
+
})),
|
|
235
|
+
});
|
|
236
|
+
}
|
|
237
|
+
function invalid(message) {
|
|
238
|
+
return {
|
|
239
|
+
code: "SEMANTIC_RESPONSE_INVALID",
|
|
240
|
+
message,
|
|
241
|
+
action: "corregí la respuesta según el 'contract' del request y reenviala",
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
function isRecord(value) {
|
|
245
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
246
|
+
}
|
|
247
|
+
//# sourceMappingURL=protocol.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"protocol.js","sourceRoot":"","sources":["../../../src/application/semantic-operation/protocol.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { dirname, join } from "node:path";
|
|
2
|
+
export async function publishArtifacts(fs, root, artifacts, options = {}) {
|
|
3
|
+
const done = [];
|
|
4
|
+
for (const artifact of artifacts) {
|
|
5
|
+
const absolute = join(root, artifact.path);
|
|
6
|
+
const failure = await writeOne(fs, absolute, artifact, options, done);
|
|
7
|
+
if (failure !== null) {
|
|
8
|
+
await rollback(fs, done);
|
|
9
|
+
return { ok: false, failure };
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
return { ok: true, value: { written: artifacts.map((a) => a.path) } };
|
|
13
|
+
}
|
|
14
|
+
async function writeOne(fs, absolute, artifact, options, done) {
|
|
15
|
+
try {
|
|
16
|
+
await fs.mkdirp(dirname(absolute));
|
|
17
|
+
const previous = await readPrevious(fs, absolute);
|
|
18
|
+
if (previous !== null && options.overwrite !== true) {
|
|
19
|
+
return {
|
|
20
|
+
code: "PUBLISH_TARGET_EXISTS",
|
|
21
|
+
message: `'${artifact.path}' ya existe y no se autorizó sobrescribir`,
|
|
22
|
+
action: "confirmá la sobrescritura explícitamente, o publicá en otro destino",
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
if (previous === null) {
|
|
26
|
+
// Exclusive create closes the check-then-write window: a concurrent run
|
|
27
|
+
// that got there first loses here, not silently.
|
|
28
|
+
const { created } = await fs.writeTextExclusive(absolute, artifact.content);
|
|
29
|
+
if (!created) {
|
|
30
|
+
return {
|
|
31
|
+
code: "PUBLISH_TARGET_EXISTS",
|
|
32
|
+
message: `'${artifact.path}' fue creado por otro proceso durante la publicación`,
|
|
33
|
+
action: "volvé a correr prepare: el inventario y la numeración cambiaron",
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
await fs.writeText(absolute, artifact.content);
|
|
39
|
+
}
|
|
40
|
+
done.push({ absolute, previous });
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
catch (err) {
|
|
44
|
+
return {
|
|
45
|
+
code: "PUBLISH_FAILED",
|
|
46
|
+
message: `no se pudo escribir '${artifact.path}': ${errorText(err)}`,
|
|
47
|
+
action: "revisá permisos y espacio en disco, y volvé a intentar",
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
async function readPrevious(fs, absolute) {
|
|
52
|
+
if (!(await fs.exists(absolute)))
|
|
53
|
+
return null;
|
|
54
|
+
try {
|
|
55
|
+
return await fs.readText(absolute);
|
|
56
|
+
}
|
|
57
|
+
catch {
|
|
58
|
+
// Unreadable but present: treat it as existing so we never clobber blindly,
|
|
59
|
+
// and as unrestorable so a rollback leaves it exactly as it was found.
|
|
60
|
+
return "";
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
/** Undo in reverse order, best effort — a failed undo must not mask the cause. */
|
|
64
|
+
async function rollback(fs, done) {
|
|
65
|
+
for (const entry of [...done].reverse()) {
|
|
66
|
+
try {
|
|
67
|
+
if (entry.previous === null)
|
|
68
|
+
await fs.remove(entry.absolute);
|
|
69
|
+
else
|
|
70
|
+
await fs.writeText(entry.absolute, entry.previous);
|
|
71
|
+
}
|
|
72
|
+
catch {
|
|
73
|
+
// ignore; the original failure is what the caller reports
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
function errorText(err) {
|
|
78
|
+
return err instanceof Error ? err.message : String(err);
|
|
79
|
+
}
|
|
80
|
+
//# sourceMappingURL=publish.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"publish.js","sourceRoot":"","sources":["../../../src/application/semantic-operation/publish.ts"],"names":[],"mappings":"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"}
|