mancode 0.3.18 → 0.4.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/README.en.md +60 -35
- package/README.md +53 -31
- package/dist/{chunk-QIOMFU35.js → chunk-K3MYY47M.js} +658 -106
- package/dist/chunk-K3MYY47M.js.map +1 -0
- package/dist/{chunk-LMXUPBCN.js → chunk-S3BAOJPP.js} +202 -50
- package/dist/chunk-S3BAOJPP.js.map +1 -0
- package/dist/cli.js +24026 -20939
- 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-URAKH6BV.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-URAKH6BV.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,6 +849,8 @@ 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
|
"- Use the same mancode requirements, plan, verification, review, and completion commands as `man`, adding `--sync` whenever the active transport requires it."
|
|
636
856
|
]
|
|
@@ -650,6 +870,9 @@ 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.",
|
|
653
876
|
"- For a governed-to-solo transition, use `mancode workflow handoff <namespace:ULID> --to solo --expected-revision <n> --session <id>`."
|
|
654
877
|
]
|
|
655
878
|
}
|
|
@@ -658,11 +881,12 @@ async function renderV3AdapterCandidate(root, platform) {
|
|
|
658
881
|
switch (platform) {
|
|
659
882
|
case "claude-code": {
|
|
660
883
|
const existing = await readAdapterTarget(root, "claude-skill");
|
|
661
|
-
return
|
|
662
|
-
"
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
884
|
+
return replaceManagedV3BlockText(
|
|
885
|
+
existing ?? "",
|
|
886
|
+
CONTINUITY_CLAUDE_START_MARKER,
|
|
887
|
+
CONTINUITY_CLAUDE_END_MARKER,
|
|
888
|
+
renderV3Bootstrap(platform)
|
|
889
|
+
);
|
|
666
890
|
}
|
|
667
891
|
case "cursor": {
|
|
668
892
|
const existing = await readAdapterTarget(root, "cursor-rule");
|
|
@@ -675,7 +899,10 @@ async function renderV3AdapterCandidate(root, platform) {
|
|
|
675
899
|
case "codex": {
|
|
676
900
|
const existing = await readAdapterTarget(root, "agents") ?? "";
|
|
677
901
|
return replaceManagedV3BlockText(
|
|
678
|
-
|
|
902
|
+
removeLegacyV3Block(
|
|
903
|
+
removeLegacyAgentsBlocks(existing),
|
|
904
|
+
LEGACY_V3_CODEX_MARKERS
|
|
905
|
+
),
|
|
679
906
|
V3_CODEX_START_MARKER,
|
|
680
907
|
V3_CODEX_END_MARKER,
|
|
681
908
|
renderV3Bootstrap(platform)
|
|
@@ -684,7 +911,10 @@ async function renderV3AdapterCandidate(root, platform) {
|
|
|
684
911
|
case "copilot": {
|
|
685
912
|
const existing = await readAdapterTarget(root, "copilot-instructions") ?? "";
|
|
686
913
|
return replaceManagedV3BlockText(
|
|
687
|
-
|
|
914
|
+
removeLegacyV3Block(
|
|
915
|
+
removeManagedBlock(existing),
|
|
916
|
+
LEGACY_V3_COPILOT_MARKERS
|
|
917
|
+
),
|
|
688
918
|
V3_COPILOT_START_MARKER,
|
|
689
919
|
V3_COPILOT_END_MARKER,
|
|
690
920
|
renderV3Bootstrap(platform)
|
|
@@ -693,7 +923,10 @@ async function renderV3AdapterCandidate(root, platform) {
|
|
|
693
923
|
case "zcode": {
|
|
694
924
|
const existing = await readAdapterTarget(root, "agents") ?? "";
|
|
695
925
|
return replaceManagedV3BlockText(
|
|
696
|
-
|
|
926
|
+
removeLegacyV3Block(
|
|
927
|
+
removeLegacyAgentsBlocks(existing),
|
|
928
|
+
LEGACY_V3_ZCODE_MARKERS
|
|
929
|
+
),
|
|
697
930
|
V3_ZCODE_START_MARKER,
|
|
698
931
|
V3_ZCODE_END_MARKER,
|
|
699
932
|
renderV3Bootstrap(platform)
|
|
@@ -701,18 +934,6 @@ async function renderV3AdapterCandidate(root, platform) {
|
|
|
701
934
|
}
|
|
702
935
|
}
|
|
703
936
|
}
|
|
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
937
|
function renderCursorRule(content) {
|
|
717
938
|
return [
|
|
718
939
|
"---",
|
|
@@ -725,39 +946,283 @@ function renderCursorRule(content) {
|
|
|
725
946
|
""
|
|
726
947
|
].join("\n");
|
|
727
948
|
}
|
|
728
|
-
|
|
949
|
+
function managedTargetSpecs(root, platform) {
|
|
950
|
+
const primary = primaryManagedTargetSpec(platform);
|
|
951
|
+
const modes = V3_MODE_NAMES.map((mode) => {
|
|
952
|
+
const fileTarget = modeEntryFileTarget(platform, mode);
|
|
953
|
+
return {
|
|
954
|
+
identity: fileTarget,
|
|
955
|
+
target: relativeAdapterPath(root, v3ModeEntryPath(root, platform, mode)),
|
|
956
|
+
fileTarget,
|
|
957
|
+
expectedManagedContent: renderV3ModeEntry(mode, platform),
|
|
958
|
+
blockMarkers: null
|
|
959
|
+
};
|
|
960
|
+
});
|
|
961
|
+
return [primary, ...modes];
|
|
962
|
+
}
|
|
963
|
+
function normalizeUpgradePlatforms(platforms) {
|
|
964
|
+
if (!Array.isArray(platforms) || platforms.length === 0) {
|
|
965
|
+
throw new Error("MANCODE_ADAPTER_UPGRADE_PLATFORM_REQUIRED");
|
|
966
|
+
}
|
|
967
|
+
const selected = /* @__PURE__ */ new Set();
|
|
968
|
+
for (const platform of platforms) {
|
|
969
|
+
if (!V3_ADAPTER_PLATFORMS.includes(platform)) {
|
|
970
|
+
throw new Error("MANCODE_ADAPTER_UPGRADE_PLATFORM_INVALID");
|
|
971
|
+
}
|
|
972
|
+
selected.add(platform);
|
|
973
|
+
}
|
|
974
|
+
return V3_ADAPTER_PLATFORMS.filter((platform) => selected.has(platform));
|
|
975
|
+
}
|
|
976
|
+
function primaryFileTarget(platform) {
|
|
977
|
+
switch (platform) {
|
|
978
|
+
case "claude-code":
|
|
979
|
+
return "claude-skill";
|
|
980
|
+
case "cursor":
|
|
981
|
+
return "cursor-rule";
|
|
982
|
+
case "codex":
|
|
983
|
+
case "zcode":
|
|
984
|
+
return "agents";
|
|
985
|
+
case "copilot":
|
|
986
|
+
return "copilot-instructions";
|
|
987
|
+
}
|
|
988
|
+
}
|
|
989
|
+
function planPlatformBootstrapUpgrade(desired, platform) {
|
|
990
|
+
const target = primaryFileTarget(platform);
|
|
991
|
+
const current = desired.get(target) ?? null;
|
|
729
992
|
switch (platform) {
|
|
730
993
|
case "claude-code":
|
|
731
|
-
|
|
732
|
-
|
|
994
|
+
desired.set(
|
|
995
|
+
target,
|
|
996
|
+
replaceManagedV3BlockText(
|
|
997
|
+
current ?? "",
|
|
998
|
+
CONTINUITY_CLAUDE_START_MARKER,
|
|
999
|
+
CONTINUITY_CLAUDE_END_MARKER,
|
|
1000
|
+
renderV3Bootstrap(platform)
|
|
1001
|
+
)
|
|
733
1002
|
);
|
|
1003
|
+
return;
|
|
734
1004
|
case "cursor":
|
|
735
|
-
|
|
736
|
-
|
|
1005
|
+
desired.set(
|
|
1006
|
+
target,
|
|
1007
|
+
managedFilePlan(
|
|
1008
|
+
target,
|
|
1009
|
+
current,
|
|
1010
|
+
renderCursorRule(renderV3Bootstrap(platform))
|
|
1011
|
+
).targetContent
|
|
737
1012
|
);
|
|
1013
|
+
return;
|
|
738
1014
|
case "codex":
|
|
739
|
-
|
|
740
|
-
|
|
1015
|
+
desired.set(
|
|
1016
|
+
target,
|
|
1017
|
+
replaceManagedV3BlockText(
|
|
1018
|
+
removeLegacyV3Block(
|
|
1019
|
+
removeLegacyAgentsBlocks(current ?? ""),
|
|
1020
|
+
LEGACY_V3_CODEX_MARKERS
|
|
1021
|
+
),
|
|
1022
|
+
V3_CODEX_START_MARKER,
|
|
1023
|
+
V3_CODEX_END_MARKER,
|
|
1024
|
+
renderV3Bootstrap(platform)
|
|
1025
|
+
)
|
|
1026
|
+
);
|
|
1027
|
+
return;
|
|
1028
|
+
case "zcode":
|
|
1029
|
+
desired.set(
|
|
1030
|
+
target,
|
|
1031
|
+
replaceManagedV3BlockText(
|
|
1032
|
+
removeLegacyV3Block(
|
|
1033
|
+
removeLegacyAgentsBlocks(current ?? ""),
|
|
1034
|
+
LEGACY_V3_ZCODE_MARKERS
|
|
1035
|
+
),
|
|
1036
|
+
V3_ZCODE_START_MARKER,
|
|
1037
|
+
V3_ZCODE_END_MARKER,
|
|
1038
|
+
renderV3Bootstrap(platform)
|
|
1039
|
+
)
|
|
1040
|
+
);
|
|
1041
|
+
return;
|
|
1042
|
+
case "copilot":
|
|
1043
|
+
desired.set(
|
|
1044
|
+
target,
|
|
1045
|
+
replaceManagedV3BlockText(
|
|
1046
|
+
removeLegacyV3Block(
|
|
1047
|
+
removeManagedBlock(current ?? ""),
|
|
1048
|
+
LEGACY_V3_COPILOT_MARKERS
|
|
1049
|
+
),
|
|
1050
|
+
V3_COPILOT_START_MARKER,
|
|
1051
|
+
V3_COPILOT_END_MARKER,
|
|
1052
|
+
renderV3Bootstrap(platform)
|
|
1053
|
+
)
|
|
1054
|
+
);
|
|
1055
|
+
}
|
|
1056
|
+
}
|
|
1057
|
+
function primaryManagedTargetSpec(platform) {
|
|
1058
|
+
const target = targetFor(platform);
|
|
1059
|
+
switch (platform) {
|
|
1060
|
+
case "claude-code":
|
|
1061
|
+
return embeddedManagedTargetSpec(
|
|
1062
|
+
target,
|
|
1063
|
+
"claude-instructions#continuity",
|
|
1064
|
+
"claude-skill",
|
|
1065
|
+
CONTINUITY_CLAUDE_START_MARKER,
|
|
1066
|
+
CONTINUITY_CLAUDE_END_MARKER,
|
|
1067
|
+
renderV3Bootstrap(platform)
|
|
1068
|
+
);
|
|
1069
|
+
case "cursor":
|
|
1070
|
+
return {
|
|
1071
|
+
identity: "cursor-rule",
|
|
1072
|
+
target,
|
|
1073
|
+
fileTarget: "cursor-rule",
|
|
1074
|
+
expectedManagedContent: renderCursorRule(renderV3Bootstrap(platform)),
|
|
1075
|
+
blockMarkers: null
|
|
1076
|
+
};
|
|
1077
|
+
case "codex":
|
|
1078
|
+
return embeddedManagedTargetSpec(
|
|
1079
|
+
target,
|
|
1080
|
+
"agents#codex",
|
|
1081
|
+
"agents",
|
|
741
1082
|
V3_CODEX_START_MARKER,
|
|
742
|
-
V3_CODEX_END_MARKER
|
|
1083
|
+
V3_CODEX_END_MARKER,
|
|
1084
|
+
renderV3Bootstrap(platform)
|
|
743
1085
|
);
|
|
744
1086
|
case "copilot":
|
|
745
|
-
return
|
|
746
|
-
|
|
1087
|
+
return embeddedManagedTargetSpec(
|
|
1088
|
+
target,
|
|
1089
|
+
"copilot-instructions#copilot",
|
|
1090
|
+
"copilot-instructions",
|
|
747
1091
|
V3_COPILOT_START_MARKER,
|
|
748
|
-
V3_COPILOT_END_MARKER
|
|
1092
|
+
V3_COPILOT_END_MARKER,
|
|
1093
|
+
renderV3Bootstrap(platform)
|
|
749
1094
|
);
|
|
750
1095
|
case "zcode":
|
|
751
|
-
return
|
|
752
|
-
|
|
1096
|
+
return embeddedManagedTargetSpec(
|
|
1097
|
+
target,
|
|
1098
|
+
"agents#zcode",
|
|
1099
|
+
"agents",
|
|
753
1100
|
V3_ZCODE_START_MARKER,
|
|
754
|
-
V3_ZCODE_END_MARKER
|
|
1101
|
+
V3_ZCODE_END_MARKER,
|
|
1102
|
+
renderV3Bootstrap(platform)
|
|
755
1103
|
);
|
|
756
1104
|
}
|
|
757
1105
|
}
|
|
1106
|
+
function embeddedManagedTargetSpec(target, identity, fileTarget, startMarker, endMarker, content) {
|
|
1107
|
+
return {
|
|
1108
|
+
identity,
|
|
1109
|
+
target,
|
|
1110
|
+
fileTarget,
|
|
1111
|
+
expectedManagedContent: [startMarker, content, endMarker].join("\n"),
|
|
1112
|
+
blockMarkers: [startMarker, endMarker]
|
|
1113
|
+
};
|
|
1114
|
+
}
|
|
1115
|
+
function modeEntryFileTarget(platform, mode) {
|
|
1116
|
+
const family = platform === "claude-code" ? "claude" : platform === "codex" || platform === "zcode" ? "agents" : platform;
|
|
1117
|
+
return `${family}-mode-${mode}`;
|
|
1118
|
+
}
|
|
1119
|
+
async function inspectManagedTarget(root, platform, spec) {
|
|
1120
|
+
const expectedDigest = adapterManagedContentDigest(
|
|
1121
|
+
spec.identity,
|
|
1122
|
+
spec.expectedManagedContent
|
|
1123
|
+
);
|
|
1124
|
+
const repair = [
|
|
1125
|
+
`Preview with \`mancode adapter upgrade --platform ${platform} --dry-run\`.`,
|
|
1126
|
+
`Confirm that exact preview with \`mancode adapter upgrade --platform ${platform} --confirm --operation-id <operationId> --session <id>\`.`
|
|
1127
|
+
].join(" ");
|
|
1128
|
+
try {
|
|
1129
|
+
const bytes = await readAdapterBytesIfExists(
|
|
1130
|
+
root,
|
|
1131
|
+
v3AdapterTargetPath(root, spec.fileTarget)
|
|
1132
|
+
);
|
|
1133
|
+
if (bytes === null) {
|
|
1134
|
+
return managedTargetStatus(
|
|
1135
|
+
spec,
|
|
1136
|
+
"missing",
|
|
1137
|
+
null,
|
|
1138
|
+
expectedDigest,
|
|
1139
|
+
repair,
|
|
1140
|
+
"Managed target does not exist."
|
|
1141
|
+
);
|
|
1142
|
+
}
|
|
1143
|
+
const content = new TextDecoder("utf-8", { fatal: true }).decode(bytes);
|
|
1144
|
+
let managedContent;
|
|
1145
|
+
if (spec.blockMarkers === null) {
|
|
1146
|
+
managedContent = content;
|
|
1147
|
+
} else {
|
|
1148
|
+
try {
|
|
1149
|
+
const extracted = extractManagedBlock(
|
|
1150
|
+
content,
|
|
1151
|
+
spec.blockMarkers[0],
|
|
1152
|
+
spec.blockMarkers[1]
|
|
1153
|
+
);
|
|
1154
|
+
if (extracted === null) {
|
|
1155
|
+
return managedTargetStatus(
|
|
1156
|
+
spec,
|
|
1157
|
+
"missing",
|
|
1158
|
+
null,
|
|
1159
|
+
expectedDigest,
|
|
1160
|
+
repair,
|
|
1161
|
+
"Managed block is absent from the target file."
|
|
1162
|
+
);
|
|
1163
|
+
}
|
|
1164
|
+
managedContent = extracted;
|
|
1165
|
+
} catch (error) {
|
|
1166
|
+
return managedTargetStatus(
|
|
1167
|
+
spec,
|
|
1168
|
+
"stale",
|
|
1169
|
+
null,
|
|
1170
|
+
expectedDigest,
|
|
1171
|
+
repair,
|
|
1172
|
+
error instanceof Error ? error.message : "Managed block is malformed."
|
|
1173
|
+
);
|
|
1174
|
+
}
|
|
1175
|
+
}
|
|
1176
|
+
const actualDigest = adapterManagedContentDigest(
|
|
1177
|
+
spec.identity,
|
|
1178
|
+
managedContent
|
|
1179
|
+
);
|
|
1180
|
+
const status = actualDigest === expectedDigest ? "ready" : "stale";
|
|
1181
|
+
return managedTargetStatus(
|
|
1182
|
+
spec,
|
|
1183
|
+
status,
|
|
1184
|
+
actualDigest,
|
|
1185
|
+
expectedDigest,
|
|
1186
|
+
status === "ready" ? "none" : repair,
|
|
1187
|
+
status === "ready" ? "Managed content matches the current renderer." : "Managed content differs from the current renderer."
|
|
1188
|
+
);
|
|
1189
|
+
} catch (error) {
|
|
1190
|
+
return managedTargetStatus(
|
|
1191
|
+
spec,
|
|
1192
|
+
"unreadable",
|
|
1193
|
+
null,
|
|
1194
|
+
expectedDigest,
|
|
1195
|
+
`Resolve the filesystem or UTF-8 error, then ${repair}`,
|
|
1196
|
+
error instanceof Error ? error.message : "Managed target is unreadable."
|
|
1197
|
+
);
|
|
1198
|
+
}
|
|
1199
|
+
}
|
|
1200
|
+
function managedTargetStatus(spec, status, actualDigest, expectedDigest, repair, detail) {
|
|
1201
|
+
return {
|
|
1202
|
+
identity: spec.identity,
|
|
1203
|
+
target: spec.target,
|
|
1204
|
+
status,
|
|
1205
|
+
actualDigest,
|
|
1206
|
+
expectedDigest,
|
|
1207
|
+
rendererVersion: V3_ADAPTER_VERSION,
|
|
1208
|
+
repair,
|
|
1209
|
+
detail
|
|
1210
|
+
};
|
|
1211
|
+
}
|
|
1212
|
+
function aggregateAdapterStatus(targets) {
|
|
1213
|
+
if (targets.every((target) => target.status === "ready")) return "ready";
|
|
1214
|
+
if (targets.some((target) => target.status === "unreadable")) {
|
|
1215
|
+
return "unreadable";
|
|
1216
|
+
}
|
|
1217
|
+
if (targets.some((target) => target.status === "stale")) return "stale";
|
|
1218
|
+
return "missing";
|
|
1219
|
+
}
|
|
1220
|
+
function relativeAdapterPath(root, target) {
|
|
1221
|
+
return path.relative(root, target).split(path.sep).join("/");
|
|
1222
|
+
}
|
|
758
1223
|
async function writeManagedFile(filePath, content) {
|
|
759
1224
|
const existing = await readTextIfExists(filePath);
|
|
760
|
-
if (existing !== null && !existing.includes(V3_ADAPTER_MANAGED_MARKER)) {
|
|
1225
|
+
if (existing !== null && !existing.includes(V3_ADAPTER_MANAGED_MARKER) && !existing.includes(LEGACY_V3_ADAPTER_MANAGED_MARKER)) {
|
|
761
1226
|
throw new Error("MANCODE_V3_ADAPTER_TARGET_USER_AUTHORED");
|
|
762
1227
|
}
|
|
763
1228
|
await mkdir(path.dirname(filePath), { recursive: true });
|
|
@@ -788,15 +1253,13 @@ async function assertV3ModeEntriesWritable(root, platform) {
|
|
|
788
1253
|
}
|
|
789
1254
|
async function removeV3ModeEntry(filePath) {
|
|
790
1255
|
const existing = await readTextIfExists(filePath);
|
|
791
|
-
if (existing?.includes(V3_MODE_ENTRY_MANAGED_MARKER)
|
|
1256
|
+
if (existing?.includes(V3_MODE_ENTRY_MANAGED_MARKER) || LEGACY_MODE_ENTRY_MANAGED_MARKERS.some(
|
|
1257
|
+
(marker) => existing?.includes(marker)
|
|
1258
|
+
)) {
|
|
792
1259
|
await rm(filePath, { force: true });
|
|
793
1260
|
await removeDirectoryIfEmpty(path.dirname(filePath));
|
|
794
1261
|
}
|
|
795
1262
|
}
|
|
796
|
-
async function v3ModeEntryPresent(filePath) {
|
|
797
|
-
const existing = await readTextIfExists(filePath);
|
|
798
|
-
return existing?.includes(V3_MODE_ENTRY_MANAGED_MARKER) ?? false;
|
|
799
|
-
}
|
|
800
1263
|
async function removeDirectoryIfEmpty(directory) {
|
|
801
1264
|
try {
|
|
802
1265
|
await rmdir(directory);
|
|
@@ -813,6 +1276,18 @@ async function removeManagedFile(filePath) {
|
|
|
813
1276
|
await rm(filePath, { force: true });
|
|
814
1277
|
}
|
|
815
1278
|
}
|
|
1279
|
+
async function removeRetiredBootstrapFiles(root, platform) {
|
|
1280
|
+
if (platform !== "claude-code" && platform !== "cursor") return;
|
|
1281
|
+
for (const retired of retiredBootstrapSpecs(root, platform)) {
|
|
1282
|
+
await assertAdapterPathSafe(root, retired.filePath);
|
|
1283
|
+
const existing = await readTextIfExists(retired.filePath);
|
|
1284
|
+
if (!retired.managedMarkers.some((marker) => existing?.includes(marker))) {
|
|
1285
|
+
continue;
|
|
1286
|
+
}
|
|
1287
|
+
await rm(retired.filePath, { force: true });
|
|
1288
|
+
await removeDirectoryIfEmpty(path.dirname(retired.filePath));
|
|
1289
|
+
}
|
|
1290
|
+
}
|
|
816
1291
|
async function replaceManagedV3Block(filePath, startMarker, endMarker, content, legacyMarkers) {
|
|
817
1292
|
const current = await readTextIfExists(filePath) ?? "";
|
|
818
1293
|
const existing = (legacyMarkers ?? []).reduce(
|
|
@@ -837,6 +1312,9 @@ function removeLegacyAgentsBlocks(existing) {
|
|
|
837
1312
|
LEGACY_ZCODE_END_MARKER
|
|
838
1313
|
);
|
|
839
1314
|
}
|
|
1315
|
+
function removeLegacyV3Block(existing, markers) {
|
|
1316
|
+
return removeManagedBlock(existing, markers[0], markers[1]);
|
|
1317
|
+
}
|
|
840
1318
|
function replaceManagedV3BlockText(existing, startMarker, endMarker, content) {
|
|
841
1319
|
return replaceManagedBlock(
|
|
842
1320
|
existing,
|
|
@@ -846,7 +1324,7 @@ function replaceManagedV3BlockText(existing, startMarker, endMarker, content) {
|
|
|
846
1324
|
);
|
|
847
1325
|
}
|
|
848
1326
|
function managedFilePlan(target, beforeContent, targetContent) {
|
|
849
|
-
if (beforeContent !== null && !beforeContent.includes(V3_ADAPTER_MANAGED_MARKER)) {
|
|
1327
|
+
if (beforeContent !== null && !beforeContent.includes(V3_ADAPTER_MANAGED_MARKER) && !beforeContent.includes(LEGACY_V3_ADAPTER_MANAGED_MARKER)) {
|
|
850
1328
|
throw new Error("MANCODE_V3_ADAPTER_TARGET_USER_AUTHORED");
|
|
851
1329
|
}
|
|
852
1330
|
return { target, beforeContent, targetContent };
|
|
@@ -1175,6 +1653,11 @@ async function assertPlatformAdapterPathsSafe(root, platform) {
|
|
|
1175
1653
|
(target) => v3AdapterTargetPath(root, target)
|
|
1176
1654
|
)
|
|
1177
1655
|
]);
|
|
1656
|
+
if (platform === "claude-code" || platform === "cursor") {
|
|
1657
|
+
for (const retired of retiredBootstrapSpecs(root, platform)) {
|
|
1658
|
+
targets.add(retired.filePath);
|
|
1659
|
+
}
|
|
1660
|
+
}
|
|
1178
1661
|
for (const target of targets) {
|
|
1179
1662
|
await assertAdapterPathSafe(root, target);
|
|
1180
1663
|
}
|
|
@@ -1216,13 +1699,35 @@ async function removeManagedV3Block(filePath, startMarker, endMarker) {
|
|
|
1216
1699
|
await rm(filePath, { force: true });
|
|
1217
1700
|
}
|
|
1218
1701
|
}
|
|
1219
|
-
async function
|
|
1702
|
+
async function anyManagedBlockPresent(filePath, markerPairs) {
|
|
1220
1703
|
const content = await readTextIfExists(filePath);
|
|
1221
|
-
return content
|
|
1704
|
+
return content !== null && markerPairs.some(
|
|
1705
|
+
([startMarker, endMarker]) => hasManagedBlock(content, startMarker, endMarker)
|
|
1706
|
+
);
|
|
1222
1707
|
}
|
|
1223
|
-
async function
|
|
1224
|
-
|
|
1225
|
-
|
|
1708
|
+
async function readAdapterBytesIfExists(root, filePath) {
|
|
1709
|
+
await assertAdapterPathSafe(root, filePath);
|
|
1710
|
+
try {
|
|
1711
|
+
const entry = await lstat(filePath);
|
|
1712
|
+
if (!entry.isFile() || entry.isSymbolicLink()) {
|
|
1713
|
+
throw new Error("MANCODE_ARTIFACT_PATH_UNSAFE");
|
|
1714
|
+
}
|
|
1715
|
+
} catch (error) {
|
|
1716
|
+
if (isNodeError(error) && error.code === "ENOENT") return null;
|
|
1717
|
+
throw error;
|
|
1718
|
+
}
|
|
1719
|
+
for (let attempt = 1; attempt <= ADAPTER_READ_MAX_ATTEMPTS; attempt += 1) {
|
|
1720
|
+
try {
|
|
1721
|
+
return await readFile(filePath);
|
|
1722
|
+
} catch (error) {
|
|
1723
|
+
if (isNodeError(error) && error.code === "ENOENT") return null;
|
|
1724
|
+
if (!isRetriableAdapterReadError(error) || attempt === ADAPTER_READ_MAX_ATTEMPTS) {
|
|
1725
|
+
throw error;
|
|
1726
|
+
}
|
|
1727
|
+
await delay(ADAPTER_READ_RETRY_DELAY_MS * attempt);
|
|
1728
|
+
}
|
|
1729
|
+
}
|
|
1730
|
+
throw new Error("MANCODE_V3_ADAPTER_READ_RETRY_EXHAUSTED");
|
|
1226
1731
|
}
|
|
1227
1732
|
async function readTextIfExists(filePath) {
|
|
1228
1733
|
for (let attempt = 1; attempt <= ADAPTER_READ_MAX_ATTEMPTS; attempt += 1) {
|
|
@@ -1253,9 +1758,9 @@ async function atomicWrite(filePath, content) {
|
|
|
1253
1758
|
function targetFor(platform) {
|
|
1254
1759
|
switch (platform) {
|
|
1255
1760
|
case "claude-code":
|
|
1256
|
-
return ".
|
|
1761
|
+
return "CLAUDE.md";
|
|
1257
1762
|
case "cursor":
|
|
1258
|
-
return ".cursor/rules/mancode-
|
|
1763
|
+
return ".cursor/rules/mancode-continuity.mdc";
|
|
1259
1764
|
case "codex":
|
|
1260
1765
|
case "zcode":
|
|
1261
1766
|
return "AGENTS.md";
|
|
@@ -1263,6 +1768,47 @@ function targetFor(platform) {
|
|
|
1263
1768
|
return ".github/copilot-instructions.md";
|
|
1264
1769
|
}
|
|
1265
1770
|
}
|
|
1771
|
+
function retiredBootstrapPlatformFor(target) {
|
|
1772
|
+
if (target === "claude-skill") return "claude-code";
|
|
1773
|
+
if (target === "cursor-rule") return "cursor";
|
|
1774
|
+
return null;
|
|
1775
|
+
}
|
|
1776
|
+
function retiredBootstrapSpecs(root, platform) {
|
|
1777
|
+
const managedMarkers = [
|
|
1778
|
+
LEGACY_V3_ADAPTER_MANAGED_MARKER,
|
|
1779
|
+
V3_ADAPTER_MANAGED_MARKER
|
|
1780
|
+
];
|
|
1781
|
+
if (platform === "claude-code") {
|
|
1782
|
+
return [
|
|
1783
|
+
{
|
|
1784
|
+
filePath: path.join(
|
|
1785
|
+
root,
|
|
1786
|
+
".claude",
|
|
1787
|
+
"skills",
|
|
1788
|
+
"mancode-v3",
|
|
1789
|
+
"SKILL.md"
|
|
1790
|
+
),
|
|
1791
|
+
managedMarkers
|
|
1792
|
+
},
|
|
1793
|
+
{
|
|
1794
|
+
filePath: path.join(
|
|
1795
|
+
root,
|
|
1796
|
+
".claude",
|
|
1797
|
+
"skills",
|
|
1798
|
+
"mancode-continuity",
|
|
1799
|
+
"SKILL.md"
|
|
1800
|
+
),
|
|
1801
|
+
managedMarkers
|
|
1802
|
+
}
|
|
1803
|
+
];
|
|
1804
|
+
}
|
|
1805
|
+
return [
|
|
1806
|
+
{
|
|
1807
|
+
filePath: path.join(root, ".cursor", "rules", "mancode-v3.mdc"),
|
|
1808
|
+
managedMarkers
|
|
1809
|
+
}
|
|
1810
|
+
];
|
|
1811
|
+
}
|
|
1266
1812
|
function platformLabelFor(platform) {
|
|
1267
1813
|
switch (platform) {
|
|
1268
1814
|
case "claude-code":
|
|
@@ -1306,9 +1852,14 @@ export {
|
|
|
1306
1852
|
V3_ADAPTER_VERSION,
|
|
1307
1853
|
V3_ADAPTER_MANAGED_MARKER,
|
|
1308
1854
|
V3_MODE_ENTRY_MANAGED_MARKER,
|
|
1855
|
+
V3_ADAPTER_DIGEST_DOMAIN,
|
|
1309
1856
|
V3_MODE_NAMES,
|
|
1857
|
+
V3_ADAPTER_PLATFORMS,
|
|
1310
1858
|
V3_ADAPTER_FILE_TARGETS,
|
|
1859
|
+
adapterManagedContentDigest,
|
|
1311
1860
|
planV3AdapterFiles,
|
|
1861
|
+
planV3AdapterUpgradeFiles,
|
|
1862
|
+
stageV3AdapterUpgradeFiles,
|
|
1312
1863
|
applyV3AdapterFilePlan,
|
|
1313
1864
|
stageV3Adapter,
|
|
1314
1865
|
v3AdapterTargetPath,
|
|
@@ -1318,8 +1869,9 @@ export {
|
|
|
1318
1869
|
assertV3AdapterInstallable,
|
|
1319
1870
|
inspectV3Adapter,
|
|
1320
1871
|
inspectV3AdapterVersions,
|
|
1872
|
+
v3AdapterVersionsFromStatuses,
|
|
1321
1873
|
removeV3Adapter,
|
|
1322
1874
|
renderV3Bootstrap,
|
|
1323
1875
|
renderV3ModeEntry
|
|
1324
1876
|
};
|
|
1325
|
-
//# sourceMappingURL=chunk-
|
|
1877
|
+
//# sourceMappingURL=chunk-K3MYY47M.js.map
|