mancode 0.3.18 → 0.4.1
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/README.en.md +69 -35
- package/README.md +60 -31
- package/dist/{chunk-LMXUPBCN.js → chunk-S3BAOJPP.js} +202 -50
- package/dist/chunk-S3BAOJPP.js.map +1 -0
- package/dist/{chunk-QIOMFU35.js → chunk-VV3MFVIG.js} +660 -107
- package/dist/chunk-VV3MFVIG.js.map +1 -0
- package/dist/cli.js +24109 -20911
- package/dist/cli.js.map +1 -1
- package/dist/{store-DCTOW75Z.js → store-LD5VRGON.js} +2 -2
- package/dist/{v3-adapter-C5EM5EHM.js → v3-adapter-OS2AEK5M.js} +14 -2
- package/package.json +2 -1
- package/dist/chunk-LMXUPBCN.js.map +0 -1
- package/dist/chunk-QIOMFU35.js.map +0 -1
- /package/dist/{store-DCTOW75Z.js.map → store-LD5VRGON.js.map} +0 -0
- /package/dist/{v3-adapter-C5EM5EHM.js.map → v3-adapter-OS2AEK5M.js.map} +0 -0
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
// src/installers/v3-adapter.ts
|
|
2
|
+
import { createHash } from "crypto";
|
|
2
3
|
import {
|
|
3
4
|
lstat,
|
|
4
5
|
mkdir,
|
|
@@ -9,6 +10,7 @@ import {
|
|
|
9
10
|
writeFile
|
|
10
11
|
} from "fs/promises";
|
|
11
12
|
import path from "path";
|
|
13
|
+
import { TextDecoder } from "util";
|
|
12
14
|
|
|
13
15
|
// src/installers/managed-block.ts
|
|
14
16
|
var DEFAULT_MANCODE_START_MARKER = "<!-- mancode:start -->";
|
|
@@ -29,6 +31,20 @@ function hasManagedBlock(existing, startMarker = DEFAULT_MANCODE_START_MARKER, e
|
|
|
29
31
|
const end = findMarkerLine(existing, endMarker);
|
|
30
32
|
return start !== null && end !== null && end.start > start.start;
|
|
31
33
|
}
|
|
34
|
+
function extractManagedBlock(existing, startMarker = DEFAULT_MANCODE_START_MARKER, endMarker = DEFAULT_MANCODE_END_MARKER) {
|
|
35
|
+
const starts = findMarkerLines(existing, startMarker);
|
|
36
|
+
const ends = findMarkerLines(existing, endMarker);
|
|
37
|
+
if (starts.length === 0 && ends.length === 0) return null;
|
|
38
|
+
if (starts.length !== 1 || ends.length !== 1) {
|
|
39
|
+
throw new Error("managed block is malformed: marker count is invalid");
|
|
40
|
+
}
|
|
41
|
+
const start = starts[0];
|
|
42
|
+
const end = ends[0];
|
|
43
|
+
if (!start || !end || end.start < start.start) {
|
|
44
|
+
throw new Error("managed block is malformed: marker order is invalid");
|
|
45
|
+
}
|
|
46
|
+
return existing.slice(start.start, end.end);
|
|
47
|
+
}
|
|
32
48
|
function cleanUpOrphanedNewlines(content) {
|
|
33
49
|
const trimmed = content.replace(/\n{3,}/gu, "\n\n").replace(/\n+$/u, "\n");
|
|
34
50
|
return trimmed || "";
|
|
@@ -75,8 +91,12 @@ function trimTrailingNewlines(value) {
|
|
|
75
91
|
return value.replace(/\n+$/u, "");
|
|
76
92
|
}
|
|
77
93
|
function findMarkerLine(content, marker) {
|
|
94
|
+
return findMarkerLines(content, marker)[0] ?? null;
|
|
95
|
+
}
|
|
96
|
+
function findMarkerLines(content, marker) {
|
|
78
97
|
let offset = 0;
|
|
79
98
|
let inFence = null;
|
|
99
|
+
const matches = [];
|
|
80
100
|
for (const lineWithBreak of content.matchAll(/[^\n]*(?:\n|$)/gu)) {
|
|
81
101
|
const rawLine = lineWithBreak[0];
|
|
82
102
|
if (!rawLine) break;
|
|
@@ -90,20 +110,23 @@ function findMarkerLine(content, marker) {
|
|
|
90
110
|
inFence = null;
|
|
91
111
|
}
|
|
92
112
|
} else if (!inFence && line === marker) {
|
|
93
|
-
|
|
113
|
+
matches.push({
|
|
94
114
|
start: offset,
|
|
95
115
|
end: offset + marker.length
|
|
96
|
-
};
|
|
116
|
+
});
|
|
97
117
|
}
|
|
98
118
|
offset += rawLine.length;
|
|
99
119
|
}
|
|
100
|
-
return
|
|
120
|
+
return matches;
|
|
101
121
|
}
|
|
102
122
|
|
|
103
123
|
// src/installers/v3-adapter.ts
|
|
104
124
|
var V3_ADAPTER_VERSION = "3";
|
|
105
|
-
var V3_ADAPTER_MANAGED_MARKER = "<!-- Managed by mancode:
|
|
106
|
-
var V3_MODE_ENTRY_MANAGED_MARKER = "<!-- Managed by mancode:
|
|
125
|
+
var V3_ADAPTER_MANAGED_MARKER = "<!-- Managed by mancode:continuity-adapter. Do not edit this marker. -->";
|
|
126
|
+
var V3_MODE_ENTRY_MANAGED_MARKER = "<!-- Managed by mancode:continuity-mode-entry. Do not edit this marker. -->";
|
|
127
|
+
var LEGACY_V3_ADAPTER_MANAGED_MARKER = "<!-- Managed by mancode:v3-adapter. Do not edit this marker. -->";
|
|
128
|
+
var LEGACY_V3_MODE_ENTRY_MANAGED_MARKER = "<!-- Managed by mancode:v3-mode-entry. Do not edit this marker. -->";
|
|
129
|
+
var V3_ADAPTER_DIGEST_DOMAIN = "mancode-adapter-digest-v1";
|
|
107
130
|
var V3_MODE_NAMES = [
|
|
108
131
|
"manba",
|
|
109
132
|
"man",
|
|
@@ -112,6 +135,7 @@ var V3_MODE_NAMES = [
|
|
|
112
135
|
"mansolo"
|
|
113
136
|
];
|
|
114
137
|
var LEGACY_MODE_ENTRY_MANAGED_MARKERS = [
|
|
138
|
+
LEGACY_V3_MODE_ENTRY_MANAGED_MARKER,
|
|
115
139
|
"<!-- Managed by mancode:claude-skill. Do not edit this marker. -->",
|
|
116
140
|
"<!-- Managed by mancode:codex-skill. Do not edit this file manually. -->",
|
|
117
141
|
"<!-- Managed by mancode:zcode-skill. Do not edit this file manually. -->",
|
|
@@ -134,12 +158,26 @@ var LEGACY_CLAUDE_SETTINGS_RAW_HINTS = [
|
|
|
134
158
|
".mancode/hooks/user-prompt-submit.",
|
|
135
159
|
...LEGACY_CLAUDE_SKILL_PATHS
|
|
136
160
|
];
|
|
137
|
-
var
|
|
138
|
-
var
|
|
139
|
-
var
|
|
140
|
-
var
|
|
141
|
-
var
|
|
142
|
-
var
|
|
161
|
+
var CONTINUITY_CLAUDE_START_MARKER = "<!-- mancode:continuity:claude:start -->";
|
|
162
|
+
var CONTINUITY_CLAUDE_END_MARKER = "<!-- mancode:continuity:claude:end -->";
|
|
163
|
+
var V3_CODEX_START_MARKER = "<!-- mancode:continuity:codex:start -->";
|
|
164
|
+
var V3_CODEX_END_MARKER = "<!-- mancode:continuity:codex:end -->";
|
|
165
|
+
var V3_ZCODE_START_MARKER = "<!-- mancode:continuity:zcode:start -->";
|
|
166
|
+
var V3_ZCODE_END_MARKER = "<!-- mancode:continuity:zcode:end -->";
|
|
167
|
+
var V3_COPILOT_START_MARKER = "<!-- mancode:continuity:copilot:start -->";
|
|
168
|
+
var V3_COPILOT_END_MARKER = "<!-- mancode:continuity:copilot:end -->";
|
|
169
|
+
var LEGACY_V3_CODEX_MARKERS = [
|
|
170
|
+
"<!-- mancode:v3:codex:start -->",
|
|
171
|
+
"<!-- mancode:v3:codex:end -->"
|
|
172
|
+
];
|
|
173
|
+
var LEGACY_V3_ZCODE_MARKERS = [
|
|
174
|
+
"<!-- mancode:v3:zcode:start -->",
|
|
175
|
+
"<!-- mancode:v3:zcode:end -->"
|
|
176
|
+
];
|
|
177
|
+
var LEGACY_V3_COPILOT_MARKERS = [
|
|
178
|
+
"<!-- mancode:v3:copilot:start -->",
|
|
179
|
+
"<!-- mancode:v3:copilot:end -->"
|
|
180
|
+
];
|
|
143
181
|
var LEGACY_CODEX_START_MARKER = "<!-- mancode:start -->";
|
|
144
182
|
var LEGACY_CODEX_END_MARKER = "<!-- mancode:end -->";
|
|
145
183
|
var LEGACY_ZCODE_START_MARKER = "<!-- mancode:zcode:start -->";
|
|
@@ -147,6 +185,13 @@ var LEGACY_ZCODE_END_MARKER = "<!-- mancode:zcode:end -->";
|
|
|
147
185
|
var RETRIABLE_ADAPTER_READ_CODES = /* @__PURE__ */ new Set(["EACCES", "EBUSY", "EPERM"]);
|
|
148
186
|
var ADAPTER_READ_MAX_ATTEMPTS = 4;
|
|
149
187
|
var ADAPTER_READ_RETRY_DELAY_MS = 25;
|
|
188
|
+
var V3_ADAPTER_PLATFORMS = [
|
|
189
|
+
"claude-code",
|
|
190
|
+
"codex",
|
|
191
|
+
"cursor",
|
|
192
|
+
"copilot",
|
|
193
|
+
"zcode"
|
|
194
|
+
];
|
|
150
195
|
var V3_MODE_ENTRY_FILE_TARGETS = V3_MODE_NAMES.flatMap((mode) => [
|
|
151
196
|
`claude-mode-${mode}`,
|
|
152
197
|
`agents-mode-${mode}`,
|
|
@@ -180,13 +225,27 @@ var V3_ADAPTER_FILE_TARGETS = [
|
|
|
180
225
|
...V3_MODE_ENTRY_FILE_TARGETS,
|
|
181
226
|
...V3_LEGACY_ADAPTER_FILE_TARGETS
|
|
182
227
|
];
|
|
228
|
+
function adapterManagedContentDigest(targetIdentity, managedContent) {
|
|
229
|
+
if (!targetIdentity.trim() || targetIdentity.includes("\0")) {
|
|
230
|
+
throw new Error("MANCODE_V3_ADAPTER_TARGET_IDENTITY_INVALID");
|
|
231
|
+
}
|
|
232
|
+
const content = typeof managedContent === "string" ? Buffer.from(managedContent, "utf8") : Buffer.from(managedContent);
|
|
233
|
+
const digest = createHash("sha256").update(Buffer.from(V3_ADAPTER_DIGEST_DOMAIN, "utf8")).update(Buffer.from([0])).update(Buffer.from(targetIdentity, "utf8")).update(Buffer.from([0])).update(content).digest("hex");
|
|
234
|
+
return `sha256:${digest}`;
|
|
235
|
+
}
|
|
183
236
|
async function planV3AdapterFiles(projectRoot) {
|
|
184
237
|
const root = path.resolve(projectRoot);
|
|
185
238
|
const existing = /* @__PURE__ */ new Map();
|
|
186
239
|
for (const target of V3_ADAPTER_FILE_TARGETS) {
|
|
187
240
|
existing.set(target, await readAdapterTarget(root, target));
|
|
188
241
|
}
|
|
189
|
-
const agents =
|
|
242
|
+
const agents = removeLegacyV3Block(
|
|
243
|
+
removeLegacyV3Block(
|
|
244
|
+
removeLegacyAgentsBlocks(existing.get("agents") ?? ""),
|
|
245
|
+
LEGACY_V3_CODEX_MARKERS
|
|
246
|
+
),
|
|
247
|
+
LEGACY_V3_ZCODE_MARKERS
|
|
248
|
+
);
|
|
190
249
|
const nextAgents = replaceManagedV3BlockText(
|
|
191
250
|
replaceManagedV3BlockText(
|
|
192
251
|
agents,
|
|
@@ -200,11 +259,16 @@ async function planV3AdapterFiles(projectRoot) {
|
|
|
200
259
|
);
|
|
201
260
|
const legacyAdapterPlans = planLegacyAdapterRetirement(existing);
|
|
202
261
|
const plans = [
|
|
203
|
-
|
|
204
|
-
"claude-skill",
|
|
205
|
-
existing.get("claude-skill") ?? null,
|
|
206
|
-
|
|
207
|
-
|
|
262
|
+
{
|
|
263
|
+
target: "claude-skill",
|
|
264
|
+
beforeContent: existing.get("claude-skill") ?? null,
|
|
265
|
+
targetContent: replaceManagedV3BlockText(
|
|
266
|
+
existing.get("claude-skill") ?? "",
|
|
267
|
+
CONTINUITY_CLAUDE_START_MARKER,
|
|
268
|
+
CONTINUITY_CLAUDE_END_MARKER,
|
|
269
|
+
renderV3Bootstrap("claude-code")
|
|
270
|
+
)
|
|
271
|
+
},
|
|
208
272
|
managedFilePlan(
|
|
209
273
|
"cursor-rule",
|
|
210
274
|
existing.get("cursor-rule") ?? null,
|
|
@@ -219,7 +283,10 @@ async function planV3AdapterFiles(projectRoot) {
|
|
|
219
283
|
target: "copilot-instructions",
|
|
220
284
|
beforeContent: existing.get("copilot-instructions") ?? null,
|
|
221
285
|
targetContent: replaceManagedV3BlockText(
|
|
222
|
-
|
|
286
|
+
removeLegacyV3Block(
|
|
287
|
+
removeManagedBlock(existing.get("copilot-instructions") ?? ""),
|
|
288
|
+
LEGACY_V3_COPILOT_MARKERS
|
|
289
|
+
),
|
|
223
290
|
V3_COPILOT_START_MARKER,
|
|
224
291
|
V3_COPILOT_END_MARKER,
|
|
225
292
|
renderV3Bootstrap("copilot")
|
|
@@ -236,6 +303,73 @@ async function planV3AdapterFiles(projectRoot) {
|
|
|
236
303
|
];
|
|
237
304
|
return plans;
|
|
238
305
|
}
|
|
306
|
+
async function planV3AdapterUpgradeFiles(projectRoot, platforms) {
|
|
307
|
+
const root = path.resolve(projectRoot);
|
|
308
|
+
const selected = normalizeUpgradePlatforms(platforms);
|
|
309
|
+
const targetSet = /* @__PURE__ */ new Set();
|
|
310
|
+
for (const platform of selected) {
|
|
311
|
+
targetSet.add(primaryFileTarget(platform));
|
|
312
|
+
for (const mode of V3_MODE_NAMES) {
|
|
313
|
+
targetSet.add(modeEntryFileTarget(platform, mode));
|
|
314
|
+
}
|
|
315
|
+
for (const target of legacyAdapterTargetsForPlatform(platform, true)) {
|
|
316
|
+
targetSet.add(target);
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
const existing = /* @__PURE__ */ new Map();
|
|
320
|
+
for (const target of targetSet) {
|
|
321
|
+
existing.set(target, await readAdapterTarget(root, target));
|
|
322
|
+
}
|
|
323
|
+
const desired = new Map(existing);
|
|
324
|
+
for (const platform of selected) {
|
|
325
|
+
planPlatformBootstrapUpgrade(desired, platform);
|
|
326
|
+
for (const mode of V3_MODE_NAMES) {
|
|
327
|
+
const target = modeEntryFileTarget(platform, mode);
|
|
328
|
+
const current = desired.get(target) ?? null;
|
|
329
|
+
desired.set(
|
|
330
|
+
target,
|
|
331
|
+
managedModeEntryPlan(target, current, renderV3ModeEntry(mode, platform)).targetContent
|
|
332
|
+
);
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
const plans = [...desired.entries()].filter(([target, targetContent]) => existing.get(target) !== targetContent).map(([target, targetContent]) => ({
|
|
336
|
+
target,
|
|
337
|
+
beforeContent: existing.get(target) ?? null,
|
|
338
|
+
targetContent: targetContent ?? ""
|
|
339
|
+
}));
|
|
340
|
+
const legacyPlans = planLegacyAdapterRetirement(existing).filter(
|
|
341
|
+
(legacyPlan) => !plans.some((candidate) => candidate.target === legacyPlan.target)
|
|
342
|
+
);
|
|
343
|
+
return [...plans, ...legacyPlans];
|
|
344
|
+
}
|
|
345
|
+
async function stageV3AdapterUpgradeFiles(projectRoot, operationId, plans) {
|
|
346
|
+
if (!/^[0-7][0-9A-HJKMNP-TV-Z]{25}$/.test(operationId)) {
|
|
347
|
+
throw new Error("MANCODE_ADAPTER_UPGRADE_OPERATION_ID_INVALID");
|
|
348
|
+
}
|
|
349
|
+
const root = path.resolve(projectRoot);
|
|
350
|
+
const staged = [];
|
|
351
|
+
for (const plan of plans) {
|
|
352
|
+
const liveTarget = v3AdapterTargetPath(root, plan.target);
|
|
353
|
+
const relative = relativeAdapterPath(root, liveTarget);
|
|
354
|
+
const stagingTarget = path.join(
|
|
355
|
+
".mancode",
|
|
356
|
+
"staging",
|
|
357
|
+
"adapters",
|
|
358
|
+
"upgrade",
|
|
359
|
+
operationId,
|
|
360
|
+
relative
|
|
361
|
+
);
|
|
362
|
+
const destination = path.join(root, stagingTarget);
|
|
363
|
+
await assertAdapterPathSafe(root, destination);
|
|
364
|
+
await mkdir(path.dirname(destination), { recursive: true });
|
|
365
|
+
await atomicWrite(destination, plan.targetContent);
|
|
366
|
+
staged.push({
|
|
367
|
+
target: plan.target,
|
|
368
|
+
stagingTarget: relativeAdapterPath(root, destination)
|
|
369
|
+
});
|
|
370
|
+
}
|
|
371
|
+
return staged;
|
|
372
|
+
}
|
|
239
373
|
async function applyV3AdapterFilePlan(projectRoot, plan) {
|
|
240
374
|
const root = path.resolve(projectRoot);
|
|
241
375
|
if (!V3_ADAPTER_FILE_TARGETS.includes(plan.target)) {
|
|
@@ -246,8 +380,30 @@ async function applyV3AdapterFilePlan(projectRoot, plan) {
|
|
|
246
380
|
}
|
|
247
381
|
const target = v3AdapterTargetPath(root, plan.target);
|
|
248
382
|
await assertAdapterPathSafe(root, target);
|
|
383
|
+
const retiredBootstrapPlatform = retiredBootstrapPlatformFor(plan.target);
|
|
384
|
+
if (retiredBootstrapPlatform !== null) {
|
|
385
|
+
for (const retired of retiredBootstrapSpecs(
|
|
386
|
+
root,
|
|
387
|
+
retiredBootstrapPlatform
|
|
388
|
+
)) {
|
|
389
|
+
await assertAdapterPathSafe(root, retired.filePath);
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
const current = await readAdapterTarget(root, plan.target);
|
|
393
|
+
if (current === plan.targetContent) {
|
|
394
|
+
if (retiredBootstrapPlatform !== null) {
|
|
395
|
+
await removeRetiredBootstrapFiles(root, retiredBootstrapPlatform);
|
|
396
|
+
}
|
|
397
|
+
return;
|
|
398
|
+
}
|
|
399
|
+
if (current !== plan.beforeContent) {
|
|
400
|
+
throw new Error("MANCODE_V3_ADAPTER_TARGET_CONFLICT");
|
|
401
|
+
}
|
|
249
402
|
await mkdir(path.dirname(target), { recursive: true });
|
|
250
403
|
await atomicWrite(target, plan.targetContent);
|
|
404
|
+
if (retiredBootstrapPlatform !== null) {
|
|
405
|
+
await removeRetiredBootstrapFiles(root, retiredBootstrapPlatform);
|
|
406
|
+
}
|
|
251
407
|
}
|
|
252
408
|
async function stageV3Adapter(projectRoot, platform) {
|
|
253
409
|
const root = path.resolve(projectRoot);
|
|
@@ -258,7 +414,7 @@ async function stageV3Adapter(projectRoot, platform) {
|
|
|
258
414
|
".mancode",
|
|
259
415
|
"staging",
|
|
260
416
|
"adapters",
|
|
261
|
-
"
|
|
417
|
+
"continuity",
|
|
262
418
|
platform,
|
|
263
419
|
target
|
|
264
420
|
);
|
|
@@ -276,7 +432,7 @@ async function stageV3Adapter(projectRoot, platform) {
|
|
|
276
432
|
".mancode",
|
|
277
433
|
"staging",
|
|
278
434
|
"adapters",
|
|
279
|
-
"
|
|
435
|
+
"continuity",
|
|
280
436
|
platform,
|
|
281
437
|
modeTarget
|
|
282
438
|
);
|
|
@@ -302,9 +458,9 @@ function v3AdapterTargetPath(projectRoot, target) {
|
|
|
302
458
|
if (legacyTarget !== null) return path.join(root, legacyTarget);
|
|
303
459
|
switch (target) {
|
|
304
460
|
case "claude-skill":
|
|
305
|
-
return path.join(root, ".
|
|
461
|
+
return path.join(root, "CLAUDE.md");
|
|
306
462
|
case "cursor-rule":
|
|
307
|
-
return path.join(root, ".cursor", "rules", "mancode-
|
|
463
|
+
return path.join(root, ".cursor", "rules", "mancode-continuity.mdc");
|
|
308
464
|
case "agents":
|
|
309
465
|
return path.join(root, "AGENTS.md");
|
|
310
466
|
case "copilot-instructions":
|
|
@@ -336,16 +492,20 @@ async function installV3Adapter(projectRoot, platform) {
|
|
|
336
492
|
const content = renderV3Bootstrap(platform);
|
|
337
493
|
switch (platform) {
|
|
338
494
|
case "claude-code":
|
|
339
|
-
await
|
|
340
|
-
path.join(root, ".
|
|
341
|
-
|
|
495
|
+
await replaceManagedV3Block(
|
|
496
|
+
path.join(root, "CLAUDE.md"),
|
|
497
|
+
CONTINUITY_CLAUDE_START_MARKER,
|
|
498
|
+
CONTINUITY_CLAUDE_END_MARKER,
|
|
499
|
+
content
|
|
342
500
|
);
|
|
501
|
+
await removeRetiredBootstrapFiles(root, platform);
|
|
343
502
|
break;
|
|
344
503
|
case "cursor":
|
|
345
504
|
await writeManagedFile(
|
|
346
|
-
path.join(root, ".cursor", "rules", "mancode-
|
|
505
|
+
path.join(root, ".cursor", "rules", "mancode-continuity.mdc"),
|
|
347
506
|
renderCursorRule(content)
|
|
348
507
|
);
|
|
508
|
+
await removeRetiredBootstrapFiles(root, platform);
|
|
349
509
|
break;
|
|
350
510
|
case "codex":
|
|
351
511
|
await replaceManagedV3Block(
|
|
@@ -354,6 +514,7 @@ async function installV3Adapter(projectRoot, platform) {
|
|
|
354
514
|
V3_CODEX_END_MARKER,
|
|
355
515
|
content,
|
|
356
516
|
[
|
|
517
|
+
LEGACY_V3_CODEX_MARKERS,
|
|
357
518
|
[LEGACY_CODEX_START_MARKER, LEGACY_CODEX_END_MARKER],
|
|
358
519
|
[LEGACY_ZCODE_START_MARKER, LEGACY_ZCODE_END_MARKER]
|
|
359
520
|
]
|
|
@@ -365,7 +526,10 @@ async function installV3Adapter(projectRoot, platform) {
|
|
|
365
526
|
V3_COPILOT_START_MARKER,
|
|
366
527
|
V3_COPILOT_END_MARKER,
|
|
367
528
|
content,
|
|
368
|
-
[
|
|
529
|
+
[
|
|
530
|
+
LEGACY_V3_COPILOT_MARKERS,
|
|
531
|
+
[LEGACY_CODEX_START_MARKER, LEGACY_CODEX_END_MARKER]
|
|
532
|
+
]
|
|
369
533
|
);
|
|
370
534
|
break;
|
|
371
535
|
case "zcode":
|
|
@@ -375,6 +539,7 @@ async function installV3Adapter(projectRoot, platform) {
|
|
|
375
539
|
V3_ZCODE_END_MARKER,
|
|
376
540
|
content,
|
|
377
541
|
[
|
|
542
|
+
LEGACY_V3_ZCODE_MARKERS,
|
|
378
543
|
[LEGACY_CODEX_START_MARKER, LEGACY_CODEX_END_MARKER],
|
|
379
544
|
[LEGACY_ZCODE_START_MARKER, LEGACY_ZCODE_END_MARKER]
|
|
380
545
|
]
|
|
@@ -403,25 +568,26 @@ async function assertV3AdapterInstallable(projectRoot, platform) {
|
|
|
403
568
|
}
|
|
404
569
|
async function inspectV3Adapter(projectRoot, platform) {
|
|
405
570
|
const root = path.resolve(projectRoot);
|
|
406
|
-
await assertPlatformAdapterPathsSafe(root, platform);
|
|
407
571
|
const target = targetFor(platform);
|
|
408
|
-
const
|
|
409
|
-
const
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
const
|
|
572
|
+
const targets = [];
|
|
573
|
+
for (const spec of managedTargetSpecs(root, platform)) {
|
|
574
|
+
targets.push(await inspectManagedTarget(root, platform, spec));
|
|
575
|
+
}
|
|
576
|
+
const ready = targets.every((item) => item.status === "ready");
|
|
577
|
+
const installed = targets.every((item) => item.status !== "missing");
|
|
578
|
+
const status = aggregateAdapterStatus(targets);
|
|
415
579
|
return {
|
|
416
580
|
version: V3_ADAPTER_VERSION,
|
|
417
581
|
installed,
|
|
418
|
-
ready
|
|
582
|
+
ready,
|
|
583
|
+
status,
|
|
419
584
|
target,
|
|
420
|
-
detail:
|
|
585
|
+
detail: status === "ready" ? "Managed adapter content matches the current renderer." : status === "missing" ? "One or more managed adapter targets are missing." : status === "stale" ? "Managed adapter content differs from the current renderer." : "One or more managed adapter targets cannot be read safely.",
|
|
586
|
+
targets,
|
|
421
587
|
capabilities: capabilitiesFor(platform)
|
|
422
588
|
};
|
|
423
589
|
}
|
|
424
|
-
async function inspectV3AdapterVersions(projectRoot) {
|
|
590
|
+
async function inspectV3AdapterVersions(projectRoot, requiredPlatforms = []) {
|
|
425
591
|
const platforms = [
|
|
426
592
|
"claude-code",
|
|
427
593
|
"codex",
|
|
@@ -429,13 +595,25 @@ async function inspectV3AdapterVersions(projectRoot) {
|
|
|
429
595
|
"copilot",
|
|
430
596
|
"zcode"
|
|
431
597
|
];
|
|
598
|
+
const required = new Set(requiredPlatforms);
|
|
432
599
|
const entries = await Promise.all(
|
|
433
|
-
platforms.map(
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
600
|
+
platforms.map(
|
|
601
|
+
async (platform) => [platform, await inspectV3Adapter(projectRoot, platform)]
|
|
602
|
+
)
|
|
603
|
+
);
|
|
604
|
+
return v3AdapterVersionsFromStatuses(entries, required);
|
|
605
|
+
}
|
|
606
|
+
function v3AdapterVersionsFromStatuses(entries, requiredPlatforms = []) {
|
|
607
|
+
const required = requiredPlatforms instanceof Set ? requiredPlatforms : new Set(requiredPlatforms);
|
|
608
|
+
const versions = entries.map(([platform, status]) => {
|
|
609
|
+
const primaryPresent = status.targets[0]?.status !== "missing";
|
|
610
|
+
return required.has(platform) || primaryPresent ? [platform, status.ready ? status.version : status.status] : null;
|
|
611
|
+
});
|
|
612
|
+
return Object.fromEntries(
|
|
613
|
+
versions.filter(
|
|
614
|
+
(entry) => entry !== null
|
|
615
|
+
)
|
|
437
616
|
);
|
|
438
|
-
return Object.fromEntries(entries);
|
|
439
617
|
}
|
|
440
618
|
async function removeV3Adapter(projectRoot, platform) {
|
|
441
619
|
const root = path.resolve(projectRoot);
|
|
@@ -443,14 +621,18 @@ async function removeV3Adapter(projectRoot, platform) {
|
|
|
443
621
|
let preserveSharedModeEntries = false;
|
|
444
622
|
switch (platform) {
|
|
445
623
|
case "claude-code":
|
|
446
|
-
await
|
|
447
|
-
path.join(root, ".
|
|
624
|
+
await removeManagedV3Block(
|
|
625
|
+
path.join(root, "CLAUDE.md"),
|
|
626
|
+
CONTINUITY_CLAUDE_START_MARKER,
|
|
627
|
+
CONTINUITY_CLAUDE_END_MARKER
|
|
448
628
|
);
|
|
629
|
+
await removeRetiredBootstrapFiles(root, platform);
|
|
449
630
|
break;
|
|
450
631
|
case "cursor":
|
|
451
632
|
await removeManagedFile(
|
|
452
|
-
path.join(root, ".cursor", "rules", "mancode-
|
|
633
|
+
path.join(root, ".cursor", "rules", "mancode-continuity.mdc")
|
|
453
634
|
);
|
|
635
|
+
await removeRetiredBootstrapFiles(root, platform);
|
|
454
636
|
break;
|
|
455
637
|
case "codex":
|
|
456
638
|
await removeManagedV3Block(
|
|
@@ -458,10 +640,13 @@ async function removeV3Adapter(projectRoot, platform) {
|
|
|
458
640
|
V3_CODEX_START_MARKER,
|
|
459
641
|
V3_CODEX_END_MARKER
|
|
460
642
|
);
|
|
461
|
-
|
|
643
|
+
await removeManagedV3Block(
|
|
644
|
+
path.join(root, "AGENTS.md"),
|
|
645
|
+
...LEGACY_V3_CODEX_MARKERS
|
|
646
|
+
);
|
|
647
|
+
preserveSharedModeEntries = await anyManagedBlockPresent(
|
|
462
648
|
path.join(root, "AGENTS.md"),
|
|
463
|
-
V3_ZCODE_START_MARKER,
|
|
464
|
-
V3_ZCODE_END_MARKER
|
|
649
|
+
[[V3_ZCODE_START_MARKER, V3_ZCODE_END_MARKER], LEGACY_V3_ZCODE_MARKERS]
|
|
465
650
|
);
|
|
466
651
|
break;
|
|
467
652
|
case "copilot":
|
|
@@ -470,6 +655,10 @@ async function removeV3Adapter(projectRoot, platform) {
|
|
|
470
655
|
V3_COPILOT_START_MARKER,
|
|
471
656
|
V3_COPILOT_END_MARKER
|
|
472
657
|
);
|
|
658
|
+
await removeManagedV3Block(
|
|
659
|
+
path.join(root, ".github", "copilot-instructions.md"),
|
|
660
|
+
...LEGACY_V3_COPILOT_MARKERS
|
|
661
|
+
);
|
|
473
662
|
break;
|
|
474
663
|
case "zcode":
|
|
475
664
|
await removeManagedV3Block(
|
|
@@ -477,10 +666,13 @@ async function removeV3Adapter(projectRoot, platform) {
|
|
|
477
666
|
V3_ZCODE_START_MARKER,
|
|
478
667
|
V3_ZCODE_END_MARKER
|
|
479
668
|
);
|
|
480
|
-
|
|
669
|
+
await removeManagedV3Block(
|
|
481
670
|
path.join(root, "AGENTS.md"),
|
|
482
|
-
|
|
483
|
-
|
|
671
|
+
...LEGACY_V3_ZCODE_MARKERS
|
|
672
|
+
);
|
|
673
|
+
preserveSharedModeEntries = await anyManagedBlockPresent(
|
|
674
|
+
path.join(root, "AGENTS.md"),
|
|
675
|
+
[[V3_CODEX_START_MARKER, V3_CODEX_END_MARKER], LEGACY_V3_CODEX_MARKERS]
|
|
484
676
|
);
|
|
485
677
|
break;
|
|
486
678
|
}
|
|
@@ -504,16 +696,25 @@ function renderV3Bootstrap(platform) {
|
|
|
504
696
|
"",
|
|
505
697
|
`- Platform: ${platformLabel}. This file is a non-authoritative bootstrap.`,
|
|
506
698
|
"- Locate the project root before running mancode commands.",
|
|
699
|
+
"- Before the first command, choose one CLI binary for the entire task: use `./node_modules/.bin/mancode` when it exists, otherwise use `mancode`. Run that selected binary with `--version` once and never mix binaries or versions.",
|
|
700
|
+
"- In every command below, `mancode` means that selected binary; when the local binary exists, invoke the command as `./node_modules/.bin/mancode ...` rather than falling back to a global executable.",
|
|
507
701
|
"- Reuse a `mancode status --brief --json` snapshot already obtained in this conversation. Only when no such snapshot exists, run it once from the project root.",
|
|
702
|
+
"- Inspect a session read-only with `mancode context session show --session <id> --client <client> --json`; do not invent other session subcommands.",
|
|
508
703
|
"- The compact status is the public mancode Continuity runtime view. In operator-facing narration, say `mancode` or `mancode Continuity`; never prefix a mode or action with a version label.",
|
|
509
704
|
"- An explicitly invoked original `man`, `manba`, `manteam`, `manps`, or `mansolo` entry supplies its authorized action. Its mode-specific steps override conflicting generic no-task or mutation guidance below.",
|
|
510
705
|
"- In particular, `manps` may run local health scans without an actor, session, or TaskRef. `mansolo` needs them only for an explicit governed handoff.",
|
|
511
|
-
|
|
706
|
+
"- Outside an explicitly invoked mode entry, treat an ordinary requested coding task as default Solo work. Ordinary Solo work requires no actor identity, session, TaskRef, or workflow; do not ask for a display name or create Continuity authority for it.",
|
|
707
|
+
"- Before editing in default Solo, inspect only the relevant project facts, implementation, tests, and contracts. A supplied instruction is not automatically sound: verify its factual assumptions and proposed solution against the repository and the operator's goal.",
|
|
708
|
+
"- If the goal and decision-changing requirements are clear, consistent with project evidence, and low risk, proceed with the narrowest useful change without ceremonial questions. Resolve repository-answerable unknowns yourself.",
|
|
709
|
+
"- When the goal is clear but requirements are incomplete, classify each remaining unknown as blocking, recommendable, or defaultable. Ask and wait only for blocking decisions that can materially change behavior, scope, acceptance, architecture, data, security, compatibility, or semantic ownership. For recommendable decisions, give bounded options and a clear recommendation. Use a default only when it is low-impact, reversible, consistent with repository conventions, and stated explicitly.",
|
|
710
|
+
"- If an explicit request conflicts with repository evidence or introduces a hard-risk change involving authentication, payment, sensitive data, deletion, migration, public APIs, untrusted input, concurrency, infrastructure, or another irreversible effect, stop before editing. Show the concrete conflict or impact, recommend the safer path, ask a focused confirmation or choice, and wait. Clarity never overrides safety or the operator's actual goal.",
|
|
711
|
+
"- A natural-language request explicitly asking for research, a plan, architecture, migration design, or formal acceptance authorizes the `man` planning path without a separate mode-confirmation question. For an ordinary implementation request whose blocking decision crosses modules or requires architecture, migration, semantic owner/source-of-truth, team coordination, or formal acceptance, recommend `/man`, explain why, and wait; never switch authority silently.",
|
|
712
|
+
'- For governed task work only, if status has no `identity.actorId`, ask for a display name and run `mancode team identity create --name "<display name>"` before creating a session.',
|
|
512
713
|
"- If status reports `session`, reuse it. `task: null` and `MANCODE_TASK_REQUIRED` do not make a session stale.",
|
|
513
714
|
`- ${sessionCreationGuidance} Pass its returned \`sessionId\` and matching client as \`${sessionArguments}\` to every later session command; an \`export\` inside one command tool does not persist to later command tools.`,
|
|
514
|
-
'- Outside an invoked original mode entry, if no
|
|
715
|
+
'- Outside an invoked original mode entry, if no coding, planning, diagnostic, or review task was requested and no TaskRef is explicitly supplied, report "no task bound" and stop. Do not probe workflow subcommands to work around `MANCODE_TASK_REQUIRED`.',
|
|
515
716
|
"- Bootstrap discovery is read-only: before the operator explicitly requests task work, do not run `mancode init`, `mancode migrate`, `mancode workflow`, or inspect mancode installed package/source.",
|
|
516
|
-
`- With an existing or supplied
|
|
717
|
+
`- With an existing or explicitly supplied TaskRef, read its Context Pack with \`mancode context show --purpose orient ${sessionArguments}\`; for anonymous diagnosis, include an explicit \`--task <namespace:id>\`. A plain-language Solo request is not a TaskRef and needs no Context Pack.`,
|
|
517
718
|
"- After an operator explicitly requests task work, perform mutations only through `mancode workflow`, `mancode team`, and `mancode context` commands with their required revision and session arguments.",
|
|
518
719
|
"- For a mode entry, request the matching Context Pack purpose: `plan`, `implement`, `review`, `verify`, or `handoff`.",
|
|
519
720
|
"- Do not persist task, mode, or session state in this adapter file or any legacy state file.",
|
|
@@ -526,6 +727,7 @@ function renderV3ModeEntry(mode, platform) {
|
|
|
526
727
|
const sessionArguments = sessionArgumentsFor(platform);
|
|
527
728
|
const sessionClientGuidance = sessionClientGuidanceFor(platform);
|
|
528
729
|
const statusGuidance = "Reuse a `mancode status --brief --json` snapshot already obtained in this conversation. Only when none exists, run it once from the project root.";
|
|
730
|
+
const cliSelectionGuidance = "Before the first command, use `./node_modules/.bin/mancode` when it exists, otherwise `mancode`; check that selected binary with `--version` once and never mix binaries or versions. In every command below, replace the literal `mancode` with that selected binary path when the local binary exists.";
|
|
529
731
|
const sessionCreationGuidance = platform === "codex" || platform === "zcode" ? "If status has no current session, reuse an explicit session ID already retained in this conversation. Only if neither exists, run `mancode context session new --client codex` in Codex or `mancode context session new --client zcode` in ZCode exactly once, then retain the returned session ID." : `If status has no current session, reuse an explicit session ID already retained in this conversation. Only if neither exists, run \`mancode context session new --client ${platform}\` exactly once and retain the returned session ID.`;
|
|
530
732
|
let authoritySteps;
|
|
531
733
|
if (mode === "manps") {
|
|
@@ -581,6 +783,7 @@ function renderV3ModeEntry(mode, platform) {
|
|
|
581
783
|
"",
|
|
582
784
|
"## Enter through mancode",
|
|
583
785
|
"",
|
|
786
|
+
cliSelectionGuidance,
|
|
584
787
|
...authoritySteps,
|
|
585
788
|
"",
|
|
586
789
|
"## Mode action",
|
|
@@ -608,9 +811,22 @@ var V3_MODE_DEFINITIONS = {
|
|
|
608
811
|
actions: [
|
|
609
812
|
"- For a read-only project orientation, inspect and answer directly; do not create governance records.",
|
|
610
813
|
'- For a new task, run `mancode workflow create man "<task>" --session <id>`.',
|
|
611
|
-
"-
|
|
814
|
+
"- Before writing requirements, inspect the relevant project facts and implementation, then run a decision-readiness gate covering both clarity and soundness. Treat the request as ready only when the goal, in-scope/out-of-scope behavior, acceptance boundary, semantic owner/source of truth, and decision-changing constraints are supplied and consistent with evidence, verifiable from the repository, or explicitly recorded as safe defaults. A supplied instruction is not automatically correct. Do not ask ceremonial questions or manufacture alternatives when the request is already clear and sound.",
|
|
815
|
+
"- Classify unresolved decisions as blocking, recommendable, or defaultable. Ask and wait for blocking decisions; for recommendable decisions, present 2\u20133 bounded options with tradeoffs and one clear recommendation; use a default only when it is low-impact, reversible, consistent with repository conventions, and recorded with its reason.",
|
|
816
|
+
"- If any unresolved ambiguity could change the goal, scope, user-visible behavior, acceptance, architecture, data, security, compatibility, owner, or source of truth, stop before requirements finalization, explain the missing decision, ask focused questions, and wait for the user answer. Ask in as many batches as needed, do not repeat answered questions, and never turn an unverified assumption into confirmed scope or confirmed coverage.",
|
|
817
|
+
"- Before waiting on a blocking answer, persist the known facts, partial decisions, and each open question with `mancode workflow requirements <namespace:ULID> draft --file <requirements.json> --expected-revision <n> --session <id>`. A draft may leave scope, coverage, technical decisions, or acceptance incomplete only while `blockingUnknowns` names the open decisions. After every answer, update the draft or finalize it so another session can resume the exact clarification state.",
|
|
818
|
+
"- If an explicit direction conflicts with repository evidence or creates a hard-risk authentication, payment, sensitive-data, deletion, migration, public-API, untrusted-input, concurrency, infrastructure, or irreversible change, stop before requirements finalization. Show the evidence and impact, recommend a safer path, ask for a focused confirmation or choice, and wait; clarity does not waive risk.",
|
|
819
|
+
"- After the user answers, summarize the resolved requirements and any remaining defaults. Continue only when no decision-changing blocking unknown remains; otherwise keep the task in clarification and ask again.",
|
|
820
|
+
"- Write requirements as semantic JSON with `version: 1`, a non-empty `goal`, non-empty `confirmedScope`, and the arrays `excludedScope`, `technicalDecisions`, `defaults`, and `blockingUnknowns`. Every array item must be a non-empty string; an array may be empty except `confirmedScope`, and `technicalDecisions` must be non-empty whenever `technical_stack` applies.",
|
|
821
|
+
'- `coverage` must contain exactly one item for each dimension: `platform`, `core_scope`, `technical_stack`, `data_and_persistence`, `performance`, `compatibility`, and `security`. Each item has the shape `{ "dimension": "platform", "status": "confirmed", "rationale": "..." }`; `status` is exactly `confirmed`, `defaulted`, or `not_applicable`, and `rationale` is non-empty.',
|
|
822
|
+
'- `acceptanceCriteria` must contain at least one required item shaped as `{ "id": "AC-1", "description": "...", "required": true, "method": "automated" }`; `method` is exactly `automated`, `manual`, or `hybrid`.',
|
|
612
823
|
"- Finalize requirements with `mancode workflow requirements <namespace:ULID> finalize --file <requirements.json> --expected-revision <n> --session <id>`.",
|
|
613
|
-
"-
|
|
824
|
+
"- Let mancode assign internal IDs and digests; do not invent canonical IDs or digests in the semantic input.",
|
|
825
|
+
"- Revise the plan with `mancode workflow plan <namespace:ULID> revise --expected-revision <n> --file <plan.md> --session <id>`.",
|
|
826
|
+
"- Confirm the current plan with `mancode workflow plan <namespace:ULID> confirm --expected-revision <n> --plan-decision <plan_only|governed_execution> --session <id>`.",
|
|
827
|
+
"- Confirming with `--plan-decision plan_only` keeps the plan as planned authority and clears this session's active workflow pointer. Resume the TaskRef explicitly before any later governed mutation.",
|
|
828
|
+
'- When new evidence materially invalidates confirmed requirements and the operator explicitly chooses to realign the same local task, resume its TaskRef if needed, generate a fresh canonical checkpoint ULID, and run `mancode workflow reframe <namespace:ULID> --expected-revision <n> --checkpoint-id <fresh-ULID> --summary "<reason>" --next-action "<step-2 action>" --session <id>`. Reframe archives the confirmed requirements and plan, clears the plan decision, and stops at Step 2 with draft requirements. Do not substitute plan revise, scope-change, or workflow update for reframe.',
|
|
829
|
+
"- Read reframe evidence without opening private authority files: `mancode workflow archive <namespace:ULID> show <archive-ULID> --json` and `mancode workflow checkpoint <namespace:ULID> show <checkpoint-ULID> --json`.",
|
|
614
830
|
"- Apply verification and review ledgers with their mancode `apply --file` commands, then use `mancode workflow complete <namespace:ULID> --expected-revision <n> --session <id>`."
|
|
615
831
|
]
|
|
616
832
|
},
|
|
@@ -620,6 +836,8 @@ var V3_MODE_DEFINITIONS = {
|
|
|
620
836
|
contextPurpose: "implement",
|
|
621
837
|
actions: [
|
|
622
838
|
'- For a new diagnostic task, run `mancode workflow create manba "<task>" --session <id>`.',
|
|
839
|
+
"- Before changing code, establish the expected behavior from reproducible evidence, tests, documentation, history, or the current semantic owner. If the bug goal is clear but the correct behavior cannot be established, ask one focused question and wait instead of inventing product behavior.",
|
|
840
|
+
"- If the requested fix conflicts with repository evidence or crosses a hard-risk boundary, show the conflict and obtain a focused confirmation or route the decision through `/man`; do not treat an explicit but unsound fix instruction as sufficient evidence.",
|
|
623
841
|
"- When this is a child investigation, add `--parent <namespace:ULID>`; report and merge the typed outcome through the mancode child commands.",
|
|
624
842
|
"- Change lifecycle only with `mancode workflow update <namespace:ULID> --status <status> --expected-revision <n> --session <id>` and finish with `workflow complete` plus the typed `--outcome`."
|
|
625
843
|
]
|
|
@@ -631,8 +849,10 @@ var V3_MODE_DEFINITIONS = {
|
|
|
631
849
|
actions: [
|
|
632
850
|
"- Confirm team membership with `mancode team status`; join invited participants before assigning shared work.",
|
|
633
851
|
'- For a new shared task, run `mancode workflow create manteam "<task>" --visibility shared --coordination team --confirm-shared --session <id>`.',
|
|
852
|
+
"- Apply the same decision-readiness gate as `man` before finalizing requirements: validate both clarity and soundness against project facts and team authority. If the goal, scope, acceptance, owner/source of truth, and constraints are clear and consistent, continue without ceremonial questions; if a decision-changing ambiguity, ownership conflict, or hard-risk direction remains, give evidence and a recommendation, ask focused questions, and wait before writing confirmed requirements.",
|
|
853
|
+
"- Persist unresolved team clarification through the same `workflow requirements <namespace:ULID> draft --file <requirements.json>` command as `man`; do not leave ownership questions or partial answers only in chat history.",
|
|
634
854
|
"- Use claims, checkpoints, sync, and handoffs through `mancode team`; never infer ownership from an adapter prompt.",
|
|
635
|
-
"-
|
|
855
|
+
"- With git-ref transport, workflow creation plus requirements, plan, review, and verification mutations use an explicit deferred publication boundary: run the workflow command without `--sync`, commit the resulting `.mancode/shared` authority changes together with the matching code head, then run `mancode team sync push <shared:ULID> --expected-task-revision <n>`. Never report cross-clone synchronization before the push returns a receipt. Use `--sync` only for a command whose contract performs an atomic git-ref mutation."
|
|
636
856
|
]
|
|
637
857
|
},
|
|
638
858
|
manps: {
|
|
@@ -650,6 +870,10 @@ var V3_MODE_DEFINITIONS = {
|
|
|
650
870
|
contextPurpose: "implement",
|
|
651
871
|
actions: [
|
|
652
872
|
"- Do not create or persist a legacy solo mode. Ordinary focused work needs no TaskRef; if the operator expects a governed task, use its bound TaskRef or report that none is bound.",
|
|
873
|
+
"- Before editing, assess both clarity and soundness using the project facts. If the request is clear, consistent, and low risk, proceed without ceremonial questions. Resolve repository-answerable unknowns yourself; classify the rest as blocking, recommendable, or defaultable. Ask and wait only when a blocking unknown could materially change behavior, scope, acceptance, data, security, compatibility, or ownership.",
|
|
874
|
+
"- A supplied implementation direction is not automatically safe. If it conflicts with repository evidence or involves authentication, payment, sensitive data, deletion, migration, public APIs, untrusted input, concurrency, infrastructure, or another irreversible effect, show the evidence and impact, recommend the safer path, ask for focused confirmation, and wait before editing.",
|
|
875
|
+
"- If resolving the ambiguity requires architecture, semantic owner/source-of-truth, cross-module scope, migration, team coordination, or formal acceptance decisions, recommend `/man`, explain the trigger, and wait for the operator to choose; advice alone never changes mode or authority.",
|
|
876
|
+
"- Detect those governance triggers after the smallest fact check needed to establish them. Stop before exhaustive discovery or proposing a concrete topology, migration layout, or implementation plan that depends on unanswered decisions.",
|
|
653
877
|
"- For a governed-to-solo transition, use `mancode workflow handoff <namespace:ULID> --to solo --expected-revision <n> --session <id>`."
|
|
654
878
|
]
|
|
655
879
|
}
|
|
@@ -658,11 +882,12 @@ async function renderV3AdapterCandidate(root, platform) {
|
|
|
658
882
|
switch (platform) {
|
|
659
883
|
case "claude-code": {
|
|
660
884
|
const existing = await readAdapterTarget(root, "claude-skill");
|
|
661
|
-
return
|
|
662
|
-
"
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
885
|
+
return replaceManagedV3BlockText(
|
|
886
|
+
existing ?? "",
|
|
887
|
+
CONTINUITY_CLAUDE_START_MARKER,
|
|
888
|
+
CONTINUITY_CLAUDE_END_MARKER,
|
|
889
|
+
renderV3Bootstrap(platform)
|
|
890
|
+
);
|
|
666
891
|
}
|
|
667
892
|
case "cursor": {
|
|
668
893
|
const existing = await readAdapterTarget(root, "cursor-rule");
|
|
@@ -675,7 +900,10 @@ async function renderV3AdapterCandidate(root, platform) {
|
|
|
675
900
|
case "codex": {
|
|
676
901
|
const existing = await readAdapterTarget(root, "agents") ?? "";
|
|
677
902
|
return replaceManagedV3BlockText(
|
|
678
|
-
|
|
903
|
+
removeLegacyV3Block(
|
|
904
|
+
removeLegacyAgentsBlocks(existing),
|
|
905
|
+
LEGACY_V3_CODEX_MARKERS
|
|
906
|
+
),
|
|
679
907
|
V3_CODEX_START_MARKER,
|
|
680
908
|
V3_CODEX_END_MARKER,
|
|
681
909
|
renderV3Bootstrap(platform)
|
|
@@ -684,7 +912,10 @@ async function renderV3AdapterCandidate(root, platform) {
|
|
|
684
912
|
case "copilot": {
|
|
685
913
|
const existing = await readAdapterTarget(root, "copilot-instructions") ?? "";
|
|
686
914
|
return replaceManagedV3BlockText(
|
|
687
|
-
|
|
915
|
+
removeLegacyV3Block(
|
|
916
|
+
removeManagedBlock(existing),
|
|
917
|
+
LEGACY_V3_COPILOT_MARKERS
|
|
918
|
+
),
|
|
688
919
|
V3_COPILOT_START_MARKER,
|
|
689
920
|
V3_COPILOT_END_MARKER,
|
|
690
921
|
renderV3Bootstrap(platform)
|
|
@@ -693,7 +924,10 @@ async function renderV3AdapterCandidate(root, platform) {
|
|
|
693
924
|
case "zcode": {
|
|
694
925
|
const existing = await readAdapterTarget(root, "agents") ?? "";
|
|
695
926
|
return replaceManagedV3BlockText(
|
|
696
|
-
|
|
927
|
+
removeLegacyV3Block(
|
|
928
|
+
removeLegacyAgentsBlocks(existing),
|
|
929
|
+
LEGACY_V3_ZCODE_MARKERS
|
|
930
|
+
),
|
|
697
931
|
V3_ZCODE_START_MARKER,
|
|
698
932
|
V3_ZCODE_END_MARKER,
|
|
699
933
|
renderV3Bootstrap(platform)
|
|
@@ -701,18 +935,6 @@ async function renderV3AdapterCandidate(root, platform) {
|
|
|
701
935
|
}
|
|
702
936
|
}
|
|
703
937
|
}
|
|
704
|
-
function renderClaudeSkill(content) {
|
|
705
|
-
return [
|
|
706
|
-
"---",
|
|
707
|
-
"name: mancode-v3",
|
|
708
|
-
'description: "Internal bootstrap for the original mancode mode entries."',
|
|
709
|
-
"user-invocable: false",
|
|
710
|
-
"---",
|
|
711
|
-
"",
|
|
712
|
-
content,
|
|
713
|
-
""
|
|
714
|
-
].join("\n");
|
|
715
|
-
}
|
|
716
938
|
function renderCursorRule(content) {
|
|
717
939
|
return [
|
|
718
940
|
"---",
|
|
@@ -725,39 +947,283 @@ function renderCursorRule(content) {
|
|
|
725
947
|
""
|
|
726
948
|
].join("\n");
|
|
727
949
|
}
|
|
728
|
-
|
|
950
|
+
function managedTargetSpecs(root, platform) {
|
|
951
|
+
const primary = primaryManagedTargetSpec(platform);
|
|
952
|
+
const modes = V3_MODE_NAMES.map((mode) => {
|
|
953
|
+
const fileTarget = modeEntryFileTarget(platform, mode);
|
|
954
|
+
return {
|
|
955
|
+
identity: fileTarget,
|
|
956
|
+
target: relativeAdapterPath(root, v3ModeEntryPath(root, platform, mode)),
|
|
957
|
+
fileTarget,
|
|
958
|
+
expectedManagedContent: renderV3ModeEntry(mode, platform),
|
|
959
|
+
blockMarkers: null
|
|
960
|
+
};
|
|
961
|
+
});
|
|
962
|
+
return [primary, ...modes];
|
|
963
|
+
}
|
|
964
|
+
function normalizeUpgradePlatforms(platforms) {
|
|
965
|
+
if (!Array.isArray(platforms) || platforms.length === 0) {
|
|
966
|
+
throw new Error("MANCODE_ADAPTER_UPGRADE_PLATFORM_REQUIRED");
|
|
967
|
+
}
|
|
968
|
+
const selected = /* @__PURE__ */ new Set();
|
|
969
|
+
for (const platform of platforms) {
|
|
970
|
+
if (!V3_ADAPTER_PLATFORMS.includes(platform)) {
|
|
971
|
+
throw new Error("MANCODE_ADAPTER_UPGRADE_PLATFORM_INVALID");
|
|
972
|
+
}
|
|
973
|
+
selected.add(platform);
|
|
974
|
+
}
|
|
975
|
+
return V3_ADAPTER_PLATFORMS.filter((platform) => selected.has(platform));
|
|
976
|
+
}
|
|
977
|
+
function primaryFileTarget(platform) {
|
|
978
|
+
switch (platform) {
|
|
979
|
+
case "claude-code":
|
|
980
|
+
return "claude-skill";
|
|
981
|
+
case "cursor":
|
|
982
|
+
return "cursor-rule";
|
|
983
|
+
case "codex":
|
|
984
|
+
case "zcode":
|
|
985
|
+
return "agents";
|
|
986
|
+
case "copilot":
|
|
987
|
+
return "copilot-instructions";
|
|
988
|
+
}
|
|
989
|
+
}
|
|
990
|
+
function planPlatformBootstrapUpgrade(desired, platform) {
|
|
991
|
+
const target = primaryFileTarget(platform);
|
|
992
|
+
const current = desired.get(target) ?? null;
|
|
729
993
|
switch (platform) {
|
|
730
994
|
case "claude-code":
|
|
731
|
-
|
|
732
|
-
|
|
995
|
+
desired.set(
|
|
996
|
+
target,
|
|
997
|
+
replaceManagedV3BlockText(
|
|
998
|
+
current ?? "",
|
|
999
|
+
CONTINUITY_CLAUDE_START_MARKER,
|
|
1000
|
+
CONTINUITY_CLAUDE_END_MARKER,
|
|
1001
|
+
renderV3Bootstrap(platform)
|
|
1002
|
+
)
|
|
733
1003
|
);
|
|
1004
|
+
return;
|
|
734
1005
|
case "cursor":
|
|
735
|
-
|
|
736
|
-
|
|
1006
|
+
desired.set(
|
|
1007
|
+
target,
|
|
1008
|
+
managedFilePlan(
|
|
1009
|
+
target,
|
|
1010
|
+
current,
|
|
1011
|
+
renderCursorRule(renderV3Bootstrap(platform))
|
|
1012
|
+
).targetContent
|
|
737
1013
|
);
|
|
1014
|
+
return;
|
|
738
1015
|
case "codex":
|
|
739
|
-
|
|
740
|
-
|
|
1016
|
+
desired.set(
|
|
1017
|
+
target,
|
|
1018
|
+
replaceManagedV3BlockText(
|
|
1019
|
+
removeLegacyV3Block(
|
|
1020
|
+
removeLegacyAgentsBlocks(current ?? ""),
|
|
1021
|
+
LEGACY_V3_CODEX_MARKERS
|
|
1022
|
+
),
|
|
1023
|
+
V3_CODEX_START_MARKER,
|
|
1024
|
+
V3_CODEX_END_MARKER,
|
|
1025
|
+
renderV3Bootstrap(platform)
|
|
1026
|
+
)
|
|
1027
|
+
);
|
|
1028
|
+
return;
|
|
1029
|
+
case "zcode":
|
|
1030
|
+
desired.set(
|
|
1031
|
+
target,
|
|
1032
|
+
replaceManagedV3BlockText(
|
|
1033
|
+
removeLegacyV3Block(
|
|
1034
|
+
removeLegacyAgentsBlocks(current ?? ""),
|
|
1035
|
+
LEGACY_V3_ZCODE_MARKERS
|
|
1036
|
+
),
|
|
1037
|
+
V3_ZCODE_START_MARKER,
|
|
1038
|
+
V3_ZCODE_END_MARKER,
|
|
1039
|
+
renderV3Bootstrap(platform)
|
|
1040
|
+
)
|
|
1041
|
+
);
|
|
1042
|
+
return;
|
|
1043
|
+
case "copilot":
|
|
1044
|
+
desired.set(
|
|
1045
|
+
target,
|
|
1046
|
+
replaceManagedV3BlockText(
|
|
1047
|
+
removeLegacyV3Block(
|
|
1048
|
+
removeManagedBlock(current ?? ""),
|
|
1049
|
+
LEGACY_V3_COPILOT_MARKERS
|
|
1050
|
+
),
|
|
1051
|
+
V3_COPILOT_START_MARKER,
|
|
1052
|
+
V3_COPILOT_END_MARKER,
|
|
1053
|
+
renderV3Bootstrap(platform)
|
|
1054
|
+
)
|
|
1055
|
+
);
|
|
1056
|
+
}
|
|
1057
|
+
}
|
|
1058
|
+
function primaryManagedTargetSpec(platform) {
|
|
1059
|
+
const target = targetFor(platform);
|
|
1060
|
+
switch (platform) {
|
|
1061
|
+
case "claude-code":
|
|
1062
|
+
return embeddedManagedTargetSpec(
|
|
1063
|
+
target,
|
|
1064
|
+
"claude-instructions#continuity",
|
|
1065
|
+
"claude-skill",
|
|
1066
|
+
CONTINUITY_CLAUDE_START_MARKER,
|
|
1067
|
+
CONTINUITY_CLAUDE_END_MARKER,
|
|
1068
|
+
renderV3Bootstrap(platform)
|
|
1069
|
+
);
|
|
1070
|
+
case "cursor":
|
|
1071
|
+
return {
|
|
1072
|
+
identity: "cursor-rule",
|
|
1073
|
+
target,
|
|
1074
|
+
fileTarget: "cursor-rule",
|
|
1075
|
+
expectedManagedContent: renderCursorRule(renderV3Bootstrap(platform)),
|
|
1076
|
+
blockMarkers: null
|
|
1077
|
+
};
|
|
1078
|
+
case "codex":
|
|
1079
|
+
return embeddedManagedTargetSpec(
|
|
1080
|
+
target,
|
|
1081
|
+
"agents#codex",
|
|
1082
|
+
"agents",
|
|
741
1083
|
V3_CODEX_START_MARKER,
|
|
742
|
-
V3_CODEX_END_MARKER
|
|
1084
|
+
V3_CODEX_END_MARKER,
|
|
1085
|
+
renderV3Bootstrap(platform)
|
|
743
1086
|
);
|
|
744
1087
|
case "copilot":
|
|
745
|
-
return
|
|
746
|
-
|
|
1088
|
+
return embeddedManagedTargetSpec(
|
|
1089
|
+
target,
|
|
1090
|
+
"copilot-instructions#copilot",
|
|
1091
|
+
"copilot-instructions",
|
|
747
1092
|
V3_COPILOT_START_MARKER,
|
|
748
|
-
V3_COPILOT_END_MARKER
|
|
1093
|
+
V3_COPILOT_END_MARKER,
|
|
1094
|
+
renderV3Bootstrap(platform)
|
|
749
1095
|
);
|
|
750
1096
|
case "zcode":
|
|
751
|
-
return
|
|
752
|
-
|
|
1097
|
+
return embeddedManagedTargetSpec(
|
|
1098
|
+
target,
|
|
1099
|
+
"agents#zcode",
|
|
1100
|
+
"agents",
|
|
753
1101
|
V3_ZCODE_START_MARKER,
|
|
754
|
-
V3_ZCODE_END_MARKER
|
|
1102
|
+
V3_ZCODE_END_MARKER,
|
|
1103
|
+
renderV3Bootstrap(platform)
|
|
755
1104
|
);
|
|
756
1105
|
}
|
|
757
1106
|
}
|
|
1107
|
+
function embeddedManagedTargetSpec(target, identity, fileTarget, startMarker, endMarker, content) {
|
|
1108
|
+
return {
|
|
1109
|
+
identity,
|
|
1110
|
+
target,
|
|
1111
|
+
fileTarget,
|
|
1112
|
+
expectedManagedContent: [startMarker, content, endMarker].join("\n"),
|
|
1113
|
+
blockMarkers: [startMarker, endMarker]
|
|
1114
|
+
};
|
|
1115
|
+
}
|
|
1116
|
+
function modeEntryFileTarget(platform, mode) {
|
|
1117
|
+
const family = platform === "claude-code" ? "claude" : platform === "codex" || platform === "zcode" ? "agents" : platform;
|
|
1118
|
+
return `${family}-mode-${mode}`;
|
|
1119
|
+
}
|
|
1120
|
+
async function inspectManagedTarget(root, platform, spec) {
|
|
1121
|
+
const expectedDigest = adapterManagedContentDigest(
|
|
1122
|
+
spec.identity,
|
|
1123
|
+
spec.expectedManagedContent
|
|
1124
|
+
);
|
|
1125
|
+
const repair = [
|
|
1126
|
+
`Preview with \`mancode adapter upgrade --platform ${platform} --dry-run\`.`,
|
|
1127
|
+
`Confirm that exact preview with \`mancode adapter upgrade --platform ${platform} --confirm --operation-id <operationId> --session <id>\`.`
|
|
1128
|
+
].join(" ");
|
|
1129
|
+
try {
|
|
1130
|
+
const bytes = await readAdapterBytesIfExists(
|
|
1131
|
+
root,
|
|
1132
|
+
v3AdapterTargetPath(root, spec.fileTarget)
|
|
1133
|
+
);
|
|
1134
|
+
if (bytes === null) {
|
|
1135
|
+
return managedTargetStatus(
|
|
1136
|
+
spec,
|
|
1137
|
+
"missing",
|
|
1138
|
+
null,
|
|
1139
|
+
expectedDigest,
|
|
1140
|
+
repair,
|
|
1141
|
+
"Managed target does not exist."
|
|
1142
|
+
);
|
|
1143
|
+
}
|
|
1144
|
+
const content = new TextDecoder("utf-8", { fatal: true }).decode(bytes);
|
|
1145
|
+
let managedContent;
|
|
1146
|
+
if (spec.blockMarkers === null) {
|
|
1147
|
+
managedContent = content;
|
|
1148
|
+
} else {
|
|
1149
|
+
try {
|
|
1150
|
+
const extracted = extractManagedBlock(
|
|
1151
|
+
content,
|
|
1152
|
+
spec.blockMarkers[0],
|
|
1153
|
+
spec.blockMarkers[1]
|
|
1154
|
+
);
|
|
1155
|
+
if (extracted === null) {
|
|
1156
|
+
return managedTargetStatus(
|
|
1157
|
+
spec,
|
|
1158
|
+
"missing",
|
|
1159
|
+
null,
|
|
1160
|
+
expectedDigest,
|
|
1161
|
+
repair,
|
|
1162
|
+
"Managed block is absent from the target file."
|
|
1163
|
+
);
|
|
1164
|
+
}
|
|
1165
|
+
managedContent = extracted;
|
|
1166
|
+
} catch (error) {
|
|
1167
|
+
return managedTargetStatus(
|
|
1168
|
+
spec,
|
|
1169
|
+
"stale",
|
|
1170
|
+
null,
|
|
1171
|
+
expectedDigest,
|
|
1172
|
+
repair,
|
|
1173
|
+
error instanceof Error ? error.message : "Managed block is malformed."
|
|
1174
|
+
);
|
|
1175
|
+
}
|
|
1176
|
+
}
|
|
1177
|
+
const actualDigest = adapterManagedContentDigest(
|
|
1178
|
+
spec.identity,
|
|
1179
|
+
managedContent
|
|
1180
|
+
);
|
|
1181
|
+
const status = actualDigest === expectedDigest ? "ready" : "stale";
|
|
1182
|
+
return managedTargetStatus(
|
|
1183
|
+
spec,
|
|
1184
|
+
status,
|
|
1185
|
+
actualDigest,
|
|
1186
|
+
expectedDigest,
|
|
1187
|
+
status === "ready" ? "none" : repair,
|
|
1188
|
+
status === "ready" ? "Managed content matches the current renderer." : "Managed content differs from the current renderer."
|
|
1189
|
+
);
|
|
1190
|
+
} catch (error) {
|
|
1191
|
+
return managedTargetStatus(
|
|
1192
|
+
spec,
|
|
1193
|
+
"unreadable",
|
|
1194
|
+
null,
|
|
1195
|
+
expectedDigest,
|
|
1196
|
+
`Resolve the filesystem or UTF-8 error, then ${repair}`,
|
|
1197
|
+
error instanceof Error ? error.message : "Managed target is unreadable."
|
|
1198
|
+
);
|
|
1199
|
+
}
|
|
1200
|
+
}
|
|
1201
|
+
function managedTargetStatus(spec, status, actualDigest, expectedDigest, repair, detail) {
|
|
1202
|
+
return {
|
|
1203
|
+
identity: spec.identity,
|
|
1204
|
+
target: spec.target,
|
|
1205
|
+
status,
|
|
1206
|
+
actualDigest,
|
|
1207
|
+
expectedDigest,
|
|
1208
|
+
rendererVersion: V3_ADAPTER_VERSION,
|
|
1209
|
+
repair,
|
|
1210
|
+
detail
|
|
1211
|
+
};
|
|
1212
|
+
}
|
|
1213
|
+
function aggregateAdapterStatus(targets) {
|
|
1214
|
+
if (targets.every((target) => target.status === "ready")) return "ready";
|
|
1215
|
+
if (targets.some((target) => target.status === "unreadable")) {
|
|
1216
|
+
return "unreadable";
|
|
1217
|
+
}
|
|
1218
|
+
if (targets.some((target) => target.status === "stale")) return "stale";
|
|
1219
|
+
return "missing";
|
|
1220
|
+
}
|
|
1221
|
+
function relativeAdapterPath(root, target) {
|
|
1222
|
+
return path.relative(root, target).split(path.sep).join("/");
|
|
1223
|
+
}
|
|
758
1224
|
async function writeManagedFile(filePath, content) {
|
|
759
1225
|
const existing = await readTextIfExists(filePath);
|
|
760
|
-
if (existing !== null && !existing.includes(V3_ADAPTER_MANAGED_MARKER)) {
|
|
1226
|
+
if (existing !== null && !existing.includes(V3_ADAPTER_MANAGED_MARKER) && !existing.includes(LEGACY_V3_ADAPTER_MANAGED_MARKER)) {
|
|
761
1227
|
throw new Error("MANCODE_V3_ADAPTER_TARGET_USER_AUTHORED");
|
|
762
1228
|
}
|
|
763
1229
|
await mkdir(path.dirname(filePath), { recursive: true });
|
|
@@ -788,15 +1254,13 @@ async function assertV3ModeEntriesWritable(root, platform) {
|
|
|
788
1254
|
}
|
|
789
1255
|
async function removeV3ModeEntry(filePath) {
|
|
790
1256
|
const existing = await readTextIfExists(filePath);
|
|
791
|
-
if (existing?.includes(V3_MODE_ENTRY_MANAGED_MARKER)
|
|
1257
|
+
if (existing?.includes(V3_MODE_ENTRY_MANAGED_MARKER) || LEGACY_MODE_ENTRY_MANAGED_MARKERS.some(
|
|
1258
|
+
(marker) => existing?.includes(marker)
|
|
1259
|
+
)) {
|
|
792
1260
|
await rm(filePath, { force: true });
|
|
793
1261
|
await removeDirectoryIfEmpty(path.dirname(filePath));
|
|
794
1262
|
}
|
|
795
1263
|
}
|
|
796
|
-
async function v3ModeEntryPresent(filePath) {
|
|
797
|
-
const existing = await readTextIfExists(filePath);
|
|
798
|
-
return existing?.includes(V3_MODE_ENTRY_MANAGED_MARKER) ?? false;
|
|
799
|
-
}
|
|
800
1264
|
async function removeDirectoryIfEmpty(directory) {
|
|
801
1265
|
try {
|
|
802
1266
|
await rmdir(directory);
|
|
@@ -813,6 +1277,18 @@ async function removeManagedFile(filePath) {
|
|
|
813
1277
|
await rm(filePath, { force: true });
|
|
814
1278
|
}
|
|
815
1279
|
}
|
|
1280
|
+
async function removeRetiredBootstrapFiles(root, platform) {
|
|
1281
|
+
if (platform !== "claude-code" && platform !== "cursor") return;
|
|
1282
|
+
for (const retired of retiredBootstrapSpecs(root, platform)) {
|
|
1283
|
+
await assertAdapterPathSafe(root, retired.filePath);
|
|
1284
|
+
const existing = await readTextIfExists(retired.filePath);
|
|
1285
|
+
if (!retired.managedMarkers.some((marker) => existing?.includes(marker))) {
|
|
1286
|
+
continue;
|
|
1287
|
+
}
|
|
1288
|
+
await rm(retired.filePath, { force: true });
|
|
1289
|
+
await removeDirectoryIfEmpty(path.dirname(retired.filePath));
|
|
1290
|
+
}
|
|
1291
|
+
}
|
|
816
1292
|
async function replaceManagedV3Block(filePath, startMarker, endMarker, content, legacyMarkers) {
|
|
817
1293
|
const current = await readTextIfExists(filePath) ?? "";
|
|
818
1294
|
const existing = (legacyMarkers ?? []).reduce(
|
|
@@ -837,6 +1313,9 @@ function removeLegacyAgentsBlocks(existing) {
|
|
|
837
1313
|
LEGACY_ZCODE_END_MARKER
|
|
838
1314
|
);
|
|
839
1315
|
}
|
|
1316
|
+
function removeLegacyV3Block(existing, markers) {
|
|
1317
|
+
return removeManagedBlock(existing, markers[0], markers[1]);
|
|
1318
|
+
}
|
|
840
1319
|
function replaceManagedV3BlockText(existing, startMarker, endMarker, content) {
|
|
841
1320
|
return replaceManagedBlock(
|
|
842
1321
|
existing,
|
|
@@ -846,7 +1325,7 @@ function replaceManagedV3BlockText(existing, startMarker, endMarker, content) {
|
|
|
846
1325
|
);
|
|
847
1326
|
}
|
|
848
1327
|
function managedFilePlan(target, beforeContent, targetContent) {
|
|
849
|
-
if (beforeContent !== null && !beforeContent.includes(V3_ADAPTER_MANAGED_MARKER)) {
|
|
1328
|
+
if (beforeContent !== null && !beforeContent.includes(V3_ADAPTER_MANAGED_MARKER) && !beforeContent.includes(LEGACY_V3_ADAPTER_MANAGED_MARKER)) {
|
|
850
1329
|
throw new Error("MANCODE_V3_ADAPTER_TARGET_USER_AUTHORED");
|
|
851
1330
|
}
|
|
852
1331
|
return { target, beforeContent, targetContent };
|
|
@@ -1175,6 +1654,11 @@ async function assertPlatformAdapterPathsSafe(root, platform) {
|
|
|
1175
1654
|
(target) => v3AdapterTargetPath(root, target)
|
|
1176
1655
|
)
|
|
1177
1656
|
]);
|
|
1657
|
+
if (platform === "claude-code" || platform === "cursor") {
|
|
1658
|
+
for (const retired of retiredBootstrapSpecs(root, platform)) {
|
|
1659
|
+
targets.add(retired.filePath);
|
|
1660
|
+
}
|
|
1661
|
+
}
|
|
1178
1662
|
for (const target of targets) {
|
|
1179
1663
|
await assertAdapterPathSafe(root, target);
|
|
1180
1664
|
}
|
|
@@ -1216,13 +1700,35 @@ async function removeManagedV3Block(filePath, startMarker, endMarker) {
|
|
|
1216
1700
|
await rm(filePath, { force: true });
|
|
1217
1701
|
}
|
|
1218
1702
|
}
|
|
1219
|
-
async function
|
|
1703
|
+
async function anyManagedBlockPresent(filePath, markerPairs) {
|
|
1220
1704
|
const content = await readTextIfExists(filePath);
|
|
1221
|
-
return content
|
|
1705
|
+
return content !== null && markerPairs.some(
|
|
1706
|
+
([startMarker, endMarker]) => hasManagedBlock(content, startMarker, endMarker)
|
|
1707
|
+
);
|
|
1222
1708
|
}
|
|
1223
|
-
async function
|
|
1224
|
-
|
|
1225
|
-
|
|
1709
|
+
async function readAdapterBytesIfExists(root, filePath) {
|
|
1710
|
+
await assertAdapterPathSafe(root, filePath);
|
|
1711
|
+
try {
|
|
1712
|
+
const entry = await lstat(filePath);
|
|
1713
|
+
if (!entry.isFile() || entry.isSymbolicLink()) {
|
|
1714
|
+
throw new Error("MANCODE_ARTIFACT_PATH_UNSAFE");
|
|
1715
|
+
}
|
|
1716
|
+
} catch (error) {
|
|
1717
|
+
if (isNodeError(error) && error.code === "ENOENT") return null;
|
|
1718
|
+
throw error;
|
|
1719
|
+
}
|
|
1720
|
+
for (let attempt = 1; attempt <= ADAPTER_READ_MAX_ATTEMPTS; attempt += 1) {
|
|
1721
|
+
try {
|
|
1722
|
+
return await readFile(filePath);
|
|
1723
|
+
} catch (error) {
|
|
1724
|
+
if (isNodeError(error) && error.code === "ENOENT") return null;
|
|
1725
|
+
if (!isRetriableAdapterReadError(error) || attempt === ADAPTER_READ_MAX_ATTEMPTS) {
|
|
1726
|
+
throw error;
|
|
1727
|
+
}
|
|
1728
|
+
await delay(ADAPTER_READ_RETRY_DELAY_MS * attempt);
|
|
1729
|
+
}
|
|
1730
|
+
}
|
|
1731
|
+
throw new Error("MANCODE_V3_ADAPTER_READ_RETRY_EXHAUSTED");
|
|
1226
1732
|
}
|
|
1227
1733
|
async function readTextIfExists(filePath) {
|
|
1228
1734
|
for (let attempt = 1; attempt <= ADAPTER_READ_MAX_ATTEMPTS; attempt += 1) {
|
|
@@ -1253,9 +1759,9 @@ async function atomicWrite(filePath, content) {
|
|
|
1253
1759
|
function targetFor(platform) {
|
|
1254
1760
|
switch (platform) {
|
|
1255
1761
|
case "claude-code":
|
|
1256
|
-
return ".
|
|
1762
|
+
return "CLAUDE.md";
|
|
1257
1763
|
case "cursor":
|
|
1258
|
-
return ".cursor/rules/mancode-
|
|
1764
|
+
return ".cursor/rules/mancode-continuity.mdc";
|
|
1259
1765
|
case "codex":
|
|
1260
1766
|
case "zcode":
|
|
1261
1767
|
return "AGENTS.md";
|
|
@@ -1263,6 +1769,47 @@ function targetFor(platform) {
|
|
|
1263
1769
|
return ".github/copilot-instructions.md";
|
|
1264
1770
|
}
|
|
1265
1771
|
}
|
|
1772
|
+
function retiredBootstrapPlatformFor(target) {
|
|
1773
|
+
if (target === "claude-skill") return "claude-code";
|
|
1774
|
+
if (target === "cursor-rule") return "cursor";
|
|
1775
|
+
return null;
|
|
1776
|
+
}
|
|
1777
|
+
function retiredBootstrapSpecs(root, platform) {
|
|
1778
|
+
const managedMarkers = [
|
|
1779
|
+
LEGACY_V3_ADAPTER_MANAGED_MARKER,
|
|
1780
|
+
V3_ADAPTER_MANAGED_MARKER
|
|
1781
|
+
];
|
|
1782
|
+
if (platform === "claude-code") {
|
|
1783
|
+
return [
|
|
1784
|
+
{
|
|
1785
|
+
filePath: path.join(
|
|
1786
|
+
root,
|
|
1787
|
+
".claude",
|
|
1788
|
+
"skills",
|
|
1789
|
+
"mancode-v3",
|
|
1790
|
+
"SKILL.md"
|
|
1791
|
+
),
|
|
1792
|
+
managedMarkers
|
|
1793
|
+
},
|
|
1794
|
+
{
|
|
1795
|
+
filePath: path.join(
|
|
1796
|
+
root,
|
|
1797
|
+
".claude",
|
|
1798
|
+
"skills",
|
|
1799
|
+
"mancode-continuity",
|
|
1800
|
+
"SKILL.md"
|
|
1801
|
+
),
|
|
1802
|
+
managedMarkers
|
|
1803
|
+
}
|
|
1804
|
+
];
|
|
1805
|
+
}
|
|
1806
|
+
return [
|
|
1807
|
+
{
|
|
1808
|
+
filePath: path.join(root, ".cursor", "rules", "mancode-v3.mdc"),
|
|
1809
|
+
managedMarkers
|
|
1810
|
+
}
|
|
1811
|
+
];
|
|
1812
|
+
}
|
|
1266
1813
|
function platformLabelFor(platform) {
|
|
1267
1814
|
switch (platform) {
|
|
1268
1815
|
case "claude-code":
|
|
@@ -1306,9 +1853,14 @@ export {
|
|
|
1306
1853
|
V3_ADAPTER_VERSION,
|
|
1307
1854
|
V3_ADAPTER_MANAGED_MARKER,
|
|
1308
1855
|
V3_MODE_ENTRY_MANAGED_MARKER,
|
|
1856
|
+
V3_ADAPTER_DIGEST_DOMAIN,
|
|
1309
1857
|
V3_MODE_NAMES,
|
|
1858
|
+
V3_ADAPTER_PLATFORMS,
|
|
1310
1859
|
V3_ADAPTER_FILE_TARGETS,
|
|
1860
|
+
adapterManagedContentDigest,
|
|
1311
1861
|
planV3AdapterFiles,
|
|
1862
|
+
planV3AdapterUpgradeFiles,
|
|
1863
|
+
stageV3AdapterUpgradeFiles,
|
|
1312
1864
|
applyV3AdapterFilePlan,
|
|
1313
1865
|
stageV3Adapter,
|
|
1314
1866
|
v3AdapterTargetPath,
|
|
@@ -1318,8 +1870,9 @@ export {
|
|
|
1318
1870
|
assertV3AdapterInstallable,
|
|
1319
1871
|
inspectV3Adapter,
|
|
1320
1872
|
inspectV3AdapterVersions,
|
|
1873
|
+
v3AdapterVersionsFromStatuses,
|
|
1321
1874
|
removeV3Adapter,
|
|
1322
1875
|
renderV3Bootstrap,
|
|
1323
1876
|
renderV3ModeEntry
|
|
1324
1877
|
};
|
|
1325
|
-
//# sourceMappingURL=chunk-
|
|
1878
|
+
//# sourceMappingURL=chunk-VV3MFVIG.js.map
|