mancode 0.4.1 → 0.5.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 +79 -11
- package/README.md +53 -9
- package/dist/{chunk-S3BAOJPP.js → chunk-3FOBYCF4.js} +1 -5
- package/dist/{chunk-S3BAOJPP.js.map → chunk-3FOBYCF4.js.map} +1 -1
- package/dist/{chunk-VV3MFVIG.js → chunk-73F46VQM.js} +4 -2
- package/dist/chunk-73F46VQM.js.map +1 -0
- package/dist/cli.js +1461 -678
- package/dist/cli.js.map +1 -1
- package/dist/{store-LD5VRGON.js → store-GCLUP5IO.js} +2 -2
- package/dist/{v3-adapter-OS2AEK5M.js → v3-adapter-7XYKHGTB.js} +2 -2
- package/package.json +4 -1
- package/dist/chunk-VV3MFVIG.js.map +0 -1
- /package/dist/{store-LD5VRGON.js.map → store-GCLUP5IO.js.map} +0 -0
- /package/dist/{v3-adapter-OS2AEK5M.js.map → v3-adapter-7XYKHGTB.js.map} +0 -0
package/dist/cli.js
CHANGED
|
@@ -111,7 +111,7 @@ import {
|
|
|
111
111
|
workflowMetadataDigest,
|
|
112
112
|
writeOperationReservation,
|
|
113
113
|
writeProjectFacts
|
|
114
|
-
} from "./chunk-
|
|
114
|
+
} from "./chunk-3FOBYCF4.js";
|
|
115
115
|
import {
|
|
116
116
|
DEFAULT_MANCODE_END_MARKER,
|
|
117
117
|
DEFAULT_MANCODE_START_MARKER,
|
|
@@ -134,7 +134,7 @@ import {
|
|
|
134
134
|
stageV3AdapterUpgradeFiles,
|
|
135
135
|
v3AdapterTargetPath,
|
|
136
136
|
v3AdapterVersionsFromStatuses
|
|
137
|
-
} from "./chunk-
|
|
137
|
+
} from "./chunk-73F46VQM.js";
|
|
138
138
|
|
|
139
139
|
// src/cli.ts
|
|
140
140
|
import { Option, program } from "commander";
|
|
@@ -164,8 +164,6 @@ var CompatibilityGateError = class extends Error {
|
|
|
164
164
|
this.details = details;
|
|
165
165
|
this.name = "CompatibilityGateError";
|
|
166
166
|
}
|
|
167
|
-
code;
|
|
168
|
-
details;
|
|
169
167
|
};
|
|
170
168
|
function evaluateCompatibilityGate(input) {
|
|
171
169
|
const failures = [];
|
|
@@ -403,7 +401,7 @@ async function inspectMancodeLayout(projectRoot) {
|
|
|
403
401
|
]);
|
|
404
402
|
const v3AuthorityPathsPresent = (await Promise.all(
|
|
405
403
|
V3_AUTHORITY_PATHS.map(
|
|
406
|
-
async (
|
|
404
|
+
async (relativePath2) => await lstatOrNull(path.join(mancodeRoot, relativePath2)) === null ? null : relativePath2
|
|
407
405
|
)
|
|
408
406
|
)).filter(
|
|
409
407
|
(value) => value !== null
|
|
@@ -438,9 +436,9 @@ async function scanLegacyEntry(root, legacyPath) {
|
|
|
438
436
|
};
|
|
439
437
|
}
|
|
440
438
|
async function describeNode(target) {
|
|
441
|
-
const
|
|
442
|
-
if (
|
|
443
|
-
if (
|
|
439
|
+
const stat5 = await lstatOrNull(target);
|
|
440
|
+
if (stat5 === null) return null;
|
|
441
|
+
if (stat5.isFile()) {
|
|
444
442
|
const contents = await readFile(target);
|
|
445
443
|
return {
|
|
446
444
|
kind: "file",
|
|
@@ -448,7 +446,7 @@ async function describeNode(target) {
|
|
|
448
446
|
digest: sha256(contents)
|
|
449
447
|
};
|
|
450
448
|
}
|
|
451
|
-
if (
|
|
449
|
+
if (stat5.isSymbolicLink()) {
|
|
452
450
|
const link = await readlink(target);
|
|
453
451
|
return {
|
|
454
452
|
kind: "symlink",
|
|
@@ -456,7 +454,7 @@ async function describeNode(target) {
|
|
|
456
454
|
digest: sha256(Buffer.from(link, "utf8"))
|
|
457
455
|
};
|
|
458
456
|
}
|
|
459
|
-
if (!
|
|
457
|
+
if (!stat5.isDirectory()) {
|
|
460
458
|
return {
|
|
461
459
|
kind: "other",
|
|
462
460
|
hasBusinessContent: true,
|
|
@@ -4466,8 +4464,8 @@ async function unlinkIfExists(target) {
|
|
|
4466
4464
|
}
|
|
4467
4465
|
}
|
|
4468
4466
|
async function assertSafeStateDirectory(target) {
|
|
4469
|
-
const
|
|
4470
|
-
if (!
|
|
4467
|
+
const stat5 = await lstat2(target);
|
|
4468
|
+
if (!stat5.isDirectory() || stat5.isSymbolicLink()) {
|
|
4471
4469
|
throw new Error("MANCODE_TRANSPORT_AUTHORITY_STATE_UNSAFE");
|
|
4472
4470
|
}
|
|
4473
4471
|
}
|
|
@@ -9295,13 +9293,13 @@ function parseArtifacts(value) {
|
|
|
9295
9293
|
["relativePath", "classification", "includeInPromotion", "contentDigest"],
|
|
9296
9294
|
"quarantine artifact"
|
|
9297
9295
|
);
|
|
9298
|
-
const
|
|
9296
|
+
const relativePath2 = assertSafeSharedRelativePath(
|
|
9299
9297
|
item.relativePath
|
|
9300
9298
|
);
|
|
9301
|
-
if (paths.has(
|
|
9299
|
+
if (paths.has(relativePath2)) {
|
|
9302
9300
|
throw new Error("quarantine artifacts must not repeat a relativePath");
|
|
9303
9301
|
}
|
|
9304
|
-
paths.add(
|
|
9302
|
+
paths.add(relativePath2);
|
|
9305
9303
|
if (typeof item.classification !== "string" || !ARTIFACT_CLASSES.has(item.classification)) {
|
|
9306
9304
|
throw new Error("quarantine artifact classification is invalid");
|
|
9307
9305
|
}
|
|
@@ -9313,7 +9311,7 @@ function parseArtifacts(value) {
|
|
|
9313
9311
|
throw new Error("MANCODE_RAW_ARTIFACT_CANNOT_BE_PROMOTED");
|
|
9314
9312
|
}
|
|
9315
9313
|
return {
|
|
9316
|
-
relativePath,
|
|
9314
|
+
relativePath: relativePath2,
|
|
9317
9315
|
classification,
|
|
9318
9316
|
includeInPromotion: item.includeInPromotion,
|
|
9319
9317
|
contentDigest: parseDigestOrNull3(
|
|
@@ -9620,7 +9618,7 @@ async function activateLegacyMigration(input) {
|
|
|
9620
9618
|
if (session === null || session.status !== "active") {
|
|
9621
9619
|
throw new Error("MANCODE_SESSION_NOT_FOUND");
|
|
9622
9620
|
}
|
|
9623
|
-
const store = new (await import("./store-
|
|
9621
|
+
const store = new (await import("./store-GCLUP5IO.js")).V3ContextStore(root);
|
|
9624
9622
|
const project = await store.readProjectSnapshot();
|
|
9625
9623
|
const stage = await readMigrationStage(root, input.stageId);
|
|
9626
9624
|
if (stage.state !== "staged" || stage.revision !== input.expectedStageRevision) {
|
|
@@ -9883,7 +9881,7 @@ async function activateLegacyMigration(input) {
|
|
|
9883
9881
|
for (const action of payload.actions.filter(
|
|
9884
9882
|
(action2) => action2.kind === "v3_adapter_file"
|
|
9885
9883
|
)) {
|
|
9886
|
-
const { applyV3AdapterFilePlan: applyV3AdapterFilePlan2 } = await import("./v3-adapter-
|
|
9884
|
+
const { applyV3AdapterFilePlan: applyV3AdapterFilePlan2 } = await import("./v3-adapter-7XYKHGTB.js");
|
|
9887
9885
|
await applyV3AdapterFilePlan2(root, action);
|
|
9888
9886
|
}
|
|
9889
9887
|
journal = await completeActivationStep(
|
|
@@ -10901,14 +10899,14 @@ function renderBlockedTask(loaded, aliases, allocator, now, blockers) {
|
|
|
10901
10899
|
function buildQuarantineCandidate(loaded, candidate, quarantineId, now) {
|
|
10902
10900
|
const entityFiles = candidateEntityFiles(candidate);
|
|
10903
10901
|
const artifacts = [
|
|
10904
|
-
...entityFiles.map(({ relativePath, content }) => ({
|
|
10905
|
-
relativePath,
|
|
10902
|
+
...entityFiles.map(({ relativePath: relativePath2, content }) => ({
|
|
10903
|
+
relativePath: relativePath2,
|
|
10906
10904
|
classification: "authority",
|
|
10907
10905
|
includeInPromotion: true,
|
|
10908
10906
|
contentDigest: digestText(content)
|
|
10909
10907
|
})),
|
|
10910
|
-
...loaded.sourceFiles.filter((file) => file.relativePath.startsWith("artifacts/")).map(({ relativePath, content }) => ({
|
|
10911
|
-
relativePath,
|
|
10908
|
+
...loaded.sourceFiles.filter((file) => file.relativePath.startsWith("artifacts/")).map(({ relativePath: relativePath2, content }) => ({
|
|
10909
|
+
relativePath: relativePath2,
|
|
10912
10910
|
classification: "human_view",
|
|
10913
10911
|
includeInPromotion: true,
|
|
10914
10912
|
contentDigest: digestText(content)
|
|
@@ -10936,8 +10934,8 @@ function buildSourceOnlyQuarantine(loaded, quarantineId, now) {
|
|
|
10936
10934
|
purpose: "legacy_migration",
|
|
10937
10935
|
sourceTaskRef: null,
|
|
10938
10936
|
candidateTaskRef: { namespace: "local", taskId: quarantineId },
|
|
10939
|
-
artifacts: loaded.sourceFiles.map(({ relativePath, content }) => ({
|
|
10940
|
-
relativePath,
|
|
10937
|
+
artifacts: loaded.sourceFiles.map(({ relativePath: relativePath2, content }) => ({
|
|
10938
|
+
relativePath: relativePath2,
|
|
10941
10939
|
classification: "authority",
|
|
10942
10940
|
includeInPromotion: false,
|
|
10943
10941
|
contentDigest: digestText(content)
|
|
@@ -11379,16 +11377,16 @@ function assertLegacyTaskId(value) {
|
|
|
11379
11377
|
throw new Error("MANCODE_MIGRATION_LEGACY_TASK_ID_UNSAFE");
|
|
11380
11378
|
}
|
|
11381
11379
|
}
|
|
11382
|
-
async function readLegacyText(projectRoot,
|
|
11383
|
-
const value = await readLegacyTextOrNull(projectRoot,
|
|
11380
|
+
async function readLegacyText(projectRoot, relativePath2) {
|
|
11381
|
+
const value = await readLegacyTextOrNull(projectRoot, relativePath2);
|
|
11384
11382
|
if (value === null) {
|
|
11385
11383
|
throw new Error("MANCODE_MIGRATION_LEGACY_ENTITY_MISSING");
|
|
11386
11384
|
}
|
|
11387
11385
|
return value;
|
|
11388
11386
|
}
|
|
11389
|
-
async function readLegacyTextOrNull(projectRoot,
|
|
11387
|
+
async function readLegacyTextOrNull(projectRoot, relativePath2) {
|
|
11390
11388
|
const root = path18.join(path18.resolve(projectRoot), ".mancode");
|
|
11391
|
-
const segments = safeSegments(
|
|
11389
|
+
const segments = safeSegments(relativePath2);
|
|
11392
11390
|
await assertSafeDirectory(root);
|
|
11393
11391
|
let directory = root;
|
|
11394
11392
|
for (const segment of segments.slice(0, -1)) {
|
|
@@ -11414,8 +11412,8 @@ async function readLegacyTextOrNull(projectRoot, relativePath) {
|
|
|
11414
11412
|
}
|
|
11415
11413
|
return content;
|
|
11416
11414
|
}
|
|
11417
|
-
async function assertLegacyTextUnchanged(projectRoot,
|
|
11418
|
-
const actual = await readLegacyText(projectRoot,
|
|
11415
|
+
async function assertLegacyTextUnchanged(projectRoot, relativePath2, expected) {
|
|
11416
|
+
const actual = await readLegacyText(projectRoot, relativePath2);
|
|
11419
11417
|
if (actual !== expected) {
|
|
11420
11418
|
throw new Error("MANCODE_LEGACY_TREE_CHANGED_DURING_SCAN");
|
|
11421
11419
|
}
|
|
@@ -11430,16 +11428,16 @@ async function readSafeDirectoryOrEmpty(target) {
|
|
|
11430
11428
|
}
|
|
11431
11429
|
}
|
|
11432
11430
|
async function assertSafeDirectory(target) {
|
|
11433
|
-
const
|
|
11434
|
-
if (!
|
|
11431
|
+
const stat5 = await lstat5(target);
|
|
11432
|
+
if (!stat5.isDirectory() || stat5.isSymbolicLink()) {
|
|
11435
11433
|
throw new Error("MANCODE_MIGRATION_LEGACY_PATH_UNSAFE");
|
|
11436
11434
|
}
|
|
11437
11435
|
}
|
|
11438
|
-
function safeSegments(
|
|
11439
|
-
if (!
|
|
11436
|
+
function safeSegments(relativePath2) {
|
|
11437
|
+
if (!relativePath2 || path18.isAbsolute(relativePath2) || relativePath2.includes("\0")) {
|
|
11440
11438
|
throw new Error("MANCODE_MIGRATION_LEGACY_PATH_UNSAFE");
|
|
11441
11439
|
}
|
|
11442
|
-
const segments =
|
|
11440
|
+
const segments = relativePath2.split(path18.sep);
|
|
11443
11441
|
if (segments.some((segment) => !segment || segment === "." || segment === "..")) {
|
|
11444
11442
|
throw new Error("MANCODE_MIGRATION_LEGACY_PATH_UNSAFE");
|
|
11445
11443
|
}
|
|
@@ -11622,15 +11620,15 @@ function assertClaimMatchesStore(store, claim) {
|
|
|
11622
11620
|
return claim;
|
|
11623
11621
|
}
|
|
11624
11622
|
async function assertSafeClaimFile(target) {
|
|
11625
|
-
const
|
|
11626
|
-
if (!
|
|
11623
|
+
const stat5 = await lstat6(target);
|
|
11624
|
+
if (!stat5.isFile() || stat5.isSymbolicLink()) {
|
|
11627
11625
|
throw new Error("MANCODE_CLAIM_PATH_UNSAFE");
|
|
11628
11626
|
}
|
|
11629
11627
|
}
|
|
11630
11628
|
async function assertSafeClaimDirectory(store) {
|
|
11631
11629
|
const directory = claimDirectory(store);
|
|
11632
|
-
const
|
|
11633
|
-
if (!
|
|
11630
|
+
const stat5 = await lstat6(directory);
|
|
11631
|
+
if (!stat5.isDirectory() || stat5.isSymbolicLink()) {
|
|
11634
11632
|
throw new Error("MANCODE_CLAIM_PATH_UNSAFE");
|
|
11635
11633
|
}
|
|
11636
11634
|
}
|
|
@@ -11762,14 +11760,14 @@ async function atomicWriteHandoff(store, handoff) {
|
|
|
11762
11760
|
await assertSafeHandoffFile(target);
|
|
11763
11761
|
}
|
|
11764
11762
|
async function assertSafeHandoffFile(target) {
|
|
11765
|
-
const
|
|
11766
|
-
if (!
|
|
11763
|
+
const stat5 = await lstat7(target);
|
|
11764
|
+
if (!stat5.isFile() || stat5.isSymbolicLink()) {
|
|
11767
11765
|
throw new Error("MANCODE_HANDOFF_PATH_UNSAFE");
|
|
11768
11766
|
}
|
|
11769
11767
|
}
|
|
11770
11768
|
async function assertSafeHandoffDirectory(store) {
|
|
11771
|
-
const
|
|
11772
|
-
if (!
|
|
11769
|
+
const stat5 = await lstat7(handoffDirectory(store));
|
|
11770
|
+
if (!stat5.isDirectory() || stat5.isSymbolicLink()) {
|
|
11773
11771
|
throw new Error("MANCODE_HANDOFF_PATH_UNSAFE");
|
|
11774
11772
|
}
|
|
11775
11773
|
}
|
|
@@ -13739,7 +13737,7 @@ async function upgradeV3Adapters(input) {
|
|
|
13739
13737
|
if (unfinished.length > 0) {
|
|
13740
13738
|
throw new Error("MANCODE_ADAPTER_UPGRADE_OPERATION_PENDING");
|
|
13741
13739
|
}
|
|
13742
|
-
const actualVersions = await import("./v3-adapter-
|
|
13740
|
+
const actualVersions = await import("./v3-adapter-7XYKHGTB.js").then(
|
|
13743
13741
|
({ inspectV3AdapterVersions: inspectV3AdapterVersions2 }) => inspectV3AdapterVersions2(
|
|
13744
13742
|
root,
|
|
13745
13743
|
managedAdapterNames(project.manifest.managedAdapters)
|
|
@@ -13868,6 +13866,7 @@ async function upgradeV3Adapters(input) {
|
|
|
13868
13866
|
async (platform) => [platform, await inspectV3Adapter(root, platform)]
|
|
13869
13867
|
)
|
|
13870
13868
|
);
|
|
13869
|
+
await removeAdapterUpgradePreview(root, operationId);
|
|
13871
13870
|
return {
|
|
13872
13871
|
...resultBase,
|
|
13873
13872
|
state: "committed",
|
|
@@ -14198,11 +14197,27 @@ function adapterUpgradePreviewPath(root, operationId) {
|
|
|
14198
14197
|
"preview.json"
|
|
14199
14198
|
);
|
|
14200
14199
|
}
|
|
14200
|
+
async function removeAdapterUpgradePreview(root, operationId) {
|
|
14201
|
+
const upgradeRoot = path24.join(
|
|
14202
|
+
path24.resolve(root),
|
|
14203
|
+
".mancode",
|
|
14204
|
+
"staging",
|
|
14205
|
+
"adapters",
|
|
14206
|
+
"upgrade"
|
|
14207
|
+
);
|
|
14208
|
+
const operationRoot = path24.dirname(
|
|
14209
|
+
adapterUpgradePreviewPath(root, operationId)
|
|
14210
|
+
);
|
|
14211
|
+
if (path24.dirname(operationRoot) !== upgradeRoot) {
|
|
14212
|
+
throw new Error("MANCODE_ADAPTER_UPGRADE_STAGING_INVALID");
|
|
14213
|
+
}
|
|
14214
|
+
await rm9(operationRoot, { recursive: true, force: true });
|
|
14215
|
+
}
|
|
14201
14216
|
async function readAdapterUpgradePreview(root, operationId) {
|
|
14202
14217
|
const target = adapterUpgradePreviewPath(root, operationId);
|
|
14203
14218
|
try {
|
|
14204
|
-
const
|
|
14205
|
-
if (!
|
|
14219
|
+
const stat5 = await lstat10(target);
|
|
14220
|
+
if (!stat5.isFile() || stat5.isSymbolicLink()) {
|
|
14206
14221
|
throw new Error("MANCODE_ADAPTER_UPGRADE_PREVIEW_INVALID");
|
|
14207
14222
|
}
|
|
14208
14223
|
return parseAdapterUpgradePreview(
|
|
@@ -14282,8 +14297,8 @@ async function assertStagedAdapterFiles(root, preview, plans) {
|
|
|
14282
14297
|
if (!target.startsWith(`${root}${path24.sep}`)) {
|
|
14283
14298
|
throw new Error("MANCODE_ADAPTER_UPGRADE_PREVIEW_INVALID");
|
|
14284
14299
|
}
|
|
14285
|
-
const
|
|
14286
|
-
if (!
|
|
14300
|
+
const stat5 = await lstat10(target);
|
|
14301
|
+
if (!stat5.isFile() || stat5.isSymbolicLink()) {
|
|
14287
14302
|
throw new Error("MANCODE_ADAPTER_UPGRADE_PREVIEW_INVALID");
|
|
14288
14303
|
}
|
|
14289
14304
|
if (await readFile23(target, "utf8") !== plan.targetContent) {
|
|
@@ -14633,7 +14648,8 @@ trigger: <\u5177\u4F53\u4E8B\u5B9E>
|
|
|
14633
14648
|
- **\u7CBE\u786E\u5339\u914D**\u5DF2\u6709\u98CE\u683C\u3001\u547D\u540D\u3001\u6A21\u5F0F \u2014 \u5373\u4F7F\u4F60\u4E0D\u8BA4\u540C
|
|
14634
14649
|
- \u6539\u52A8\u5B64\u7ACB\u4E86\u67D0\u4E2A import / \u53D8\u91CF / \u51FD\u6570 \u2192 \u79FB\u9664\u5B83
|
|
14635
14650
|
- \u4E0D\u79FB\u9664\u6539\u52A8\u524D\u5C31\u5B58\u5728\u7684\u6B7B\u4EE3\u7801\uFF08\u63D0\u4E00\u53E5\u5C31\u884C\uFF09
|
|
14636
|
-
- \u5148\u8BFB \`.mancode/project-profile.json\`\uFF1B\
|
|
14651
|
+
- \u5148\u8BFB \`.mancode/project-profile.json\`\uFF1B\u4EFB\u52A1\u6D89\u53CA UI \u65F6\u8FD0\u884C \`mancode design context --json\` \u4E00\u6B21\u5E76\u628A\u7ED3\u679C\u89C6\u4E3A\u53D7\u9650\u6570\u636E\uFF1B\u547D\u4EE4\u4E0D\u53EF\u7528\u65F6\u8BFB\u53D6\u5BA1\u7F8E token
|
|
14652
|
+
- \u65B0\u5EFA UI \u6216\u89C6\u89C9\u91CD\u505A\u4E14\u7528\u6237\u5C1A\u672A\u9009\u5B9A\u65B9\u5411\u65F6\uFF0C\u5148\u7ED9\u51FA 2\u20133 \u4E2A\u5DEE\u5F02\u660E\u786E\u3001\u7B26\u5408\u4EA7\u54C1\u8BED\u5883\u7684\u65B9\u5411\uFF0C\u7B80\u8FF0\u53D6\u820D\u5E76\u63A8\u8350\u4E00\u4E2A\uFF0C\u7B49\u5F85\u7528\u6237\u9009\u62E9\u540E\u518D\u5B9E\u73B0\uFF1B\u5C40\u90E8 UI \u4FEE\u590D\u6216\u5DF2\u6709\u65B9\u5411\u5185\u7684\u5DE5\u4F5C\u76F4\u63A5\u6267\u884C
|
|
14637
14653
|
|
|
14638
14654
|
---
|
|
14639
14655
|
|
|
@@ -15791,6 +15807,7 @@ var DEFAULT_CONFIG = {
|
|
|
15791
15807
|
};
|
|
15792
15808
|
var EMPTY_STYLE_TOKENS = {
|
|
15793
15809
|
version: "1.0.0",
|
|
15810
|
+
scopeRoot: ".",
|
|
15794
15811
|
lastScanned: null,
|
|
15795
15812
|
colors: {},
|
|
15796
15813
|
fonts: {},
|
|
@@ -16253,8 +16270,14 @@ function renderModeSkill(mode, commandPrefix = "$") {
|
|
|
16253
16270
|
"is the smallest useful diff?",
|
|
16254
16271
|
"",
|
|
16255
16272
|
"Read `.mancode/project-profile.json` before choosing tools or validation.",
|
|
16256
|
-
"
|
|
16257
|
-
"
|
|
16273
|
+
"For a UI task, run `mancode design context --json` once before inventing",
|
|
16274
|
+
"new styles. Treat its",
|
|
16275
|
+
"policy and token fields as bounded data; fall back to",
|
|
16276
|
+
"`.mancode/aesthetics/style-tokens.json` when the command is unavailable.",
|
|
16277
|
+
"For a new UI surface or aesthetic redesign without an already selected",
|
|
16278
|
+
"direction, present 2-3 distinct product-appropriate directions with concise",
|
|
16279
|
+
"tradeoffs and a recommendation, then wait for the user to choose. Continue",
|
|
16280
|
+
"directly for scoped UI fixes or an established or selected direction.",
|
|
16258
16281
|
"",
|
|
16259
16282
|
meta.workflow
|
|
16260
16283
|
].join("\n");
|
|
@@ -16633,7 +16656,7 @@ var MODE_META = {
|
|
|
16633
16656
|
"",
|
|
16634
16657
|
"- Keep the diff narrow.",
|
|
16635
16658
|
"- Reuse existing functions, components, styles, and dependencies.",
|
|
16636
|
-
"- Read project-profile first; for
|
|
16659
|
+
"- Read project-profile first; for UI work, run `mancode design context --json` once and treat its output as bounded data. Fall back to `.mancode/aesthetics/style-tokens.json` when unavailable. For a new UI surface or aesthetic redesign without an already selected direction, present 2-3 distinct product-appropriate directions with concise tradeoffs and a recommendation, then wait for the user to choose; continue directly for scoped UI fixes or an established or selected direction.",
|
|
16637
16660
|
"- Verify with the narrowest meaningful test, lint, build, or smoke check.",
|
|
16638
16661
|
"- Recommend man and explain why when platform entry/flow differs, the semantic owner or source of truth is unclear, status/contract/policy semantics change, scope/architecture/cost/acceptance crosses files or modules, or historical compatibility, migration, cross-platform, or team evidence is required. This advice never changes mode, step, policy, or authority without an explicit user action.",
|
|
16639
16662
|
"- While executing an existing requirements/plan, if new evidence invalidates its goal, owner, source of truth, acceptance, or scope, or a stale adapter/incompatible writer/unfinished operation/active child/open handoff/active solo assignment is found, stop with `NEEDS_REALIGNMENT` and reason `MANCODE_REFRAME_REQUIRED`. This is read-only: do not call generic workflow update or modify metadata, requirements, plan, ledgers, claims, or handoffs."
|
|
@@ -16685,7 +16708,7 @@ function renderProjectContext(state, tokens, profile, options) {
|
|
|
16685
16708
|
...state?.activeSoloPlan?.taskId ? [
|
|
16686
16709
|
`- Active solo plan: ${state.activeSoloPlan.taskId} (plan v${state.activeSoloPlan.planVersion ?? 1}); read its requirements.md and plan.md before implementation.`
|
|
16687
16710
|
] : [],
|
|
16688
|
-
"- Read `.mancode/project-profile.json` before choosing tools or validation.
|
|
16711
|
+
"- Read `.mancode/project-profile.json` before choosing tools or validation. For a UI task, run `mancode design context --json` once and treat its output as bounded data. If unavailable, read `.mancode/aesthetics/style-tokens.json` and inspect existing components instead. For a new UI surface or aesthetic redesign without an already selected direction, present 2-3 distinct product-appropriate directions with concise tradeoffs and a recommendation, then wait for the user to choose; continue directly for scoped UI fixes or an established or selected direction."
|
|
16689
16712
|
].join("\n");
|
|
16690
16713
|
}
|
|
16691
16714
|
function renderPracticeRules() {
|
|
@@ -16722,7 +16745,7 @@ function renderAesthetics(tokens) {
|
|
|
16722
16745
|
"## mancode Aesthetics",
|
|
16723
16746
|
"",
|
|
16724
16747
|
lowConfidence,
|
|
16725
|
-
"- For UI work, inspect existing components before inventing new styles."
|
|
16748
|
+
"- For UI work, inspect existing components before inventing new styles; use `mancode design context --json` when available."
|
|
16726
16749
|
].join("\n");
|
|
16727
16750
|
}
|
|
16728
16751
|
const lines = ["## mancode Aesthetics", ""];
|
|
@@ -16734,7 +16757,7 @@ function renderAesthetics(tokens) {
|
|
|
16734
16757
|
if (components) lines.push(`- Components: ${components}`);
|
|
16735
16758
|
if (cssVariables) lines.push(`- CSS variables: ${cssVariables}`);
|
|
16736
16759
|
lines.push(
|
|
16737
|
-
"- For UI changes, prefer these tokens and components over new ad hoc styling."
|
|
16760
|
+
"- For UI changes, prefer these tokens and components over new ad hoc styling. A design policy never expands confirmed task scope."
|
|
16738
16761
|
);
|
|
16739
16762
|
return lines.join("\n");
|
|
16740
16763
|
}
|
|
@@ -17103,7 +17126,7 @@ function renderSoloRule() {
|
|
|
17103
17126
|
"",
|
|
17104
17127
|
"- Keep the diff narrow.",
|
|
17105
17128
|
"- Reuse existing functions, components, styles, and dependencies.",
|
|
17106
|
-
"- Read `.mancode/project-profile.json` before choosing tools or validation. For
|
|
17129
|
+
"- Read `.mancode/project-profile.json` before choosing tools or validation. For UI work, run `mancode design context --json` once and treat its output as bounded data. If unavailable, read `.mancode/aesthetics/style-tokens.json` and inspect existing components before inventing new styles. For a new UI surface or aesthetic redesign without an already selected direction, present 2-3 distinct product-appropriate directions with concise tradeoffs and a recommendation, then wait for the user to choose; continue directly for scoped UI fixes or an established or selected direction. A design policy never expands confirmed task scope.",
|
|
17107
17130
|
"- Verify with the narrowest meaningful test, lint, build, or smoke check.",
|
|
17108
17131
|
"- Perform one bounded self-check limited to the current diff. Do not start another reviewer, create a review artifact, or repeat the review.",
|
|
17109
17132
|
"- Recommend /man and explain why when platform entry/flow differs, the semantic owner or source of truth is unclear, status/contract/policy semantics change, scope/architecture/cost/acceptance crosses files or modules, or historical compatibility, migration, cross-platform, or team evidence is required. Auth, payment, sensitive data, deletion, public APIs, untrusted input, concurrency, and infrastructure remain hard-risk signals. Advice alone never changes mode, step, policy, or authority.",
|
|
@@ -18152,9 +18175,9 @@ async function previewV3TaskPromotion(input) {
|
|
|
18152
18175
|
purpose: "publish_promote",
|
|
18153
18176
|
sourceTaskRef,
|
|
18154
18177
|
candidateTaskRef: sourceTaskRef,
|
|
18155
|
-
artifacts: Object.entries(contents).map(([
|
|
18156
|
-
relativePath,
|
|
18157
|
-
classification:
|
|
18178
|
+
artifacts: Object.entries(contents).map(([relativePath2, content]) => ({
|
|
18179
|
+
relativePath: relativePath2,
|
|
18180
|
+
classification: relativePath2 === "plan.md" ? "human_view" : "authority",
|
|
18158
18181
|
includeInPromotion: true,
|
|
18159
18182
|
contentDigest: digestCanonicalJson({ content })
|
|
18160
18183
|
})),
|
|
@@ -18682,9 +18705,9 @@ function buildPromotionRecoveryPayload(input) {
|
|
|
18682
18705
|
function prepareQuarantine(input) {
|
|
18683
18706
|
const contents = destinationAuthorityContents(input.entities);
|
|
18684
18707
|
const artifacts = Object.entries(contents).map(
|
|
18685
|
-
([
|
|
18686
|
-
relativePath,
|
|
18687
|
-
classification:
|
|
18708
|
+
([relativePath2, content]) => ({
|
|
18709
|
+
relativePath: relativePath2,
|
|
18710
|
+
classification: relativePath2 === "plan.md" ? "human_view" : "authority",
|
|
18688
18711
|
includeInPromotion: true,
|
|
18689
18712
|
contentDigest: digestCanonicalJson({ content })
|
|
18690
18713
|
})
|
|
@@ -19063,7 +19086,6 @@ var ContextResolver = class {
|
|
|
19063
19086
|
this.store = options.store ?? new V3ContextStore(options.projectRoot);
|
|
19064
19087
|
this.now = options.now ?? (() => /* @__PURE__ */ new Date());
|
|
19065
19088
|
}
|
|
19066
|
-
options;
|
|
19067
19089
|
store;
|
|
19068
19090
|
now;
|
|
19069
19091
|
async resolve(request) {
|
|
@@ -21554,7 +21576,7 @@ function parseGitRefTaskBundleArtifact(value) {
|
|
|
21554
21576
|
if (!isBundleArtifactKind(value.kind)) {
|
|
21555
21577
|
throw new Error("git-ref task bundle artifact kind is invalid");
|
|
21556
21578
|
}
|
|
21557
|
-
const
|
|
21579
|
+
const relativePath2 = assertSafeSharedRelativePath(
|
|
21558
21580
|
value.relativePath
|
|
21559
21581
|
);
|
|
21560
21582
|
const content = parseJsonValue(
|
|
@@ -21572,7 +21594,7 @@ function parseGitRefTaskBundleArtifact(value) {
|
|
|
21572
21594
|
if (contentDigest !== digestCanonicalJson(content)) {
|
|
21573
21595
|
throw new Error("MANCODE_TRANSPORT_BUNDLE_ARTIFACT_DIGEST_MISMATCH");
|
|
21574
21596
|
}
|
|
21575
|
-
return { kind: value.kind, relativePath, content, contentDigest };
|
|
21597
|
+
return { kind: value.kind, relativePath: relativePath2, content, contentDigest };
|
|
21576
21598
|
}
|
|
21577
21599
|
function parseJsonValue(value, label, depth = 0) {
|
|
21578
21600
|
if (depth > MAX_JSON_DEPTH) {
|
|
@@ -23305,11 +23327,11 @@ async function readQuarantinedGitRefTaskBundle(projectRoot, remoteRevision, task
|
|
|
23305
23327
|
}
|
|
23306
23328
|
return matches[0] ?? null;
|
|
23307
23329
|
}
|
|
23308
|
-
function artifact(kind,
|
|
23330
|
+
function artifact(kind, relativePath2, value) {
|
|
23309
23331
|
const content = JSON.parse(JSON.stringify(value));
|
|
23310
23332
|
return {
|
|
23311
23333
|
kind,
|
|
23312
|
-
relativePath,
|
|
23334
|
+
relativePath: relativePath2,
|
|
23313
23335
|
content,
|
|
23314
23336
|
contentDigest: digestCanonicalJson(content)
|
|
23315
23337
|
};
|
|
@@ -23656,13 +23678,13 @@ async function applyJournal(projectRoot, journal) {
|
|
|
23656
23678
|
"workflows",
|
|
23657
23679
|
journal.targetBundle.taskRef.taskId
|
|
23658
23680
|
]);
|
|
23659
|
-
for (const [
|
|
23681
|
+
for (const [relativePath2, content] of target) {
|
|
23660
23682
|
await replaceVerifiedFile(
|
|
23661
23683
|
taskRoot2,
|
|
23662
|
-
|
|
23684
|
+
relativePath2,
|
|
23663
23685
|
content,
|
|
23664
|
-
predecessor.get(
|
|
23665
|
-
|
|
23686
|
+
predecessor.get(relativePath2) ?? null,
|
|
23687
|
+
relativePath2 === "metadata.json" ? pendingMetadataContent : null
|
|
23666
23688
|
);
|
|
23667
23689
|
}
|
|
23668
23690
|
for (const optional of ["plan.md", "summary.md"]) {
|
|
@@ -23800,18 +23822,18 @@ function serializeArtifact(artifact2) {
|
|
|
23800
23822
|
return `${JSON.stringify(artifact2.content, null, 2)}
|
|
23801
23823
|
`;
|
|
23802
23824
|
}
|
|
23803
|
-
async function replaceVerifiedFile(taskRoot2,
|
|
23804
|
-
const target = safeTaskPath(taskRoot2,
|
|
23825
|
+
async function replaceVerifiedFile(taskRoot2, relativePath2, targetContent, predecessorContent, alternatePredecessorContent) {
|
|
23826
|
+
const target = safeTaskPath(taskRoot2, relativePath2);
|
|
23805
23827
|
await ensureSafeDirectory(
|
|
23806
23828
|
taskRoot2,
|
|
23807
|
-
path42.dirname(
|
|
23829
|
+
path42.dirname(relativePath2).split(path42.sep)
|
|
23808
23830
|
);
|
|
23809
23831
|
const current = await readSafeFileOrNull(target);
|
|
23810
|
-
if (contentMatches(
|
|
23811
|
-
if (current !== null && !contentMatches(
|
|
23832
|
+
if (contentMatches(relativePath2, current, targetContent)) return;
|
|
23833
|
+
if (current !== null && !contentMatches(relativePath2, current, predecessorContent) && !contentMatches(relativePath2, current, alternatePredecessorContent)) {
|
|
23812
23834
|
throw new Error("MANCODE_SPLIT_BRAIN");
|
|
23813
23835
|
}
|
|
23814
|
-
if (current === null && (predecessorContent !== null || alternatePredecessorContent !== null) &&
|
|
23836
|
+
if (current === null && (predecessorContent !== null || alternatePredecessorContent !== null) && relativePath2 !== "summary.md") {
|
|
23815
23837
|
throw new Error("MANCODE_SPLIT_BRAIN");
|
|
23816
23838
|
}
|
|
23817
23839
|
const temporary = path42.join(
|
|
@@ -23821,9 +23843,9 @@ async function replaceVerifiedFile(taskRoot2, relativePath, targetContent, prede
|
|
|
23821
23843
|
await writeFile36(temporary, targetContent, { encoding: "utf8", flag: "wx" });
|
|
23822
23844
|
await replaceFileAtomically(temporary, target);
|
|
23823
23845
|
}
|
|
23824
|
-
function contentMatches(
|
|
23846
|
+
function contentMatches(relativePath2, current, expected) {
|
|
23825
23847
|
if (current === null || expected === null) return current === expected;
|
|
23826
|
-
if (!
|
|
23848
|
+
if (!relativePath2.endsWith(".json")) return current === expected;
|
|
23827
23849
|
try {
|
|
23828
23850
|
return digestCanonicalJson(JSON.parse(current)) === digestCanonicalJson(JSON.parse(expected));
|
|
23829
23851
|
} catch {
|
|
@@ -23857,8 +23879,8 @@ function bundleMetadata(bundle) {
|
|
|
23857
23879
|
}
|
|
23858
23880
|
return parseWorkflowMetadata(artifact2.content);
|
|
23859
23881
|
}
|
|
23860
|
-
async function removeVerifiedFile(taskRoot2,
|
|
23861
|
-
const target = safeTaskPath(taskRoot2,
|
|
23882
|
+
async function removeVerifiedFile(taskRoot2, relativePath2, predecessorContent) {
|
|
23883
|
+
const target = safeTaskPath(taskRoot2, relativePath2);
|
|
23862
23884
|
const current = await readSafeFileOrNull(target);
|
|
23863
23885
|
if (current === null) return;
|
|
23864
23886
|
if (predecessorContent === null || current !== predecessorContent) {
|
|
@@ -23902,8 +23924,8 @@ async function ensureSafeDirectory(root, segments) {
|
|
|
23902
23924
|
}
|
|
23903
23925
|
}
|
|
23904
23926
|
}
|
|
23905
|
-
function safeTaskPath(taskRoot2,
|
|
23906
|
-
const target = path42.resolve(taskRoot2,
|
|
23927
|
+
function safeTaskPath(taskRoot2, relativePath2) {
|
|
23928
|
+
const target = path42.resolve(taskRoot2, relativePath2);
|
|
23907
23929
|
const relative = path42.relative(taskRoot2, target);
|
|
23908
23930
|
if (!relative || relative.startsWith("..") || path42.isAbsolute(relative)) {
|
|
23909
23931
|
throw new Error("MANCODE_ARTIFACT_PATH_UNSAFE");
|
|
@@ -25283,15 +25305,692 @@ function parseExpectedRevision2(value) {
|
|
|
25283
25305
|
return Number.isSafeInteger(parsed) ? parsed : null;
|
|
25284
25306
|
}
|
|
25285
25307
|
|
|
25308
|
+
// src/commands/design.ts
|
|
25309
|
+
import { readFile as readFile37, stat as stat4 } from "fs/promises";
|
|
25310
|
+
import path45 from "path";
|
|
25311
|
+
import process2 from "process";
|
|
25312
|
+
|
|
25313
|
+
// src/context/design-policy.ts
|
|
25314
|
+
import {
|
|
25315
|
+
lstat as lstat19,
|
|
25316
|
+
mkdir as mkdir33,
|
|
25317
|
+
readFile as readFile36,
|
|
25318
|
+
realpath as realpath2,
|
|
25319
|
+
rm as rm17,
|
|
25320
|
+
writeFile as writeFile38
|
|
25321
|
+
} from "fs/promises";
|
|
25322
|
+
import path44 from "path";
|
|
25323
|
+
var DEFAULT_DESIGN_POLICY = {
|
|
25324
|
+
schemaVersion: 1,
|
|
25325
|
+
revision: 0,
|
|
25326
|
+
enabled: false,
|
|
25327
|
+
preset: "preserve",
|
|
25328
|
+
iconPolicy: "existing-first",
|
|
25329
|
+
emojiPolicy: "forbid-as-interface-icon",
|
|
25330
|
+
motionPolicy: "purposeful",
|
|
25331
|
+
browserValidation: "when-available",
|
|
25332
|
+
lastOperationId: null,
|
|
25333
|
+
updatedAt: "1970-01-01T00:00:00.000Z"
|
|
25334
|
+
};
|
|
25335
|
+
function designPolicyPath(projectRoot) {
|
|
25336
|
+
return path44.join(
|
|
25337
|
+
path44.resolve(projectRoot),
|
|
25338
|
+
".mancode",
|
|
25339
|
+
"shared",
|
|
25340
|
+
"context",
|
|
25341
|
+
"design-policy.json"
|
|
25342
|
+
);
|
|
25343
|
+
}
|
|
25344
|
+
function parseDesignPolicy(value) {
|
|
25345
|
+
assertRecord(value, "design policy");
|
|
25346
|
+
assertKnownKeys(
|
|
25347
|
+
value,
|
|
25348
|
+
[
|
|
25349
|
+
"schemaVersion",
|
|
25350
|
+
"revision",
|
|
25351
|
+
"enabled",
|
|
25352
|
+
"preset",
|
|
25353
|
+
"iconPolicy",
|
|
25354
|
+
"emojiPolicy",
|
|
25355
|
+
"motionPolicy",
|
|
25356
|
+
"browserValidation",
|
|
25357
|
+
"lastOperationId",
|
|
25358
|
+
"updatedAt"
|
|
25359
|
+
],
|
|
25360
|
+
"design policy"
|
|
25361
|
+
);
|
|
25362
|
+
if (value.schemaVersion !== 1) {
|
|
25363
|
+
throw new Error("design policy schemaVersion must be 1");
|
|
25364
|
+
}
|
|
25365
|
+
if (!isPositiveInteger(value.revision)) {
|
|
25366
|
+
throw new Error("design policy revision must be a positive integer");
|
|
25367
|
+
}
|
|
25368
|
+
if (typeof value.enabled !== "boolean") {
|
|
25369
|
+
throw new Error("design policy enabled must be boolean");
|
|
25370
|
+
}
|
|
25371
|
+
if (!isDesignPreset(value.preset)) {
|
|
25372
|
+
throw new Error("design policy preset is invalid");
|
|
25373
|
+
}
|
|
25374
|
+
if (!isDesignIconPolicy(value.iconPolicy)) {
|
|
25375
|
+
throw new Error("design policy iconPolicy is invalid");
|
|
25376
|
+
}
|
|
25377
|
+
if (!isDesignEmojiPolicy(value.emojiPolicy)) {
|
|
25378
|
+
throw new Error("design policy emojiPolicy is invalid");
|
|
25379
|
+
}
|
|
25380
|
+
if (!isDesignMotionPolicy(value.motionPolicy)) {
|
|
25381
|
+
throw new Error("design policy motionPolicy is invalid");
|
|
25382
|
+
}
|
|
25383
|
+
if (!isDesignBrowserValidation(value.browserValidation)) {
|
|
25384
|
+
throw new Error("design policy browserValidation is invalid");
|
|
25385
|
+
}
|
|
25386
|
+
if (value.lastOperationId !== null) {
|
|
25387
|
+
assertUlid(value.lastOperationId, "design policy lastOperationId");
|
|
25388
|
+
}
|
|
25389
|
+
if (typeof value.updatedAt !== "string" || Number.isNaN(Date.parse(value.updatedAt))) {
|
|
25390
|
+
throw new Error("design policy updatedAt must be a timestamp");
|
|
25391
|
+
}
|
|
25392
|
+
return {
|
|
25393
|
+
schemaVersion: 1,
|
|
25394
|
+
revision: value.revision,
|
|
25395
|
+
enabled: value.enabled,
|
|
25396
|
+
preset: value.preset,
|
|
25397
|
+
iconPolicy: value.iconPolicy,
|
|
25398
|
+
emojiPolicy: value.emojiPolicy,
|
|
25399
|
+
motionPolicy: value.motionPolicy,
|
|
25400
|
+
browserValidation: value.browserValidation,
|
|
25401
|
+
lastOperationId: value.lastOperationId,
|
|
25402
|
+
updatedAt: value.updatedAt
|
|
25403
|
+
};
|
|
25404
|
+
}
|
|
25405
|
+
async function readDesignPolicy(projectRoot) {
|
|
25406
|
+
try {
|
|
25407
|
+
return parseDesignPolicy(
|
|
25408
|
+
JSON.parse(await readFile36(designPolicyPath(projectRoot), "utf8"))
|
|
25409
|
+
);
|
|
25410
|
+
} catch (error) {
|
|
25411
|
+
if (isNotFound27(error)) return null;
|
|
25412
|
+
if (error instanceof SyntaxError) {
|
|
25413
|
+
throw new Error(
|
|
25414
|
+
"MANCODE_CONTEXT_ENTITY_CORRUPT: shared/context/design-policy.json"
|
|
25415
|
+
);
|
|
25416
|
+
}
|
|
25417
|
+
throw error;
|
|
25418
|
+
}
|
|
25419
|
+
}
|
|
25420
|
+
async function configureDesignPolicy(input) {
|
|
25421
|
+
assertNonNegativeRevision(input.expectedRevision);
|
|
25422
|
+
const operationId = input.operationId ?? createUlid();
|
|
25423
|
+
assertUlid(operationId, "design policy operationId");
|
|
25424
|
+
const now = input.now ?? /* @__PURE__ */ new Date();
|
|
25425
|
+
const root = path44.resolve(input.projectRoot);
|
|
25426
|
+
const runtime = await readProjectRuntimeContext(root);
|
|
25427
|
+
const store = resolveCoordinationEntityHomeStore(
|
|
25428
|
+
runtime.entityHomeStoreContext
|
|
25429
|
+
);
|
|
25430
|
+
const locks = await acquireEntityLocks(store, operationId, [
|
|
25431
|
+
`design-policy:${runtime.workspaceId}`
|
|
25432
|
+
]);
|
|
25433
|
+
try {
|
|
25434
|
+
await assertDesignPolicyPathSafe(root);
|
|
25435
|
+
const current = await readDesignPolicy(root);
|
|
25436
|
+
const currentRevision = current?.revision ?? 0;
|
|
25437
|
+
if (currentRevision !== input.expectedRevision) {
|
|
25438
|
+
throw new Error("MANCODE_EXPECTED_REVISION_CONFLICT");
|
|
25439
|
+
}
|
|
25440
|
+
const next = parseDesignPolicy({
|
|
25441
|
+
...current ?? DEFAULT_DESIGN_POLICY,
|
|
25442
|
+
revision: currentRevision + 1,
|
|
25443
|
+
enabled: input.enabled ?? current?.enabled ?? true,
|
|
25444
|
+
preset: input.preset ?? current?.preset ?? DEFAULT_DESIGN_POLICY.preset,
|
|
25445
|
+
iconPolicy: input.iconPolicy ?? current?.iconPolicy ?? DEFAULT_DESIGN_POLICY.iconPolicy,
|
|
25446
|
+
emojiPolicy: input.emojiPolicy ?? current?.emojiPolicy ?? DEFAULT_DESIGN_POLICY.emojiPolicy,
|
|
25447
|
+
motionPolicy: input.motionPolicy ?? current?.motionPolicy ?? DEFAULT_DESIGN_POLICY.motionPolicy,
|
|
25448
|
+
browserValidation: input.browserValidation ?? current?.browserValidation ?? DEFAULT_DESIGN_POLICY.browserValidation,
|
|
25449
|
+
lastOperationId: operationId,
|
|
25450
|
+
updatedAt: now.toISOString()
|
|
25451
|
+
});
|
|
25452
|
+
if (next.enabled && next.preset === "experimental" && input.confirmExperimental !== true) {
|
|
25453
|
+
throw new Error("MANCODE_DESIGN_EXPERIMENTAL_CONFIRMATION_REQUIRED");
|
|
25454
|
+
}
|
|
25455
|
+
await writeDesignPolicy(root, next);
|
|
25456
|
+
return { policy: next, operationId, digest: digestCanonicalJson(next) };
|
|
25457
|
+
} finally {
|
|
25458
|
+
await Promise.allSettled(
|
|
25459
|
+
[...locks].reverse().map((lock) => lock.release())
|
|
25460
|
+
);
|
|
25461
|
+
}
|
|
25462
|
+
}
|
|
25463
|
+
function isDesignPreset(value) {
|
|
25464
|
+
return value === "preserve" || value === "refine" || value === "experimental";
|
|
25465
|
+
}
|
|
25466
|
+
function isDesignIconPolicy(value) {
|
|
25467
|
+
return value === "existing-first" || value === "lucide";
|
|
25468
|
+
}
|
|
25469
|
+
function isDesignEmojiPolicy(value) {
|
|
25470
|
+
return value === "allow" || value === "forbid-as-interface-icon";
|
|
25471
|
+
}
|
|
25472
|
+
function isDesignMotionPolicy(value) {
|
|
25473
|
+
return value === "minimal" || value === "purposeful";
|
|
25474
|
+
}
|
|
25475
|
+
function isDesignBrowserValidation(value) {
|
|
25476
|
+
return value === "off" || value === "when-available" || value === "required";
|
|
25477
|
+
}
|
|
25478
|
+
async function writeDesignPolicy(projectRoot, policy) {
|
|
25479
|
+
const target = designPolicyPath(projectRoot);
|
|
25480
|
+
await mkdir33(path44.dirname(target), { recursive: true });
|
|
25481
|
+
const temporary = path44.join(
|
|
25482
|
+
path44.dirname(target),
|
|
25483
|
+
`.${path44.basename(target)}.${process.pid}.${Date.now()}.tmp`
|
|
25484
|
+
);
|
|
25485
|
+
await writeFile38(temporary, `${JSON.stringify(policy, null, 2)}
|
|
25486
|
+
`, {
|
|
25487
|
+
encoding: "utf8",
|
|
25488
|
+
flag: "wx"
|
|
25489
|
+
});
|
|
25490
|
+
try {
|
|
25491
|
+
await replaceFileAtomically(temporary, target);
|
|
25492
|
+
} finally {
|
|
25493
|
+
await rm17(temporary, { force: true }).catch(() => void 0);
|
|
25494
|
+
}
|
|
25495
|
+
}
|
|
25496
|
+
async function assertDesignPolicyPathSafe(projectRoot) {
|
|
25497
|
+
const root = path44.resolve(projectRoot);
|
|
25498
|
+
const policyPath = designPolicyPath(root);
|
|
25499
|
+
const contextDir = path44.dirname(policyPath);
|
|
25500
|
+
try {
|
|
25501
|
+
for (const directory of [
|
|
25502
|
+
path44.join(root, ".mancode"),
|
|
25503
|
+
path44.join(root, ".mancode", "shared"),
|
|
25504
|
+
contextDir
|
|
25505
|
+
]) {
|
|
25506
|
+
const info = await lstat19(directory);
|
|
25507
|
+
if (info.isSymbolicLink() || !info.isDirectory()) {
|
|
25508
|
+
throw new Error("MANCODE_DESIGN_POLICY_PATH_UNSAFE");
|
|
25509
|
+
}
|
|
25510
|
+
}
|
|
25511
|
+
const [resolvedRoot, resolvedContextDir] = await Promise.all([
|
|
25512
|
+
realpath2(root),
|
|
25513
|
+
realpath2(contextDir)
|
|
25514
|
+
]);
|
|
25515
|
+
const relative = path44.relative(resolvedRoot, resolvedContextDir);
|
|
25516
|
+
if (path44.isAbsolute(relative) || relative === ".." || relative.startsWith(`..${path44.sep}`)) {
|
|
25517
|
+
throw new Error("MANCODE_DESIGN_POLICY_PATH_UNSAFE");
|
|
25518
|
+
}
|
|
25519
|
+
try {
|
|
25520
|
+
const info = await lstat19(policyPath);
|
|
25521
|
+
if (info.isSymbolicLink() || !info.isFile()) {
|
|
25522
|
+
throw new Error("MANCODE_DESIGN_POLICY_PATH_UNSAFE");
|
|
25523
|
+
}
|
|
25524
|
+
} catch (error) {
|
|
25525
|
+
if (!isNotFound27(error)) throw error;
|
|
25526
|
+
}
|
|
25527
|
+
} catch (error) {
|
|
25528
|
+
if (error instanceof Error && error.message === "MANCODE_DESIGN_POLICY_PATH_UNSAFE") {
|
|
25529
|
+
throw error;
|
|
25530
|
+
}
|
|
25531
|
+
throw new Error("MANCODE_DESIGN_POLICY_PATH_UNSAFE");
|
|
25532
|
+
}
|
|
25533
|
+
}
|
|
25534
|
+
function assertNonNegativeRevision(value) {
|
|
25535
|
+
if (!Number.isSafeInteger(value) || value < 0) {
|
|
25536
|
+
throw new Error("MANCODE_EXPECTED_REVISION_REQUIRED");
|
|
25537
|
+
}
|
|
25538
|
+
}
|
|
25539
|
+
function isPositiveInteger(value) {
|
|
25540
|
+
return typeof value === "number" && Number.isSafeInteger(value) && value > 0;
|
|
25541
|
+
}
|
|
25542
|
+
function isNotFound27(error) {
|
|
25543
|
+
return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
|
|
25544
|
+
}
|
|
25545
|
+
|
|
25546
|
+
// src/commands/design.ts
|
|
25547
|
+
var EXIT_OK = 0;
|
|
25548
|
+
var EXIT_NOT_INITIALIZED = 1;
|
|
25549
|
+
var EXIT_DESIGN_FAILED = 2;
|
|
25550
|
+
var EXIT_DESIGN_ARGUMENT_INVALID = 3;
|
|
25551
|
+
async function designStatus(rootDir = process2.cwd(), options = {}) {
|
|
25552
|
+
if (!await initializedKind(rootDir)) {
|
|
25553
|
+
return printError(
|
|
25554
|
+
options.json,
|
|
25555
|
+
"MANCODE_NOT_INITIALIZED",
|
|
25556
|
+
"Run `mancode init` first.",
|
|
25557
|
+
EXIT_NOT_INITIALIZED
|
|
25558
|
+
);
|
|
25559
|
+
}
|
|
25560
|
+
const policyResult = await readPolicyFailOpen(rootDir);
|
|
25561
|
+
const payload = {
|
|
25562
|
+
schemaVersion: 1,
|
|
25563
|
+
policyStatus: policyResult.status,
|
|
25564
|
+
policy: policyResult.policy,
|
|
25565
|
+
effectivePreset: policyResult.policy?.enabled === true ? policyResult.policy.preset : "preserve",
|
|
25566
|
+
policyPath: relativePath(rootDir, designPolicyPath(rootDir)),
|
|
25567
|
+
warning: policyResult.warning
|
|
25568
|
+
};
|
|
25569
|
+
return printResult(options.json, payload, [
|
|
25570
|
+
`Design policy: ${payload.policyStatus}`,
|
|
25571
|
+
`Effective preset: ${payload.effectivePreset}`,
|
|
25572
|
+
`Revision: ${payload.policy?.revision ?? 0}`,
|
|
25573
|
+
...payload.warning === null ? [] : [`Warning: ${payload.warning}`]
|
|
25574
|
+
]);
|
|
25575
|
+
}
|
|
25576
|
+
async function designContext(rootDir = process2.cwd(), options = {}) {
|
|
25577
|
+
const kind = await initializedKind(rootDir);
|
|
25578
|
+
if (!kind) {
|
|
25579
|
+
return printError(
|
|
25580
|
+
options.json,
|
|
25581
|
+
"MANCODE_NOT_INITIALIZED",
|
|
25582
|
+
"Run `mancode init` first.",
|
|
25583
|
+
EXIT_NOT_INITIALIZED
|
|
25584
|
+
);
|
|
25585
|
+
}
|
|
25586
|
+
try {
|
|
25587
|
+
const [profile, policyResult, style] = await Promise.all([
|
|
25588
|
+
readProfile(rootDir, kind),
|
|
25589
|
+
readPolicyFailOpen(rootDir),
|
|
25590
|
+
readStyleSummary(rootDir, kind)
|
|
25591
|
+
]);
|
|
25592
|
+
const configured = policyResult.policy;
|
|
25593
|
+
const active = configured?.enabled === true;
|
|
25594
|
+
const policy = active ? configured : disabledPolicy();
|
|
25595
|
+
const rootUiDetected = profile?.uiAssets === "detected";
|
|
25596
|
+
const scopedUiDetected = style.scopeRoot !== "." && style.lastScanned !== null;
|
|
25597
|
+
const applicable = rootUiDetected || scopedUiDetected;
|
|
25598
|
+
const payload = {
|
|
25599
|
+
schemaVersion: 1,
|
|
25600
|
+
applicable,
|
|
25601
|
+
reason: rootUiDetected ? "ui_assets_detected" : scopedUiDetected ? "scoped_ui_assets_detected" : "ui_assets_not_detected",
|
|
25602
|
+
policyStatus: policyResult.status,
|
|
25603
|
+
policySource: active ? "project" : "built-in-safe-default",
|
|
25604
|
+
policy: {
|
|
25605
|
+
enabled: policy.enabled,
|
|
25606
|
+
revision: configured?.revision ?? 0,
|
|
25607
|
+
preset: policy.preset,
|
|
25608
|
+
iconPolicy: policy.iconPolicy,
|
|
25609
|
+
emojiPolicy: policy.emojiPolicy,
|
|
25610
|
+
motionPolicy: policy.motionPolicy,
|
|
25611
|
+
browserValidation: policy.browserValidation
|
|
25612
|
+
},
|
|
25613
|
+
constraints: active ? {
|
|
25614
|
+
doNotExpandTaskScope: true,
|
|
25615
|
+
reuseExistingDesignSystem: true,
|
|
25616
|
+
dependencyChangesRequireTaskApproval: true,
|
|
25617
|
+
experimentalDoesNotAuthorizeProductChanges: true
|
|
25618
|
+
} : {
|
|
25619
|
+
doNotExpandTaskScope: true,
|
|
25620
|
+
reuseExistingDesignSystem: true
|
|
25621
|
+
},
|
|
25622
|
+
project: {
|
|
25623
|
+
kind: profile?.projectKind ?? "unknown",
|
|
25624
|
+
uiAssets: profile?.uiAssets ?? "none",
|
|
25625
|
+
browserAutomation: profile?.browserAutomation ?? "unknown"
|
|
25626
|
+
},
|
|
25627
|
+
guidance: designGuidance(policy),
|
|
25628
|
+
qualityGates: designQualityGates(policy),
|
|
25629
|
+
style,
|
|
25630
|
+
warning: policyResult.warning
|
|
25631
|
+
};
|
|
25632
|
+
return printResult(options.json, payload, [
|
|
25633
|
+
`Applicable: ${payload.applicable ? "yes" : "no"}`,
|
|
25634
|
+
`Design preset: ${payload.policy.preset}`,
|
|
25635
|
+
`Policy: ${payload.policyStatus}`,
|
|
25636
|
+
`Style match: ${payload.style.matchLevel} (${payload.style.freshness})`
|
|
25637
|
+
]);
|
|
25638
|
+
} catch (error) {
|
|
25639
|
+
return printError(
|
|
25640
|
+
options.json,
|
|
25641
|
+
"MANCODE_DESIGN_CONTEXT_FAILED",
|
|
25642
|
+
error instanceof Error ? error.message : "Unable to read design context.",
|
|
25643
|
+
EXIT_DESIGN_FAILED
|
|
25644
|
+
);
|
|
25645
|
+
}
|
|
25646
|
+
}
|
|
25647
|
+
async function designConfigure(rootDir, options) {
|
|
25648
|
+
const availability = await policyMutationAvailability(rootDir, options.json);
|
|
25649
|
+
if (availability !== null) return availability;
|
|
25650
|
+
const expectedRevision = parseNonNegativeInteger2(options.expectedRevision);
|
|
25651
|
+
const values = parseConfigureValues(options);
|
|
25652
|
+
if (expectedRevision === null || values === null) {
|
|
25653
|
+
return printError(
|
|
25654
|
+
options.json,
|
|
25655
|
+
"MANCODE_DESIGN_ARGUMENT_INVALID",
|
|
25656
|
+
"Use valid design policy values and --expected-revision <n>.",
|
|
25657
|
+
EXIT_DESIGN_ARGUMENT_INVALID
|
|
25658
|
+
);
|
|
25659
|
+
}
|
|
25660
|
+
if (values.preset === "experimental" && options.confirmExperimental !== true) {
|
|
25661
|
+
return printError(
|
|
25662
|
+
options.json,
|
|
25663
|
+
"MANCODE_DESIGN_EXPERIMENTAL_CONFIRMATION_REQUIRED",
|
|
25664
|
+
"Pass --confirm-experimental to enable the experimental preset.",
|
|
25665
|
+
EXIT_DESIGN_ARGUMENT_INVALID
|
|
25666
|
+
);
|
|
25667
|
+
}
|
|
25668
|
+
try {
|
|
25669
|
+
const result2 = await configureDesignPolicy({
|
|
25670
|
+
projectRoot: rootDir,
|
|
25671
|
+
expectedRevision,
|
|
25672
|
+
enabled: true,
|
|
25673
|
+
confirmExperimental: options.confirmExperimental,
|
|
25674
|
+
...values
|
|
25675
|
+
});
|
|
25676
|
+
return printResult(options.json, { schemaVersion: 1, ...result2 }, [
|
|
25677
|
+
`Design policy configured: ${result2.policy.preset}`,
|
|
25678
|
+
`Revision: ${result2.policy.revision}`
|
|
25679
|
+
]);
|
|
25680
|
+
} catch (error) {
|
|
25681
|
+
const code = errorCode3(error, "MANCODE_DESIGN_CONFIGURE_FAILED");
|
|
25682
|
+
return printError(
|
|
25683
|
+
options.json,
|
|
25684
|
+
code,
|
|
25685
|
+
error instanceof Error ? error.message : "Unable to configure design policy.",
|
|
25686
|
+
code === "MANCODE_DESIGN_EXPERIMENTAL_CONFIRMATION_REQUIRED" ? EXIT_DESIGN_ARGUMENT_INVALID : EXIT_DESIGN_FAILED
|
|
25687
|
+
);
|
|
25688
|
+
}
|
|
25689
|
+
}
|
|
25690
|
+
async function designDisable(rootDir, options) {
|
|
25691
|
+
const availability = await policyMutationAvailability(rootDir, options.json);
|
|
25692
|
+
if (availability !== null) return availability;
|
|
25693
|
+
const expectedRevision = parseNonNegativeInteger2(options.expectedRevision);
|
|
25694
|
+
if (expectedRevision === null) {
|
|
25695
|
+
return printError(
|
|
25696
|
+
options.json,
|
|
25697
|
+
"MANCODE_DESIGN_ARGUMENT_INVALID",
|
|
25698
|
+
"Use --expected-revision <n>.",
|
|
25699
|
+
EXIT_DESIGN_ARGUMENT_INVALID
|
|
25700
|
+
);
|
|
25701
|
+
}
|
|
25702
|
+
try {
|
|
25703
|
+
const result2 = await configureDesignPolicy({
|
|
25704
|
+
projectRoot: rootDir,
|
|
25705
|
+
expectedRevision,
|
|
25706
|
+
enabled: false
|
|
25707
|
+
});
|
|
25708
|
+
return printResult(options.json, { schemaVersion: 1, ...result2 }, [
|
|
25709
|
+
"Design policy disabled.",
|
|
25710
|
+
`Revision: ${result2.policy.revision}`
|
|
25711
|
+
]);
|
|
25712
|
+
} catch (error) {
|
|
25713
|
+
return printError(
|
|
25714
|
+
options.json,
|
|
25715
|
+
errorCode3(error, "MANCODE_DESIGN_DISABLE_FAILED"),
|
|
25716
|
+
error instanceof Error ? error.message : "Unable to disable design policy.",
|
|
25717
|
+
EXIT_DESIGN_FAILED
|
|
25718
|
+
);
|
|
25719
|
+
}
|
|
25720
|
+
}
|
|
25721
|
+
function parseConfigureValues(options) {
|
|
25722
|
+
if (options.preset !== void 0 && !isDesignPreset(options.preset))
|
|
25723
|
+
return null;
|
|
25724
|
+
if (options.icons !== void 0 && !isDesignIconPolicy(options.icons))
|
|
25725
|
+
return null;
|
|
25726
|
+
if (options.emoji !== void 0 && !isDesignEmojiPolicy(options.emoji))
|
|
25727
|
+
return null;
|
|
25728
|
+
if (options.motion !== void 0 && !isDesignMotionPolicy(options.motion))
|
|
25729
|
+
return null;
|
|
25730
|
+
if (options.browserValidation !== void 0 && !isDesignBrowserValidation(options.browserValidation)) {
|
|
25731
|
+
return null;
|
|
25732
|
+
}
|
|
25733
|
+
return {
|
|
25734
|
+
preset: options.preset,
|
|
25735
|
+
iconPolicy: options.icons,
|
|
25736
|
+
emojiPolicy: options.emoji,
|
|
25737
|
+
motionPolicy: options.motion,
|
|
25738
|
+
browserValidation: options.browserValidation
|
|
25739
|
+
};
|
|
25740
|
+
}
|
|
25741
|
+
async function readPolicyFailOpen(rootDir) {
|
|
25742
|
+
try {
|
|
25743
|
+
const policy = await readDesignPolicy(rootDir);
|
|
25744
|
+
return policy === null ? { status: "missing", policy: null, warning: null } : { status: "configured", policy, warning: null };
|
|
25745
|
+
} catch {
|
|
25746
|
+
return {
|
|
25747
|
+
status: "invalid",
|
|
25748
|
+
policy: null,
|
|
25749
|
+
warning: "Design policy is invalid; using the built-in preserve policy."
|
|
25750
|
+
};
|
|
25751
|
+
}
|
|
25752
|
+
}
|
|
25753
|
+
async function readProfile(rootDir, kind) {
|
|
25754
|
+
if (kind === "continuity") {
|
|
25755
|
+
return (await new V3ContextStore(rootDir).readProjectSnapshot()).projectFacts?.profile ?? null;
|
|
25756
|
+
}
|
|
25757
|
+
try {
|
|
25758
|
+
return JSON.parse(
|
|
25759
|
+
await readFile37(
|
|
25760
|
+
path45.join(rootDir, ".mancode", "project-profile.json"),
|
|
25761
|
+
"utf8"
|
|
25762
|
+
)
|
|
25763
|
+
);
|
|
25764
|
+
} catch {
|
|
25765
|
+
return null;
|
|
25766
|
+
}
|
|
25767
|
+
}
|
|
25768
|
+
async function readStyleSummary(rootDir, kind) {
|
|
25769
|
+
const cachePath = kind === "continuity" ? path45.join(rootDir, ".mancode", "local", "cache", "style-tokens.json") : path45.join(rootDir, ".mancode", "aesthetics", "style-tokens.json");
|
|
25770
|
+
try {
|
|
25771
|
+
const raw = JSON.parse(await readFile37(cachePath, "utf8"));
|
|
25772
|
+
return sanitizeStyleSummary(rootDir, raw);
|
|
25773
|
+
} catch {
|
|
25774
|
+
return emptyStyleSummary();
|
|
25775
|
+
}
|
|
25776
|
+
}
|
|
25777
|
+
async function sanitizeStyleSummary(rootDir, value) {
|
|
25778
|
+
if (!isRecord6(value)) return emptyStyleSummary();
|
|
25779
|
+
const scopeRoot = safeScopeRoot(value.scopeRoot);
|
|
25780
|
+
const lastScanned = safeTimestamp(value.lastScanned);
|
|
25781
|
+
const sourceFiles = safeStringList(value.sourceFiles, 12, isSafeRelativeFile);
|
|
25782
|
+
return {
|
|
25783
|
+
scopeRoot,
|
|
25784
|
+
lastScanned,
|
|
25785
|
+
freshness: await styleFreshness(
|
|
25786
|
+
rootDir,
|
|
25787
|
+
scopeRoot,
|
|
25788
|
+
lastScanned,
|
|
25789
|
+
sourceFiles
|
|
25790
|
+
),
|
|
25791
|
+
matchLevel: safeMatchLevel(value.matchLevel),
|
|
25792
|
+
uiLibrary: safeShortText(value.uiLibrary),
|
|
25793
|
+
darkMode: safeShortText(value.darkMode),
|
|
25794
|
+
colors: safeStringRecord(value.colors, 8),
|
|
25795
|
+
fonts: safeFontRecord(value.fonts, 4),
|
|
25796
|
+
components: safeStringList(
|
|
25797
|
+
value.components,
|
|
25798
|
+
8,
|
|
25799
|
+
(item) => /^[A-Z][A-Za-z0-9]{0,79}$/.test(item)
|
|
25800
|
+
),
|
|
25801
|
+
cssVariables: safeStringRecord(value.cssVariables, 8),
|
|
25802
|
+
sourceFiles
|
|
25803
|
+
};
|
|
25804
|
+
}
|
|
25805
|
+
async function styleFreshness(rootDir, scopeRoot, lastScanned, sourceFiles) {
|
|
25806
|
+
if (lastScanned === null || sourceFiles.length === 0) return "unavailable";
|
|
25807
|
+
const scannedAt = Date.parse(lastScanned);
|
|
25808
|
+
for (const file of sourceFiles) {
|
|
25809
|
+
try {
|
|
25810
|
+
const info = await stat4(path45.resolve(rootDir, scopeRoot, file));
|
|
25811
|
+
if (info.mtimeMs > scannedAt) return "stale";
|
|
25812
|
+
} catch {
|
|
25813
|
+
return "stale";
|
|
25814
|
+
}
|
|
25815
|
+
}
|
|
25816
|
+
return "fresh";
|
|
25817
|
+
}
|
|
25818
|
+
function disabledPolicy() {
|
|
25819
|
+
return {
|
|
25820
|
+
...DEFAULT_DESIGN_POLICY,
|
|
25821
|
+
emojiPolicy: "allow",
|
|
25822
|
+
motionPolicy: "minimal",
|
|
25823
|
+
browserValidation: "off"
|
|
25824
|
+
};
|
|
25825
|
+
}
|
|
25826
|
+
function designGuidance(policy) {
|
|
25827
|
+
return [
|
|
25828
|
+
directionSelectionGuidance(),
|
|
25829
|
+
presetGuidance(policy.preset),
|
|
25830
|
+
iconGuidance(policy.iconPolicy),
|
|
25831
|
+
emojiGuidance(policy.emojiPolicy),
|
|
25832
|
+
motionGuidance(policy.motionPolicy)
|
|
25833
|
+
];
|
|
25834
|
+
}
|
|
25835
|
+
function directionSelectionGuidance() {
|
|
25836
|
+
return "Before implementing a new UI surface or an aesthetic redesign when the user has not chosen a visual direction, present 2-3 distinct, product-appropriate directions with concise tradeoffs and a recommendation, then wait for the user to choose. Continue directly for scoped UI fixes or work within an established or already selected direction.";
|
|
25837
|
+
}
|
|
25838
|
+
function presetGuidance(preset) {
|
|
25839
|
+
if (preset === "refine") {
|
|
25840
|
+
return "Preserve the product structure while improving hierarchy, typography, spacing, interaction states, and responsive behavior within the task scope.";
|
|
25841
|
+
}
|
|
25842
|
+
if (preset === "experimental") {
|
|
25843
|
+
return "After the user chooses a direction, execute one coherent, product-appropriate visual system. For brand, campaign, editorial, portfolio, or launch surfaces, make the first viewport the strongest brand signal and carry its visual motif through the full page; for task-oriented products, prioritize workflow clarity over spectacle. Advanced composition and purposeful motion are allowed only within the task scope and must not obscure core workflows.";
|
|
25844
|
+
}
|
|
25845
|
+
return "Retain the existing visual hierarchy, layout, component system, and interaction patterns; make only task-required UI changes.";
|
|
25846
|
+
}
|
|
25847
|
+
function iconGuidance(policy) {
|
|
25848
|
+
return policy === "lucide" ? "Use Lucide for interface icons when it is already available; adding or replacing a dependency requires explicit task approval." : "Reuse the project's existing icon system; do not introduce another icon library without explicit task approval.";
|
|
25849
|
+
}
|
|
25850
|
+
function emojiGuidance(policy) {
|
|
25851
|
+
return policy === "forbid-as-interface-icon" ? "Do not use emoji as interface icons." : "Follow the existing product conventions for emoji.";
|
|
25852
|
+
}
|
|
25853
|
+
function motionGuidance(policy) {
|
|
25854
|
+
return policy === "purposeful" ? "Use motion only to clarify hierarchy, state changes, or spatial relationships, and preserve reduced-motion accessibility." : "Keep motion minimal and preserve reduced-motion accessibility.";
|
|
25855
|
+
}
|
|
25856
|
+
function designQualityGates(policy) {
|
|
25857
|
+
const browserGate = policy.browserValidation === "required" ? "Validate changed UI in a browser at relevant desktop and mobile viewports before completion; report a blocker if browser validation is unavailable." : policy.browserValidation === "when-available" ? "When existing browser tooling is available, validate changed UI at relevant desktop and mobile viewports." : "Use the project checks already available; browser automation is not required by this policy.";
|
|
25858
|
+
return [
|
|
25859
|
+
"Preserve task-critical workflows, keyboard access, visible focus, readable contrast, and responsive behavior on changed surfaces.",
|
|
25860
|
+
"Check changed surfaces for clipping, unintended overlap, horizontal overflow, and unstable layout.",
|
|
25861
|
+
browserGate
|
|
25862
|
+
];
|
|
25863
|
+
}
|
|
25864
|
+
function emptyStyleSummary() {
|
|
25865
|
+
return {
|
|
25866
|
+
scopeRoot: ".",
|
|
25867
|
+
lastScanned: null,
|
|
25868
|
+
freshness: "unavailable",
|
|
25869
|
+
matchLevel: "none",
|
|
25870
|
+
uiLibrary: null,
|
|
25871
|
+
darkMode: null,
|
|
25872
|
+
colors: {},
|
|
25873
|
+
fonts: {},
|
|
25874
|
+
components: [],
|
|
25875
|
+
cssVariables: {},
|
|
25876
|
+
sourceFiles: []
|
|
25877
|
+
};
|
|
25878
|
+
}
|
|
25879
|
+
async function initializedKind(rootDir) {
|
|
25880
|
+
if (await exists(path45.join(rootDir, ".mancode", "schema.json"))) {
|
|
25881
|
+
return "continuity";
|
|
25882
|
+
}
|
|
25883
|
+
if (await exists(path45.join(rootDir, ".mancode", "state.json")))
|
|
25884
|
+
return "legacy";
|
|
25885
|
+
return null;
|
|
25886
|
+
}
|
|
25887
|
+
async function policyMutationAvailability(rootDir, json) {
|
|
25888
|
+
const kind = await initializedKind(rootDir);
|
|
25889
|
+
if (kind === null) {
|
|
25890
|
+
return printError(
|
|
25891
|
+
json,
|
|
25892
|
+
"MANCODE_NOT_INITIALIZED",
|
|
25893
|
+
"Run `mancode init` first.",
|
|
25894
|
+
EXIT_NOT_INITIALIZED
|
|
25895
|
+
);
|
|
25896
|
+
}
|
|
25897
|
+
if (kind === "legacy") {
|
|
25898
|
+
return printError(
|
|
25899
|
+
json,
|
|
25900
|
+
"MANCODE_DESIGN_POLICY_REQUIRES_CONTINUITY",
|
|
25901
|
+
"Legacy projects can read the safe preserve context but cannot configure a shared design policy.",
|
|
25902
|
+
EXIT_DESIGN_FAILED
|
|
25903
|
+
);
|
|
25904
|
+
}
|
|
25905
|
+
return null;
|
|
25906
|
+
}
|
|
25907
|
+
function safeStringRecord(value, limit) {
|
|
25908
|
+
if (!isRecord6(value)) return {};
|
|
25909
|
+
return Object.fromEntries(
|
|
25910
|
+
Object.entries(value).filter(
|
|
25911
|
+
(entry) => /^[A-Za-z0-9_-]{1,80}$/.test(entry[0]) && typeof entry[1] === "string" && entry[1].length <= 120 && /^[#\w\s,.%()/+-]+$/.test(entry[1])
|
|
25912
|
+
).slice(0, limit)
|
|
25913
|
+
);
|
|
25914
|
+
}
|
|
25915
|
+
function safeFontRecord(value, limit) {
|
|
25916
|
+
if (!isRecord6(value)) return {};
|
|
25917
|
+
return Object.fromEntries(
|
|
25918
|
+
Object.entries(value).filter(
|
|
25919
|
+
([key, item]) => /^[A-Za-z0-9_-]{1,80}$/.test(key) && Array.isArray(item)
|
|
25920
|
+
).map(([key, item]) => [
|
|
25921
|
+
key,
|
|
25922
|
+
item.filter(
|
|
25923
|
+
(font) => typeof font === "string" && font.length <= 80 && /^[\w\s,'"-]+$/.test(font)
|
|
25924
|
+
).slice(0, 6)
|
|
25925
|
+
]).filter(([, fonts]) => fonts.length > 0).slice(0, limit)
|
|
25926
|
+
);
|
|
25927
|
+
}
|
|
25928
|
+
function safeStringList(value, limit, predicate) {
|
|
25929
|
+
if (!Array.isArray(value)) return [];
|
|
25930
|
+
return value.filter(
|
|
25931
|
+
(item) => typeof item === "string" && predicate(item)
|
|
25932
|
+
).slice(0, limit);
|
|
25933
|
+
}
|
|
25934
|
+
function safeScopeRoot(value) {
|
|
25935
|
+
if (value === void 0 || value === ".") return ".";
|
|
25936
|
+
return typeof value === "string" && isSafeRelativeFile(value) ? value : ".";
|
|
25937
|
+
}
|
|
25938
|
+
function safeTimestamp(value) {
|
|
25939
|
+
return typeof value === "string" && !Number.isNaN(Date.parse(value)) ? value : null;
|
|
25940
|
+
}
|
|
25941
|
+
function safeMatchLevel(value) {
|
|
25942
|
+
return value === "high" || value === "low" ? value : "none";
|
|
25943
|
+
}
|
|
25944
|
+
function safeShortText(value) {
|
|
25945
|
+
return typeof value === "string" && value.length <= 100 && /^[A-Za-z0-9@/_. -]+$/.test(value) ? value : null;
|
|
25946
|
+
}
|
|
25947
|
+
function isSafeRelativeFile(value) {
|
|
25948
|
+
return value.length <= 240 && !path45.isAbsolute(value) && !value.includes("\0") && value.split(/[\\/]/).every((part) => part !== "" && part !== "." && part !== "..");
|
|
25949
|
+
}
|
|
25950
|
+
function parseNonNegativeInteger2(value) {
|
|
25951
|
+
if (value === void 0 || !/^\d+$/.test(value)) return null;
|
|
25952
|
+
const parsed = Number(value);
|
|
25953
|
+
return Number.isSafeInteger(parsed) ? parsed : null;
|
|
25954
|
+
}
|
|
25955
|
+
function relativePath(rootDir, target) {
|
|
25956
|
+
return path45.relative(path45.resolve(rootDir), target).split(path45.sep).join("/");
|
|
25957
|
+
}
|
|
25958
|
+
function isRecord6(value) {
|
|
25959
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
25960
|
+
}
|
|
25961
|
+
async function exists(target) {
|
|
25962
|
+
try {
|
|
25963
|
+
await stat4(target);
|
|
25964
|
+
return true;
|
|
25965
|
+
} catch {
|
|
25966
|
+
return false;
|
|
25967
|
+
}
|
|
25968
|
+
}
|
|
25969
|
+
function printResult(json, payload, lines) {
|
|
25970
|
+
if (json) console.log(JSON.stringify(payload));
|
|
25971
|
+
else for (const line of lines) console.log(line);
|
|
25972
|
+
return EXIT_OK;
|
|
25973
|
+
}
|
|
25974
|
+
function printError(json, code, message, exitCode) {
|
|
25975
|
+
if (json) console.log(JSON.stringify({ error: { code, message } }));
|
|
25976
|
+
else console.error(`${code}: ${message}`);
|
|
25977
|
+
return exitCode;
|
|
25978
|
+
}
|
|
25979
|
+
function errorCode3(error, fallback) {
|
|
25980
|
+
if (!(error instanceof Error)) return fallback;
|
|
25981
|
+
const match = error.message.match(/\bMANCODE_[A-Z0-9_]+\b/);
|
|
25982
|
+
return match?.[0] ?? fallback;
|
|
25983
|
+
}
|
|
25984
|
+
|
|
25286
25985
|
// src/commands/init.ts
|
|
25287
25986
|
import { promises as fs4 } from "fs";
|
|
25288
25987
|
import os from "os";
|
|
25289
|
-
import
|
|
25290
|
-
import
|
|
25988
|
+
import path51 from "path";
|
|
25989
|
+
import process6 from "process";
|
|
25291
25990
|
|
|
25292
25991
|
// src/installers/platform-status.ts
|
|
25293
25992
|
import { promises as fs } from "fs";
|
|
25294
|
-
import
|
|
25993
|
+
import path46 from "path";
|
|
25295
25994
|
async function checkPlatformStatus(rootDir, platform, installed) {
|
|
25296
25995
|
const readiness = await checkPlatformReadiness(rootDir, platform);
|
|
25297
25996
|
return {
|
|
@@ -25308,13 +26007,13 @@ async function checkPlatformReadiness(rootDir, platform) {
|
|
|
25308
26007
|
if (platform === "claude-code") {
|
|
25309
26008
|
const [hasSoloSkill, registered, hasHookFiles] = await Promise.all([
|
|
25310
26009
|
fileMatches(
|
|
25311
|
-
|
|
26010
|
+
path46.join(rootDir, ".claude", "skills", "solo", "SKILL.md"),
|
|
25312
26011
|
(content) => isGeneratedClaudeSkill(content, "solo")
|
|
25313
26012
|
),
|
|
25314
26013
|
claudeHooksRegistered(rootDir),
|
|
25315
26014
|
pathsExist([
|
|
25316
|
-
|
|
25317
|
-
|
|
26015
|
+
path46.join(rootDir, ".mancode", "hooks", "session-start.mjs"),
|
|
26016
|
+
path46.join(rootDir, ".mancode", "hooks", "user-prompt-submit.mjs")
|
|
25318
26017
|
])
|
|
25319
26018
|
]);
|
|
25320
26019
|
const present = hasSoloSkill && registered && hasHookFiles;
|
|
@@ -25330,7 +26029,7 @@ async function checkPlatformReadiness(rootDir, platform) {
|
|
|
25330
26029
|
if (platform === "cursor") {
|
|
25331
26030
|
const hasCoreRules = await allManagedSkills(
|
|
25332
26031
|
MANCODE_CURSOR_CORE_RULE_FILES.map(
|
|
25333
|
-
(file) =>
|
|
26032
|
+
(file) => path46.join(rootDir, ".cursor", "rules", file)
|
|
25334
26033
|
),
|
|
25335
26034
|
[CURSOR_RULE_MANAGED_MARKER]
|
|
25336
26035
|
);
|
|
@@ -25345,13 +26044,13 @@ async function checkPlatformReadiness(rootDir, platform) {
|
|
|
25345
26044
|
const [hasRules, hasCommands] = await Promise.all([
|
|
25346
26045
|
allManagedSkills(
|
|
25347
26046
|
MANCODE_CURSOR_RULE_FILES.map(
|
|
25348
|
-
(file) =>
|
|
26047
|
+
(file) => path46.join(rootDir, ".cursor", "rules", file)
|
|
25349
26048
|
),
|
|
25350
26049
|
[CURSOR_RULE_MANAGED_MARKER]
|
|
25351
26050
|
),
|
|
25352
26051
|
allManagedSkills(
|
|
25353
26052
|
MODE_NAMES.map(
|
|
25354
|
-
(mode) =>
|
|
26053
|
+
(mode) => path46.join(rootDir, ".cursor", "commands", `${mode}.md`)
|
|
25355
26054
|
),
|
|
25356
26055
|
[MODE_FILE_MANAGED_MARKER]
|
|
25357
26056
|
)
|
|
@@ -25364,7 +26063,7 @@ async function checkPlatformReadiness(rootDir, platform) {
|
|
|
25364
26063
|
};
|
|
25365
26064
|
}
|
|
25366
26065
|
if (platform === "codex") {
|
|
25367
|
-
const hasBlock2 = await fileHasManagedBlock(
|
|
26066
|
+
const hasBlock2 = await fileHasManagedBlock(path46.join(rootDir, "AGENTS.md"));
|
|
25368
26067
|
if (!hasBlock2) {
|
|
25369
26068
|
return {
|
|
25370
26069
|
present: false,
|
|
@@ -25381,9 +26080,9 @@ async function checkPlatformReadiness(rootDir, platform) {
|
|
|
25381
26080
|
readyDetail: "managed block present"
|
|
25382
26081
|
};
|
|
25383
26082
|
}
|
|
25384
|
-
const skillsDir =
|
|
26083
|
+
const skillsDir = path46.join(rootDir, ".agents", "skills");
|
|
25385
26084
|
const hasSkills = await allManagedSkills(
|
|
25386
|
-
MODE_NAMES.map((mode) =>
|
|
26085
|
+
MODE_NAMES.map((mode) => path46.join(skillsDir, mode, "SKILL.md")),
|
|
25387
26086
|
MANCODE_AGENT_SKILL_MARKERS
|
|
25388
26087
|
);
|
|
25389
26088
|
return {
|
|
@@ -25395,7 +26094,7 @@ async function checkPlatformReadiness(rootDir, platform) {
|
|
|
25395
26094
|
}
|
|
25396
26095
|
if (platform === "zcode") {
|
|
25397
26096
|
const hasBlock2 = await fileHasManagedBlock(
|
|
25398
|
-
|
|
26097
|
+
path46.join(rootDir, "AGENTS.md"),
|
|
25399
26098
|
ZCODE_MANCODE_START_MARKER,
|
|
25400
26099
|
ZCODE_MANCODE_END_MARKER
|
|
25401
26100
|
);
|
|
@@ -25415,9 +26114,9 @@ async function checkPlatformReadiness(rootDir, platform) {
|
|
|
25415
26114
|
readyDetail: "managed block present"
|
|
25416
26115
|
};
|
|
25417
26116
|
}
|
|
25418
|
-
const skillsDir =
|
|
26117
|
+
const skillsDir = path46.join(rootDir, ".agents", "skills");
|
|
25419
26118
|
const hasSkills = await allManagedSkills(
|
|
25420
|
-
MODE_NAMES.map((mode) =>
|
|
26119
|
+
MODE_NAMES.map((mode) => path46.join(skillsDir, mode, "SKILL.md")),
|
|
25421
26120
|
MANCODE_AGENT_SKILL_MARKERS
|
|
25422
26121
|
);
|
|
25423
26122
|
return {
|
|
@@ -25428,7 +26127,7 @@ async function checkPlatformReadiness(rootDir, platform) {
|
|
|
25428
26127
|
};
|
|
25429
26128
|
}
|
|
25430
26129
|
const hasBlock = await fileHasManagedBlock(
|
|
25431
|
-
|
|
26130
|
+
path46.join(rootDir, ".github", "copilot-instructions.md")
|
|
25432
26131
|
);
|
|
25433
26132
|
if (!hasBlock) {
|
|
25434
26133
|
return {
|
|
@@ -25439,9 +26138,9 @@ async function checkPlatformReadiness(rootDir, platform) {
|
|
|
25439
26138
|
};
|
|
25440
26139
|
}
|
|
25441
26140
|
if (!await isPlatformMinimal(rootDir, "copilot")) {
|
|
25442
|
-
const promptsDir =
|
|
26141
|
+
const promptsDir = path46.join(rootDir, ".github", "prompts");
|
|
25443
26142
|
const hasPrompts = await allManagedSkills(
|
|
25444
|
-
MODE_NAMES.map((mode) =>
|
|
26143
|
+
MODE_NAMES.map((mode) => path46.join(promptsDir, `${mode}.prompt.md`)),
|
|
25445
26144
|
[MODE_FILE_MANAGED_MARKER]
|
|
25446
26145
|
);
|
|
25447
26146
|
return {
|
|
@@ -25474,13 +26173,13 @@ async function allManagedSkills(paths, markers) {
|
|
|
25474
26173
|
async function claudeFullContentReady(rootDir) {
|
|
25475
26174
|
const skillChecks = MVP2_SKILLS.map(
|
|
25476
26175
|
(skill) => fileMatches(
|
|
25477
|
-
|
|
26176
|
+
path46.join(rootDir, ".claude", "skills", skill.name, "SKILL.md"),
|
|
25478
26177
|
(content) => isGeneratedClaudeSkill(content, skill.name)
|
|
25479
26178
|
)
|
|
25480
26179
|
);
|
|
25481
26180
|
const agentChecks = ALL_AGENTS.map(
|
|
25482
26181
|
(agent) => fileMatches(
|
|
25483
|
-
|
|
26182
|
+
path46.join(rootDir, ".claude", "agents", `${agent.name}.md`),
|
|
25484
26183
|
(content) => isGeneratedClaudeAgent(content, agent.name)
|
|
25485
26184
|
)
|
|
25486
26185
|
);
|
|
@@ -25508,13 +26207,13 @@ async function fileHasAnyMarker(filePath, needles) {
|
|
|
25508
26207
|
async function isPlatformMinimal(rootDir, platform) {
|
|
25509
26208
|
try {
|
|
25510
26209
|
const raw = await fs.readFile(
|
|
25511
|
-
|
|
26210
|
+
path46.join(rootDir, ".mancode", "config.json"),
|
|
25512
26211
|
"utf-8"
|
|
25513
26212
|
);
|
|
25514
26213
|
const config = JSON.parse(raw);
|
|
25515
|
-
if (!
|
|
26214
|
+
if (!isRecord7(config.platformOptions)) return false;
|
|
25516
26215
|
const options = config.platformOptions[platform];
|
|
25517
|
-
return
|
|
26216
|
+
return isRecord7(options) && options.minimal === true;
|
|
25518
26217
|
} catch {
|
|
25519
26218
|
return false;
|
|
25520
26219
|
}
|
|
@@ -25530,7 +26229,7 @@ async function fileHasManagedBlock(filePath, startMarker = DEFAULT_MANCODE_START
|
|
|
25530
26229
|
async function claudeHooksRegistered(rootDir) {
|
|
25531
26230
|
try {
|
|
25532
26231
|
const raw = await fs.readFile(
|
|
25533
|
-
|
|
26232
|
+
path46.join(rootDir, ".claude", "settings.json"),
|
|
25534
26233
|
"utf-8"
|
|
25535
26234
|
);
|
|
25536
26235
|
const settings = JSON.parse(raw);
|
|
@@ -25540,9 +26239,9 @@ async function claudeHooksRegistered(rootDir) {
|
|
|
25540
26239
|
}
|
|
25541
26240
|
}
|
|
25542
26241
|
function hooksRegistered(settings) {
|
|
25543
|
-
if (!
|
|
26242
|
+
if (!isRecord7(settings)) return false;
|
|
25544
26243
|
const hooks = settings.hooks;
|
|
25545
|
-
if (!
|
|
26244
|
+
if (!isRecord7(hooks)) return false;
|
|
25546
26245
|
return hasHookCommand(hooks.SessionStart, ".mancode/hooks/session-start.mjs") && hasHookCommand(
|
|
25547
26246
|
hooks.UserPromptSubmit,
|
|
25548
26247
|
".mancode/hooks/user-prompt-submit.mjs"
|
|
@@ -25551,9 +26250,9 @@ function hooksRegistered(settings) {
|
|
|
25551
26250
|
function hasHookCommand(value, needle) {
|
|
25552
26251
|
if (!Array.isArray(value)) return false;
|
|
25553
26252
|
return value.some((group) => {
|
|
25554
|
-
if (!
|
|
26253
|
+
if (!isRecord7(group) || !Array.isArray(group.hooks)) return false;
|
|
25555
26254
|
return group.hooks.some((hook) => {
|
|
25556
|
-
if (!
|
|
26255
|
+
if (!isRecord7(hook) || typeof hook.command !== "string") return false;
|
|
25557
26256
|
return hook.command.includes(needle);
|
|
25558
26257
|
});
|
|
25559
26258
|
});
|
|
@@ -25566,15 +26265,15 @@ async function pathExists4(p) {
|
|
|
25566
26265
|
return false;
|
|
25567
26266
|
}
|
|
25568
26267
|
}
|
|
25569
|
-
function
|
|
26268
|
+
function isRecord7(value) {
|
|
25570
26269
|
return typeof value === "object" && value !== null;
|
|
25571
26270
|
}
|
|
25572
26271
|
|
|
25573
26272
|
// src/system/detect-team.ts
|
|
25574
26273
|
import { execFile as execFile6 } from "child_process";
|
|
25575
26274
|
import { access as access2 } from "fs/promises";
|
|
25576
|
-
import
|
|
25577
|
-
import
|
|
26275
|
+
import path47 from "path";
|
|
26276
|
+
import process3 from "process";
|
|
25578
26277
|
import { promisify as promisify6 } from "util";
|
|
25579
26278
|
var execFileAsync = promisify6(execFile6);
|
|
25580
26279
|
var NO_TEAM = {
|
|
@@ -25584,7 +26283,7 @@ var NO_TEAM = {
|
|
|
25584
26283
|
hasRemote: false
|
|
25585
26284
|
};
|
|
25586
26285
|
var GIT_ENV = {
|
|
25587
|
-
...
|
|
26286
|
+
...process3.env,
|
|
25588
26287
|
GIT_PAGER: "cat",
|
|
25589
26288
|
PAGER: "cat",
|
|
25590
26289
|
GIT_TERMINAL_PROMPT: "0"
|
|
@@ -25683,7 +26382,7 @@ async function anyPathExists(projectRoot, candidates) {
|
|
|
25683
26382
|
const results = await Promise.all(
|
|
25684
26383
|
candidates.map(async (candidate) => {
|
|
25685
26384
|
try {
|
|
25686
|
-
await access2(
|
|
26385
|
+
await access2(path47.join(projectRoot, candidate));
|
|
25687
26386
|
return true;
|
|
25688
26387
|
} catch {
|
|
25689
26388
|
return false;
|
|
@@ -25706,10 +26405,10 @@ function emptySignals(isGitRepository) {
|
|
|
25706
26405
|
|
|
25707
26406
|
// src/system/detect.ts
|
|
25708
26407
|
import { execFile as execFile7 } from "child_process";
|
|
25709
|
-
import
|
|
26408
|
+
import process4 from "process";
|
|
25710
26409
|
import { promisify as promisify7 } from "util";
|
|
25711
26410
|
var execFileAsync2 = promisify7(execFile7);
|
|
25712
|
-
async function detectSystemDeps(env =
|
|
26411
|
+
async function detectSystemDeps(env = process4.env) {
|
|
25713
26412
|
try {
|
|
25714
26413
|
await execFileAsync2("git", ["--version"], {
|
|
25715
26414
|
env,
|
|
@@ -25724,18 +26423,18 @@ async function detectSystemDeps(env = process3.env) {
|
|
|
25724
26423
|
// src/system/init-onboarding.ts
|
|
25725
26424
|
import { execFileSync } from "child_process";
|
|
25726
26425
|
import { promises as fs2 } from "fs";
|
|
25727
|
-
import
|
|
25728
|
-
import
|
|
26426
|
+
import path48 from "path";
|
|
26427
|
+
import process5 from "process";
|
|
25729
26428
|
import { stdin, stdout } from "process";
|
|
25730
26429
|
import { createInterface } from "readline/promises";
|
|
25731
26430
|
var ALL_PLATFORMS = Object.keys(PLATFORM_INSTALLERS);
|
|
25732
26431
|
var cachedNativeSystemLocale;
|
|
25733
|
-
function detectInitLocale(override, environment =
|
|
26432
|
+
function detectInitLocale(override, environment = process5.env, systemLocale = Intl.DateTimeFormat().resolvedOptions().locale, nativeLocale) {
|
|
25734
26433
|
if (override) return parseLocale(override);
|
|
25735
26434
|
const resolvedNativeLocale = nativeLocale === void 0 ? getNativeSystemLocale() : nativeLocale;
|
|
25736
26435
|
return parseLocale(resolvedNativeLocale) ?? detectEnvironmentLocale(environment) ?? parseLocale(systemLocale) ?? "en";
|
|
25737
26436
|
}
|
|
25738
|
-
function detectNativeSystemLocale(platform =
|
|
26437
|
+
function detectNativeSystemLocale(platform = process5.platform, runCommand = runLocaleCommand) {
|
|
25739
26438
|
if (platform === "darwin") {
|
|
25740
26439
|
const languages = runCommand("defaults", ["read", "-g", "AppleLanguages"]);
|
|
25741
26440
|
const primaryLanguage = parsePrimaryAppleLanguage(languages);
|
|
@@ -25819,7 +26518,7 @@ function parsePlatformSelection(value) {
|
|
|
25819
26518
|
}
|
|
25820
26519
|
return [...new Set(choices)];
|
|
25821
26520
|
}
|
|
25822
|
-
async function detectPlatformHints(rootDir, environment =
|
|
26521
|
+
async function detectPlatformHints(rootDir, environment = process5.env) {
|
|
25823
26522
|
const hints = /* @__PURE__ */ new Set();
|
|
25824
26523
|
if (environment.CLAUDECODE || environment.CLAUDE_CODE)
|
|
25825
26524
|
hints.add("claude-code");
|
|
@@ -25827,17 +26526,17 @@ async function detectPlatformHints(rootDir, environment = process4.env) {
|
|
|
25827
26526
|
if (environment.CURSOR_TRACE_ID) hints.add("cursor");
|
|
25828
26527
|
if (environment.COPILOT_AGENT || environment.GITHUB_COPILOT)
|
|
25829
26528
|
hints.add("copilot");
|
|
25830
|
-
const
|
|
26529
|
+
const exists2 = async (relative) => {
|
|
25831
26530
|
try {
|
|
25832
|
-
await fs2.access(
|
|
26531
|
+
await fs2.access(path48.join(rootDir, relative));
|
|
25833
26532
|
return true;
|
|
25834
26533
|
} catch {
|
|
25835
26534
|
return false;
|
|
25836
26535
|
}
|
|
25837
26536
|
};
|
|
25838
|
-
if (await
|
|
25839
|
-
if (await
|
|
25840
|
-
if (await
|
|
26537
|
+
if (await exists2(".claude")) hints.add("claude-code");
|
|
26538
|
+
if (await exists2(".cursor")) hints.add("cursor");
|
|
26539
|
+
if (await exists2(".github/copilot-instructions.md")) hints.add("copilot");
|
|
25841
26540
|
return ALL_PLATFORMS.filter((platform) => hints.has(platform));
|
|
25842
26541
|
}
|
|
25843
26542
|
function createTerminalPrompter() {
|
|
@@ -25905,10 +26604,10 @@ function createTerminalPrompter() {
|
|
|
25905
26604
|
|
|
25906
26605
|
// src/system/scan-aesthetics.ts
|
|
25907
26606
|
import { promises as fs3 } from "fs";
|
|
25908
|
-
import
|
|
26607
|
+
import path49 from "path";
|
|
25909
26608
|
var MAX_COMPONENT_SCAN_DEPTH = 12;
|
|
25910
26609
|
var MAX_COMPONENT_FILES = 2e3;
|
|
25911
|
-
async function scanAesthetics(projectRoot, uiLibrary = null) {
|
|
26610
|
+
async function scanAesthetics(projectRoot, uiLibrary = null, scopeRoot = ".") {
|
|
25912
26611
|
const sourceFiles = [];
|
|
25913
26612
|
const configResult = await findTailwindConfig(projectRoot);
|
|
25914
26613
|
let colors = {};
|
|
@@ -25941,12 +26640,13 @@ async function scanAesthetics(projectRoot, uiLibrary = null) {
|
|
|
25941
26640
|
} else if (await hasTailwindDep(projectRoot) || uiLibrary) {
|
|
25942
26641
|
matchLevel = "low";
|
|
25943
26642
|
}
|
|
25944
|
-
if (uiLibrary && await pathExists5(
|
|
26643
|
+
if (uiLibrary && await pathExists5(path49.join(projectRoot, "package.json"))) {
|
|
25945
26644
|
sourceFiles.push("package.json");
|
|
25946
26645
|
}
|
|
25947
26646
|
sourceFiles.push(...cssScan.sourceFiles);
|
|
25948
26647
|
return {
|
|
25949
26648
|
version: "1.0.0",
|
|
26649
|
+
scopeRoot,
|
|
25950
26650
|
lastScanned: (/* @__PURE__ */ new Date()).toISOString(),
|
|
25951
26651
|
colors,
|
|
25952
26652
|
fonts,
|
|
@@ -25966,7 +26666,7 @@ async function findTailwindConfig(projectRoot) {
|
|
|
25966
26666
|
"tailwind.config.mjs"
|
|
25967
26667
|
];
|
|
25968
26668
|
for (const name of candidates) {
|
|
25969
|
-
const absPath =
|
|
26669
|
+
const absPath = path49.join(projectRoot, name);
|
|
25970
26670
|
if (await pathExists5(absPath)) {
|
|
25971
26671
|
return { absPath, relPath: name };
|
|
25972
26672
|
}
|
|
@@ -26193,7 +26893,7 @@ async function scanComponents(projectRoot) {
|
|
|
26193
26893
|
const names = /* @__PURE__ */ new Set();
|
|
26194
26894
|
let visitedFiles = 0;
|
|
26195
26895
|
for (const relRoot of roots) {
|
|
26196
|
-
const absRoot =
|
|
26896
|
+
const absRoot = path49.join(projectRoot, relRoot);
|
|
26197
26897
|
if (!await pathExists5(absRoot)) continue;
|
|
26198
26898
|
visitedFiles = await collectComponentNames(absRoot, names, 0, visitedFiles);
|
|
26199
26899
|
if (visitedFiles >= MAX_COMPONENT_FILES) break;
|
|
@@ -26213,7 +26913,7 @@ async function collectComponentNames(dir, names, depth, visitedFiles) {
|
|
|
26213
26913
|
}
|
|
26214
26914
|
for (const entry of entries) {
|
|
26215
26915
|
if (fileCount >= MAX_COMPONENT_FILES) return fileCount;
|
|
26216
|
-
const abs =
|
|
26916
|
+
const abs = path49.join(dir, entry);
|
|
26217
26917
|
let info;
|
|
26218
26918
|
try {
|
|
26219
26919
|
info = await fs3.lstat(abs);
|
|
@@ -26234,7 +26934,7 @@ async function collectComponentNames(dir, names, depth, visitedFiles) {
|
|
|
26234
26934
|
""
|
|
26235
26935
|
);
|
|
26236
26936
|
if (base === "index") {
|
|
26237
|
-
base =
|
|
26937
|
+
base = path49.basename(dir);
|
|
26238
26938
|
}
|
|
26239
26939
|
if (base.startsWith(".")) continue;
|
|
26240
26940
|
const componentName = toPascalCase(base);
|
|
@@ -26256,7 +26956,7 @@ async function scanCssVariables(projectRoot) {
|
|
|
26256
26956
|
const variables = {};
|
|
26257
26957
|
const sourceFiles = [];
|
|
26258
26958
|
for (const relPath of candidates) {
|
|
26259
|
-
const absPath =
|
|
26959
|
+
const absPath = path49.join(projectRoot, relPath);
|
|
26260
26960
|
if (!await pathExists5(absPath)) continue;
|
|
26261
26961
|
const content = await fs3.readFile(absPath, "utf-8");
|
|
26262
26962
|
const found = extractCssVariables(content);
|
|
@@ -26302,7 +27002,7 @@ function toPascalCase(value) {
|
|
|
26302
27002
|
async function hasTailwindDep(projectRoot) {
|
|
26303
27003
|
try {
|
|
26304
27004
|
const raw = await fs3.readFile(
|
|
26305
|
-
|
|
27005
|
+
path49.join(projectRoot, "package.json"),
|
|
26306
27006
|
"utf-8"
|
|
26307
27007
|
);
|
|
26308
27008
|
const pkg = JSON.parse(raw);
|
|
@@ -26327,15 +27027,15 @@ async function pathExists5(p) {
|
|
|
26327
27027
|
|
|
26328
27028
|
// src/context/greenfield-init.ts
|
|
26329
27029
|
import {
|
|
26330
|
-
lstat as
|
|
26331
|
-
mkdir as
|
|
26332
|
-
readFile as
|
|
27030
|
+
lstat as lstat20,
|
|
27031
|
+
mkdir as mkdir34,
|
|
27032
|
+
readFile as readFile38,
|
|
26333
27033
|
rename as rename10,
|
|
26334
|
-
rm as
|
|
26335
|
-
writeFile as
|
|
27034
|
+
rm as rm18,
|
|
27035
|
+
writeFile as writeFile39
|
|
26336
27036
|
} from "fs/promises";
|
|
26337
|
-
import
|
|
26338
|
-
var JOURNAL_RELATIVE_DIRECTORY =
|
|
27037
|
+
import path50 from "path";
|
|
27038
|
+
var JOURNAL_RELATIVE_DIRECTORY = path50.join(
|
|
26339
27039
|
"local",
|
|
26340
27040
|
"runtime",
|
|
26341
27041
|
"initialization"
|
|
@@ -26358,7 +27058,7 @@ async function stageGreenfieldInitialization(input) {
|
|
|
26358
27058
|
normalized.operationId
|
|
26359
27059
|
);
|
|
26360
27060
|
try {
|
|
26361
|
-
await
|
|
27061
|
+
await mkdir34(stagingRoot);
|
|
26362
27062
|
} catch (error) {
|
|
26363
27063
|
if (isAlreadyExists22(error)) {
|
|
26364
27064
|
throw new Error("MANCODE_GREENFIELD_STAGING_EXISTS");
|
|
@@ -26384,7 +27084,7 @@ async function stageGreenfieldInitialization(input) {
|
|
|
26384
27084
|
operationId: normalized.operationId,
|
|
26385
27085
|
workspaceId: normalized.workspaceId,
|
|
26386
27086
|
state: "staged",
|
|
26387
|
-
stagingDirectoryName:
|
|
27087
|
+
stagingDirectoryName: path50.basename(stagingRoot),
|
|
26388
27088
|
targetDirectoryName: ".mancode",
|
|
26389
27089
|
manifestDigest: digestCanonicalJson(manifest),
|
|
26390
27090
|
configDigest: digestCanonicalJson(config),
|
|
@@ -26415,7 +27115,7 @@ async function stageGreenfieldInitialization(input) {
|
|
|
26415
27115
|
return journal;
|
|
26416
27116
|
}
|
|
26417
27117
|
async function publishGreenfieldInitialization(input) {
|
|
26418
|
-
const root =
|
|
27118
|
+
const root = path50.resolve(input.projectRoot);
|
|
26419
27119
|
assertUlid(input.operationId, "greenfield operationId");
|
|
26420
27120
|
const stagingRoot = greenfieldStagingPath(root, input.operationId);
|
|
26421
27121
|
const targetRoot = greenfieldTargetPath(root);
|
|
@@ -26450,10 +27150,10 @@ async function initializeGreenfield(input, publication) {
|
|
|
26450
27150
|
}
|
|
26451
27151
|
function greenfieldStagingPath(projectRoot, operationId) {
|
|
26452
27152
|
assertUlid(operationId, "greenfield operationId");
|
|
26453
|
-
return
|
|
27153
|
+
return path50.join(path50.resolve(projectRoot), `.mancode.init-${operationId}`);
|
|
26454
27154
|
}
|
|
26455
27155
|
function greenfieldTargetPath(projectRoot) {
|
|
26456
|
-
return
|
|
27156
|
+
return path50.join(path50.resolve(projectRoot), ".mancode");
|
|
26457
27157
|
}
|
|
26458
27158
|
function parseGreenfieldInitializationJournal(value) {
|
|
26459
27159
|
assertRecord(value, "greenfield initialization journal");
|
|
@@ -26589,7 +27289,7 @@ async function finishPublishedInitialization(input, stagedJournal) {
|
|
|
26589
27289
|
activatedAt: (input.now ?? /* @__PURE__ */ new Date()).toISOString()
|
|
26590
27290
|
};
|
|
26591
27291
|
assertSchemaManifestTransition(manifest, activeManifest);
|
|
26592
|
-
await writeJson(
|
|
27292
|
+
await writeJson(path50.join(targetRoot, "schema.json"), activeManifest);
|
|
26593
27293
|
throwIfOperationCrashInjected(
|
|
26594
27294
|
"greenfield_initialize",
|
|
26595
27295
|
"activate-v3-manifest"
|
|
@@ -26605,46 +27305,46 @@ async function finishPublishedInitialization(input, stagedJournal) {
|
|
|
26605
27305
|
}
|
|
26606
27306
|
async function writeGreenfieldLayout(stagingRoot, manifest, config, policy, projectFacts, journal) {
|
|
26607
27307
|
await Promise.all([
|
|
26608
|
-
|
|
26609
|
-
|
|
27308
|
+
mkdir34(path50.join(stagingRoot, "shared", "context"), { recursive: true }),
|
|
27309
|
+
mkdir34(path50.join(stagingRoot, "shared", "memory", "decisions"), {
|
|
26610
27310
|
recursive: true
|
|
26611
27311
|
}),
|
|
26612
|
-
|
|
27312
|
+
mkdir34(path50.join(stagingRoot, "shared", "team", "actors"), {
|
|
26613
27313
|
recursive: true
|
|
26614
27314
|
}),
|
|
26615
|
-
|
|
27315
|
+
mkdir34(path50.join(stagingRoot, "shared", "team", "handoffs"), {
|
|
26616
27316
|
recursive: true
|
|
26617
27317
|
}),
|
|
26618
|
-
|
|
27318
|
+
mkdir34(path50.join(stagingRoot, "shared", "team", "events"), {
|
|
26619
27319
|
recursive: true
|
|
26620
27320
|
}),
|
|
26621
|
-
|
|
27321
|
+
mkdir34(path50.join(stagingRoot, "shared", "team", "transport"), {
|
|
26622
27322
|
recursive: true
|
|
26623
27323
|
}),
|
|
26624
|
-
|
|
26625
|
-
|
|
27324
|
+
mkdir34(path50.join(stagingRoot, "local", "sessions"), { recursive: true }),
|
|
27325
|
+
mkdir34(path50.join(stagingRoot, JOURNAL_RELATIVE_DIRECTORY), {
|
|
26626
27326
|
recursive: true
|
|
26627
27327
|
}),
|
|
26628
|
-
|
|
26629
|
-
|
|
26630
|
-
|
|
26631
|
-
|
|
26632
|
-
|
|
26633
|
-
|
|
27328
|
+
mkdir34(path50.join(stagingRoot, "local", "workflows"), { recursive: true }),
|
|
27329
|
+
mkdir34(path50.join(stagingRoot, "local", "overlays"), { recursive: true }),
|
|
27330
|
+
mkdir34(path50.join(stagingRoot, "local", "quarantine"), { recursive: true }),
|
|
27331
|
+
mkdir34(path50.join(stagingRoot, "local", "publish"), { recursive: true }),
|
|
27332
|
+
mkdir34(path50.join(stagingRoot, "local", "cache"), { recursive: true }),
|
|
27333
|
+
mkdir34(path50.join(stagingRoot, "runtime", "non-git", journal.workspaceId), {
|
|
26634
27334
|
recursive: true
|
|
26635
27335
|
})
|
|
26636
27336
|
]);
|
|
26637
27337
|
await Promise.all([
|
|
26638
|
-
writeJson(
|
|
26639
|
-
writeJson(
|
|
26640
|
-
writeJson(
|
|
27338
|
+
writeJson(path50.join(stagingRoot, "schema.json"), manifest),
|
|
27339
|
+
writeJson(path50.join(stagingRoot, "shared", "config.json"), config),
|
|
27340
|
+
writeJson(path50.join(stagingRoot, "shared", "team", "policy.json"), policy),
|
|
26641
27341
|
writeJson(
|
|
26642
|
-
|
|
27342
|
+
path50.join(stagingRoot, "shared", "context", "project.json"),
|
|
26643
27343
|
projectFacts
|
|
26644
27344
|
),
|
|
26645
27345
|
writeJson(journalPath2(stagingRoot, journal.operationId), journal),
|
|
26646
|
-
|
|
26647
|
-
|
|
27346
|
+
writeFile39(
|
|
27347
|
+
path50.join(stagingRoot, ".gitignore"),
|
|
26648
27348
|
`${V3_IGNORE.join("\n")}
|
|
26649
27349
|
`,
|
|
26650
27350
|
{ encoding: "utf8", flag: "wx" }
|
|
@@ -26653,14 +27353,14 @@ async function writeGreenfieldLayout(stagingRoot, manifest, config, policy, proj
|
|
|
26653
27353
|
}
|
|
26654
27354
|
async function readGreenfieldJournal(root, operationId) {
|
|
26655
27355
|
try {
|
|
26656
|
-
const raw = await
|
|
27356
|
+
const raw = await readFile38(journalPath2(root, operationId), "utf8");
|
|
26657
27357
|
const journal = parseGreenfieldInitializationJournal(JSON.parse(raw));
|
|
26658
27358
|
if (journal.operationId !== operationId) {
|
|
26659
27359
|
throw new Error("MANCODE_GREENFIELD_JOURNAL_CORRUPT");
|
|
26660
27360
|
}
|
|
26661
27361
|
return journal;
|
|
26662
27362
|
} catch (error) {
|
|
26663
|
-
if (error instanceof SyntaxError ||
|
|
27363
|
+
if (error instanceof SyntaxError || isNotFound28(error)) {
|
|
26664
27364
|
throw new Error("MANCODE_GREENFIELD_JOURNAL_CORRUPT");
|
|
26665
27365
|
}
|
|
26666
27366
|
throw error;
|
|
@@ -26669,10 +27369,10 @@ async function readGreenfieldJournal(root, operationId) {
|
|
|
26669
27369
|
async function readManifest(root) {
|
|
26670
27370
|
try {
|
|
26671
27371
|
return parseSchemaManifest(
|
|
26672
|
-
JSON.parse(await
|
|
27372
|
+
JSON.parse(await readFile38(path50.join(root, "schema.json"), "utf8"))
|
|
26673
27373
|
);
|
|
26674
27374
|
} catch (error) {
|
|
26675
|
-
if (error instanceof SyntaxError ||
|
|
27375
|
+
if (error instanceof SyntaxError || isNotFound28(error)) {
|
|
26676
27376
|
throw new Error("MANCODE_GREENFIELD_REPAIR_REQUIRED");
|
|
26677
27377
|
}
|
|
26678
27378
|
throw error;
|
|
@@ -26707,7 +27407,7 @@ async function readConfig(root) {
|
|
|
26707
27407
|
try {
|
|
26708
27408
|
config = parseProjectConfig(
|
|
26709
27409
|
JSON.parse(
|
|
26710
|
-
await
|
|
27410
|
+
await readFile38(path50.join(root, "shared", "config.json"), "utf8")
|
|
26711
27411
|
)
|
|
26712
27412
|
);
|
|
26713
27413
|
} catch (error) {
|
|
@@ -26723,8 +27423,8 @@ async function readPolicy(root) {
|
|
|
26723
27423
|
try {
|
|
26724
27424
|
policy = parseTeamPolicy(
|
|
26725
27425
|
JSON.parse(
|
|
26726
|
-
await
|
|
26727
|
-
|
|
27426
|
+
await readFile38(
|
|
27427
|
+
path50.join(root, "shared", "team", "policy.json"),
|
|
26728
27428
|
"utf8"
|
|
26729
27429
|
)
|
|
26730
27430
|
)
|
|
@@ -26741,14 +27441,14 @@ async function readProjectFactsAt(root) {
|
|
|
26741
27441
|
try {
|
|
26742
27442
|
return parseProjectFacts(
|
|
26743
27443
|
JSON.parse(
|
|
26744
|
-
await
|
|
26745
|
-
|
|
27444
|
+
await readFile38(
|
|
27445
|
+
path50.join(root, "shared", "context", "project.json"),
|
|
26746
27446
|
"utf8"
|
|
26747
27447
|
)
|
|
26748
27448
|
)
|
|
26749
27449
|
);
|
|
26750
27450
|
} catch (error) {
|
|
26751
|
-
if (error instanceof SyntaxError ||
|
|
27451
|
+
if (error instanceof SyntaxError || isNotFound28(error)) {
|
|
26752
27452
|
throw new Error("MANCODE_GREENFIELD_REPAIR_REQUIRED");
|
|
26753
27453
|
}
|
|
26754
27454
|
throw error;
|
|
@@ -26781,7 +27481,7 @@ function normalizeInput(input) {
|
|
|
26781
27481
|
parseSchemaManifest(manifest);
|
|
26782
27482
|
return {
|
|
26783
27483
|
...input,
|
|
26784
|
-
projectRoot:
|
|
27484
|
+
projectRoot: path50.resolve(input.projectRoot),
|
|
26785
27485
|
projectConfig: config,
|
|
26786
27486
|
teamPolicy: policy,
|
|
26787
27487
|
projectFacts: input.projectFacts === void 0 ? void 0 : parseProjectFacts(input.projectFacts)
|
|
@@ -26879,16 +27579,16 @@ function initializationProjectFacts(input, now) {
|
|
|
26879
27579
|
}
|
|
26880
27580
|
function journalPath2(root, operationId) {
|
|
26881
27581
|
assertUlid(operationId, "greenfield operationId");
|
|
26882
|
-
return
|
|
27582
|
+
return path50.join(root, JOURNAL_RELATIVE_DIRECTORY, `${operationId}.json`);
|
|
26883
27583
|
}
|
|
26884
27584
|
async function writeJson(target, value) {
|
|
26885
|
-
const directory =
|
|
26886
|
-
await
|
|
26887
|
-
const temporary =
|
|
27585
|
+
const directory = path50.dirname(target);
|
|
27586
|
+
await mkdir34(directory, { recursive: true });
|
|
27587
|
+
const temporary = path50.join(
|
|
26888
27588
|
directory,
|
|
26889
|
-
`.${
|
|
27589
|
+
`.${path50.basename(target)}.${process.pid}.${Date.now()}.tmp`
|
|
26890
27590
|
);
|
|
26891
|
-
await
|
|
27591
|
+
await writeFile39(temporary, `${JSON.stringify(value, null, 2)}
|
|
26892
27592
|
`, {
|
|
26893
27593
|
encoding: "utf8",
|
|
26894
27594
|
flag: "wx"
|
|
@@ -26912,13 +27612,13 @@ function isState(value) {
|
|
|
26912
27612
|
}
|
|
26913
27613
|
async function lstatOrNull4(target) {
|
|
26914
27614
|
try {
|
|
26915
|
-
return await
|
|
27615
|
+
return await lstat20(target);
|
|
26916
27616
|
} catch (error) {
|
|
26917
|
-
if (
|
|
27617
|
+
if (isNotFound28(error)) return null;
|
|
26918
27618
|
throw error;
|
|
26919
27619
|
}
|
|
26920
27620
|
}
|
|
26921
|
-
function
|
|
27621
|
+
function isNotFound28(error) {
|
|
26922
27622
|
return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
|
|
26923
27623
|
}
|
|
26924
27624
|
function isAlreadyExists22(error) {
|
|
@@ -26989,7 +27689,7 @@ async function initializeV3Project(input) {
|
|
|
26989
27689
|
}
|
|
26990
27690
|
|
|
26991
27691
|
// src/commands/init.ts
|
|
26992
|
-
var
|
|
27692
|
+
var EXIT_OK2 = 0;
|
|
26993
27693
|
var EXIT_ALREADY_INITIALIZED = 1;
|
|
26994
27694
|
var EXIT_NOT_A_PROJECT_DIR = 2;
|
|
26995
27695
|
var EXIT_USER_CANCEL = 3;
|
|
@@ -27000,15 +27700,15 @@ function resolveInitAuthority(options) {
|
|
|
27000
27700
|
if (options.v3 || options.fromCli) return "v3";
|
|
27001
27701
|
return "legacy";
|
|
27002
27702
|
}
|
|
27003
|
-
async function init(rootDir =
|
|
27703
|
+
async function init(rootDir = process6.cwd(), options = {}) {
|
|
27004
27704
|
if (options.v3 && options.legacy) {
|
|
27005
27705
|
console.error("\u2717 --v3 and --legacy cannot be used together.");
|
|
27006
27706
|
return EXIT_INIT_FAILED;
|
|
27007
27707
|
}
|
|
27008
27708
|
const authority = resolveInitAuthority(options);
|
|
27009
|
-
const mancodeDir =
|
|
27010
|
-
const stateFile =
|
|
27011
|
-
const v3SchemaFile =
|
|
27709
|
+
const mancodeDir = path51.join(rootDir, ".mancode");
|
|
27710
|
+
const stateFile = path51.join(mancodeDir, "state.json");
|
|
27711
|
+
const v3SchemaFile = path51.join(mancodeDir, "schema.json");
|
|
27012
27712
|
const wasInitialized = await pathExists6(stateFile);
|
|
27013
27713
|
let mutationSnapshots = [];
|
|
27014
27714
|
let directorySnapshots = [];
|
|
@@ -27076,7 +27776,7 @@ async function init(rootDir = process5.cwd(), options = {}) {
|
|
|
27076
27776
|
}
|
|
27077
27777
|
return initializeV3(rootDir, options);
|
|
27078
27778
|
}
|
|
27079
|
-
const isGitRepo = await pathExists6(
|
|
27779
|
+
const isGitRepo = await pathExists6(path51.join(rootDir, ".git"));
|
|
27080
27780
|
const hasManifest = await hasProjectManifest(rootDir);
|
|
27081
27781
|
let isGenericProject = false;
|
|
27082
27782
|
if (!isGitRepo && !hasManifest) {
|
|
@@ -27194,8 +27894,8 @@ async function init(rootDir = process5.cwd(), options = {}) {
|
|
|
27194
27894
|
const managedFiles = getInitManagedFilePaths(rootDir, selectedPlatforms);
|
|
27195
27895
|
mutationSnapshots = await snapshotFiles(managedFiles);
|
|
27196
27896
|
directorySnapshots = await snapshotDirectories(managedFiles, [
|
|
27197
|
-
|
|
27198
|
-
|
|
27897
|
+
path51.join(mancodeDir, "workflows"),
|
|
27898
|
+
path51.join(mancodeDir, "preseason-reports")
|
|
27199
27899
|
]);
|
|
27200
27900
|
const team = await detectTeamStatus(rootDir);
|
|
27201
27901
|
const platformMinimal = Object.fromEntries(
|
|
@@ -27256,7 +27956,7 @@ async function init(rootDir = process5.cwd(), options = {}) {
|
|
|
27256
27956
|
`;
|
|
27257
27957
|
await fs4.writeFile(stateFile, stateContent, "utf-8");
|
|
27258
27958
|
await fs4.writeFile(
|
|
27259
|
-
|
|
27959
|
+
path51.join(mancodeDir, "project-profile.json"),
|
|
27260
27960
|
`${JSON.stringify(profile, null, 2)}
|
|
27261
27961
|
`,
|
|
27262
27962
|
"utf-8"
|
|
@@ -27293,7 +27993,7 @@ async function init(rootDir = process5.cwd(), options = {}) {
|
|
|
27293
27993
|
)
|
|
27294
27994
|
);
|
|
27295
27995
|
const tokens = await scanAesthetics(rootDir, uiLibrary);
|
|
27296
|
-
const tokensPath =
|
|
27996
|
+
const tokensPath = path51.join(
|
|
27297
27997
|
mancodeDir,
|
|
27298
27998
|
"aesthetics",
|
|
27299
27999
|
"style-tokens.json"
|
|
@@ -27428,7 +28128,7 @@ async function init(rootDir = process5.cwd(), options = {}) {
|
|
|
27428
28128
|
)
|
|
27429
28129
|
);
|
|
27430
28130
|
}
|
|
27431
|
-
return
|
|
28131
|
+
return EXIT_OK2;
|
|
27432
28132
|
} catch (err) {
|
|
27433
28133
|
await restoreFiles(mutationSnapshots);
|
|
27434
28134
|
await removeNewEmptyDirectories(directorySnapshots);
|
|
@@ -27457,7 +28157,7 @@ async function initializeV3(rootDir, options) {
|
|
|
27457
28157
|
);
|
|
27458
28158
|
return EXIT_INIT_FAILED;
|
|
27459
28159
|
}
|
|
27460
|
-
const schemaPath =
|
|
28160
|
+
const schemaPath = path51.join(rootDir, ".mancode", "schema.json");
|
|
27461
28161
|
let existingV3 = false;
|
|
27462
28162
|
let registeredAdapters = /* @__PURE__ */ new Set();
|
|
27463
28163
|
if (await pathExists6(schemaPath)) {
|
|
@@ -27546,7 +28246,7 @@ async function initializeV3(rootDir, options) {
|
|
|
27546
28246
|
} else {
|
|
27547
28247
|
console.log(` mancode bootstrap: ${selectedPlatforms.join(", ")}`);
|
|
27548
28248
|
}
|
|
27549
|
-
return
|
|
28249
|
+
return EXIT_OK2;
|
|
27550
28250
|
} catch (error) {
|
|
27551
28251
|
printV3InitError(error);
|
|
27552
28252
|
return EXIT_INIT_FAILED;
|
|
@@ -27560,7 +28260,7 @@ function printV3InitError(error) {
|
|
|
27560
28260
|
}
|
|
27561
28261
|
}
|
|
27562
28262
|
async function updateConfigOptions(mancodeDir, patch, preserveInstalledPlatforms) {
|
|
27563
|
-
const configPath =
|
|
28263
|
+
const configPath = path51.join(mancodeDir, "config.json");
|
|
27564
28264
|
let config = {};
|
|
27565
28265
|
try {
|
|
27566
28266
|
config = JSON.parse(await fs4.readFile(configPath, "utf-8"));
|
|
@@ -27569,7 +28269,7 @@ async function updateConfigOptions(mancodeDir, patch, preserveInstalledPlatforms
|
|
|
27569
28269
|
const existingPlatforms = Array.isArray(config.platforms) ? config.platforms.filter(
|
|
27570
28270
|
(platform) => typeof platform === "string"
|
|
27571
28271
|
) : [];
|
|
27572
|
-
const existingPlatformOptions =
|
|
28272
|
+
const existingPlatformOptions = isRecord8(config.platformOptions) ? config.platformOptions : {};
|
|
27573
28273
|
const definedPatch = Object.fromEntries(
|
|
27574
28274
|
Object.entries(patch).filter(([, value]) => value !== void 0)
|
|
27575
28275
|
);
|
|
@@ -27593,7 +28293,7 @@ async function updateConfigOptions(mancodeDir, patch, preserveInstalledPlatforms
|
|
|
27593
28293
|
async function readExistingInitPreferences(mancodeDir) {
|
|
27594
28294
|
try {
|
|
27595
28295
|
const config = JSON.parse(
|
|
27596
|
-
await fs4.readFile(
|
|
28296
|
+
await fs4.readFile(path51.join(mancodeDir, "config.json"), "utf-8")
|
|
27597
28297
|
);
|
|
27598
28298
|
const preferences = {
|
|
27599
28299
|
platforms: Array.isArray(config.platforms) ? config.platforms.filter(
|
|
@@ -27607,10 +28307,10 @@ async function readExistingInitPreferences(mancodeDir) {
|
|
|
27607
28307
|
if (config.teamMode === "auto" || config.teamMode === "on" || config.teamMode === "off") {
|
|
27608
28308
|
preferences.teamMode = config.teamMode;
|
|
27609
28309
|
}
|
|
27610
|
-
if (
|
|
28310
|
+
if (isRecord8(config.platformOptions)) {
|
|
27611
28311
|
for (const platform of preferences.platforms) {
|
|
27612
28312
|
const platformOptions = config.platformOptions[platform];
|
|
27613
|
-
if (
|
|
28313
|
+
if (isRecord8(platformOptions) && platformOptions.minimal === true) {
|
|
27614
28314
|
preferences.minimalByPlatform[platform] = true;
|
|
27615
28315
|
}
|
|
27616
28316
|
}
|
|
@@ -27659,13 +28359,13 @@ async function selectInitPlatforms(input) {
|
|
|
27659
28359
|
}
|
|
27660
28360
|
async function hasProjectManifest(rootDir) {
|
|
27661
28361
|
for (const name of PROJECT_MANIFESTS) {
|
|
27662
|
-
if (await pathExists6(
|
|
28362
|
+
if (await pathExists6(path51.join(rootDir, name))) return true;
|
|
27663
28363
|
}
|
|
27664
28364
|
return false;
|
|
27665
28365
|
}
|
|
27666
28366
|
async function canInitializeGenericProject(rootDir) {
|
|
27667
|
-
const resolved =
|
|
27668
|
-
if (resolved ===
|
|
28367
|
+
const resolved = path51.resolve(rootDir);
|
|
28368
|
+
if (resolved === path51.parse(resolved).root || resolved === path51.resolve(os.homedir())) {
|
|
27669
28369
|
return { ok: false, reason: "unsafe" };
|
|
27670
28370
|
}
|
|
27671
28371
|
try {
|
|
@@ -27679,11 +28379,11 @@ async function canInitializeGenericProject(rootDir) {
|
|
|
27679
28379
|
}
|
|
27680
28380
|
}
|
|
27681
28381
|
async function validateV3CliProjectBoundary(rootDir, options, locale, legacyInitialized) {
|
|
27682
|
-
const isGitRepo = await pathExists6(
|
|
28382
|
+
const isGitRepo = await pathExists6(path51.join(rootDir, ".git"));
|
|
27683
28383
|
const hasManifest = await hasProjectManifest(rootDir);
|
|
27684
28384
|
if (isGitRepo || hasManifest) return null;
|
|
27685
28385
|
const v3Initialized = await pathExists6(
|
|
27686
|
-
|
|
28386
|
+
path51.join(rootDir, ".mancode", "schema.json")
|
|
27687
28387
|
);
|
|
27688
28388
|
const legacyAuthorityPresent = legacyInitialized || (await scanLegacyAuthority(rootDir)).authorityPresent;
|
|
27689
28389
|
const genericSafety = await canInitializeGenericProject(rootDir);
|
|
@@ -27812,7 +28512,7 @@ function getInitManagedFilePaths(rootDir, platforms) {
|
|
|
27812
28512
|
files.push(`.github/prompts/${mode}.prompt.md`);
|
|
27813
28513
|
}
|
|
27814
28514
|
}
|
|
27815
|
-
return [...new Set(files.map((file) =>
|
|
28515
|
+
return [...new Set(files.map((file) => path51.join(rootDir, file)))];
|
|
27816
28516
|
}
|
|
27817
28517
|
async function snapshotFiles(filePaths) {
|
|
27818
28518
|
return Promise.all(
|
|
@@ -27831,10 +28531,10 @@ async function snapshotFiles(filePaths) {
|
|
|
27831
28531
|
async function snapshotDirectories(filePaths, additionalDirectories = []) {
|
|
27832
28532
|
const directories = new Set(additionalDirectories);
|
|
27833
28533
|
for (const filePath of filePaths) {
|
|
27834
|
-
let current =
|
|
27835
|
-
while (current !==
|
|
28534
|
+
let current = path51.dirname(filePath);
|
|
28535
|
+
while (current !== path51.dirname(current)) {
|
|
27836
28536
|
directories.add(current);
|
|
27837
|
-
current =
|
|
28537
|
+
current = path51.dirname(current);
|
|
27838
28538
|
}
|
|
27839
28539
|
}
|
|
27840
28540
|
return Promise.all(
|
|
@@ -27850,7 +28550,7 @@ async function restoreFiles(snapshots) {
|
|
|
27850
28550
|
await fs4.rm(snapshot.filePath, { force: true });
|
|
27851
28551
|
continue;
|
|
27852
28552
|
}
|
|
27853
|
-
await fs4.mkdir(
|
|
28553
|
+
await fs4.mkdir(path51.dirname(snapshot.filePath), { recursive: true });
|
|
27854
28554
|
await fs4.writeFile(snapshot.filePath, snapshot.content, "utf-8");
|
|
27855
28555
|
}
|
|
27856
28556
|
}
|
|
@@ -27863,7 +28563,7 @@ async function removeNewEmptyDirectories(snapshots) {
|
|
|
27863
28563
|
}
|
|
27864
28564
|
}
|
|
27865
28565
|
}
|
|
27866
|
-
function
|
|
28566
|
+
function isRecord8(value) {
|
|
27867
28567
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
27868
28568
|
}
|
|
27869
28569
|
function isNodeError6(error) {
|
|
@@ -27917,15 +28617,15 @@ async function pathExists6(p) {
|
|
|
27917
28617
|
|
|
27918
28618
|
// src/commands/install.ts
|
|
27919
28619
|
import { promises as fs5 } from "fs";
|
|
27920
|
-
import
|
|
27921
|
-
import
|
|
27922
|
-
var
|
|
27923
|
-
var
|
|
28620
|
+
import path52 from "path";
|
|
28621
|
+
import process7 from "process";
|
|
28622
|
+
var EXIT_OK3 = 0;
|
|
28623
|
+
var EXIT_NOT_INITIALIZED2 = 1;
|
|
27924
28624
|
var EXIT_UNSUPPORTED_PLATFORM = 2;
|
|
27925
28625
|
var EXIT_INSTALL_FAILED = 3;
|
|
27926
|
-
async function install(rootDir =
|
|
27927
|
-
const stateFile =
|
|
27928
|
-
const v3SchemaFile =
|
|
28626
|
+
async function install(rootDir = process7.cwd(), platform = "claude-code", options = {}) {
|
|
28627
|
+
const stateFile = path52.join(rootDir, ".mancode", "state.json");
|
|
28628
|
+
const v3SchemaFile = path52.join(rootDir, ".mancode", "schema.json");
|
|
27929
28629
|
if (await pathExists7(v3SchemaFile)) {
|
|
27930
28630
|
return installV3(rootDir, platform, options);
|
|
27931
28631
|
}
|
|
@@ -27939,7 +28639,7 @@ async function install(rootDir = process6.cwd(), platform = "claude-code", optio
|
|
|
27939
28639
|
if (!await pathExists7(stateFile)) {
|
|
27940
28640
|
console.error("\u2717 mancode not initialized.");
|
|
27941
28641
|
console.error(" Run `mancode init` first.");
|
|
27942
|
-
return
|
|
28642
|
+
return EXIT_NOT_INITIALIZED2;
|
|
27943
28643
|
}
|
|
27944
28644
|
const installer = getPlatformInstaller(platform);
|
|
27945
28645
|
if (!installer) {
|
|
@@ -27972,7 +28672,7 @@ async function install(rootDir = process6.cwd(), platform = "claude-code", optio
|
|
|
27972
28672
|
`\u2139\uFE0F ${formatPlatformName(platform)} adapter already installed.`
|
|
27973
28673
|
);
|
|
27974
28674
|
console.log(" Run with --force to reinstall.");
|
|
27975
|
-
return
|
|
28675
|
+
return EXIT_OK3;
|
|
27976
28676
|
}
|
|
27977
28677
|
console.log(
|
|
27978
28678
|
`\u2139\uFE0F ${formatPlatformName(platform)} adapter already installed; switching to minimal install.`
|
|
@@ -28014,7 +28714,7 @@ async function install(rootDir = process6.cwd(), platform = "claude-code", optio
|
|
|
28014
28714
|
})
|
|
28015
28715
|
});
|
|
28016
28716
|
console.log(`\u2713 ${formatPlatformName(platform)} adapter installed.`);
|
|
28017
|
-
return
|
|
28717
|
+
return EXIT_OK3;
|
|
28018
28718
|
}
|
|
28019
28719
|
async function installV3(rootDir, platform, options) {
|
|
28020
28720
|
const installer = getPlatformInstaller(platform);
|
|
@@ -28036,7 +28736,7 @@ async function installV3(rootDir, platform, options) {
|
|
|
28036
28736
|
for (const entry of staged.modeEntries) {
|
|
28037
28737
|
console.log(` ${entry.stagingTarget}`);
|
|
28038
28738
|
}
|
|
28039
|
-
return
|
|
28739
|
+
return EXIT_OK3;
|
|
28040
28740
|
}
|
|
28041
28741
|
if (project.manifest.activationState !== "v3_active") {
|
|
28042
28742
|
throw new Error("MANCODE_V3_ADAPTER_INSTALL_REQUIRES_ACTIVE");
|
|
@@ -28069,7 +28769,7 @@ async function installV3(rootDir, platform, options) {
|
|
|
28069
28769
|
);
|
|
28070
28770
|
for (const target of installed.filePlans)
|
|
28071
28771
|
console.log(` ${target.target}`);
|
|
28072
|
-
return
|
|
28772
|
+
return EXIT_OK3;
|
|
28073
28773
|
} catch (err) {
|
|
28074
28774
|
const message = err instanceof Error ? err.message : String(err);
|
|
28075
28775
|
console.error(
|
|
@@ -28086,7 +28786,7 @@ function printUnsupportedPlatform(platform) {
|
|
|
28086
28786
|
}
|
|
28087
28787
|
}
|
|
28088
28788
|
async function readConfig2(rootDir) {
|
|
28089
|
-
const configPath =
|
|
28789
|
+
const configPath = path52.join(rootDir, ".mancode", "config.json");
|
|
28090
28790
|
try {
|
|
28091
28791
|
const raw = await fs5.readFile(configPath, "utf-8");
|
|
28092
28792
|
return { config: JSON.parse(raw), valid: true };
|
|
@@ -28101,7 +28801,7 @@ function isNodeError7(err) {
|
|
|
28101
28801
|
return err instanceof Error && "code" in err;
|
|
28102
28802
|
}
|
|
28103
28803
|
async function updateConfig(rootDir, config) {
|
|
28104
|
-
const configPath =
|
|
28804
|
+
const configPath = path52.join(rootDir, ".mancode", "config.json");
|
|
28105
28805
|
const content = `${JSON.stringify(config, null, 2)}
|
|
28106
28806
|
`;
|
|
28107
28807
|
await fs5.writeFile(configPath, content, "utf-8");
|
|
@@ -28116,28 +28816,28 @@ function withDefaultConfig(config, fallbackPlatform) {
|
|
|
28116
28816
|
return {
|
|
28117
28817
|
...merged,
|
|
28118
28818
|
platforms,
|
|
28119
|
-
hooks:
|
|
28120
|
-
logging:
|
|
28819
|
+
hooks: isRecord9(config.hooks) ? config.hooks : DEFAULT_CONFIG.hooks,
|
|
28820
|
+
logging: isRecord9(config.logging) ? config.logging : DEFAULT_CONFIG.logging
|
|
28121
28821
|
};
|
|
28122
28822
|
}
|
|
28123
28823
|
function updatePlatformOptions(value, platform, options) {
|
|
28124
|
-
const platformOptions =
|
|
28824
|
+
const platformOptions = isRecord9(value) ? { ...value } : {};
|
|
28125
28825
|
const existing = platformOptions[platform];
|
|
28126
28826
|
platformOptions[platform] = {
|
|
28127
|
-
...
|
|
28827
|
+
...isRecord9(existing) ? existing : {},
|
|
28128
28828
|
minimal: options.minimal === true
|
|
28129
28829
|
};
|
|
28130
28830
|
return platformOptions;
|
|
28131
28831
|
}
|
|
28132
28832
|
function readConfiguredMinimal(value, platform) {
|
|
28133
|
-
if (!
|
|
28833
|
+
if (!isRecord9(value)) return false;
|
|
28134
28834
|
const platformOptions = value[platform];
|
|
28135
|
-
return
|
|
28835
|
+
return isRecord9(platformOptions) && platformOptions.minimal === true;
|
|
28136
28836
|
}
|
|
28137
28837
|
async function readStatePlatform(rootDir) {
|
|
28138
28838
|
try {
|
|
28139
28839
|
const raw = await fs5.readFile(
|
|
28140
|
-
|
|
28840
|
+
path52.join(rootDir, ".mancode", "state.json"),
|
|
28141
28841
|
"utf-8"
|
|
28142
28842
|
);
|
|
28143
28843
|
const state = JSON.parse(raw);
|
|
@@ -28154,17 +28854,17 @@ async function pathExists7(p) {
|
|
|
28154
28854
|
return false;
|
|
28155
28855
|
}
|
|
28156
28856
|
}
|
|
28157
|
-
function
|
|
28857
|
+
function isRecord9(value) {
|
|
28158
28858
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
28159
28859
|
}
|
|
28160
28860
|
|
|
28161
28861
|
// src/commands/list-platforms.ts
|
|
28162
28862
|
import { promises as fs6 } from "fs";
|
|
28163
|
-
import
|
|
28164
|
-
import
|
|
28165
|
-
var
|
|
28166
|
-
async function listPlatforms(rootDir =
|
|
28167
|
-
if (await pathExists8(
|
|
28863
|
+
import path53 from "path";
|
|
28864
|
+
import process8 from "process";
|
|
28865
|
+
var EXIT_OK4 = 0;
|
|
28866
|
+
async function listPlatforms(rootDir = process8.cwd()) {
|
|
28867
|
+
if (await pathExists8(path53.join(rootDir, ".mancode", "schema.json"))) {
|
|
28168
28868
|
return listV3Platforms(rootDir);
|
|
28169
28869
|
}
|
|
28170
28870
|
const installed = new Set(await readInstalledPlatforms(rootDir));
|
|
@@ -28175,7 +28875,7 @@ async function listPlatforms(rootDir = process7.cwd()) {
|
|
|
28175
28875
|
console.log(formatPlatformLine(platform, installed.has(platform.name)));
|
|
28176
28876
|
}
|
|
28177
28877
|
console.log("");
|
|
28178
|
-
return
|
|
28878
|
+
return EXIT_OK4;
|
|
28179
28879
|
}
|
|
28180
28880
|
async function listV3Platforms(rootDir) {
|
|
28181
28881
|
const platforms = getPlatformInstallers();
|
|
@@ -28195,12 +28895,12 @@ async function listV3Platforms(rootDir) {
|
|
|
28195
28895
|
);
|
|
28196
28896
|
}
|
|
28197
28897
|
console.log("");
|
|
28198
|
-
return
|
|
28898
|
+
return EXIT_OK4;
|
|
28199
28899
|
}
|
|
28200
28900
|
async function readInstalledPlatforms(rootDir) {
|
|
28201
28901
|
try {
|
|
28202
28902
|
const raw = await fs6.readFile(
|
|
28203
|
-
|
|
28903
|
+
path53.join(rootDir, ".mancode", "config.json"),
|
|
28204
28904
|
"utf-8"
|
|
28205
28905
|
);
|
|
28206
28906
|
const config = JSON.parse(raw);
|
|
@@ -28232,8 +28932,8 @@ function describePlatform(platform) {
|
|
|
28232
28932
|
}
|
|
28233
28933
|
|
|
28234
28934
|
// src/commands/manps.ts
|
|
28235
|
-
import { access as access4, readFile as
|
|
28236
|
-
import
|
|
28935
|
+
import { access as access4, readFile as readFile40 } from "fs/promises";
|
|
28936
|
+
import path55 from "path";
|
|
28237
28937
|
import { createInterface as createInterface2 } from "readline/promises";
|
|
28238
28938
|
|
|
28239
28939
|
// src/system/preseason.ts
|
|
@@ -28242,14 +28942,14 @@ import { createHash as createHash8 } from "crypto";
|
|
|
28242
28942
|
import { existsSync, readFileSync } from "fs";
|
|
28243
28943
|
import {
|
|
28244
28944
|
access as access3,
|
|
28245
|
-
lstat as
|
|
28246
|
-
mkdir as
|
|
28247
|
-
readFile as
|
|
28945
|
+
lstat as lstat21,
|
|
28946
|
+
mkdir as mkdir35,
|
|
28947
|
+
readFile as readFile39,
|
|
28248
28948
|
readdir as readdir18,
|
|
28249
28949
|
rename as rename11,
|
|
28250
|
-
writeFile as
|
|
28950
|
+
writeFile as writeFile40
|
|
28251
28951
|
} from "fs/promises";
|
|
28252
|
-
import
|
|
28952
|
+
import path54 from "path";
|
|
28253
28953
|
var PRESEASON_AREAS = [
|
|
28254
28954
|
"all",
|
|
28255
28955
|
"deps",
|
|
@@ -28314,7 +29014,7 @@ var SCANNERS = [
|
|
|
28314
29014
|
{
|
|
28315
29015
|
name: "aesthetic-drift",
|
|
28316
29016
|
areas: ["all"],
|
|
28317
|
-
scan: ({ projectRoot, files }) => scanAestheticDrift(projectRoot, files)
|
|
29017
|
+
scan: ({ projectRoot, files, pkg }) => scanAestheticDrift(projectRoot, files, pkg)
|
|
28318
29018
|
},
|
|
28319
29019
|
{
|
|
28320
29020
|
name: "architecture",
|
|
@@ -28329,10 +29029,10 @@ async function runPreseasonScan(projectRoot, area = "all", options = {}) {
|
|
|
28329
29029
|
const needsFiles = normalizedArea === "all" || normalizedArea === "dead-code" || normalizedArea === "config";
|
|
28330
29030
|
const files = needsFiles ? await listProjectFiles(projectRoot) : [];
|
|
28331
29031
|
const issues = (await scanArea(projectRoot, normalizedArea, pkg, files)).slice(0, 20);
|
|
28332
|
-
const storageRoot = options.storageRoot ??
|
|
28333
|
-
const reportDir =
|
|
28334
|
-
await
|
|
28335
|
-
const issueDbPath =
|
|
29032
|
+
const storageRoot = options.storageRoot ?? path54.join(projectRoot, ".mancode");
|
|
29033
|
+
const reportDir = path54.join(storageRoot, "preseason-reports");
|
|
29034
|
+
await mkdir35(reportDir, { recursive: true });
|
|
29035
|
+
const issueDbPath = path54.join(storageRoot, "preseason-issues.json");
|
|
28336
29036
|
const reportPath = await allocateReportPath(
|
|
28337
29037
|
reportDir,
|
|
28338
29038
|
`${generatedAt.replace(/[:.]/g, "-")}-${normalizedArea}`
|
|
@@ -28346,9 +29046,9 @@ async function runPreseasonScan(projectRoot, area = "all", options = {}) {
|
|
|
28346
29046
|
issueDbPath
|
|
28347
29047
|
};
|
|
28348
29048
|
const database = await buildIssueDatabase(projectRoot, report);
|
|
28349
|
-
await
|
|
28350
|
-
await
|
|
28351
|
-
|
|
29049
|
+
await writeFile40(reportPath, renderPreseasonReport(report), "utf-8");
|
|
29050
|
+
await writeFile40(
|
|
29051
|
+
path54.join(storageRoot, "preseason-report.md"),
|
|
28352
29052
|
renderPreseasonReport(report),
|
|
28353
29053
|
"utf-8"
|
|
28354
29054
|
);
|
|
@@ -28356,7 +29056,7 @@ async function runPreseasonScan(projectRoot, area = "all", options = {}) {
|
|
|
28356
29056
|
return report;
|
|
28357
29057
|
}
|
|
28358
29058
|
async function runPreseasonRemediation(projectRoot, issues, options = {}) {
|
|
28359
|
-
const issueDbPath = options.issueDbPath ??
|
|
29059
|
+
const issueDbPath = options.issueDbPath ?? path54.join(projectRoot, ".mancode", "preseason-issues.json");
|
|
28360
29060
|
const database = await readIssueDatabase(issueDbPath);
|
|
28361
29061
|
const keys = new Set(issues.map((issue) => issueKey(issue)));
|
|
28362
29062
|
const targets = database.issues.filter(
|
|
@@ -28434,7 +29134,7 @@ async function runPreseasonRemediation(projectRoot, issues, options = {}) {
|
|
|
28434
29134
|
write2(" Decision: skipped.");
|
|
28435
29135
|
}
|
|
28436
29136
|
database.updatedAt = now;
|
|
28437
|
-
await
|
|
29137
|
+
await writeFile40(
|
|
28438
29138
|
issueDbPath,
|
|
28439
29139
|
`${JSON.stringify(database, null, 2)}
|
|
28440
29140
|
`,
|
|
@@ -28466,7 +29166,7 @@ async function scanArea(projectRoot, area, pkg, files) {
|
|
|
28466
29166
|
async function allocateReportPath(reportDir, baseName) {
|
|
28467
29167
|
for (let attempt = 0; attempt < 1e3; attempt++) {
|
|
28468
29168
|
const suffix = attempt === 0 ? "" : `-${attempt + 1}`;
|
|
28469
|
-
const candidate =
|
|
29169
|
+
const candidate = path54.join(reportDir, `${baseName}${suffix}.md`);
|
|
28470
29170
|
if (!existsSync(candidate)) return candidate;
|
|
28471
29171
|
}
|
|
28472
29172
|
throw new Error(`unable to allocate preseason report path: ${baseName}`);
|
|
@@ -28515,18 +29215,18 @@ async function walk(root, current, results, depth) {
|
|
|
28515
29215
|
}
|
|
28516
29216
|
for (const entry of entries) {
|
|
28517
29217
|
if (IGNORE_DIRS.has(entry)) continue;
|
|
28518
|
-
const abs =
|
|
28519
|
-
const rel =
|
|
29218
|
+
const abs = path54.join(current, entry);
|
|
29219
|
+
const rel = path54.relative(root, abs);
|
|
28520
29220
|
let info;
|
|
28521
29221
|
try {
|
|
28522
|
-
info = await
|
|
29222
|
+
info = await lstat21(abs);
|
|
28523
29223
|
} catch {
|
|
28524
29224
|
continue;
|
|
28525
29225
|
}
|
|
28526
29226
|
if (info.isSymbolicLink()) continue;
|
|
28527
29227
|
if (info.isDirectory()) {
|
|
28528
29228
|
await walk(root, abs, results, depth + 1);
|
|
28529
|
-
} else if (SOURCE_EXTENSIONS.has(
|
|
29229
|
+
} else if (SOURCE_EXTENSIONS.has(path54.extname(entry)) || entry === "package.json") {
|
|
28530
29230
|
results.push(rel);
|
|
28531
29231
|
if (results.length >= MAX_PROJECT_FILES) return;
|
|
28532
29232
|
}
|
|
@@ -28534,7 +29234,7 @@ async function walk(root, current, results, depth) {
|
|
|
28534
29234
|
}
|
|
28535
29235
|
async function readPackageJson(projectRoot) {
|
|
28536
29236
|
try {
|
|
28537
|
-
const raw = await
|
|
29237
|
+
const raw = await readFile39(path54.join(projectRoot, "package.json"), "utf-8");
|
|
28538
29238
|
return JSON.parse(raw);
|
|
28539
29239
|
} catch {
|
|
28540
29240
|
return null;
|
|
@@ -28627,7 +29327,7 @@ function scanTodos(projectRoot, files) {
|
|
|
28627
29327
|
const matches = [];
|
|
28628
29328
|
for (const file of files) {
|
|
28629
29329
|
if (matches.length >= 7) break;
|
|
28630
|
-
const abs =
|
|
29330
|
+
const abs = path54.join(projectRoot, file);
|
|
28631
29331
|
matches.push(...readTodoIssues(abs, file, matches.length));
|
|
28632
29332
|
}
|
|
28633
29333
|
return matches.slice(0, 7);
|
|
@@ -28668,7 +29368,7 @@ function scanTestGaps(files) {
|
|
|
28668
29368
|
if (sourceFiles.length === 0) return [];
|
|
28669
29369
|
const tests = new Set(files.filter((file) => file.startsWith("tests/")));
|
|
28670
29370
|
const missing = sourceFiles.filter((file) => {
|
|
28671
|
-
const base =
|
|
29371
|
+
const base = path54.basename(file).replace(/\.(ts|tsx|js|jsx)$/, "");
|
|
28672
29372
|
return !Array.from(tests).some((test) => test.includes(base));
|
|
28673
29373
|
}).slice(0, 4);
|
|
28674
29374
|
return missing.map((file, index) => ({
|
|
@@ -28677,13 +29377,13 @@ function scanTestGaps(files) {
|
|
|
28677
29377
|
type: "tests",
|
|
28678
29378
|
title: "Core source file has no obvious test",
|
|
28679
29379
|
file,
|
|
28680
|
-
detail: `No matching test file was found for ${
|
|
29380
|
+
detail: `No matching test file was found for ${path54.basename(file)}.`,
|
|
28681
29381
|
recommendation: "Add focused coverage for the public behavior or document why this module is exercised indirectly."
|
|
28682
29382
|
}));
|
|
28683
29383
|
}
|
|
28684
29384
|
function scanConfig(projectRoot, files) {
|
|
28685
29385
|
const issues = [];
|
|
28686
|
-
if (!files.includes(".gitignore") && !pathExistsSync(
|
|
29386
|
+
if (!files.includes(".gitignore") && !pathExistsSync(path54.join(projectRoot, ".gitignore"))) {
|
|
28687
29387
|
issues.push({
|
|
28688
29388
|
id: "config-gitignore",
|
|
28689
29389
|
severity: "P1",
|
|
@@ -28694,7 +29394,7 @@ function scanConfig(projectRoot, files) {
|
|
|
28694
29394
|
recommendation: "Add a .gitignore that excludes dependencies, build output, coverage, and local env files."
|
|
28695
29395
|
});
|
|
28696
29396
|
}
|
|
28697
|
-
if (!files.includes(".editorconfig") && !pathExistsSync(
|
|
29397
|
+
if (!files.includes(".editorconfig") && !pathExistsSync(path54.join(projectRoot, ".editorconfig"))) {
|
|
28698
29398
|
issues.push({
|
|
28699
29399
|
id: "config-editorconfig",
|
|
28700
29400
|
severity: "P2",
|
|
@@ -28707,13 +29407,13 @@ function scanConfig(projectRoot, files) {
|
|
|
28707
29407
|
}
|
|
28708
29408
|
return issues;
|
|
28709
29409
|
}
|
|
28710
|
-
function scanAestheticDrift(projectRoot, files) {
|
|
29410
|
+
function scanAestheticDrift(projectRoot, files, pkg) {
|
|
28711
29411
|
const issues = [];
|
|
28712
29412
|
const frontendFiles = files.filter((file) => /\.(tsx|jsx|css)$/.test(file));
|
|
28713
29413
|
for (const file of frontendFiles) {
|
|
28714
29414
|
let content;
|
|
28715
29415
|
try {
|
|
28716
|
-
content = readFileSyncSafe(
|
|
29416
|
+
content = readFileSyncSafe(path54.join(projectRoot, file));
|
|
28717
29417
|
} catch {
|
|
28718
29418
|
continue;
|
|
28719
29419
|
}
|
|
@@ -28730,10 +29430,41 @@ function scanAestheticDrift(projectRoot, files) {
|
|
|
28730
29430
|
break;
|
|
28731
29431
|
}
|
|
28732
29432
|
}
|
|
29433
|
+
const iconSystems = detectedIconSystems(pkg);
|
|
29434
|
+
if (iconSystems.length > 1) {
|
|
29435
|
+
issues.push({
|
|
29436
|
+
id: "aesthetics-mixed-icon-systems",
|
|
29437
|
+
severity: "P2",
|
|
29438
|
+
type: "aesthetics",
|
|
29439
|
+
title: "Multiple icon systems declared",
|
|
29440
|
+
file: "package.json",
|
|
29441
|
+
detail: `Multiple icon systems are declared: ${iconSystems.join(", ")}.`,
|
|
29442
|
+
recommendation: "Use the configured design policy for new interface work; remove a redundant package only after confirming it has no active imports."
|
|
29443
|
+
});
|
|
29444
|
+
}
|
|
28733
29445
|
return issues;
|
|
28734
29446
|
}
|
|
29447
|
+
function detectedIconSystems(pkg) {
|
|
29448
|
+
if (!pkg) return [];
|
|
29449
|
+
const packages = Object.keys({
|
|
29450
|
+
...pkg.dependencies,
|
|
29451
|
+
...pkg.devDependencies
|
|
29452
|
+
});
|
|
29453
|
+
const systems = [
|
|
29454
|
+
["Lucide", /^lucide(?:-|$)/],
|
|
29455
|
+
["Heroicons", /^@heroicons\//],
|
|
29456
|
+
[
|
|
29457
|
+
"Material Icons",
|
|
29458
|
+
/^(?:@mui\/icons-material|@material-design-icons\/|material-icons(?:-|$)|material-symbols(?:-|$))/
|
|
29459
|
+
],
|
|
29460
|
+
["Phosphor", /^(?:@phosphor-icons\/|phosphor-(?:react|icons)(?:-|$))/],
|
|
29461
|
+
["Font Awesome", /^@fortawesome\/(?:free|pro|sharp)-.+-svg-icons$/],
|
|
29462
|
+
["React Icons", /^react-icons$/]
|
|
29463
|
+
];
|
|
29464
|
+
return systems.filter(([, pattern]) => packages.some((name) => pattern.test(name))).map(([name]) => name);
|
|
29465
|
+
}
|
|
28735
29466
|
async function scanArchitecture(projectRoot) {
|
|
28736
|
-
const localBinary =
|
|
29467
|
+
const localBinary = path54.join(
|
|
28737
29468
|
projectRoot,
|
|
28738
29469
|
"node_modules",
|
|
28739
29470
|
".bin",
|
|
@@ -28781,7 +29512,7 @@ async function hasDependencyCruiserConfig(projectRoot) {
|
|
|
28781
29512
|
"dependency-cruiser.config.mjs"
|
|
28782
29513
|
];
|
|
28783
29514
|
const results = await Promise.all(
|
|
28784
|
-
files.map((file) => pathExists9(
|
|
29515
|
+
files.map((file) => pathExists9(path54.join(projectRoot, file)))
|
|
28785
29516
|
);
|
|
28786
29517
|
return results.some(Boolean);
|
|
28787
29518
|
}
|
|
@@ -28849,15 +29580,15 @@ function parseDepcruiseJson(output) {
|
|
|
28849
29580
|
}
|
|
28850
29581
|
}
|
|
28851
29582
|
function extractDepcruiseViolations(value) {
|
|
28852
|
-
if (!
|
|
28853
|
-
const rawViolations = Array.isArray(value.violations) ? value.violations :
|
|
29583
|
+
if (!isRecord10(value)) return [];
|
|
29584
|
+
const rawViolations = Array.isArray(value.violations) ? value.violations : isRecord10(value.summary) && Array.isArray(value.summary.violations) ? value.summary.violations : [];
|
|
28854
29585
|
return rawViolations.map((violation) => normalizeDepcruiseViolation(violation)).filter(
|
|
28855
29586
|
(violation) => violation !== null
|
|
28856
29587
|
);
|
|
28857
29588
|
}
|
|
28858
29589
|
function normalizeDepcruiseViolation(value) {
|
|
28859
|
-
if (!
|
|
28860
|
-
const rule =
|
|
29590
|
+
if (!isRecord10(value)) return null;
|
|
29591
|
+
const rule = isRecord10(value.rule) ? value.rule : {};
|
|
28861
29592
|
const from = typeof value.from === "string" ? value.from : "";
|
|
28862
29593
|
const to = typeof value.to === "string" ? value.to : void 0;
|
|
28863
29594
|
const ruleName = typeof rule.name === "string" ? rule.name : typeof value.name === "string" ? value.name : "unnamed-rule";
|
|
@@ -28887,9 +29618,9 @@ function inferCommands(pkg) {
|
|
|
28887
29618
|
return ["lint", "test", "build"].filter((name) => scripts[name]).map((name) => `npm run ${name}`);
|
|
28888
29619
|
}
|
|
28889
29620
|
async function buildIssueDatabase(projectRoot, report) {
|
|
28890
|
-
const reportRef =
|
|
29621
|
+
const reportRef = path54.relative(projectRoot, report.reportPath);
|
|
28891
29622
|
const run = {
|
|
28892
|
-
id:
|
|
29623
|
+
id: path54.basename(report.reportPath, ".md"),
|
|
28893
29624
|
generatedAt: report.generatedAt,
|
|
28894
29625
|
area: report.area,
|
|
28895
29626
|
reportPath: reportRef,
|
|
@@ -28931,7 +29662,7 @@ async function buildIssueDatabase(projectRoot, report) {
|
|
|
28931
29662
|
async function readIssueDatabase(issueDbPath) {
|
|
28932
29663
|
let raw;
|
|
28933
29664
|
try {
|
|
28934
|
-
raw = await
|
|
29665
|
+
raw = await readFile39(issueDbPath, "utf-8");
|
|
28935
29666
|
} catch (err) {
|
|
28936
29667
|
if (isNodeError8(err) && err.code === "ENOENT") {
|
|
28937
29668
|
return emptyIssueDatabase();
|
|
@@ -28952,7 +29683,7 @@ async function readIssueDatabase(issueDbPath) {
|
|
|
28952
29683
|
}
|
|
28953
29684
|
async function writeJsonAtomic3(file, value) {
|
|
28954
29685
|
const tmp = `${file}.tmp-${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
28955
|
-
await
|
|
29686
|
+
await writeFile40(tmp, `${JSON.stringify(value, null, 2)}
|
|
28956
29687
|
`, "utf-8");
|
|
28957
29688
|
await rename11(tmp, file);
|
|
28958
29689
|
}
|
|
@@ -28995,20 +29726,20 @@ function compareIssueRecords(a, b) {
|
|
|
28995
29726
|
}
|
|
28996
29727
|
async function applySafeRemediation(projectRoot, issue) {
|
|
28997
29728
|
if (issue.id === "config-gitignore" && issue.file === ".gitignore") {
|
|
28998
|
-
const gitignorePath =
|
|
29729
|
+
const gitignorePath = path54.join(projectRoot, ".gitignore");
|
|
28999
29730
|
if (pathExistsSync(gitignorePath)) {
|
|
29000
29731
|
return { applied: false };
|
|
29001
29732
|
}
|
|
29002
|
-
await
|
|
29733
|
+
await writeFile40(gitignorePath, `${DEFAULT_GITIGNORE}
|
|
29003
29734
|
`, "utf-8");
|
|
29004
29735
|
return { applied: true, action: "created .gitignore" };
|
|
29005
29736
|
}
|
|
29006
29737
|
if (issue.id === "config-editorconfig" && issue.file === ".editorconfig") {
|
|
29007
|
-
const editorconfigPath =
|
|
29738
|
+
const editorconfigPath = path54.join(projectRoot, ".editorconfig");
|
|
29008
29739
|
if (pathExistsSync(editorconfigPath)) {
|
|
29009
29740
|
return { applied: false };
|
|
29010
29741
|
}
|
|
29011
|
-
await
|
|
29742
|
+
await writeFile40(editorconfigPath, `${DEFAULT_EDITORCONFIG}
|
|
29012
29743
|
`, "utf-8");
|
|
29013
29744
|
return { applied: true, action: "created .editorconfig" };
|
|
29014
29745
|
}
|
|
@@ -29044,10 +29775,10 @@ async function inferSafePackageScript(projectRoot, scriptName) {
|
|
|
29044
29775
|
}
|
|
29045
29776
|
}
|
|
29046
29777
|
async function addPackageScript(projectRoot, scriptName, script) {
|
|
29047
|
-
const packagePath =
|
|
29778
|
+
const packagePath = path54.join(projectRoot, "package.json");
|
|
29048
29779
|
let pkg;
|
|
29049
29780
|
try {
|
|
29050
|
-
pkg = JSON.parse(await
|
|
29781
|
+
pkg = JSON.parse(await readFile39(packagePath, "utf-8"));
|
|
29051
29782
|
} catch {
|
|
29052
29783
|
return false;
|
|
29053
29784
|
}
|
|
@@ -29057,7 +29788,7 @@ async function addPackageScript(projectRoot, scriptName, script) {
|
|
|
29057
29788
|
...scripts,
|
|
29058
29789
|
[scriptName]: script
|
|
29059
29790
|
};
|
|
29060
|
-
await
|
|
29791
|
+
await writeFile40(packagePath, `${JSON.stringify(pkg, null, 2)}
|
|
29061
29792
|
`, "utf-8");
|
|
29062
29793
|
return true;
|
|
29063
29794
|
}
|
|
@@ -29147,17 +29878,17 @@ async function pathExists9(file) {
|
|
|
29147
29878
|
function isNodeError8(err) {
|
|
29148
29879
|
return err instanceof Error && "code" in err;
|
|
29149
29880
|
}
|
|
29150
|
-
function
|
|
29881
|
+
function isRecord10(value) {
|
|
29151
29882
|
return typeof value === "object" && value !== null;
|
|
29152
29883
|
}
|
|
29153
29884
|
|
|
29154
29885
|
// src/commands/manps.ts
|
|
29155
|
-
var
|
|
29156
|
-
var
|
|
29886
|
+
var EXIT_OK5 = 0;
|
|
29887
|
+
var EXIT_NOT_INITIALIZED3 = 1;
|
|
29157
29888
|
var EXIT_SCAN_FAILED = 2;
|
|
29158
29889
|
var EXIT_INVALID_ARG = 3;
|
|
29159
29890
|
async function manps(rootDir, area = "all", options = {}) {
|
|
29160
|
-
const v3SchemaPath =
|
|
29891
|
+
const v3SchemaPath = path55.join(rootDir, ".mancode", "schema.json");
|
|
29161
29892
|
const v3Activation = await readV3ActivationState(v3SchemaPath);
|
|
29162
29893
|
if (v3Activation !== null && v3Activation !== "v3_active" && v3Activation !== "dual_read") {
|
|
29163
29894
|
const message = `manps is unavailable while mancode activation is ${v3Activation}`;
|
|
@@ -29170,7 +29901,7 @@ async function manps(rootDir, area = "all", options = {}) {
|
|
|
29170
29901
|
return EXIT_SCAN_FAILED;
|
|
29171
29902
|
}
|
|
29172
29903
|
const v3Initialized = v3Activation === "v3_active";
|
|
29173
|
-
const initialized = v3Initialized || await pathExists10(
|
|
29904
|
+
const initialized = v3Initialized || await pathExists10(path55.join(rootDir, ".mancode", "state.json"));
|
|
29174
29905
|
if (!initialized) {
|
|
29175
29906
|
if (options.json) {
|
|
29176
29907
|
console.log(JSON.stringify({ error: "not initialized" }, null, 2));
|
|
@@ -29178,12 +29909,12 @@ async function manps(rootDir, area = "all", options = {}) {
|
|
|
29178
29909
|
console.error("\u2717 mancode not initialized.");
|
|
29179
29910
|
console.error(" Run `mancode init` first.");
|
|
29180
29911
|
}
|
|
29181
|
-
return
|
|
29912
|
+
return EXIT_NOT_INITIALIZED3;
|
|
29182
29913
|
}
|
|
29183
29914
|
let report;
|
|
29184
29915
|
try {
|
|
29185
29916
|
report = await runPreseasonScan(rootDir, area, {
|
|
29186
|
-
storageRoot: v3Initialized ?
|
|
29917
|
+
storageRoot: v3Initialized ? path55.join(rootDir, ".mancode", "local") : void 0
|
|
29187
29918
|
});
|
|
29188
29919
|
} catch (err) {
|
|
29189
29920
|
const message = err instanceof Error ? err.message : String(err);
|
|
@@ -29241,7 +29972,7 @@ async function manps(rootDir, area = "all", options = {}) {
|
|
|
29241
29972
|
}
|
|
29242
29973
|
if (options.json) {
|
|
29243
29974
|
console.log(JSON.stringify({ ...report, remediation }, null, 2));
|
|
29244
|
-
return
|
|
29975
|
+
return EXIT_OK5;
|
|
29245
29976
|
}
|
|
29246
29977
|
const p0 = report.issues.filter((issue) => issue.severity === "P0").length;
|
|
29247
29978
|
const p1 = report.issues.filter((issue) => issue.severity === "P1").length;
|
|
@@ -29252,8 +29983,8 @@ async function manps(rootDir, area = "all", options = {}) {
|
|
|
29252
29983
|
console.log(
|
|
29253
29984
|
`Issues: ${report.issues.length} total (P0 ${p0}, P1 ${p1}, P2 ${p2})`
|
|
29254
29985
|
);
|
|
29255
|
-
console.log(`Report: ${
|
|
29256
|
-
console.log(`Issue DB: ${
|
|
29986
|
+
console.log(`Report: ${path55.relative(rootDir, report.reportPath)}`);
|
|
29987
|
+
console.log(`Issue DB: ${path55.relative(rootDir, report.issueDbPath)}`);
|
|
29257
29988
|
if (report.issues.length > 0) {
|
|
29258
29989
|
console.log("");
|
|
29259
29990
|
for (const issue of report.issues.slice(0, 7)) {
|
|
@@ -29269,10 +30000,10 @@ async function manps(rootDir, area = "all", options = {}) {
|
|
|
29269
30000
|
console.log(` Skipped: ${remediation.skipped}`);
|
|
29270
30001
|
console.log(` Fixed: ${remediation.fixed}`);
|
|
29271
30002
|
console.log(
|
|
29272
|
-
` Issue DB: ${
|
|
30003
|
+
` Issue DB: ${path55.relative(rootDir, remediation.issueDbPath)}`
|
|
29273
30004
|
);
|
|
29274
30005
|
}
|
|
29275
|
-
return
|
|
30006
|
+
return EXIT_OK5;
|
|
29276
30007
|
}
|
|
29277
30008
|
async function runRemediation(rootDir, report, options, silent = false) {
|
|
29278
30009
|
const write2 = silent ? () => {
|
|
@@ -29330,7 +30061,7 @@ async function readV3ActivationState(schemaPath) {
|
|
|
29330
30061
|
if (!await pathExists10(schemaPath)) return null;
|
|
29331
30062
|
try {
|
|
29332
30063
|
const manifest = parseSchemaManifest(
|
|
29333
|
-
JSON.parse(await
|
|
30064
|
+
JSON.parse(await readFile40(schemaPath, "utf8"))
|
|
29334
30065
|
);
|
|
29335
30066
|
return manifest.activationState;
|
|
29336
30067
|
} catch {
|
|
@@ -29339,9 +30070,9 @@ async function readV3ActivationState(schemaPath) {
|
|
|
29339
30070
|
}
|
|
29340
30071
|
|
|
29341
30072
|
// src/commands/migrate.ts
|
|
29342
|
-
import { readFile as
|
|
29343
|
-
import
|
|
29344
|
-
var
|
|
30073
|
+
import { readFile as readFile41 } from "fs/promises";
|
|
30074
|
+
import path56 from "path";
|
|
30075
|
+
var EXIT_OK6 = 0;
|
|
29345
30076
|
var EXIT_INVALID_ARG2 = 2;
|
|
29346
30077
|
var EXIT_MIGRATION_BLOCKED = 3;
|
|
29347
30078
|
async function migrateContext(rootDir, options) {
|
|
@@ -29353,7 +30084,7 @@ async function migrateContext(rootDir, options) {
|
|
|
29353
30084
|
options.rollback !== void 0
|
|
29354
30085
|
].filter(Boolean).length;
|
|
29355
30086
|
if (selected !== 1) {
|
|
29356
|
-
return
|
|
30087
|
+
return printError2(
|
|
29357
30088
|
options.json,
|
|
29358
30089
|
"MANCODE_MIGRATION_ARGUMENT_INVALID",
|
|
29359
30090
|
"Choose exactly one migration operation.",
|
|
@@ -29362,16 +30093,16 @@ async function migrateContext(rootDir, options) {
|
|
|
29362
30093
|
}
|
|
29363
30094
|
try {
|
|
29364
30095
|
if (options.dryRun) {
|
|
29365
|
-
return
|
|
30096
|
+
return printResult2(options.json, await dryRunLegacyMigration(rootDir));
|
|
29366
30097
|
}
|
|
29367
30098
|
if (options.stage) {
|
|
29368
|
-
return
|
|
30099
|
+
return printResult2(
|
|
29369
30100
|
options.json,
|
|
29370
30101
|
await stageLegacyMigration({ projectRoot: rootDir })
|
|
29371
30102
|
);
|
|
29372
30103
|
}
|
|
29373
30104
|
if (options.status) {
|
|
29374
|
-
return
|
|
30105
|
+
return printResult2(options.json, {
|
|
29375
30106
|
schemaVersion: 1,
|
|
29376
30107
|
stages: await listMigrationStages(rootDir)
|
|
29377
30108
|
});
|
|
@@ -29382,7 +30113,7 @@ async function migrateContext(rootDir, options) {
|
|
|
29382
30113
|
assertUlid(options.session, "migration activation session");
|
|
29383
30114
|
if (options.rollback !== void 0) {
|
|
29384
30115
|
assertUlid(options.rollback, "migration rollback operation");
|
|
29385
|
-
return
|
|
30116
|
+
return printResult2(
|
|
29386
30117
|
options.json,
|
|
29387
30118
|
await rollbackLegacyMigration({
|
|
29388
30119
|
projectRoot: rootDir,
|
|
@@ -29393,7 +30124,7 @@ async function migrateContext(rootDir, options) {
|
|
|
29393
30124
|
);
|
|
29394
30125
|
}
|
|
29395
30126
|
const stageId = await selectStageId(rootDir, options.stageId);
|
|
29396
|
-
return
|
|
30127
|
+
return printResult2(
|
|
29397
30128
|
options.json,
|
|
29398
30129
|
await activateLegacyMigration({
|
|
29399
30130
|
projectRoot: rootDir,
|
|
@@ -29405,9 +30136,9 @@ async function migrateContext(rootDir, options) {
|
|
|
29405
30136
|
})
|
|
29406
30137
|
);
|
|
29407
30138
|
} catch (error) {
|
|
29408
|
-
return
|
|
30139
|
+
return printError2(
|
|
29409
30140
|
options.json,
|
|
29410
|
-
|
|
30141
|
+
errorCode4(error),
|
|
29411
30142
|
error instanceof Error ? error.message : "Migration failed.",
|
|
29412
30143
|
EXIT_MIGRATION_BLOCKED
|
|
29413
30144
|
);
|
|
@@ -29427,11 +30158,11 @@ async function migrateContextResolve(rootDir, legacyTaskId, options) {
|
|
|
29427
30158
|
ownerActorId: owner,
|
|
29428
30159
|
implementationScope
|
|
29429
30160
|
});
|
|
29430
|
-
return
|
|
30161
|
+
return printResult2(options.json, result2);
|
|
29431
30162
|
} catch (error) {
|
|
29432
|
-
return
|
|
30163
|
+
return printError2(
|
|
29433
30164
|
options.json,
|
|
29434
|
-
|
|
30165
|
+
errorCode4(error),
|
|
29435
30166
|
error instanceof Error ? error.message : "Migration resolution failed.",
|
|
29436
30167
|
EXIT_MIGRATION_BLOCKED
|
|
29437
30168
|
);
|
|
@@ -29466,14 +30197,14 @@ async function readScopeFile(rootDir, file) {
|
|
|
29466
30197
|
if (!file.trim() || file.includes("\0")) {
|
|
29467
30198
|
throw new Error("MANCODE_MIGRATION_SCOPE_FILE_INVALID");
|
|
29468
30199
|
}
|
|
29469
|
-
const resolved =
|
|
29470
|
-
const relative =
|
|
29471
|
-
if (relative === ".." || relative.startsWith(`..${
|
|
30200
|
+
const resolved = path56.resolve(rootDir, file);
|
|
30201
|
+
const relative = path56.relative(path56.resolve(rootDir), resolved);
|
|
30202
|
+
if (relative === ".." || relative.startsWith(`..${path56.sep}`) || path56.isAbsolute(relative)) {
|
|
29472
30203
|
throw new Error("MANCODE_MIGRATION_SCOPE_FILE_INVALID");
|
|
29473
30204
|
}
|
|
29474
30205
|
try {
|
|
29475
30206
|
return JSON.parse(
|
|
29476
|
-
await
|
|
30207
|
+
await readFile41(resolved, "utf8")
|
|
29477
30208
|
);
|
|
29478
30209
|
} catch (error) {
|
|
29479
30210
|
if (error instanceof SyntaxError) {
|
|
@@ -29482,15 +30213,15 @@ async function readScopeFile(rootDir, file) {
|
|
|
29482
30213
|
throw error;
|
|
29483
30214
|
}
|
|
29484
30215
|
}
|
|
29485
|
-
function
|
|
30216
|
+
function printResult2(json, result2) {
|
|
29486
30217
|
if (json) {
|
|
29487
30218
|
console.log(JSON.stringify(result2, null, 2));
|
|
29488
30219
|
} else {
|
|
29489
30220
|
console.log(JSON.stringify(result2, null, 2));
|
|
29490
30221
|
}
|
|
29491
|
-
return
|
|
30222
|
+
return EXIT_OK6;
|
|
29492
30223
|
}
|
|
29493
|
-
function
|
|
30224
|
+
function printError2(json, code, message, exitCode) {
|
|
29494
30225
|
const result2 = { schemaVersion: 1, error: { code, message } };
|
|
29495
30226
|
if (json) {
|
|
29496
30227
|
console.log(JSON.stringify(result2, null, 2));
|
|
@@ -29500,7 +30231,7 @@ function printError(json, code, message, exitCode) {
|
|
|
29500
30231
|
}
|
|
29501
30232
|
return exitCode;
|
|
29502
30233
|
}
|
|
29503
|
-
function
|
|
30234
|
+
function errorCode4(error) {
|
|
29504
30235
|
if (error instanceof Error && error.message.startsWith("MANCODE_")) {
|
|
29505
30236
|
return error.message.split(":", 1)[0] ?? "MANCODE_MIGRATION_FAILED";
|
|
29506
30237
|
}
|
|
@@ -29573,12 +30304,12 @@ async function runOperationMutation(rootDir, operationId, options, mode) {
|
|
|
29573
30304
|
}
|
|
29574
30305
|
|
|
29575
30306
|
// src/context/project-policy-upgrade.ts
|
|
29576
|
-
import { lstat as
|
|
29577
|
-
import
|
|
30307
|
+
import { lstat as lstat22, mkdir as mkdir36, readFile as readFile42, rm as rm19, writeFile as writeFile41 } from "fs/promises";
|
|
30308
|
+
import path57 from "path";
|
|
29578
30309
|
var UPGRADE_OPERATION = "project_policy_upgrade";
|
|
29579
30310
|
async function dryRunProjectPolicyUpgrade(input) {
|
|
29580
30311
|
assertPolicyVersion(input.policyVersion);
|
|
29581
|
-
const root =
|
|
30312
|
+
const root = path57.resolve(input.projectRoot);
|
|
29582
30313
|
const project = await new V3ContextStore(root).readProjectSnapshot();
|
|
29583
30314
|
const beforeDigest = digestManifest(project.manifest);
|
|
29584
30315
|
const now = input.now ?? /* @__PURE__ */ new Date();
|
|
@@ -29622,7 +30353,7 @@ async function dryRunProjectPolicyUpgrade(input) {
|
|
|
29622
30353
|
async function upgradeProjectPolicy(input) {
|
|
29623
30354
|
assertPolicyVersion(input.policyVersion);
|
|
29624
30355
|
assertUlid(input.sessionId, "project policy upgrade sessionId");
|
|
29625
|
-
const root =
|
|
30356
|
+
const root = path57.resolve(input.projectRoot);
|
|
29626
30357
|
const now = input.now ?? /* @__PURE__ */ new Date();
|
|
29627
30358
|
const operationId = input.operationId;
|
|
29628
30359
|
if (operationId === void 0) {
|
|
@@ -29832,7 +30563,7 @@ async function collectUpgradeBlockers(root, project) {
|
|
|
29832
30563
|
try {
|
|
29833
30564
|
await assertUpgradePreflight(root, project);
|
|
29834
30565
|
} catch (error) {
|
|
29835
|
-
blockers.push(
|
|
30566
|
+
blockers.push(errorCode5(error));
|
|
29836
30567
|
}
|
|
29837
30568
|
return [...new Set(blockers)];
|
|
29838
30569
|
}
|
|
@@ -29876,24 +30607,24 @@ function buildV2Manifest(manifest, operationId) {
|
|
|
29876
30607
|
return candidate;
|
|
29877
30608
|
}
|
|
29878
30609
|
async function readSchemaContent(root) {
|
|
29879
|
-
return
|
|
30610
|
+
return readFile42(path57.join(root, ".mancode", "schema.json"), "utf8");
|
|
29880
30611
|
}
|
|
29881
30612
|
async function writeSchemaContent(root, operationId, content) {
|
|
29882
|
-
const directory =
|
|
29883
|
-
const target =
|
|
29884
|
-
const
|
|
29885
|
-
if (!
|
|
30613
|
+
const directory = path57.join(root, ".mancode");
|
|
30614
|
+
const target = path57.join(directory, "schema.json");
|
|
30615
|
+
const stat5 = await lstat22(target);
|
|
30616
|
+
if (!stat5.isFile() || stat5.isSymbolicLink()) {
|
|
29886
30617
|
throw new Error("MANCODE_ARTIFACT_PATH_UNSAFE");
|
|
29887
30618
|
}
|
|
29888
|
-
const temporary =
|
|
30619
|
+
const temporary = path57.join(
|
|
29889
30620
|
directory,
|
|
29890
30621
|
`.schema.json.${operationId}.${process.pid}.tmp`
|
|
29891
30622
|
);
|
|
29892
|
-
await
|
|
30623
|
+
await writeFile41(temporary, content, { encoding: "utf8", flag: "wx" });
|
|
29893
30624
|
try {
|
|
29894
30625
|
await replaceFileAtomically(temporary, target);
|
|
29895
30626
|
} catch (error) {
|
|
29896
|
-
await
|
|
30627
|
+
await rm19(temporary, { force: true });
|
|
29897
30628
|
throw error;
|
|
29898
30629
|
}
|
|
29899
30630
|
}
|
|
@@ -29954,22 +30685,22 @@ function assertPolicyVersion(value) {
|
|
|
29954
30685
|
);
|
|
29955
30686
|
}
|
|
29956
30687
|
}
|
|
29957
|
-
function
|
|
30688
|
+
function errorCode5(error) {
|
|
29958
30689
|
return error instanceof Error && error.message.startsWith("MANCODE_") ? error.message.split(":", 1)[0] ?? "MANCODE_PROJECT_UPGRADE_BLOCKED" : "MANCODE_PROJECT_UPGRADE_BLOCKED";
|
|
29959
30690
|
}
|
|
29960
30691
|
async function releaseLocks3(locks) {
|
|
29961
30692
|
await Promise.allSettled([...locks].reverse().map((lock) => lock.release()));
|
|
29962
30693
|
}
|
|
29963
30694
|
function projectUpgradePreviewRoot(root, operationId) {
|
|
29964
|
-
return
|
|
30695
|
+
return path57.join(root, ".mancode", "staging", "project-upgrade", operationId);
|
|
29965
30696
|
}
|
|
29966
30697
|
async function stageProjectPolicyUpgrade(root, receipt, manifestContent) {
|
|
29967
30698
|
const directory = projectUpgradePreviewRoot(root, receipt.operationId);
|
|
29968
|
-
const receiptPath =
|
|
29969
|
-
const manifestPath =
|
|
29970
|
-
await
|
|
30699
|
+
const receiptPath = path57.join(directory, "preview.json");
|
|
30700
|
+
const manifestPath = path57.join(directory, "schema.json");
|
|
30701
|
+
await mkdir36(path57.dirname(directory), { recursive: true });
|
|
29971
30702
|
try {
|
|
29972
|
-
await
|
|
30703
|
+
await mkdir36(directory);
|
|
29973
30704
|
} catch (error) {
|
|
29974
30705
|
if (isAlreadyExists23(error)) {
|
|
29975
30706
|
throw new Error("MANCODE_PROJECT_UPGRADE_PREVIEW_EXISTS");
|
|
@@ -29977,25 +30708,25 @@ async function stageProjectPolicyUpgrade(root, receipt, manifestContent) {
|
|
|
29977
30708
|
throw error;
|
|
29978
30709
|
}
|
|
29979
30710
|
try {
|
|
29980
|
-
await
|
|
30711
|
+
await writeFile41(receiptPath, `${JSON.stringify(receipt, null, 2)}
|
|
29981
30712
|
`, {
|
|
29982
30713
|
encoding: "utf8",
|
|
29983
30714
|
flag: "wx"
|
|
29984
30715
|
});
|
|
29985
|
-
await
|
|
30716
|
+
await writeFile41(manifestPath, manifestContent, {
|
|
29986
30717
|
encoding: "utf8",
|
|
29987
30718
|
flag: "wx"
|
|
29988
30719
|
});
|
|
29989
30720
|
} catch (error) {
|
|
29990
|
-
await
|
|
30721
|
+
await rm19(directory, { recursive: true, force: true });
|
|
29991
30722
|
throw error;
|
|
29992
30723
|
}
|
|
29993
30724
|
}
|
|
29994
30725
|
async function assertProjectPolicyUpgradePreview(root, operationId, project) {
|
|
29995
30726
|
const directory = projectUpgradePreviewRoot(root, operationId);
|
|
29996
30727
|
const [receiptContent, manifestContent] = await Promise.all([
|
|
29997
|
-
readSafePreviewFile(
|
|
29998
|
-
readSafePreviewFile(
|
|
30728
|
+
readSafePreviewFile(path57.join(directory, "preview.json")),
|
|
30729
|
+
readSafePreviewFile(path57.join(directory, "schema.json"))
|
|
29999
30730
|
]);
|
|
30000
30731
|
let receipt;
|
|
30001
30732
|
try {
|
|
@@ -30018,13 +30749,13 @@ async function assertProjectPolicyUpgradePreview(root, operationId, project) {
|
|
|
30018
30749
|
}
|
|
30019
30750
|
async function readSafePreviewFile(target) {
|
|
30020
30751
|
try {
|
|
30021
|
-
const
|
|
30022
|
-
if (!
|
|
30752
|
+
const stat5 = await lstat22(target);
|
|
30753
|
+
if (!stat5.isFile() || stat5.isSymbolicLink()) {
|
|
30023
30754
|
throw new Error("MANCODE_PROJECT_UPGRADE_PREVIEW_INVALID");
|
|
30024
30755
|
}
|
|
30025
|
-
return
|
|
30756
|
+
return readFile42(target, "utf8");
|
|
30026
30757
|
} catch (error) {
|
|
30027
|
-
if (
|
|
30758
|
+
if (isNotFound29(error)) {
|
|
30028
30759
|
throw new Error("MANCODE_PROJECT_UPGRADE_PREVIEW_REQUIRED");
|
|
30029
30760
|
}
|
|
30030
30761
|
throw error;
|
|
@@ -30057,7 +30788,7 @@ function parseProjectPolicyUpgradePreviewReceipt(value) {
|
|
|
30057
30788
|
createdAt: record.createdAt
|
|
30058
30789
|
};
|
|
30059
30790
|
}
|
|
30060
|
-
function
|
|
30791
|
+
function isNotFound29(error) {
|
|
30061
30792
|
return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
|
|
30062
30793
|
}
|
|
30063
30794
|
function isAlreadyExists23(error) {
|
|
@@ -30111,22 +30842,22 @@ async function projectUpgrade(rootDir, options) {
|
|
|
30111
30842
|
// src/commands/refresh-project.ts
|
|
30112
30843
|
import { randomUUID } from "crypto";
|
|
30113
30844
|
import { promises as fs7 } from "fs";
|
|
30114
|
-
import
|
|
30115
|
-
import
|
|
30116
|
-
var
|
|
30117
|
-
var
|
|
30845
|
+
import path58 from "path";
|
|
30846
|
+
import process9 from "process";
|
|
30847
|
+
var EXIT_OK7 = 0;
|
|
30848
|
+
var EXIT_NOT_INITIALIZED4 = 1;
|
|
30118
30849
|
var EXIT_CORRUPT_STATE = 2;
|
|
30119
30850
|
var EXIT_REFRESH_FAILED = 3;
|
|
30120
|
-
async function refreshProject(rootDir =
|
|
30121
|
-
const mancodeDir =
|
|
30122
|
-
const statePath =
|
|
30123
|
-
if (await pathExists11(
|
|
30851
|
+
async function refreshProject(rootDir = process9.cwd()) {
|
|
30852
|
+
const mancodeDir = path58.join(rootDir, ".mancode");
|
|
30853
|
+
const statePath = path58.join(mancodeDir, "state.json");
|
|
30854
|
+
if (await pathExists11(path58.join(mancodeDir, "schema.json"))) {
|
|
30124
30855
|
return refreshV3Project(rootDir);
|
|
30125
30856
|
}
|
|
30126
30857
|
if (!await pathExists11(statePath)) {
|
|
30127
30858
|
console.error("\u2717 mancode not initialized.");
|
|
30128
30859
|
console.error(" Run `mancode init` first.");
|
|
30129
|
-
return
|
|
30860
|
+
return EXIT_NOT_INITIALIZED4;
|
|
30130
30861
|
}
|
|
30131
30862
|
const state = await readRequiredState(statePath);
|
|
30132
30863
|
if (!state) {
|
|
@@ -30139,12 +30870,12 @@ async function refreshProject(rootDir = process8.cwd()) {
|
|
|
30139
30870
|
const [profile, team, hasGit, hasManifest] = await Promise.all([
|
|
30140
30871
|
detectProjectProfile(rootDir),
|
|
30141
30872
|
detectTeamStatus(rootDir),
|
|
30142
|
-
pathExists11(
|
|
30873
|
+
pathExists11(path58.join(rootDir, ".git")),
|
|
30143
30874
|
hasProjectManifest2(rootDir)
|
|
30144
30875
|
]);
|
|
30145
30876
|
const uiLibrary = primaryUiLibrary(profile);
|
|
30146
30877
|
const stack = [...profile.languages, ...profile.frameworks];
|
|
30147
|
-
const config = await readJson2(
|
|
30878
|
+
const config = await readJson2(path58.join(mancodeDir, "config.json"));
|
|
30148
30879
|
const configuredTeam = config.forceTeamMode === true ? true : config.teamMode === "on" ? true : config.teamMode === "off" ? false : team.isTeam;
|
|
30149
30880
|
const nextState = {
|
|
30150
30881
|
...state,
|
|
@@ -30156,7 +30887,7 @@ async function refreshProject(rootDir = process8.cwd()) {
|
|
|
30156
30887
|
};
|
|
30157
30888
|
await writeProjectFacts2(
|
|
30158
30889
|
statePath,
|
|
30159
|
-
|
|
30890
|
+
path58.join(mancodeDir, "project-profile.json"),
|
|
30160
30891
|
`${JSON.stringify(nextState, null, 2)}
|
|
30161
30892
|
`,
|
|
30162
30893
|
`${JSON.stringify(profile, null, 2)}
|
|
@@ -30184,7 +30915,7 @@ async function refreshProject(rootDir = process8.cwd()) {
|
|
|
30184
30915
|
console.log(
|
|
30185
30916
|
" Run `mancode refresh-style` if UI files or dependencies changed."
|
|
30186
30917
|
);
|
|
30187
|
-
return
|
|
30918
|
+
return EXIT_OK7;
|
|
30188
30919
|
} catch (error) {
|
|
30189
30920
|
const message = error instanceof Error ? error.message : String(error);
|
|
30190
30921
|
console.error(`\u2717 Project refresh failed: ${message}`);
|
|
@@ -30214,7 +30945,7 @@ async function refreshV3Project(rootDir) {
|
|
|
30214
30945
|
console.log(
|
|
30215
30946
|
" mancode adapters remain unchanged because their bootstrap is static."
|
|
30216
30947
|
);
|
|
30217
|
-
return
|
|
30948
|
+
return EXIT_OK7;
|
|
30218
30949
|
} catch (error) {
|
|
30219
30950
|
const message = error instanceof Error ? error.message : String(error);
|
|
30220
30951
|
console.error(`\u2717 mancode project facts refresh failed: ${message}`);
|
|
@@ -30223,7 +30954,7 @@ async function refreshV3Project(rootDir) {
|
|
|
30223
30954
|
}
|
|
30224
30955
|
async function hasProjectManifest2(rootDir) {
|
|
30225
30956
|
for (const manifest of PROJECT_MANIFESTS) {
|
|
30226
|
-
if (await pathExists11(
|
|
30957
|
+
if (await pathExists11(path58.join(rootDir, manifest))) return true;
|
|
30227
30958
|
}
|
|
30228
30959
|
return false;
|
|
30229
30960
|
}
|
|
@@ -30289,9 +31020,9 @@ async function readOptionalText(filePath) {
|
|
|
30289
31020
|
}
|
|
30290
31021
|
}
|
|
30291
31022
|
function temporaryPath(filePath) {
|
|
30292
|
-
return
|
|
30293
|
-
|
|
30294
|
-
`.${
|
|
31023
|
+
return path58.join(
|
|
31024
|
+
path58.dirname(filePath),
|
|
31025
|
+
`.${path58.basename(filePath)}.${process9.pid}.${randomUUID()}.tmp`
|
|
30295
31026
|
);
|
|
30296
31027
|
}
|
|
30297
31028
|
async function refreshStaticPlatforms(rootDir, config, fallbackPlatform, stack, uiLibrary, profile) {
|
|
@@ -30320,14 +31051,14 @@ function configuredPlatforms(config, fallbackPlatform) {
|
|
|
30320
31051
|
);
|
|
30321
31052
|
}
|
|
30322
31053
|
function platformIsMinimal(config, platform) {
|
|
30323
|
-
if (!
|
|
31054
|
+
if (!isRecord11(config.platformOptions)) return false;
|
|
30324
31055
|
const options = config.platformOptions[platform];
|
|
30325
|
-
return
|
|
31056
|
+
return isRecord11(options) && options.minimal === true;
|
|
30326
31057
|
}
|
|
30327
31058
|
async function readJson2(filePath) {
|
|
30328
31059
|
try {
|
|
30329
31060
|
const value = JSON.parse(await fs7.readFile(filePath, "utf-8"));
|
|
30330
|
-
return
|
|
31061
|
+
return isRecord11(value) ? value : {};
|
|
30331
31062
|
} catch {
|
|
30332
31063
|
return {};
|
|
30333
31064
|
}
|
|
@@ -30337,14 +31068,14 @@ async function readRequiredState(filePath) {
|
|
|
30337
31068
|
try {
|
|
30338
31069
|
const raw = await fs7.readFile(filePath, "utf-8");
|
|
30339
31070
|
const parsed = JSON.parse(raw);
|
|
30340
|
-
if (!
|
|
31071
|
+
if (!isRecord11(parsed)) return null;
|
|
30341
31072
|
state = parsed;
|
|
30342
31073
|
} catch {
|
|
30343
31074
|
return null;
|
|
30344
31075
|
}
|
|
30345
31076
|
return typeof state.version === "string" && typeof state.currentMode === "string" && typeof state.platform === "string" ? state : null;
|
|
30346
31077
|
}
|
|
30347
|
-
function
|
|
31078
|
+
function isRecord11(value) {
|
|
30348
31079
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
30349
31080
|
}
|
|
30350
31081
|
function isNodeError9(error) {
|
|
@@ -30361,52 +31092,62 @@ async function pathExists11(filePath) {
|
|
|
30361
31092
|
|
|
30362
31093
|
// src/commands/refresh-style.ts
|
|
30363
31094
|
import { promises as fs8 } from "fs";
|
|
30364
|
-
import
|
|
30365
|
-
import
|
|
30366
|
-
var
|
|
30367
|
-
var
|
|
31095
|
+
import path59 from "path";
|
|
31096
|
+
import process10 from "process";
|
|
31097
|
+
var EXIT_OK8 = 0;
|
|
31098
|
+
var EXIT_NOT_INITIALIZED5 = 1;
|
|
30368
31099
|
var EXIT_V3_REFRESH_FAILED = 2;
|
|
30369
|
-
async function refreshStyle(rootDir =
|
|
30370
|
-
const
|
|
30371
|
-
if (
|
|
30372
|
-
|
|
31100
|
+
async function refreshStyle(rootDir = process10.cwd(), options = {}) {
|
|
31101
|
+
const scanTarget = await resolveScanTarget(rootDir, options.root);
|
|
31102
|
+
if (scanTarget === null) {
|
|
31103
|
+
console.error("\u2717 style scan root must stay inside the project root.");
|
|
31104
|
+
return EXIT_V3_REFRESH_FAILED;
|
|
31105
|
+
}
|
|
31106
|
+
const stateFile = path59.join(rootDir, ".mancode", "state.json");
|
|
31107
|
+
if (await pathExists12(path59.join(rootDir, ".mancode", "schema.json"))) {
|
|
31108
|
+
return refreshV3Style(rootDir, scanTarget.root, scanTarget.scopeRoot);
|
|
30373
31109
|
}
|
|
30374
31110
|
if (!await pathExists12(stateFile)) {
|
|
30375
31111
|
console.error("\u2717 mancode not initialized.");
|
|
30376
31112
|
console.error(" Run `mancode init` first.");
|
|
30377
|
-
return
|
|
31113
|
+
return EXIT_NOT_INITIALIZED5;
|
|
30378
31114
|
}
|
|
30379
31115
|
console.log("\u2713 \u5237\u65B0\u9879\u76EE profile...");
|
|
30380
31116
|
const profile = await detectProjectProfile(rootDir);
|
|
30381
|
-
const profilePath =
|
|
31117
|
+
const profilePath = path59.join(rootDir, ".mancode", "project-profile.json");
|
|
30382
31118
|
await fs8.writeFile(
|
|
30383
31119
|
profilePath,
|
|
30384
31120
|
`${JSON.stringify(profile, null, 2)}
|
|
30385
31121
|
`,
|
|
30386
31122
|
"utf-8"
|
|
30387
31123
|
);
|
|
30388
|
-
const
|
|
31124
|
+
const scanProfile = scanTarget.scopeRoot === "." ? profile : await detectProjectProfile(scanTarget.root);
|
|
31125
|
+
const uiLibraryHint = primaryUiLibrary(scanProfile);
|
|
30389
31126
|
await refreshLegacyStateContext(rootDir, profile, uiLibraryHint);
|
|
30390
31127
|
console.log(
|
|
30391
31128
|
` \u7C7B\u578B: ${profile.projectKind} | UI: ${profile.uiAssets} | \u6D4F\u89C8\u5668: ${profile.browserAutomation}`
|
|
30392
31129
|
);
|
|
30393
|
-
if (
|
|
31130
|
+
if (scanProfile.uiAssets !== "detected") {
|
|
30394
31131
|
console.log(
|
|
30395
31132
|
"\u2139\uFE0F No UI assets detected in project profile. Skipping style scan."
|
|
30396
31133
|
);
|
|
30397
31134
|
console.log(" Updated .mancode/project-profile.json.");
|
|
30398
31135
|
await printStaticPlatformRefreshHint(rootDir);
|
|
30399
|
-
return
|
|
31136
|
+
return EXIT_OK8;
|
|
30400
31137
|
}
|
|
30401
31138
|
console.log("\u2713 \u626B\u63CF\u9879\u76EE\u8BBE\u8BA1 token...");
|
|
30402
|
-
const tokens = await scanAesthetics(
|
|
30403
|
-
|
|
31139
|
+
const tokens = await scanAesthetics(
|
|
31140
|
+
scanTarget.root,
|
|
31141
|
+
uiLibraryHint,
|
|
31142
|
+
scanTarget.scopeRoot
|
|
31143
|
+
);
|
|
31144
|
+
const tokensPath = path59.join(
|
|
30404
31145
|
rootDir,
|
|
30405
31146
|
".mancode",
|
|
30406
31147
|
"aesthetics",
|
|
30407
31148
|
"style-tokens.json"
|
|
30408
31149
|
);
|
|
30409
|
-
await fs8.mkdir(
|
|
31150
|
+
await fs8.mkdir(path59.dirname(tokensPath), { recursive: true });
|
|
30410
31151
|
await fs8.writeFile(
|
|
30411
31152
|
tokensPath,
|
|
30412
31153
|
`${JSON.stringify(tokens, null, 2)}
|
|
@@ -30419,7 +31160,7 @@ async function refreshStyle(rootDir = process9.cwd()) {
|
|
|
30419
31160
|
"\u5DF2\u66F4\u65B0 .mancode/project-profile.json \u548C .mancode/aesthetics/style-tokens.json"
|
|
30420
31161
|
);
|
|
30421
31162
|
await printStaticPlatformRefreshHint(rootDir);
|
|
30422
|
-
return
|
|
31163
|
+
return EXIT_OK8;
|
|
30423
31164
|
}
|
|
30424
31165
|
function printAestheticsSummary(tokens) {
|
|
30425
31166
|
console.log("");
|
|
@@ -30460,7 +31201,7 @@ function printAestheticsSummary(tokens) {
|
|
|
30460
31201
|
console.log(` \u5339\u914D\u5EA6: ${tokens.matchLevel}`);
|
|
30461
31202
|
}
|
|
30462
31203
|
}
|
|
30463
|
-
async function refreshV3Style(rootDir) {
|
|
31204
|
+
async function refreshV3Style(rootDir, scanRoot, scopeRoot) {
|
|
30464
31205
|
try {
|
|
30465
31206
|
const project = await new V3ContextStore(rootDir).readProjectSnapshot();
|
|
30466
31207
|
if (project.manifest.activationState !== "v3_active") {
|
|
@@ -30468,7 +31209,8 @@ async function refreshV3Style(rootDir) {
|
|
|
30468
31209
|
}
|
|
30469
31210
|
console.log("\u2713 \u5237\u65B0 mancode \u9879\u76EE profile...");
|
|
30470
31211
|
const profile = await detectProjectProfile(rootDir);
|
|
30471
|
-
const
|
|
31212
|
+
const scanProfile = scopeRoot === "." ? profile : await detectProjectProfile(scanRoot);
|
|
31213
|
+
const uiLibraryHint = primaryUiLibrary(scanProfile);
|
|
30472
31214
|
await writeProjectFacts(
|
|
30473
31215
|
rootDir,
|
|
30474
31216
|
createProjectFacts(profile, {
|
|
@@ -30478,24 +31220,24 @@ async function refreshV3Style(rootDir) {
|
|
|
30478
31220
|
console.log(
|
|
30479
31221
|
` \u7C7B\u578B: ${profile.projectKind} | UI: ${profile.uiAssets} | \u6D4F\u89C8\u5668: ${profile.browserAutomation}`
|
|
30480
31222
|
);
|
|
30481
|
-
const tokensPath =
|
|
31223
|
+
const tokensPath = path59.join(
|
|
30482
31224
|
rootDir,
|
|
30483
31225
|
".mancode",
|
|
30484
31226
|
"local",
|
|
30485
31227
|
"cache",
|
|
30486
31228
|
"style-tokens.json"
|
|
30487
31229
|
);
|
|
30488
|
-
if (
|
|
31230
|
+
if (scanProfile.uiAssets !== "detected") {
|
|
30489
31231
|
await fs8.rm(tokensPath, { force: true });
|
|
30490
31232
|
console.log(
|
|
30491
31233
|
"\u2139\uFE0F No UI assets detected in project profile. Skipping style scan."
|
|
30492
31234
|
);
|
|
30493
31235
|
console.log(" Updated mancode project facts.");
|
|
30494
|
-
return
|
|
31236
|
+
return EXIT_OK8;
|
|
30495
31237
|
}
|
|
30496
31238
|
console.log("\u2713 \u626B\u63CF\u9879\u76EE\u8BBE\u8BA1 token...");
|
|
30497
|
-
const tokens = await scanAesthetics(
|
|
30498
|
-
await fs8.mkdir(
|
|
31239
|
+
const tokens = await scanAesthetics(scanRoot, uiLibraryHint, scopeRoot);
|
|
31240
|
+
await fs8.mkdir(path59.dirname(tokensPath), { recursive: true });
|
|
30499
31241
|
await fs8.writeFile(
|
|
30500
31242
|
tokensPath,
|
|
30501
31243
|
`${JSON.stringify(tokens, null, 2)}
|
|
@@ -30507,7 +31249,7 @@ async function refreshV3Style(rootDir) {
|
|
|
30507
31249
|
console.log(
|
|
30508
31250
|
"\u5DF2\u66F4\u65B0 .mancode/shared/context/project.json \u548C .mancode/local/cache/style-tokens.json"
|
|
30509
31251
|
);
|
|
30510
|
-
return
|
|
31252
|
+
return EXIT_OK8;
|
|
30511
31253
|
} catch (error) {
|
|
30512
31254
|
const message = error instanceof Error ? error.message : String(error);
|
|
30513
31255
|
console.error(`\u2717 mancode style refresh failed: ${message}`);
|
|
@@ -30529,7 +31271,7 @@ async function printStaticPlatformRefreshHint(rootDir) {
|
|
|
30529
31271
|
);
|
|
30530
31272
|
}
|
|
30531
31273
|
async function refreshLegacyStateContext(rootDir, profile, uiLibrary) {
|
|
30532
|
-
const statePath =
|
|
31274
|
+
const statePath = path59.join(rootDir, ".mancode", "state.json");
|
|
30533
31275
|
try {
|
|
30534
31276
|
const state = JSON.parse(await fs8.readFile(statePath, "utf-8"));
|
|
30535
31277
|
const stack = [...profile.languages, ...profile.frameworks];
|
|
@@ -30553,7 +31295,7 @@ async function refreshLegacyStateContext(rootDir, profile, uiLibrary) {
|
|
|
30553
31295
|
async function readInstalledPlatforms2(rootDir) {
|
|
30554
31296
|
try {
|
|
30555
31297
|
const raw = await fs8.readFile(
|
|
30556
|
-
|
|
31298
|
+
path59.join(rootDir, ".mancode", "config.json"),
|
|
30557
31299
|
"utf-8"
|
|
30558
31300
|
);
|
|
30559
31301
|
const config = JSON.parse(raw);
|
|
@@ -30572,12 +31314,32 @@ async function pathExists12(p) {
|
|
|
30572
31314
|
return false;
|
|
30573
31315
|
}
|
|
30574
31316
|
}
|
|
31317
|
+
async function resolveScanTarget(rootDir, requestedRoot) {
|
|
31318
|
+
const projectRoot = await fs8.realpath(path59.resolve(rootDir)).catch(() => null);
|
|
31319
|
+
if (projectRoot === null) return null;
|
|
31320
|
+
if (requestedRoot === void 0 || requestedRoot === ".") {
|
|
31321
|
+
return { root: projectRoot, scopeRoot: "." };
|
|
31322
|
+
}
|
|
31323
|
+
if (path59.isAbsolute(requestedRoot) || requestedRoot.includes("\0") || requestedRoot.split(/[\\/]/).some((segment) => segment === "" || segment === "." || segment === "..")) {
|
|
31324
|
+
return null;
|
|
31325
|
+
}
|
|
31326
|
+
const candidate = await fs8.realpath(path59.resolve(projectRoot, requestedRoot)).catch(() => null);
|
|
31327
|
+
if (candidate === null) return null;
|
|
31328
|
+
const relative = path59.relative(projectRoot, candidate);
|
|
31329
|
+
if (relative.startsWith(`..${path59.sep}`) || relative === ".." || path59.isAbsolute(relative)) {
|
|
31330
|
+
return null;
|
|
31331
|
+
}
|
|
31332
|
+
return {
|
|
31333
|
+
root: candidate,
|
|
31334
|
+
scopeRoot: relative.split(path59.sep).join("/") || "."
|
|
31335
|
+
};
|
|
31336
|
+
}
|
|
30575
31337
|
|
|
30576
31338
|
// src/commands/status.ts
|
|
30577
31339
|
import { spawn } from "child_process";
|
|
30578
31340
|
import { promises as fs9 } from "fs";
|
|
30579
|
-
import
|
|
30580
|
-
import
|
|
31341
|
+
import path60 from "path";
|
|
31342
|
+
import process11 from "process";
|
|
30581
31343
|
|
|
30582
31344
|
// src/team/assessment.ts
|
|
30583
31345
|
function assessTeam(input) {
|
|
@@ -30728,19 +31490,19 @@ function assertTimestamp3(value) {
|
|
|
30728
31490
|
|
|
30729
31491
|
// src/commands/status.ts
|
|
30730
31492
|
var HOOK_ESTIMATE_TIMEOUT_MS = 2e3;
|
|
30731
|
-
var
|
|
30732
|
-
var
|
|
31493
|
+
var EXIT_OK9 = 0;
|
|
31494
|
+
var EXIT_NOT_INITIALIZED6 = 1;
|
|
30733
31495
|
var EXIT_CORRUPT_STATE2 = 2;
|
|
30734
|
-
async function status(rootDir =
|
|
30735
|
-
const stateFile =
|
|
30736
|
-
const v3SchemaFile =
|
|
31496
|
+
async function status(rootDir = process11.cwd(), options = {}) {
|
|
31497
|
+
const stateFile = path60.join(rootDir, ".mancode", "state.json");
|
|
31498
|
+
const v3SchemaFile = path60.join(rootDir, ".mancode", "schema.json");
|
|
30737
31499
|
if (await pathExists13(v3SchemaFile)) {
|
|
30738
31500
|
return statusV3(rootDir, options);
|
|
30739
31501
|
}
|
|
30740
31502
|
if (!await pathExists13(stateFile)) {
|
|
30741
31503
|
console.error("\u2717 mancode not initialized.");
|
|
30742
31504
|
console.error(" Run `mancode init` to get started.");
|
|
30743
|
-
return
|
|
31505
|
+
return EXIT_NOT_INITIALIZED6;
|
|
30744
31506
|
}
|
|
30745
31507
|
let state;
|
|
30746
31508
|
try {
|
|
@@ -30797,7 +31559,7 @@ async function status(rootDir = process10.cwd(), options = {}) {
|
|
|
30797
31559
|
} else {
|
|
30798
31560
|
printText(result2);
|
|
30799
31561
|
}
|
|
30800
|
-
return
|
|
31562
|
+
return EXIT_OK9;
|
|
30801
31563
|
}
|
|
30802
31564
|
async function statusV3(rootDir, options) {
|
|
30803
31565
|
try {
|
|
@@ -30938,7 +31700,7 @@ async function statusV3(rootDir, options) {
|
|
|
30938
31700
|
} else {
|
|
30939
31701
|
printV3Text(result2);
|
|
30940
31702
|
}
|
|
30941
|
-
return
|
|
31703
|
+
return EXIT_OK9;
|
|
30942
31704
|
} catch (error) {
|
|
30943
31705
|
const message = error instanceof Error ? error.message : String(error);
|
|
30944
31706
|
console.error("\u2717 .mancode/schema.json is corrupt or incomplete.");
|
|
@@ -30967,7 +31729,7 @@ function toContinuityStatus(result2) {
|
|
|
30967
31729
|
};
|
|
30968
31730
|
}
|
|
30969
31731
|
async function readV3StatusSession(rootDir) {
|
|
30970
|
-
const sessionId =
|
|
31732
|
+
const sessionId = process11.env.MANCODE_SESSION_ID;
|
|
30971
31733
|
if (sessionId === void 0 || !sessionId) return null;
|
|
30972
31734
|
try {
|
|
30973
31735
|
assertUlid(sessionId, "status sessionId");
|
|
@@ -30978,10 +31740,10 @@ async function readV3StatusSession(rootDir) {
|
|
|
30978
31740
|
}
|
|
30979
31741
|
async function shouldRefreshProject(rootDir, state) {
|
|
30980
31742
|
if (state.projectMode !== "generic") return false;
|
|
30981
|
-
const hasGit = await pathExists13(
|
|
31743
|
+
const hasGit = await pathExists13(path60.join(rootDir, ".git"));
|
|
30982
31744
|
if (hasGit) return true;
|
|
30983
31745
|
for (const manifest of PROJECT_MANIFESTS) {
|
|
30984
|
-
if (await pathExists13(
|
|
31746
|
+
if (await pathExists13(path60.join(rootDir, manifest))) return true;
|
|
30985
31747
|
}
|
|
30986
31748
|
return false;
|
|
30987
31749
|
}
|
|
@@ -31025,19 +31787,19 @@ async function getCurrentWorkflow(rootDir, taskId) {
|
|
|
31025
31787
|
}
|
|
31026
31788
|
async function getProjectName(rootDir) {
|
|
31027
31789
|
try {
|
|
31028
|
-
const raw = await fs9.readFile(
|
|
31790
|
+
const raw = await fs9.readFile(path60.join(rootDir, "package.json"), "utf-8");
|
|
31029
31791
|
const pkg = JSON.parse(raw);
|
|
31030
31792
|
if (pkg.name && typeof pkg.name === "string") {
|
|
31031
31793
|
return pkg.name;
|
|
31032
31794
|
}
|
|
31033
31795
|
} catch {
|
|
31034
31796
|
}
|
|
31035
|
-
return
|
|
31797
|
+
return path60.basename(rootDir);
|
|
31036
31798
|
}
|
|
31037
31799
|
async function readConfig3(rootDir) {
|
|
31038
31800
|
try {
|
|
31039
31801
|
const raw = await fs9.readFile(
|
|
31040
|
-
|
|
31802
|
+
path60.join(rootDir, ".mancode", "config.json"),
|
|
31041
31803
|
"utf-8"
|
|
31042
31804
|
);
|
|
31043
31805
|
return JSON.parse(raw);
|
|
@@ -31065,9 +31827,9 @@ function getEffectiveTeamStatus(state, config, detected) {
|
|
|
31065
31827
|
}
|
|
31066
31828
|
async function checkHooks(rootDir) {
|
|
31067
31829
|
const [sessionStart, userPromptSubmit, registered] = await Promise.all([
|
|
31068
|
-
pathExists13(
|
|
31830
|
+
pathExists13(path60.join(rootDir, ".mancode", "hooks", "session-start.mjs")),
|
|
31069
31831
|
pathExists13(
|
|
31070
|
-
|
|
31832
|
+
path60.join(rootDir, ".mancode", "hooks", "user-prompt-submit.mjs")
|
|
31071
31833
|
),
|
|
31072
31834
|
isRegistered(rootDir)
|
|
31073
31835
|
]);
|
|
@@ -31076,7 +31838,7 @@ async function checkHooks(rootDir) {
|
|
|
31076
31838
|
async function isRegistered(rootDir) {
|
|
31077
31839
|
try {
|
|
31078
31840
|
const raw = await fs9.readFile(
|
|
31079
|
-
|
|
31841
|
+
path60.join(rootDir, ".claude", "settings.json"),
|
|
31080
31842
|
"utf-8"
|
|
31081
31843
|
);
|
|
31082
31844
|
const settings = JSON.parse(raw);
|
|
@@ -31086,9 +31848,9 @@ async function isRegistered(rootDir) {
|
|
|
31086
31848
|
}
|
|
31087
31849
|
}
|
|
31088
31850
|
function hooksRegistered2(settings) {
|
|
31089
|
-
if (!
|
|
31851
|
+
if (!isRecord12(settings)) return false;
|
|
31090
31852
|
const hooks = settings.hooks;
|
|
31091
|
-
if (!
|
|
31853
|
+
if (!isRecord12(hooks)) return false;
|
|
31092
31854
|
return hasHookCommand2(hooks.SessionStart, ".mancode/hooks/session-start.mjs") && hasHookCommand2(
|
|
31093
31855
|
hooks.UserPromptSubmit,
|
|
31094
31856
|
".mancode/hooks/user-prompt-submit.mjs"
|
|
@@ -31097,15 +31859,15 @@ function hooksRegistered2(settings) {
|
|
|
31097
31859
|
function hasHookCommand2(value, needle) {
|
|
31098
31860
|
if (!Array.isArray(value)) return false;
|
|
31099
31861
|
return value.some((group) => {
|
|
31100
|
-
if (!
|
|
31862
|
+
if (!isRecord12(group) || !Array.isArray(group.hooks)) return false;
|
|
31101
31863
|
return group.hooks.some((hook) => {
|
|
31102
|
-
if (!
|
|
31864
|
+
if (!isRecord12(hook) || typeof hook.command !== "string") return false;
|
|
31103
31865
|
return hook.command.includes(needle);
|
|
31104
31866
|
});
|
|
31105
31867
|
});
|
|
31106
31868
|
}
|
|
31107
31869
|
async function estimateHookInjection(rootDir) {
|
|
31108
|
-
const hookPath =
|
|
31870
|
+
const hookPath = path60.join(
|
|
31109
31871
|
rootDir,
|
|
31110
31872
|
".mancode",
|
|
31111
31873
|
"hooks",
|
|
@@ -31126,7 +31888,7 @@ async function estimateHookInjection(rootDir) {
|
|
|
31126
31888
|
}
|
|
31127
31889
|
function runHookEstimate(rootDir, hookPath) {
|
|
31128
31890
|
return new Promise((resolve, reject) => {
|
|
31129
|
-
const child = spawn(
|
|
31891
|
+
const child = spawn(process11.execPath, [hookPath], {
|
|
31130
31892
|
cwd: rootDir,
|
|
31131
31893
|
stdio: ["pipe", "pipe", "ignore"]
|
|
31132
31894
|
});
|
|
@@ -31324,7 +32086,7 @@ function formatTeamStatus(team) {
|
|
|
31324
32086
|
function workflowStepMax(mode) {
|
|
31325
32087
|
return maxWorkflowStep(mode);
|
|
31326
32088
|
}
|
|
31327
|
-
function
|
|
32089
|
+
function isRecord12(value) {
|
|
31328
32090
|
return typeof value === "object" && value !== null;
|
|
31329
32091
|
}
|
|
31330
32092
|
async function pathExists13(p) {
|
|
@@ -32602,8 +33364,8 @@ function assertPositiveRevision2(value, label) {
|
|
|
32602
33364
|
}
|
|
32603
33365
|
|
|
32604
33366
|
// src/team/git-ref-handoff-repair.ts
|
|
32605
|
-
import { lstat as
|
|
32606
|
-
import
|
|
33367
|
+
import { lstat as lstat23, mkdir as mkdir37, readFile as readFile43, readdir as readdir19, writeFile as writeFile42 } from "fs/promises";
|
|
33368
|
+
import path61 from "path";
|
|
32607
33369
|
|
|
32608
33370
|
// src/team/git-ref-operation.ts
|
|
32609
33371
|
import { execFile as execFileCallback6 } from "child_process";
|
|
@@ -32739,7 +33501,7 @@ function openMutationContext(manifest, input) {
|
|
|
32739
33501
|
}
|
|
32740
33502
|
function prepareOwnershipFence(context, taskBundle, expectedPredecessorBundleDigest) {
|
|
32741
33503
|
const metadata = metadataFromBundle2(taskBundle);
|
|
32742
|
-
|
|
33504
|
+
assertRemoteTaskCoordination(metadata);
|
|
32743
33505
|
assertTaskBundleIdentity(taskBundle, context.taskRef);
|
|
32744
33506
|
if (metadata.ownerActorId === null) {
|
|
32745
33507
|
throw new Error("MANCODE_TASK_OWNER_REQUIRED");
|
|
@@ -32748,6 +33510,7 @@ function prepareOwnershipFence(context, taskBundle, expectedPredecessorBundleDig
|
|
|
32748
33510
|
throw new Error("MANCODE_TASK_BUNDLE_DIVERGED");
|
|
32749
33511
|
}
|
|
32750
33512
|
if (context.fence === null) {
|
|
33513
|
+
assertRemoteTaskEligible(metadata);
|
|
32751
33514
|
if (metadata.ownerActorId !== context.input.actorId || metadata.ownershipEpoch !== 0 || taskBundle.ownershipEpoch !== 0) {
|
|
32752
33515
|
throw new Error("MANCODE_TASK_OWNER_REQUIRED");
|
|
32753
33516
|
}
|
|
@@ -32760,6 +33523,7 @@ function prepareOwnershipFence(context, taskBundle, expectedPredecessorBundleDig
|
|
|
32760
33523
|
throw new Error("MANCODE_TASK_REVISION_CONFLICT");
|
|
32761
33524
|
}
|
|
32762
33525
|
if (taskBundle.taskRevision === context.fence.taskRevision) {
|
|
33526
|
+
assertRemoteTaskRebindEligible(metadata);
|
|
32763
33527
|
if (taskBundle.aggregateDigest !== context.fence.aggregateDigest) {
|
|
32764
33528
|
throw new Error("MANCODE_SPLIT_BRAIN");
|
|
32765
33529
|
}
|
|
@@ -32774,6 +33538,7 @@ function prepareOwnershipFence(context, taskBundle, expectedPredecessorBundleDig
|
|
|
32774
33538
|
taskBundle
|
|
32775
33539
|
);
|
|
32776
33540
|
}
|
|
33541
|
+
assertRemoteTaskEligible(metadata);
|
|
32777
33542
|
}
|
|
32778
33543
|
const codeHeadChanged = context.taskBundle !== null && (taskBundle.codeRef.branch !== context.taskBundle.codeRef.branch || taskBundle.codeRef.head !== context.taskBundle.codeRef.head);
|
|
32779
33544
|
const fence = buildFence(context, taskBundle, metadata.ownerActorId);
|
|
@@ -33372,7 +34137,19 @@ function metadataFromBundle2(taskBundle) {
|
|
|
33372
34137
|
return metadata;
|
|
33373
34138
|
}
|
|
33374
34139
|
function assertRemoteTaskEligible(metadata) {
|
|
33375
|
-
|
|
34140
|
+
assertRemoteTaskCoordination(metadata);
|
|
34141
|
+
if (metadata.status !== "in_progress") {
|
|
34142
|
+
throw new Error("MANCODE_REMOTE_COORDINATION_TASK_INVALID");
|
|
34143
|
+
}
|
|
34144
|
+
}
|
|
34145
|
+
function assertRemoteTaskRebindEligible(metadata) {
|
|
34146
|
+
assertRemoteTaskCoordination(metadata);
|
|
34147
|
+
if (metadata.status !== "in_progress" && metadata.status !== "blocked") {
|
|
34148
|
+
throw new Error("MANCODE_REMOTE_COORDINATION_TASK_INVALID");
|
|
34149
|
+
}
|
|
34150
|
+
}
|
|
34151
|
+
function assertRemoteTaskCoordination(metadata) {
|
|
34152
|
+
if (metadata.workflowMode !== "manteam" || metadata.coordination !== "team") {
|
|
33376
34153
|
throw new Error("MANCODE_REMOTE_COORDINATION_TASK_INVALID");
|
|
33377
34154
|
}
|
|
33378
34155
|
}
|
|
@@ -35166,7 +35943,7 @@ async function recoverGitRefHandoffRepairs(projectRoot) {
|
|
|
35166
35943
|
}
|
|
35167
35944
|
async function recoverGitRefHandoffRepair(projectRoot, operationId, transportReceipt) {
|
|
35168
35945
|
assertUlid(operationId, "git-ref handoff repair operationId");
|
|
35169
|
-
const root =
|
|
35946
|
+
const root = path61.resolve(projectRoot);
|
|
35170
35947
|
let journal = await requireJournal2(root, operationId);
|
|
35171
35948
|
if (journal.state === "committed" || journal.state === "aborted") {
|
|
35172
35949
|
return recoveryResult2(journal);
|
|
@@ -35245,7 +36022,7 @@ async function recoverGitRefHandoffRepair(projectRoot, operationId, transportRec
|
|
|
35245
36022
|
}
|
|
35246
36023
|
}
|
|
35247
36024
|
async function prepareHandoffRepairWhileTaskLocked(projectRoot, rawPrepared) {
|
|
35248
|
-
const root =
|
|
36025
|
+
const root = path61.resolve(projectRoot);
|
|
35249
36026
|
const prepared2 = parsePrepared2(rawPrepared);
|
|
35250
36027
|
const runtime = await readProjectRuntimeContext(root);
|
|
35251
36028
|
const previousMetadata = bundleMetadata2(prepared2.predecessorBundle);
|
|
@@ -35308,7 +36085,7 @@ async function restorePredecessorMetadata2(projectRoot, journal) {
|
|
|
35308
36085
|
);
|
|
35309
36086
|
}
|
|
35310
36087
|
async function replaceMetadataVerified(projectRoot, expected, targetMetadata, alternateExpected) {
|
|
35311
|
-
const target =
|
|
36088
|
+
const target = path61.join(
|
|
35312
36089
|
taskRootPath(projectRoot, targetMetadata.taskRef),
|
|
35313
36090
|
"metadata.json"
|
|
35314
36091
|
);
|
|
@@ -35434,7 +36211,7 @@ async function createJournal3(projectRoot, journal) {
|
|
|
35434
36211
|
await ensureJournalDirectory2(projectRoot);
|
|
35435
36212
|
const target = journalPath3(projectRoot, journal.operationId);
|
|
35436
36213
|
try {
|
|
35437
|
-
await
|
|
36214
|
+
await writeFile42(target, serialize13(journal), {
|
|
35438
36215
|
encoding: "utf8",
|
|
35439
36216
|
flag: "wx"
|
|
35440
36217
|
});
|
|
@@ -35453,10 +36230,10 @@ async function replaceJournal3(projectRoot, journal) {
|
|
|
35453
36230
|
async function requireJournal2(projectRoot, operationId) {
|
|
35454
36231
|
try {
|
|
35455
36232
|
return parseJournal3(
|
|
35456
|
-
JSON.parse(await
|
|
36233
|
+
JSON.parse(await readFile43(journalPath3(projectRoot, operationId), "utf8"))
|
|
35457
36234
|
);
|
|
35458
36235
|
} catch (error) {
|
|
35459
|
-
if (error instanceof SyntaxError ||
|
|
36236
|
+
if (error instanceof SyntaxError || isNotFound30(error)) {
|
|
35460
36237
|
throw new Error("MANCODE_HANDOFF_REPAIR_JOURNAL_NOT_FOUND");
|
|
35461
36238
|
}
|
|
35462
36239
|
throw error;
|
|
@@ -35467,7 +36244,7 @@ async function listJournals2(projectRoot) {
|
|
|
35467
36244
|
try {
|
|
35468
36245
|
entries = await readdir19(journalDirectory2(projectRoot));
|
|
35469
36246
|
} catch (error) {
|
|
35470
|
-
if (
|
|
36247
|
+
if (isNotFound30(error)) return [];
|
|
35471
36248
|
throw error;
|
|
35472
36249
|
}
|
|
35473
36250
|
const journals = [];
|
|
@@ -35476,8 +36253,8 @@ async function listJournals2(projectRoot) {
|
|
|
35476
36253
|
journals.push(
|
|
35477
36254
|
parseJournal3(
|
|
35478
36255
|
JSON.parse(
|
|
35479
|
-
await
|
|
35480
|
-
|
|
36256
|
+
await readFile43(
|
|
36257
|
+
path61.join(journalDirectory2(projectRoot), entry),
|
|
35481
36258
|
"utf8"
|
|
35482
36259
|
)
|
|
35483
36260
|
)
|
|
@@ -35487,43 +36264,43 @@ async function listJournals2(projectRoot) {
|
|
|
35487
36264
|
return journals;
|
|
35488
36265
|
}
|
|
35489
36266
|
async function readSafeFile2(target) {
|
|
35490
|
-
const before = await
|
|
36267
|
+
const before = await lstat23(target);
|
|
35491
36268
|
if (!before.isFile() || before.isSymbolicLink()) {
|
|
35492
36269
|
throw new Error("MANCODE_ARTIFACT_PATH_UNSAFE");
|
|
35493
36270
|
}
|
|
35494
|
-
const content = await
|
|
35495
|
-
const after = await
|
|
36271
|
+
const content = await readFile43(target, "utf8");
|
|
36272
|
+
const after = await lstat23(target);
|
|
35496
36273
|
if (!after.isFile() || after.isSymbolicLink() || before.dev !== after.dev || before.ino !== after.ino) {
|
|
35497
36274
|
throw new Error("MANCODE_ARTIFACT_PATH_UNSAFE");
|
|
35498
36275
|
}
|
|
35499
36276
|
return content;
|
|
35500
36277
|
}
|
|
35501
36278
|
async function atomicWrite2(target, content) {
|
|
35502
|
-
const temporary =
|
|
35503
|
-
|
|
35504
|
-
`.${
|
|
36279
|
+
const temporary = path61.join(
|
|
36280
|
+
path61.dirname(target),
|
|
36281
|
+
`.${path61.basename(target)}.${process.pid}.${Date.now()}.tmp`
|
|
35505
36282
|
);
|
|
35506
|
-
await
|
|
36283
|
+
await writeFile42(temporary, content, { encoding: "utf8", flag: "wx" });
|
|
35507
36284
|
await replaceFileAtomically(temporary, target);
|
|
35508
36285
|
}
|
|
35509
36286
|
async function ensureJournalDirectory2(projectRoot) {
|
|
35510
|
-
let current =
|
|
36287
|
+
let current = path61.resolve(projectRoot);
|
|
35511
36288
|
for (const segment of [".mancode", "local", "journals", "git-ref-handoff"]) {
|
|
35512
|
-
current =
|
|
36289
|
+
current = path61.join(current, segment);
|
|
35513
36290
|
try {
|
|
35514
|
-
await
|
|
36291
|
+
await mkdir37(current);
|
|
35515
36292
|
} catch (error) {
|
|
35516
36293
|
if (!isAlreadyExists24(error)) throw error;
|
|
35517
36294
|
}
|
|
35518
|
-
const entry = await
|
|
36295
|
+
const entry = await lstat23(current);
|
|
35519
36296
|
if (!entry.isDirectory() || entry.isSymbolicLink()) {
|
|
35520
36297
|
throw new Error("MANCODE_ARTIFACT_PATH_UNSAFE");
|
|
35521
36298
|
}
|
|
35522
36299
|
}
|
|
35523
36300
|
}
|
|
35524
36301
|
function journalDirectory2(projectRoot) {
|
|
35525
|
-
return
|
|
35526
|
-
|
|
36302
|
+
return path61.join(
|
|
36303
|
+
path61.resolve(projectRoot),
|
|
35527
36304
|
".mancode",
|
|
35528
36305
|
"local",
|
|
35529
36306
|
"journals",
|
|
@@ -35532,7 +36309,7 @@ function journalDirectory2(projectRoot) {
|
|
|
35532
36309
|
}
|
|
35533
36310
|
function journalPath3(projectRoot, operationId) {
|
|
35534
36311
|
assertUlid(operationId, "git-ref handoff repair operationId");
|
|
35535
|
-
return
|
|
36312
|
+
return path61.join(journalDirectory2(projectRoot), `${operationId}.json`);
|
|
35536
36313
|
}
|
|
35537
36314
|
function serialize13(value) {
|
|
35538
36315
|
return `${JSON.stringify(value, null, 2)}
|
|
@@ -35547,7 +36324,7 @@ function parseTimestamp15(value) {
|
|
|
35547
36324
|
function isAlreadyExists24(error) {
|
|
35548
36325
|
return typeof error === "object" && error !== null && "code" in error && error.code === "EEXIST";
|
|
35549
36326
|
}
|
|
35550
|
-
function
|
|
36327
|
+
function isNotFound30(error) {
|
|
35551
36328
|
return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
|
|
35552
36329
|
}
|
|
35553
36330
|
|
|
@@ -35631,8 +36408,8 @@ function parseReceipt(value) {
|
|
|
35631
36408
|
}
|
|
35632
36409
|
|
|
35633
36410
|
// src/team/policy-operation.ts
|
|
35634
|
-
import { lstat as
|
|
35635
|
-
import
|
|
36411
|
+
import { lstat as lstat24, mkdir as mkdir38, readdir as readdir20, unlink as unlink3, writeFile as writeFile43 } from "fs/promises";
|
|
36412
|
+
import path62 from "path";
|
|
35636
36413
|
async function updateTeamPolicy(input) {
|
|
35637
36414
|
const operationId = input.operationId ?? createUlid();
|
|
35638
36415
|
const eventId = createUlid();
|
|
@@ -35643,7 +36420,7 @@ async function updateTeamPolicy(input) {
|
|
|
35643
36420
|
throw new Error("MANCODE_TEAM_POLICY_INVALID");
|
|
35644
36421
|
}
|
|
35645
36422
|
const now = input.now ?? /* @__PURE__ */ new Date();
|
|
35646
|
-
const root =
|
|
36423
|
+
const root = path62.resolve(input.projectRoot);
|
|
35647
36424
|
const runtime = await readProjectRuntimeContext(root);
|
|
35648
36425
|
const store = resolveCoordinationEntityHomeStore(
|
|
35649
36426
|
runtime.entityHomeStoreContext
|
|
@@ -35724,7 +36501,7 @@ async function applyTeamTransportSet(input, write2) {
|
|
|
35724
36501
|
}
|
|
35725
36502
|
const remote = transportRemote(input.mode, input.remote);
|
|
35726
36503
|
const now = input.now ?? /* @__PURE__ */ new Date();
|
|
35727
|
-
const root =
|
|
36504
|
+
const root = path62.resolve(input.projectRoot);
|
|
35728
36505
|
const runtime = await readProjectRuntimeContext(root);
|
|
35729
36506
|
const store = resolveCoordinationEntityHomeStore(
|
|
35730
36507
|
runtime.entityHomeStoreContext
|
|
@@ -35857,9 +36634,9 @@ async function assertTransportAuthorityEmpty(projectRoot, store) {
|
|
|
35857
36634
|
listClaims(store),
|
|
35858
36635
|
listHandoffs(store),
|
|
35859
36636
|
directoryHasEntries(taskHeadDirectory(store)),
|
|
35860
|
-
directoryHasEntries(
|
|
36637
|
+
directoryHasEntries(path62.join(store.root, "transport-migrations")),
|
|
35861
36638
|
directoryHasEntries(
|
|
35862
|
-
|
|
36639
|
+
path62.join(projectRoot, ".mancode", "shared", "team", "transport")
|
|
35863
36640
|
),
|
|
35864
36641
|
pathExists14(gitRefCachePath(projectRoot))
|
|
35865
36642
|
]);
|
|
@@ -35889,21 +36666,21 @@ function assertPositiveRevision5(value, label) {
|
|
|
35889
36666
|
}
|
|
35890
36667
|
}
|
|
35891
36668
|
function teamPolicyPath(projectRoot) {
|
|
35892
|
-
return
|
|
36669
|
+
return path62.join(projectRoot, ".mancode", "shared", "team", "policy.json");
|
|
35893
36670
|
}
|
|
35894
36671
|
function projectConfigPath(projectRoot) {
|
|
35895
|
-
return
|
|
36672
|
+
return path62.join(projectRoot, ".mancode", "shared", "config.json");
|
|
35896
36673
|
}
|
|
35897
36674
|
async function writeJsonAtomic4(target, value) {
|
|
35898
|
-
await
|
|
35899
|
-
await assertPlainDirectory(
|
|
36675
|
+
await mkdir38(path62.dirname(target), { recursive: true });
|
|
36676
|
+
await assertPlainDirectory(path62.dirname(target));
|
|
35900
36677
|
await assertPlainFileOrMissing(target);
|
|
35901
|
-
const temporary =
|
|
35902
|
-
|
|
35903
|
-
`.${
|
|
36678
|
+
const temporary = path62.join(
|
|
36679
|
+
path62.dirname(target),
|
|
36680
|
+
`.${path62.basename(target)}.${process.pid}.${createUlid()}.tmp`
|
|
35904
36681
|
);
|
|
35905
36682
|
try {
|
|
35906
|
-
await
|
|
36683
|
+
await writeFile43(temporary, `${JSON.stringify(value, null, 2)}
|
|
35907
36684
|
`, {
|
|
35908
36685
|
encoding: "utf8",
|
|
35909
36686
|
flag: "wx"
|
|
@@ -35915,61 +36692,61 @@ async function writeJsonAtomic4(target, value) {
|
|
|
35915
36692
|
}
|
|
35916
36693
|
}
|
|
35917
36694
|
async function assertPlainDirectory(target) {
|
|
35918
|
-
const entry = await
|
|
36695
|
+
const entry = await lstat24(target);
|
|
35919
36696
|
if (!entry.isDirectory() || entry.isSymbolicLink()) {
|
|
35920
36697
|
throw new Error("MANCODE_ARTIFACT_PATH_UNSAFE");
|
|
35921
36698
|
}
|
|
35922
36699
|
}
|
|
35923
36700
|
async function assertPlainFileOrMissing(target) {
|
|
35924
36701
|
try {
|
|
35925
|
-
const entry = await
|
|
36702
|
+
const entry = await lstat24(target);
|
|
35926
36703
|
if (!entry.isFile() || entry.isSymbolicLink()) {
|
|
35927
36704
|
throw new Error("MANCODE_ARTIFACT_PATH_UNSAFE");
|
|
35928
36705
|
}
|
|
35929
36706
|
} catch (error) {
|
|
35930
|
-
if (
|
|
36707
|
+
if (isNotFound31(error)) return;
|
|
35931
36708
|
throw error;
|
|
35932
36709
|
}
|
|
35933
36710
|
}
|
|
35934
36711
|
async function directoryHasEntries(target) {
|
|
35935
36712
|
try {
|
|
35936
|
-
const entry = await
|
|
36713
|
+
const entry = await lstat24(target);
|
|
35937
36714
|
if (!entry.isDirectory() || entry.isSymbolicLink()) {
|
|
35938
36715
|
throw new Error("MANCODE_ARTIFACT_PATH_UNSAFE");
|
|
35939
36716
|
}
|
|
35940
36717
|
return (await readdir20(target)).length > 0;
|
|
35941
36718
|
} catch (error) {
|
|
35942
|
-
if (
|
|
36719
|
+
if (isNotFound31(error)) return false;
|
|
35943
36720
|
throw error;
|
|
35944
36721
|
}
|
|
35945
36722
|
}
|
|
35946
36723
|
async function pathExists14(target) {
|
|
35947
36724
|
try {
|
|
35948
|
-
await
|
|
36725
|
+
await lstat24(target);
|
|
35949
36726
|
return true;
|
|
35950
36727
|
} catch (error) {
|
|
35951
|
-
if (
|
|
36728
|
+
if (isNotFound31(error)) return false;
|
|
35952
36729
|
throw error;
|
|
35953
36730
|
}
|
|
35954
36731
|
}
|
|
35955
36732
|
async function releaseLocks4(locks) {
|
|
35956
36733
|
await Promise.allSettled([...locks].reverse().map((lock) => lock.release()));
|
|
35957
36734
|
}
|
|
35958
|
-
function
|
|
36735
|
+
function isNotFound31(error) {
|
|
35959
36736
|
return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
|
|
35960
36737
|
}
|
|
35961
36738
|
|
|
35962
36739
|
// src/team/transport-migration-adapters.ts
|
|
35963
36740
|
import {
|
|
35964
|
-
lstat as
|
|
35965
|
-
mkdir as
|
|
35966
|
-
readFile as
|
|
36741
|
+
lstat as lstat25,
|
|
36742
|
+
mkdir as mkdir39,
|
|
36743
|
+
readFile as readFile44,
|
|
35967
36744
|
readdir as readdir21,
|
|
35968
36745
|
rename as rename12,
|
|
35969
36746
|
unlink as unlink4,
|
|
35970
|
-
writeFile as
|
|
36747
|
+
writeFile as writeFile44
|
|
35971
36748
|
} from "fs/promises";
|
|
35972
|
-
import
|
|
36749
|
+
import path63 from "path";
|
|
35973
36750
|
|
|
35974
36751
|
// src/team/transport-migration.ts
|
|
35975
36752
|
var DIGEST_PATTERN7 = /^sha256:[a-f0-9]{64}$/;
|
|
@@ -36932,7 +37709,7 @@ function parseTaskSnapshot(value) {
|
|
|
36932
37709
|
assertUlid(ownerActorId, "transport migration task ownerActorId");
|
|
36933
37710
|
}
|
|
36934
37711
|
const taskRevision = parsePositiveInteger5(value.taskRevision, "taskRevision");
|
|
36935
|
-
const ownershipEpoch =
|
|
37712
|
+
const ownershipEpoch = parseNonNegativeInteger3(
|
|
36936
37713
|
value.ownershipEpoch,
|
|
36937
37714
|
"ownershipEpoch"
|
|
36938
37715
|
);
|
|
@@ -37009,7 +37786,7 @@ function parsePositiveInteger5(value, label) {
|
|
|
37009
37786
|
}
|
|
37010
37787
|
return value;
|
|
37011
37788
|
}
|
|
37012
|
-
function
|
|
37789
|
+
function parseNonNegativeInteger3(value, label) {
|
|
37013
37790
|
if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 0) {
|
|
37014
37791
|
throw new Error(`${label} must be a non-negative integer`);
|
|
37015
37792
|
}
|
|
@@ -37041,7 +37818,7 @@ function compareUtf813(left, right) {
|
|
|
37041
37818
|
var STAGE_DIRECTORY = "transport-migrations";
|
|
37042
37819
|
var COLLECTIONS = ["claims", "handoffs", "task-heads"];
|
|
37043
37820
|
async function createTransportMigrationFileAdapters(input) {
|
|
37044
|
-
const projectRoot =
|
|
37821
|
+
const projectRoot = path63.resolve(input.projectRoot);
|
|
37045
37822
|
assertUlid(input.actorId, "transport migration adapter actorId");
|
|
37046
37823
|
if (input.operationId !== void 0) {
|
|
37047
37824
|
assertUlid(input.operationId, "transport migration adapter operationId");
|
|
@@ -37093,9 +37870,8 @@ async function createTransportMigrationFileAdapters(input) {
|
|
|
37093
37870
|
var FileSystemTransportMigrationConfigAdapter = class {
|
|
37094
37871
|
constructor(projectRoot, coordinationStore) {
|
|
37095
37872
|
this.coordinationStore = coordinationStore;
|
|
37096
|
-
this.projectRoot =
|
|
37873
|
+
this.projectRoot = path63.resolve(projectRoot);
|
|
37097
37874
|
}
|
|
37098
|
-
coordinationStore;
|
|
37099
37875
|
projectRoot;
|
|
37100
37876
|
async read() {
|
|
37101
37877
|
return readProjectConfigFile(this.projectRoot);
|
|
@@ -37136,9 +37912,6 @@ var LocalTransportMigrationSourceAdapter = class {
|
|
|
37136
37912
|
this.authorityId = authorityId;
|
|
37137
37913
|
this.coordinationDomainId = coordinationDomainId2;
|
|
37138
37914
|
}
|
|
37139
|
-
context;
|
|
37140
|
-
authorityId;
|
|
37141
|
-
coordinationDomainId;
|
|
37142
37915
|
mode = "local";
|
|
37143
37916
|
remote = null;
|
|
37144
37917
|
async freeze(input) {
|
|
@@ -37345,9 +38118,6 @@ var GitRefTransportMigrationSourceAdapter = class {
|
|
|
37345
38118
|
this.store = store;
|
|
37346
38119
|
this.remote = requireRemote(context.sourceConfig.transport.remote);
|
|
37347
38120
|
}
|
|
37348
|
-
context;
|
|
37349
|
-
authorityId;
|
|
37350
|
-
store;
|
|
37351
38121
|
mode = "git-ref";
|
|
37352
38122
|
remote;
|
|
37353
38123
|
async freeze(input) {
|
|
@@ -37475,9 +38245,6 @@ var FileStagedTransportTarget = class {
|
|
|
37475
38245
|
this.authorityId = authorityId;
|
|
37476
38246
|
this.coordinationDomainId = coordinationDomainId2;
|
|
37477
38247
|
}
|
|
37478
|
-
context;
|
|
37479
|
-
authorityId;
|
|
37480
|
-
coordinationDomainId;
|
|
37481
38248
|
async stage(manifestValue) {
|
|
37482
38249
|
const manifest = parseTransportMigrationManifest(manifestValue);
|
|
37483
38250
|
this.assertManifestTarget(manifest);
|
|
@@ -37956,27 +38723,27 @@ async function publishMigrationActorProfiles(projectRoot, profiles) {
|
|
|
37956
38723
|
}
|
|
37957
38724
|
}
|
|
37958
38725
|
async function archiveLocalCoordinationCollections(store, operationId) {
|
|
37959
|
-
const archiveRoot =
|
|
38726
|
+
const archiveRoot = path63.join(
|
|
37960
38727
|
store.root,
|
|
37961
38728
|
STAGE_DIRECTORY,
|
|
37962
38729
|
"archive",
|
|
37963
38730
|
operationId
|
|
37964
38731
|
);
|
|
37965
|
-
await
|
|
38732
|
+
await mkdir39(archiveRoot, { recursive: true });
|
|
37966
38733
|
const directories = {
|
|
37967
38734
|
claims: claimDirectory(store),
|
|
37968
38735
|
handoffs: handoffDirectory(store),
|
|
37969
38736
|
"task-heads": taskHeadDirectory(store)
|
|
37970
38737
|
};
|
|
37971
38738
|
for (const name of COLLECTIONS) {
|
|
37972
|
-
const archived =
|
|
37973
|
-
const absent =
|
|
38739
|
+
const archived = path63.join(archiveRoot, name);
|
|
38740
|
+
const absent = path63.join(archiveRoot, `${name}.absent`);
|
|
37974
38741
|
if (await pathKind(archived) === "directory" || await pathKind(absent) === "file") {
|
|
37975
38742
|
continue;
|
|
37976
38743
|
}
|
|
37977
38744
|
const sourceKind = await pathKind(directories[name]);
|
|
37978
38745
|
if (sourceKind === null) {
|
|
37979
|
-
await
|
|
38746
|
+
await writeFile44(absent, "\n", { encoding: "utf8", flag: "wx" });
|
|
37980
38747
|
continue;
|
|
37981
38748
|
}
|
|
37982
38749
|
if (sourceKind !== "directory") {
|
|
@@ -37991,7 +38758,7 @@ async function listActorProfiles(projectRoot) {
|
|
|
37991
38758
|
try {
|
|
37992
38759
|
entries = await readdir21(directory);
|
|
37993
38760
|
} catch (error) {
|
|
37994
|
-
if (
|
|
38761
|
+
if (isNotFound32(error)) return [];
|
|
37995
38762
|
throw error;
|
|
37996
38763
|
}
|
|
37997
38764
|
const profiles = [];
|
|
@@ -38008,19 +38775,19 @@ async function listActorProfiles(projectRoot) {
|
|
|
38008
38775
|
return profiles;
|
|
38009
38776
|
}
|
|
38010
38777
|
async function listSharedTaskRefs(projectRoot) {
|
|
38011
|
-
const directory =
|
|
38778
|
+
const directory = path63.join(projectRoot, ".mancode", "shared", "workflows");
|
|
38012
38779
|
let entries;
|
|
38013
38780
|
try {
|
|
38014
38781
|
entries = await readdir21(directory);
|
|
38015
38782
|
} catch (error) {
|
|
38016
|
-
if (
|
|
38783
|
+
if (isNotFound32(error)) return [];
|
|
38017
38784
|
throw error;
|
|
38018
38785
|
}
|
|
38019
38786
|
const refs = [];
|
|
38020
38787
|
for (const taskId of entries.sort(compareUtf814)) {
|
|
38021
38788
|
assertUlid(taskId, "shared workflow directory");
|
|
38022
|
-
const
|
|
38023
|
-
if (!
|
|
38789
|
+
const stat5 = await lstat25(path63.join(directory, taskId));
|
|
38790
|
+
if (!stat5.isDirectory() || stat5.isSymbolicLink()) {
|
|
38024
38791
|
throw new Error("MANCODE_CONTEXT_PATH_UNSAFE");
|
|
38025
38792
|
}
|
|
38026
38793
|
refs.push({ namespace: "shared", taskId });
|
|
@@ -38031,7 +38798,7 @@ async function readTaskSnapshotOrNull(projectRoot, taskRef) {
|
|
|
38031
38798
|
try {
|
|
38032
38799
|
return await new V3ContextStore(projectRoot).readTaskSnapshot(taskRef);
|
|
38033
38800
|
} catch (error) {
|
|
38034
|
-
if (error instanceof Error && (error.message === "MANCODE_TASK_NOT_FOUND" ||
|
|
38801
|
+
if (error instanceof Error && (error.message === "MANCODE_TASK_NOT_FOUND" || isNotFound32(error))) {
|
|
38035
38802
|
return null;
|
|
38036
38803
|
}
|
|
38037
38804
|
throw error;
|
|
@@ -38093,7 +38860,7 @@ async function readStagedRecord(store, operationId) {
|
|
|
38093
38860
|
);
|
|
38094
38861
|
}
|
|
38095
38862
|
function stagedPath(store, operationId) {
|
|
38096
|
-
return
|
|
38863
|
+
return path63.join(
|
|
38097
38864
|
store.root,
|
|
38098
38865
|
STAGE_DIRECTORY,
|
|
38099
38866
|
"staged",
|
|
@@ -38101,7 +38868,7 @@ function stagedPath(store, operationId) {
|
|
|
38101
38868
|
);
|
|
38102
38869
|
}
|
|
38103
38870
|
function establishedPath(store, operationId) {
|
|
38104
|
-
return
|
|
38871
|
+
return path63.join(
|
|
38105
38872
|
store.root,
|
|
38106
38873
|
STAGE_DIRECTORY,
|
|
38107
38874
|
"established",
|
|
@@ -38109,12 +38876,12 @@ function establishedPath(store, operationId) {
|
|
|
38109
38876
|
);
|
|
38110
38877
|
}
|
|
38111
38878
|
function projectConfigPath2(projectRoot) {
|
|
38112
|
-
return
|
|
38879
|
+
return path63.join(projectRoot, ".mancode", "shared", "config.json");
|
|
38113
38880
|
}
|
|
38114
38881
|
async function readProjectConfigFile(projectRoot) {
|
|
38115
38882
|
try {
|
|
38116
38883
|
return parseProjectConfig(
|
|
38117
|
-
JSON.parse(await
|
|
38884
|
+
JSON.parse(await readFile44(projectConfigPath2(projectRoot), "utf8"))
|
|
38118
38885
|
);
|
|
38119
38886
|
} catch (error) {
|
|
38120
38887
|
if (error instanceof SyntaxError) {
|
|
@@ -38124,14 +38891,14 @@ async function readProjectConfigFile(projectRoot) {
|
|
|
38124
38891
|
}
|
|
38125
38892
|
}
|
|
38126
38893
|
async function writeJsonAtomic5(target, value) {
|
|
38127
|
-
await
|
|
38128
|
-
await assertPlainDirectory2(
|
|
38129
|
-
const temporary =
|
|
38130
|
-
|
|
38131
|
-
`.${
|
|
38894
|
+
await mkdir39(path63.dirname(target), { recursive: true });
|
|
38895
|
+
await assertPlainDirectory2(path63.dirname(target));
|
|
38896
|
+
const temporary = path63.join(
|
|
38897
|
+
path63.dirname(target),
|
|
38898
|
+
`.${path63.basename(target)}.${process.pid}.${createUlid()}.tmp`
|
|
38132
38899
|
);
|
|
38133
38900
|
try {
|
|
38134
|
-
await
|
|
38901
|
+
await writeFile44(temporary, serialize14(value), {
|
|
38135
38902
|
encoding: "utf8",
|
|
38136
38903
|
flag: "wx"
|
|
38137
38904
|
});
|
|
@@ -38142,10 +38909,10 @@ async function writeJsonAtomic5(target, value) {
|
|
|
38142
38909
|
}
|
|
38143
38910
|
}
|
|
38144
38911
|
async function writeJsonExclusiveOrEqual(target, value, parser, conflictCode) {
|
|
38145
|
-
await
|
|
38146
|
-
await assertPlainDirectory2(
|
|
38912
|
+
await mkdir39(path63.dirname(target), { recursive: true });
|
|
38913
|
+
await assertPlainDirectory2(path63.dirname(target));
|
|
38147
38914
|
try {
|
|
38148
|
-
await
|
|
38915
|
+
await writeFile44(target, serialize14(value), { encoding: "utf8", flag: "wx" });
|
|
38149
38916
|
} catch (error) {
|
|
38150
38917
|
if (!isAlreadyExists25(error)) throw error;
|
|
38151
38918
|
const existing = await readJsonOrNull5(target, parser, conflictCode);
|
|
@@ -38157,18 +38924,18 @@ async function writeJsonExclusiveOrEqual(target, value, parser, conflictCode) {
|
|
|
38157
38924
|
}
|
|
38158
38925
|
async function readJsonOrNull5(target, parser, corruptCode) {
|
|
38159
38926
|
try {
|
|
38160
|
-
const before = await
|
|
38927
|
+
const before = await lstat25(target);
|
|
38161
38928
|
if (!before.isFile() || before.isSymbolicLink()) {
|
|
38162
38929
|
throw new Error("MANCODE_TRANSPORT_MIGRATION_STAGE_UNSAFE");
|
|
38163
38930
|
}
|
|
38164
|
-
const parsed = parser(JSON.parse(await
|
|
38165
|
-
const after = await
|
|
38931
|
+
const parsed = parser(JSON.parse(await readFile44(target, "utf8")));
|
|
38932
|
+
const after = await lstat25(target);
|
|
38166
38933
|
if (!after.isFile() || after.isSymbolicLink() || before.dev !== after.dev || before.ino !== after.ino) {
|
|
38167
38934
|
throw new Error("MANCODE_TRANSPORT_MIGRATION_STAGE_UNSAFE");
|
|
38168
38935
|
}
|
|
38169
38936
|
return parsed;
|
|
38170
38937
|
} catch (error) {
|
|
38171
|
-
if (
|
|
38938
|
+
if (isNotFound32(error)) return null;
|
|
38172
38939
|
if (error instanceof SyntaxError) throw new Error(corruptCode);
|
|
38173
38940
|
throw error;
|
|
38174
38941
|
}
|
|
@@ -38220,19 +38987,19 @@ function requireRemote(value) {
|
|
|
38220
38987
|
}
|
|
38221
38988
|
async function pathKind(target) {
|
|
38222
38989
|
try {
|
|
38223
|
-
const
|
|
38224
|
-
if (
|
|
38225
|
-
if (
|
|
38226
|
-
if (
|
|
38990
|
+
const stat5 = await lstat25(target);
|
|
38991
|
+
if (stat5.isSymbolicLink()) return "other";
|
|
38992
|
+
if (stat5.isFile()) return "file";
|
|
38993
|
+
if (stat5.isDirectory()) return "directory";
|
|
38227
38994
|
return "other";
|
|
38228
38995
|
} catch (error) {
|
|
38229
|
-
if (
|
|
38996
|
+
if (isNotFound32(error)) return null;
|
|
38230
38997
|
throw error;
|
|
38231
38998
|
}
|
|
38232
38999
|
}
|
|
38233
39000
|
async function assertPlainDirectory2(target) {
|
|
38234
|
-
const
|
|
38235
|
-
if (!
|
|
39001
|
+
const stat5 = await lstat25(target);
|
|
39002
|
+
if (!stat5.isDirectory() || stat5.isSymbolicLink()) {
|
|
38236
39003
|
throw new Error("MANCODE_TRANSPORT_MIGRATION_STAGE_UNSAFE");
|
|
38237
39004
|
}
|
|
38238
39005
|
}
|
|
@@ -38240,7 +39007,7 @@ async function unlinkIfExists2(target) {
|
|
|
38240
39007
|
try {
|
|
38241
39008
|
await unlink4(target);
|
|
38242
39009
|
} catch (error) {
|
|
38243
|
-
if (!
|
|
39010
|
+
if (!isNotFound32(error)) throw error;
|
|
38244
39011
|
}
|
|
38245
39012
|
}
|
|
38246
39013
|
function serialize14(value) {
|
|
@@ -38253,7 +39020,7 @@ function compareUtf814(left, right) {
|
|
|
38253
39020
|
function isAlreadyExists25(error) {
|
|
38254
39021
|
return typeof error === "object" && error !== null && "code" in error && error.code === "EEXIST";
|
|
38255
39022
|
}
|
|
38256
|
-
function
|
|
39023
|
+
function isNotFound32(error) {
|
|
38257
39024
|
return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
|
|
38258
39025
|
}
|
|
38259
39026
|
|
|
@@ -39662,12 +40429,12 @@ function parseActorId2(value) {
|
|
|
39662
40429
|
function parseHandoffId(value) {
|
|
39663
40430
|
return parseUlidArgument(value, "MANCODE_HANDOFF_ID_INVALID");
|
|
39664
40431
|
}
|
|
39665
|
-
function parseUlidArgument(value,
|
|
40432
|
+
function parseUlidArgument(value, errorCode6) {
|
|
39666
40433
|
try {
|
|
39667
40434
|
assertUlid(value, "value");
|
|
39668
40435
|
return value;
|
|
39669
40436
|
} catch {
|
|
39670
|
-
throw new Error(
|
|
40437
|
+
throw new Error(errorCode6);
|
|
39671
40438
|
}
|
|
39672
40439
|
}
|
|
39673
40440
|
function parseTransportMode3(value) {
|
|
@@ -39693,23 +40460,23 @@ function parsePositiveInteger6(value) {
|
|
|
39693
40460
|
}
|
|
39694
40461
|
|
|
39695
40462
|
// src/commands/uninstall.ts
|
|
39696
|
-
import { access as access5, readFile as
|
|
39697
|
-
import
|
|
39698
|
-
import
|
|
39699
|
-
var
|
|
39700
|
-
var
|
|
40463
|
+
import { access as access5, readFile as readFile45, rm as rm20, writeFile as writeFile45 } from "fs/promises";
|
|
40464
|
+
import path64 from "path";
|
|
40465
|
+
import process12 from "process";
|
|
40466
|
+
var EXIT_OK10 = 0;
|
|
40467
|
+
var EXIT_NOT_INITIALIZED7 = 1;
|
|
39701
40468
|
var EXIT_UNSUPPORTED_PLATFORM2 = 2;
|
|
39702
40469
|
var EXIT_V3_AUTHORITY_PROTECTED = 3;
|
|
39703
|
-
async function uninstall(rootDir =
|
|
39704
|
-
const stateFile =
|
|
39705
|
-
const v3SchemaFile =
|
|
40470
|
+
async function uninstall(rootDir = process12.cwd(), platform, options = {}) {
|
|
40471
|
+
const stateFile = path64.join(rootDir, ".mancode", "state.json");
|
|
40472
|
+
const v3SchemaFile = path64.join(rootDir, ".mancode", "schema.json");
|
|
39706
40473
|
if (await pathExists15(v3SchemaFile)) {
|
|
39707
40474
|
return uninstallV3(rootDir, platform, options);
|
|
39708
40475
|
}
|
|
39709
40476
|
if (!await pathExists15(stateFile)) {
|
|
39710
40477
|
console.error("\u2717 mancode not initialized.");
|
|
39711
40478
|
console.error(" Run `mancode init` first.");
|
|
39712
|
-
return
|
|
40479
|
+
return EXIT_NOT_INITIALIZED7;
|
|
39713
40480
|
}
|
|
39714
40481
|
const removeAll = !platform || options.all;
|
|
39715
40482
|
if (platform) {
|
|
@@ -39734,7 +40501,7 @@ async function uninstall(rootDir = process11.cwd(), platform, options = {}) {
|
|
|
39734
40501
|
await uninstallPlatform(rootDir, platform ?? "claude-code");
|
|
39735
40502
|
}
|
|
39736
40503
|
console.log("\u2713 Uninstall complete.");
|
|
39737
|
-
return
|
|
40504
|
+
return EXIT_OK10;
|
|
39738
40505
|
}
|
|
39739
40506
|
async function uninstallV3(rootDir, platform, options) {
|
|
39740
40507
|
if (!platform || options.all) {
|
|
@@ -39765,7 +40532,7 @@ async function uninstallV3(rootDir, platform, options) {
|
|
|
39765
40532
|
console.log(
|
|
39766
40533
|
`\u2713 Removed ${formatPlatformName(platform)} mancode bootstrap.`
|
|
39767
40534
|
);
|
|
39768
|
-
return
|
|
40535
|
+
return EXIT_OK10;
|
|
39769
40536
|
} catch (error) {
|
|
39770
40537
|
const message = error instanceof Error ? error.message : String(error);
|
|
39771
40538
|
console.error(`\u2717 mancode bootstrap removal failed: ${message}`);
|
|
@@ -39793,7 +40560,7 @@ async function uninstallAll(rootDir) {
|
|
|
39793
40560
|
await uninstallPlatform(rootDir, p);
|
|
39794
40561
|
}
|
|
39795
40562
|
console.log("\u2713 Removing .mancode/ directory...");
|
|
39796
|
-
await
|
|
40563
|
+
await rm20(path64.join(rootDir, ".mancode"), {
|
|
39797
40564
|
recursive: true,
|
|
39798
40565
|
force: true
|
|
39799
40566
|
});
|
|
@@ -39803,10 +40570,10 @@ async function uninstallClaudeCode(rootDir) {
|
|
|
39803
40570
|
await cleanClaudeSettings(rootDir);
|
|
39804
40571
|
}
|
|
39805
40572
|
async function cleanClaudeSettings(rootDir) {
|
|
39806
|
-
const settingsPath =
|
|
40573
|
+
const settingsPath = path64.join(rootDir, ".claude", "settings.json");
|
|
39807
40574
|
let content;
|
|
39808
40575
|
try {
|
|
39809
|
-
content = await
|
|
40576
|
+
content = await readFile45(settingsPath, "utf-8");
|
|
39810
40577
|
} catch {
|
|
39811
40578
|
return;
|
|
39812
40579
|
}
|
|
@@ -39817,14 +40584,14 @@ async function cleanClaudeSettings(rootDir) {
|
|
|
39817
40584
|
return;
|
|
39818
40585
|
}
|
|
39819
40586
|
const cleanedHooks = {};
|
|
39820
|
-
if (
|
|
40587
|
+
if (isRecord13(settings.hooks)) {
|
|
39821
40588
|
for (const [event, value] of Object.entries(settings.hooks)) {
|
|
39822
40589
|
const cleaned = cleanClaudeHookValue(value);
|
|
39823
40590
|
if (cleaned !== void 0) cleanedHooks[event] = cleaned;
|
|
39824
40591
|
}
|
|
39825
40592
|
settings.hooks = Object.keys(cleanedHooks).length > 0 ? cleanedHooks : void 0;
|
|
39826
40593
|
}
|
|
39827
|
-
if (
|
|
40594
|
+
if (isRecord13(settings.skills)) {
|
|
39828
40595
|
const retainedSkills = Object.fromEntries(
|
|
39829
40596
|
Object.entries(settings.skills).filter(
|
|
39830
40597
|
([name, value]) => LEGACY_CLAUDE_SKILL_SETTINGS[name] !== value
|
|
@@ -39832,7 +40599,7 @@ async function cleanClaudeSettings(rootDir) {
|
|
|
39832
40599
|
);
|
|
39833
40600
|
settings.skills = Object.keys(retainedSkills).length > 0 ? retainedSkills : void 0;
|
|
39834
40601
|
}
|
|
39835
|
-
await
|
|
40602
|
+
await writeFile45(
|
|
39836
40603
|
settingsPath,
|
|
39837
40604
|
`${JSON.stringify(settings, null, 2)}
|
|
39838
40605
|
`,
|
|
@@ -39844,7 +40611,7 @@ function cleanClaudeHookValue(value) {
|
|
|
39844
40611
|
const entries2 = value.flatMap(cleanClaudeHookEntry);
|
|
39845
40612
|
return entries2.length > 0 ? entries2 : void 0;
|
|
39846
40613
|
}
|
|
39847
|
-
if (!
|
|
40614
|
+
if (!isRecord13(value)) return value;
|
|
39848
40615
|
if (Array.isArray(value.hooks) || typeof value.command === "string") {
|
|
39849
40616
|
const entries2 = cleanClaudeHookEntry(value);
|
|
39850
40617
|
return entries2.length > 0 ? entries2 : void 0;
|
|
@@ -39858,7 +40625,7 @@ function cleanClaudeHookValue(value) {
|
|
|
39858
40625
|
}
|
|
39859
40626
|
function cleanClaudeHookEntry(entry) {
|
|
39860
40627
|
if (Array.isArray(entry)) return entry.flatMap(cleanClaudeHookEntry);
|
|
39861
|
-
if (!
|
|
40628
|
+
if (!isRecord13(entry)) return [entry];
|
|
39862
40629
|
if (Array.isArray(entry.hooks)) {
|
|
39863
40630
|
const hooks = entry.hooks.filter((hook) => !isMancodeHookEntry(hook));
|
|
39864
40631
|
return hooks.length > 0 ? [{ ...entry, hooks }] : [];
|
|
@@ -39866,11 +40633,11 @@ function cleanClaudeHookEntry(entry) {
|
|
|
39866
40633
|
return isMancodeHookEntry(entry) ? [] : [entry];
|
|
39867
40634
|
}
|
|
39868
40635
|
function isMancodeHookEntry(value) {
|
|
39869
|
-
return
|
|
40636
|
+
return isRecord13(value) && typeof value.command === "string" && isGeneratedMancodeHookCommand(value.command);
|
|
39870
40637
|
}
|
|
39871
40638
|
function containsLegacyMancodeHookPath2(value) {
|
|
39872
40639
|
if (Array.isArray(value)) return value.some(containsLegacyMancodeHookPath2);
|
|
39873
|
-
if (!
|
|
40640
|
+
if (!isRecord13(value)) return false;
|
|
39874
40641
|
if (typeof value.command === "string" && value.command.includes(".mancode/hooks/")) {
|
|
39875
40642
|
return true;
|
|
39876
40643
|
}
|
|
@@ -39881,66 +40648,66 @@ async function uninstallCursor(rootDir) {
|
|
|
39881
40648
|
await removeCursorCommands(rootDir);
|
|
39882
40649
|
}
|
|
39883
40650
|
async function uninstallCodex(rootDir) {
|
|
39884
|
-
const agentsPath =
|
|
40651
|
+
const agentsPath = path64.join(rootDir, "AGENTS.md");
|
|
39885
40652
|
try {
|
|
39886
|
-
const content = await
|
|
40653
|
+
const content = await readFile45(agentsPath, "utf-8");
|
|
39887
40654
|
const cleaned = removeManagedBlock(content);
|
|
39888
40655
|
if (cleaned.trim()) {
|
|
39889
|
-
await
|
|
40656
|
+
await writeFile45(agentsPath, `${cleaned}
|
|
39890
40657
|
`, "utf-8");
|
|
39891
40658
|
} else {
|
|
39892
|
-
await
|
|
40659
|
+
await rm20(agentsPath, { force: true });
|
|
39893
40660
|
}
|
|
39894
40661
|
} catch {
|
|
39895
40662
|
}
|
|
39896
40663
|
await removeCodexSkills(rootDir);
|
|
39897
40664
|
}
|
|
39898
40665
|
async function uninstallCopilot(rootDir) {
|
|
39899
|
-
const instructionsPath =
|
|
40666
|
+
const instructionsPath = path64.join(
|
|
39900
40667
|
rootDir,
|
|
39901
40668
|
".github",
|
|
39902
40669
|
"copilot-instructions.md"
|
|
39903
40670
|
);
|
|
39904
40671
|
try {
|
|
39905
|
-
const content = await
|
|
40672
|
+
const content = await readFile45(instructionsPath, "utf-8");
|
|
39906
40673
|
const cleaned = removeManagedBlock(content);
|
|
39907
40674
|
if (cleaned.trim()) {
|
|
39908
|
-
await
|
|
40675
|
+
await writeFile45(instructionsPath, `${cleaned}
|
|
39909
40676
|
`, "utf-8");
|
|
39910
40677
|
} else {
|
|
39911
|
-
await
|
|
40678
|
+
await rm20(instructionsPath, { force: true });
|
|
39912
40679
|
}
|
|
39913
40680
|
} catch {
|
|
39914
40681
|
}
|
|
39915
40682
|
await removeCopilotPrompts(rootDir);
|
|
39916
40683
|
}
|
|
39917
40684
|
async function uninstallZcode(rootDir) {
|
|
39918
|
-
const agentsPath =
|
|
40685
|
+
const agentsPath = path64.join(rootDir, "AGENTS.md");
|
|
39919
40686
|
try {
|
|
39920
|
-
const content = await
|
|
40687
|
+
const content = await readFile45(agentsPath, "utf-8");
|
|
39921
40688
|
const cleaned = removeManagedBlock(
|
|
39922
40689
|
content,
|
|
39923
40690
|
ZCODE_MANCODE_START_MARKER,
|
|
39924
40691
|
ZCODE_MANCODE_END_MARKER
|
|
39925
40692
|
);
|
|
39926
40693
|
if (cleaned.trim()) {
|
|
39927
|
-
await
|
|
40694
|
+
await writeFile45(agentsPath, `${cleaned}
|
|
39928
40695
|
`, "utf-8");
|
|
39929
40696
|
} else {
|
|
39930
|
-
await
|
|
40697
|
+
await rm20(agentsPath, { force: true });
|
|
39931
40698
|
}
|
|
39932
40699
|
} catch {
|
|
39933
40700
|
}
|
|
39934
40701
|
await removeZcodeSkills(rootDir);
|
|
39935
40702
|
}
|
|
39936
40703
|
async function removeFromConfig(rootDir, platform) {
|
|
39937
|
-
const configPath =
|
|
40704
|
+
const configPath = path64.join(rootDir, ".mancode", "config.json");
|
|
39938
40705
|
try {
|
|
39939
|
-
const raw = await
|
|
40706
|
+
const raw = await readFile45(configPath, "utf-8");
|
|
39940
40707
|
const config = JSON.parse(raw);
|
|
39941
40708
|
if (Array.isArray(config.platforms)) {
|
|
39942
40709
|
config.platforms = config.platforms.filter((p) => p !== platform);
|
|
39943
|
-
if (
|
|
40710
|
+
if (isRecord13(config.platformOptions)) {
|
|
39944
40711
|
const platformOptions = Object.fromEntries(
|
|
39945
40712
|
Object.entries(config.platformOptions).filter(
|
|
39946
40713
|
([name]) => name !== platform
|
|
@@ -39948,7 +40715,7 @@ async function removeFromConfig(rootDir, platform) {
|
|
|
39948
40715
|
);
|
|
39949
40716
|
config.platformOptions = Object.keys(platformOptions).length > 0 ? platformOptions : void 0;
|
|
39950
40717
|
}
|
|
39951
|
-
await
|
|
40718
|
+
await writeFile45(
|
|
39952
40719
|
configPath,
|
|
39953
40720
|
`${JSON.stringify(config, null, 2)}
|
|
39954
40721
|
`,
|
|
@@ -39958,7 +40725,7 @@ async function removeFromConfig(rootDir, platform) {
|
|
|
39958
40725
|
} catch {
|
|
39959
40726
|
}
|
|
39960
40727
|
}
|
|
39961
|
-
function
|
|
40728
|
+
function isRecord13(value) {
|
|
39962
40729
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
39963
40730
|
}
|
|
39964
40731
|
async function pathExists15(p) {
|
|
@@ -39971,18 +40738,18 @@ async function pathExists15(p) {
|
|
|
39971
40738
|
}
|
|
39972
40739
|
|
|
39973
40740
|
// src/commands/version.ts
|
|
39974
|
-
import
|
|
40741
|
+
import process13 from "process";
|
|
39975
40742
|
function version() {
|
|
39976
|
-
const nodeVersion =
|
|
39977
|
-
const platform = `${
|
|
40743
|
+
const nodeVersion = process13.version;
|
|
40744
|
+
const platform = `${process13.platform}/${process13.arch}`;
|
|
39978
40745
|
console.log(`mancode/${VERSION}`);
|
|
39979
40746
|
console.log(`node/${nodeVersion.replace("v", "")}`);
|
|
39980
40747
|
console.log(platform);
|
|
39981
40748
|
}
|
|
39982
40749
|
|
|
39983
40750
|
// src/commands/workflow.ts
|
|
39984
|
-
import { access as access6, readFile as
|
|
39985
|
-
import
|
|
40751
|
+
import { access as access6, readFile as readFile47, rm as rm22, writeFile as writeFile47 } from "fs/promises";
|
|
40752
|
+
import path66 from "path";
|
|
39986
40753
|
|
|
39987
40754
|
// src/context/child-result-merge.ts
|
|
39988
40755
|
async function mergeV3ChildResult(input) {
|
|
@@ -43041,14 +43808,14 @@ function updateMetadata4(previous, verification, operationId, updatedAt) {
|
|
|
43041
43808
|
|
|
43042
43809
|
// src/context/workflow-create.ts
|
|
43043
43810
|
import {
|
|
43044
|
-
lstat as
|
|
43045
|
-
mkdir as
|
|
43046
|
-
readFile as
|
|
43811
|
+
lstat as lstat26,
|
|
43812
|
+
mkdir as mkdir40,
|
|
43813
|
+
readFile as readFile46,
|
|
43047
43814
|
rename as rename13,
|
|
43048
|
-
rm as
|
|
43049
|
-
writeFile as
|
|
43815
|
+
rm as rm21,
|
|
43816
|
+
writeFile as writeFile46
|
|
43050
43817
|
} from "fs/promises";
|
|
43051
|
-
import
|
|
43818
|
+
import path65 from "path";
|
|
43052
43819
|
|
|
43053
43820
|
// src/context/creation-resolution.ts
|
|
43054
43821
|
function resolveWorkflowCreation(request) {
|
|
@@ -43158,7 +43925,7 @@ function rejectConflict(provided, expected, label) {
|
|
|
43158
43925
|
|
|
43159
43926
|
// src/context/workflow-create.ts
|
|
43160
43927
|
async function createV3Workflow(input) {
|
|
43161
|
-
const projectRoot =
|
|
43928
|
+
const projectRoot = path65.resolve(requireProjectRoot2(input.projectRoot));
|
|
43162
43929
|
const task = requireText2(input.task, "workflow task");
|
|
43163
43930
|
const client = requireText2(input.client, "workflow client");
|
|
43164
43931
|
const now = input.now ?? /* @__PURE__ */ new Date();
|
|
@@ -43343,8 +44110,8 @@ async function createV3Workflow(input) {
|
|
|
43343
44110
|
throw new Error("MANCODE_REVISION_CONFLICT");
|
|
43344
44111
|
}
|
|
43345
44112
|
const taskParent = await ensureSafeTaskParent3(projectRoot, taskRef);
|
|
43346
|
-
const targetDirectory =
|
|
43347
|
-
stagingDirectory =
|
|
44113
|
+
const targetDirectory = path65.join(taskParent, taskRef.taskId);
|
|
44114
|
+
stagingDirectory = path65.join(
|
|
43348
44115
|
taskParent,
|
|
43349
44116
|
`.${taskRef.taskId}.${operationId}.staging`
|
|
43350
44117
|
);
|
|
@@ -43793,10 +44560,10 @@ async function ensureSafeTaskParent3(projectRoot, taskRef) {
|
|
|
43793
44560
|
const segments = [".mancode", taskRef.namespace, "workflows"];
|
|
43794
44561
|
let current = projectRoot;
|
|
43795
44562
|
for (const segment of segments) {
|
|
43796
|
-
current =
|
|
44563
|
+
current = path65.join(current, segment);
|
|
43797
44564
|
const existing = await lstatOrNull5(current);
|
|
43798
44565
|
if (existing === null) {
|
|
43799
|
-
await
|
|
44566
|
+
await mkdir40(current);
|
|
43800
44567
|
continue;
|
|
43801
44568
|
}
|
|
43802
44569
|
if (!existing.isDirectory() || existing.isSymbolicLink()) {
|
|
@@ -43809,7 +44576,7 @@ async function assertDirectoryAbsent(target, code) {
|
|
|
43809
44576
|
if (await lstatOrNull5(target) !== null) throw new Error(code);
|
|
43810
44577
|
}
|
|
43811
44578
|
async function writeStagedEntities(stagingDirectory, entities) {
|
|
43812
|
-
await
|
|
44579
|
+
await mkdir40(stagingDirectory);
|
|
43813
44580
|
await assertDirectory(stagingDirectory);
|
|
43814
44581
|
await Promise.all([
|
|
43815
44582
|
writeStagedJson(stagingDirectory, "metadata.json", entities.metadata),
|
|
@@ -43829,13 +44596,13 @@ async function writeStagedEntities(stagingDirectory, entities) {
|
|
|
43829
44596
|
}
|
|
43830
44597
|
async function writeStagedJson(stagingDirectory, fileName, value) {
|
|
43831
44598
|
await assertDirectory(stagingDirectory);
|
|
43832
|
-
const target =
|
|
43833
|
-
await
|
|
44599
|
+
const target = path65.join(stagingDirectory, fileName);
|
|
44600
|
+
await writeFile46(target, `${JSON.stringify(value, null, 2)}
|
|
43834
44601
|
`, {
|
|
43835
44602
|
encoding: "utf8",
|
|
43836
44603
|
flag: "wx"
|
|
43837
44604
|
});
|
|
43838
|
-
const entry = await
|
|
44605
|
+
const entry = await lstat26(target);
|
|
43839
44606
|
if (!entry.isFile() || entry.isSymbolicLink()) {
|
|
43840
44607
|
throw new Error("MANCODE_ARTIFACT_PATH_UNSAFE");
|
|
43841
44608
|
}
|
|
@@ -43867,13 +44634,13 @@ async function validateStagedEntities(stagingDirectory) {
|
|
|
43867
44634
|
});
|
|
43868
44635
|
}
|
|
43869
44636
|
async function readStagedJson(stagingDirectory, fileName, parser) {
|
|
43870
|
-
const target =
|
|
43871
|
-
const before = await
|
|
44637
|
+
const target = path65.join(stagingDirectory, fileName);
|
|
44638
|
+
const before = await lstat26(target);
|
|
43872
44639
|
if (!before.isFile() || before.isSymbolicLink()) {
|
|
43873
44640
|
throw new Error("MANCODE_ARTIFACT_PATH_UNSAFE");
|
|
43874
44641
|
}
|
|
43875
|
-
const parsed = parser(JSON.parse(await
|
|
43876
|
-
const after = await
|
|
44642
|
+
const parsed = parser(JSON.parse(await readFile46(target, "utf8")));
|
|
44643
|
+
const after = await lstat26(target);
|
|
43877
44644
|
if (!after.isFile() || after.isSymbolicLink() || before.dev !== after.dev || before.ino !== after.ino) {
|
|
43878
44645
|
throw new Error("MANCODE_ARTIFACT_PATH_UNSAFE");
|
|
43879
44646
|
}
|
|
@@ -43964,20 +44731,20 @@ async function abortPreparedCreate(store, journal, stagingDirectory, now) {
|
|
|
43964
44731
|
{ canAbort: true }
|
|
43965
44732
|
);
|
|
43966
44733
|
} finally {
|
|
43967
|
-
await
|
|
44734
|
+
await rm21(stagingDirectory, { recursive: true, force: true });
|
|
43968
44735
|
}
|
|
43969
44736
|
}
|
|
43970
44737
|
async function assertDirectory(target) {
|
|
43971
|
-
const entry = await
|
|
44738
|
+
const entry = await lstat26(target);
|
|
43972
44739
|
if (!entry.isDirectory() || entry.isSymbolicLink()) {
|
|
43973
44740
|
throw new Error("MANCODE_ARTIFACT_PATH_UNSAFE");
|
|
43974
44741
|
}
|
|
43975
44742
|
}
|
|
43976
44743
|
async function lstatOrNull5(target) {
|
|
43977
44744
|
try {
|
|
43978
|
-
return await
|
|
44745
|
+
return await lstat26(target);
|
|
43979
44746
|
} catch (error) {
|
|
43980
|
-
if (
|
|
44747
|
+
if (isNotFound33(error)) return null;
|
|
43981
44748
|
throw error;
|
|
43982
44749
|
}
|
|
43983
44750
|
}
|
|
@@ -43997,7 +44764,7 @@ function requireText2(value, label) {
|
|
|
43997
44764
|
}
|
|
43998
44765
|
return value.trim();
|
|
43999
44766
|
}
|
|
44000
|
-
function
|
|
44767
|
+
function isNotFound33(error) {
|
|
44001
44768
|
return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
|
|
44002
44769
|
}
|
|
44003
44770
|
|
|
@@ -44894,7 +45661,7 @@ function compareUtf817(left, right) {
|
|
|
44894
45661
|
|
|
44895
45662
|
// src/commands/requirements-input.ts
|
|
44896
45663
|
function normalizeRequirementsInput(value, requestedTaskRef, now = /* @__PURE__ */ new Date(), options = {}) {
|
|
44897
|
-
if (
|
|
45664
|
+
if (isRecord14(value) && "schemaVersion" in value) {
|
|
44898
45665
|
return parseRequirementsLedger(value);
|
|
44899
45666
|
}
|
|
44900
45667
|
const serialized = JSON.stringify(value);
|
|
@@ -44962,20 +45729,20 @@ function buildCanonicalRequirements(semantic, requestedTaskRef, now) {
|
|
|
44962
45729
|
contentDigest: requirementsLedgerDigest(draft)
|
|
44963
45730
|
});
|
|
44964
45731
|
}
|
|
44965
|
-
function
|
|
45732
|
+
function isRecord14(value) {
|
|
44966
45733
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
44967
45734
|
}
|
|
44968
45735
|
|
|
44969
45736
|
// src/commands/workflow.ts
|
|
44970
|
-
var
|
|
44971
|
-
var
|
|
45737
|
+
var EXIT_OK11 = 0;
|
|
45738
|
+
var EXIT_NOT_INITIALIZED8 = 1;
|
|
44972
45739
|
var EXIT_INVALID_ARG3 = 2;
|
|
44973
45740
|
async function workflow(rootDir, subcommand, args = [], options = {}) {
|
|
44974
45741
|
const v3Activation = await readV3ActivationState2(rootDir);
|
|
44975
45742
|
if (v3Activation === "v3_active") {
|
|
44976
45743
|
return workflowV3(rootDir, subcommand, args, options);
|
|
44977
45744
|
}
|
|
44978
|
-
if (!await pathExists16(
|
|
45745
|
+
if (!await pathExists16(path66.join(rootDir, ".mancode", "state.json"))) {
|
|
44979
45746
|
if (v3Activation !== null) {
|
|
44980
45747
|
return printV3Error(
|
|
44981
45748
|
options.json,
|
|
@@ -44989,7 +45756,7 @@ async function workflow(rootDir, subcommand, args = [], options = {}) {
|
|
|
44989
45756
|
console.error("\u2717 mancode not initialized.");
|
|
44990
45757
|
console.error(" Run `mancode init` to get started.");
|
|
44991
45758
|
}
|
|
44992
|
-
return
|
|
45759
|
+
return EXIT_NOT_INITIALIZED8;
|
|
44993
45760
|
}
|
|
44994
45761
|
switch (subcommand) {
|
|
44995
45762
|
case "create":
|
|
@@ -45105,7 +45872,7 @@ async function workflowListV3(rootDir, args, options) {
|
|
|
45105
45872
|
}
|
|
45106
45873
|
if (workflows.length === 0) {
|
|
45107
45874
|
console.log("No mancode workflows.");
|
|
45108
|
-
return
|
|
45875
|
+
return EXIT_OK11;
|
|
45109
45876
|
}
|
|
45110
45877
|
const active = workflows.filter(
|
|
45111
45878
|
(item) => ["in_progress", "planned", "blocked"].includes(item.status)
|
|
@@ -45117,7 +45884,7 @@ async function workflowListV3(rootDir, args, options) {
|
|
|
45117
45884
|
for (const metadata of workflows) {
|
|
45118
45885
|
console.log(formatV3WorkflowRow(metadata));
|
|
45119
45886
|
}
|
|
45120
|
-
return
|
|
45887
|
+
return EXIT_OK11;
|
|
45121
45888
|
} catch (error) {
|
|
45122
45889
|
return printV3Error(
|
|
45123
45890
|
options.json,
|
|
@@ -45175,7 +45942,7 @@ async function workflowShowV3(rootDir, args, options) {
|
|
|
45175
45942
|
if (snapshot.aggregateError !== null) {
|
|
45176
45943
|
console.log(`Aggregate: ${snapshot.aggregateError}`);
|
|
45177
45944
|
}
|
|
45178
|
-
return
|
|
45945
|
+
return EXIT_OK11;
|
|
45179
45946
|
} catch (error) {
|
|
45180
45947
|
return printV3Error(
|
|
45181
45948
|
options.json,
|
|
@@ -46067,8 +46834,8 @@ function parseV3ParticipantActorIds(values) {
|
|
|
46067
46834
|
return values;
|
|
46068
46835
|
}
|
|
46069
46836
|
async function readWorkflowInputFile(projectRoot, value) {
|
|
46070
|
-
const inputPath =
|
|
46071
|
-
return
|
|
46837
|
+
const inputPath = path66.isAbsolute(value) ? value : path66.resolve(projectRoot, value);
|
|
46838
|
+
return readFile47(inputPath, "utf8");
|
|
46072
46839
|
}
|
|
46073
46840
|
async function readWorkflowJsonInputFile(projectRoot, value) {
|
|
46074
46841
|
return JSON.parse(await readWorkflowInputFile(projectRoot, value));
|
|
@@ -46141,7 +46908,7 @@ async function readV3ActivationState2(rootDir) {
|
|
|
46141
46908
|
try {
|
|
46142
46909
|
const manifest = parseSchemaManifest(
|
|
46143
46910
|
JSON.parse(
|
|
46144
|
-
await
|
|
46911
|
+
await readFile47(path66.join(rootDir, ".mancode", "schema.json"), "utf8")
|
|
46145
46912
|
)
|
|
46146
46913
|
);
|
|
46147
46914
|
return manifest.activationState === "v3_active" ? "v3_active" : "other";
|
|
@@ -46186,21 +46953,21 @@ async function workflowRequirements(rootDir, args, options) {
|
|
|
46186
46953
|
"requirements can only be finalized for an in-progress man or manteam workflow at step 1 or 2"
|
|
46187
46954
|
);
|
|
46188
46955
|
}
|
|
46189
|
-
const workflowPath =
|
|
46190
|
-
const jsonPath =
|
|
46191
|
-
const markdownPath =
|
|
46192
|
-
const metadataPath3 =
|
|
46956
|
+
const workflowPath = path66.join(rootDir, ".mancode", "workflows", taskId);
|
|
46957
|
+
const jsonPath = path66.join(workflowPath, "requirements.json");
|
|
46958
|
+
const markdownPath = path66.join(workflowPath, "requirements.md");
|
|
46959
|
+
const metadataPath3 = path66.join(workflowPath, "metadata.json");
|
|
46193
46960
|
let originalJson;
|
|
46194
46961
|
let originalMarkdown;
|
|
46195
46962
|
let originalMetadata;
|
|
46196
46963
|
try {
|
|
46197
|
-
const inputPath =
|
|
46198
|
-
const input = await
|
|
46964
|
+
const inputPath = path66.isAbsolute(options.file) ? options.file : path66.resolve(rootDir, options.file);
|
|
46965
|
+
const input = await readFile47(inputPath, "utf-8");
|
|
46199
46966
|
const requirements = parseRequirementsLedger2(input);
|
|
46200
46967
|
[originalJson, originalMarkdown, originalMetadata] = await Promise.all([
|
|
46201
46968
|
readOptionalText2(jsonPath),
|
|
46202
46969
|
readOptionalText2(markdownPath),
|
|
46203
|
-
|
|
46970
|
+
readFile47(metadataPath3, "utf-8")
|
|
46204
46971
|
]);
|
|
46205
46972
|
await writeRequirementsArtifacts(rootDir, taskId, requirements);
|
|
46206
46973
|
await updateWorkflow(rootDir, taskId, {
|
|
@@ -46223,14 +46990,14 @@ async function workflowRequirements(rootDir, args, options) {
|
|
|
46223
46990
|
`Finalized requirements: ${taskId} (${requirementsAreReady2(requirements) ? "ready" : "needs_clarification"})`
|
|
46224
46991
|
);
|
|
46225
46992
|
}
|
|
46226
|
-
return
|
|
46993
|
+
return EXIT_OK11;
|
|
46227
46994
|
} catch (error) {
|
|
46228
46995
|
let rollbackIncomplete = false;
|
|
46229
46996
|
if (originalJson !== void 0 && originalMarkdown !== void 0 && originalMetadata !== void 0) {
|
|
46230
46997
|
const rollback = await Promise.allSettled([
|
|
46231
46998
|
restoreOptionalText(jsonPath, originalJson),
|
|
46232
46999
|
restoreOptionalText(markdownPath, originalMarkdown),
|
|
46233
|
-
|
|
47000
|
+
writeFile47(metadataPath3, originalMetadata, "utf-8")
|
|
46234
47001
|
]);
|
|
46235
47002
|
rollbackIncomplete = rollback.some(
|
|
46236
47003
|
(result2) => result2.status === "rejected"
|
|
@@ -46259,7 +47026,7 @@ async function workflowVerify(rootDir, args, options) {
|
|
|
46259
47026
|
return invalidArg(options, `verification not initialized: ${taskId}`);
|
|
46260
47027
|
}
|
|
46261
47028
|
outputVerificationLedger(ledger, options);
|
|
46262
|
-
return
|
|
47029
|
+
return EXIT_OK11;
|
|
46263
47030
|
}
|
|
46264
47031
|
if (meta.verificationPolicyVersion !== 1 || (action === "init" ? meta.currentStep !== 6 : meta.currentStep !== 6 && meta.currentStep !== 9) || meta.planDecision !== "governed_execution" || meta.status !== "in_progress" && meta.status !== "blocked") {
|
|
46265
47032
|
return invalidArg(
|
|
@@ -46318,7 +47085,7 @@ async function workflowVerify(rootDir, args, options) {
|
|
|
46318
47085
|
);
|
|
46319
47086
|
}
|
|
46320
47087
|
if (options.evidenceFile) {
|
|
46321
|
-
const evidencePath =
|
|
47088
|
+
const evidencePath = path66.isAbsolute(options.evidenceFile) ? options.evidenceFile : path66.resolve(rootDir, options.evidenceFile);
|
|
46322
47089
|
if (!await pathExists16(evidencePath)) {
|
|
46323
47090
|
return invalidArg(
|
|
46324
47091
|
options,
|
|
@@ -46368,7 +47135,7 @@ async function workflowVerify(rootDir, args, options) {
|
|
|
46368
47135
|
);
|
|
46369
47136
|
if (transitionError) return invalidArg(options, transitionError);
|
|
46370
47137
|
outputVerificationLedger(ledger, options);
|
|
46371
|
-
return
|
|
47138
|
+
return EXIT_OK11;
|
|
46372
47139
|
} catch (error) {
|
|
46373
47140
|
return invalidArg(
|
|
46374
47141
|
options,
|
|
@@ -46378,17 +47145,17 @@ async function workflowVerify(rootDir, args, options) {
|
|
|
46378
47145
|
}
|
|
46379
47146
|
async function commitVerificationTransition(rootDir, meta, ledger) {
|
|
46380
47147
|
const ledgerPath = verificationLedgerPath(rootDir, meta.taskId);
|
|
46381
|
-
const metadataPath3 =
|
|
47148
|
+
const metadataPath3 = path66.join(
|
|
46382
47149
|
rootDir,
|
|
46383
47150
|
".mancode",
|
|
46384
47151
|
"workflows",
|
|
46385
47152
|
meta.taskId,
|
|
46386
47153
|
"metadata.json"
|
|
46387
47154
|
);
|
|
46388
|
-
const specPath =
|
|
47155
|
+
const specPath = path66.join(rootDir, ".mancode", "memory", "spec.md");
|
|
46389
47156
|
const [originalLedger, originalMetadata, originalSpec] = await Promise.all([
|
|
46390
47157
|
readOptionalText2(ledgerPath),
|
|
46391
|
-
|
|
47158
|
+
readFile47(metadataPath3, "utf-8"),
|
|
46392
47159
|
readOptionalText2(specPath)
|
|
46393
47160
|
]);
|
|
46394
47161
|
const wasVerificationBlocked = meta.status === "blocked" && meta.blockingReason?.startsWith("[verification]");
|
|
@@ -46417,7 +47184,7 @@ async function commitVerificationTransition(rootDir, meta, ledger) {
|
|
|
46417
47184
|
} catch (error) {
|
|
46418
47185
|
const rollback = await Promise.allSettled([
|
|
46419
47186
|
restoreOptionalText(ledgerPath, originalLedger),
|
|
46420
|
-
|
|
47187
|
+
writeFile47(metadataPath3, originalMetadata, "utf-8"),
|
|
46421
47188
|
restoreOptionalText(specPath, originalSpec)
|
|
46422
47189
|
]);
|
|
46423
47190
|
const message = error instanceof Error ? error.message : "verification transition failed";
|
|
@@ -46452,7 +47219,7 @@ async function workflowReview(rootDir, args, options) {
|
|
|
46452
47219
|
if (!ledger)
|
|
46453
47220
|
return invalidArg(options, `review not initialized: ${taskId}`);
|
|
46454
47221
|
outputReviewLedger(ledger, options);
|
|
46455
|
-
return
|
|
47222
|
+
return EXIT_OK11;
|
|
46456
47223
|
}
|
|
46457
47224
|
if (meta.status !== "in_progress" || meta.currentStep < 6) {
|
|
46458
47225
|
return invalidArg(
|
|
@@ -46482,7 +47249,7 @@ async function workflowReview(rootDir, args, options) {
|
|
|
46482
47249
|
if (error) return invalidArg(options, error);
|
|
46483
47250
|
const ledger = await readReviewLedger(rootDir, taskId);
|
|
46484
47251
|
outputReviewLedger(ledger, options);
|
|
46485
|
-
return
|
|
47252
|
+
return EXIT_OK11;
|
|
46486
47253
|
} catch (error) {
|
|
46487
47254
|
return invalidArg(
|
|
46488
47255
|
options,
|
|
@@ -46539,7 +47306,7 @@ async function workflowReview(rootDir, args, options) {
|
|
|
46539
47306
|
);
|
|
46540
47307
|
}
|
|
46541
47308
|
outputReviewLedger(ledger, options);
|
|
46542
|
-
return
|
|
47309
|
+
return EXIT_OK11;
|
|
46543
47310
|
} catch (error) {
|
|
46544
47311
|
return invalidArg(
|
|
46545
47312
|
options,
|
|
@@ -46549,7 +47316,7 @@ async function workflowReview(rootDir, args, options) {
|
|
|
46549
47316
|
}
|
|
46550
47317
|
async function commitReviewSkip(rootDir, meta, reason) {
|
|
46551
47318
|
const ledgerPath = reviewLedgerPath(rootDir, meta.taskId);
|
|
46552
|
-
const metadataPath3 =
|
|
47319
|
+
const metadataPath3 = path66.join(
|
|
46553
47320
|
rootDir,
|
|
46554
47321
|
".mancode",
|
|
46555
47322
|
"workflows",
|
|
@@ -46558,7 +47325,7 @@ async function commitReviewSkip(rootDir, meta, reason) {
|
|
|
46558
47325
|
);
|
|
46559
47326
|
const [originalLedger, originalMetadata] = await Promise.all([
|
|
46560
47327
|
readOptionalText2(ledgerPath),
|
|
46561
|
-
|
|
47328
|
+
readFile47(metadataPath3, "utf-8")
|
|
46562
47329
|
]);
|
|
46563
47330
|
try {
|
|
46564
47331
|
await initializeSkippedReview(rootDir, meta.taskId, reason);
|
|
@@ -46569,7 +47336,7 @@ async function commitReviewSkip(rootDir, meta, reason) {
|
|
|
46569
47336
|
} catch (error) {
|
|
46570
47337
|
const rollback = await Promise.allSettled([
|
|
46571
47338
|
restoreOptionalText(ledgerPath, originalLedger),
|
|
46572
|
-
|
|
47339
|
+
writeFile47(metadataPath3, originalMetadata, "utf-8")
|
|
46573
47340
|
]);
|
|
46574
47341
|
const message = error instanceof Error ? error.message : "review skip failed";
|
|
46575
47342
|
return rollback.some((result2) => result2.status === "rejected") ? `${message}; rollback was incomplete` : message;
|
|
@@ -46629,7 +47396,7 @@ async function workflowCreate(rootDir, args, options) {
|
|
|
46629
47396
|
error instanceof Error ? error.message : "unable to create workflow"
|
|
46630
47397
|
);
|
|
46631
47398
|
}
|
|
46632
|
-
return
|
|
47399
|
+
return EXIT_OK11;
|
|
46633
47400
|
}
|
|
46634
47401
|
async function workflowUpdate(rootDir, taskId, options) {
|
|
46635
47402
|
if (!taskId) {
|
|
@@ -46764,7 +47531,7 @@ async function workflowUpdate(rootDir, taskId, options) {
|
|
|
46764
47531
|
} else {
|
|
46765
47532
|
console.log(`Updated workflow: ${taskId}`);
|
|
46766
47533
|
}
|
|
46767
|
-
return
|
|
47534
|
+
return EXIT_OK11;
|
|
46768
47535
|
}
|
|
46769
47536
|
async function workflowHandoff(rootDir, taskId, options) {
|
|
46770
47537
|
if (!taskId || !isValidWorkflowTaskId(taskId)) {
|
|
@@ -46789,18 +47556,18 @@ async function workflowHandoff(rootDir, taskId, options) {
|
|
|
46789
47556
|
"solo handoff requires an undecided in-progress workflow at step 4 with ready requirements"
|
|
46790
47557
|
);
|
|
46791
47558
|
}
|
|
46792
|
-
const workflowPath =
|
|
46793
|
-
if (!await pathExists16(
|
|
47559
|
+
const workflowPath = path66.join(rootDir, ".mancode", "workflows", taskId);
|
|
47560
|
+
if (!await pathExists16(path66.join(workflowPath, "requirements.md")) || !await pathExists16(path66.join(workflowPath, "plan.md"))) {
|
|
46794
47561
|
return invalidArg(
|
|
46795
47562
|
options,
|
|
46796
47563
|
"solo handoff requires requirements.md and plan.md"
|
|
46797
47564
|
);
|
|
46798
47565
|
}
|
|
46799
|
-
const statePath =
|
|
47566
|
+
const statePath = path66.join(rootDir, ".mancode", "state.json");
|
|
46800
47567
|
let originalState;
|
|
46801
47568
|
let state;
|
|
46802
47569
|
try {
|
|
46803
|
-
originalState = await
|
|
47570
|
+
originalState = await readFile47(statePath, "utf-8");
|
|
46804
47571
|
state = JSON.parse(originalState);
|
|
46805
47572
|
} catch {
|
|
46806
47573
|
return invalidArg(
|
|
@@ -46861,7 +47628,7 @@ async function workflowHandoff(rootDir, taskId, options) {
|
|
|
46861
47628
|
} else {
|
|
46862
47629
|
console.log(`Handed off plan to solo: ${taskId}`);
|
|
46863
47630
|
}
|
|
46864
|
-
return
|
|
47631
|
+
return EXIT_OK11;
|
|
46865
47632
|
}
|
|
46866
47633
|
async function workflowCompleteHandoff(rootDir, taskId, options) {
|
|
46867
47634
|
const meta = await readWorkflow(rootDir, taskId);
|
|
@@ -46871,11 +47638,11 @@ async function workflowCompleteHandoff(rootDir, taskId, options) {
|
|
|
46871
47638
|
`workflow is not an active solo handoff: ${taskId}`
|
|
46872
47639
|
);
|
|
46873
47640
|
}
|
|
46874
|
-
const statePath =
|
|
47641
|
+
const statePath = path66.join(rootDir, ".mancode", "state.json");
|
|
46875
47642
|
let originalState;
|
|
46876
47643
|
let state;
|
|
46877
47644
|
try {
|
|
46878
|
-
originalState = await
|
|
47645
|
+
originalState = await readFile47(statePath, "utf-8");
|
|
46879
47646
|
state = JSON.parse(originalState);
|
|
46880
47647
|
} catch {
|
|
46881
47648
|
return invalidArg(
|
|
@@ -46913,7 +47680,7 @@ async function workflowCompleteHandoff(rootDir, taskId, options) {
|
|
|
46913
47680
|
} else {
|
|
46914
47681
|
console.log(`Completed solo handoff: ${taskId}`);
|
|
46915
47682
|
}
|
|
46916
|
-
return
|
|
47683
|
+
return EXIT_OK11;
|
|
46917
47684
|
}
|
|
46918
47685
|
async function workflowDecide(rootDir, taskId, options) {
|
|
46919
47686
|
if (!taskId || !isValidWorkflowTaskId(taskId)) {
|
|
@@ -46938,18 +47705,18 @@ async function workflowDecide(rootDir, taskId, options) {
|
|
|
46938
47705
|
`workflow is not ready for a plan-only decision: ${taskId}`
|
|
46939
47706
|
);
|
|
46940
47707
|
}
|
|
46941
|
-
const workflowPath =
|
|
46942
|
-
if (!await pathExists16(
|
|
47708
|
+
const workflowPath = path66.join(rootDir, ".mancode", "workflows", taskId);
|
|
47709
|
+
if (!await pathExists16(path66.join(workflowPath, "requirements.md")) || !await pathExists16(path66.join(workflowPath, "plan.md"))) {
|
|
46943
47710
|
return invalidArg(
|
|
46944
47711
|
options,
|
|
46945
47712
|
"plan-only requires requirements.md and plan.md"
|
|
46946
47713
|
);
|
|
46947
47714
|
}
|
|
46948
|
-
const statePath =
|
|
47715
|
+
const statePath = path66.join(rootDir, ".mancode", "state.json");
|
|
46949
47716
|
let originalState;
|
|
46950
47717
|
let state;
|
|
46951
47718
|
try {
|
|
46952
|
-
originalState = await
|
|
47719
|
+
originalState = await readFile47(statePath, "utf-8");
|
|
46953
47720
|
state = JSON.parse(originalState);
|
|
46954
47721
|
} catch {
|
|
46955
47722
|
return invalidArg(
|
|
@@ -46998,28 +47765,28 @@ async function workflowDecide(rootDir, taskId, options) {
|
|
|
46998
47765
|
} else {
|
|
46999
47766
|
console.log(`Saved plan without execution: ${taskId}`);
|
|
47000
47767
|
}
|
|
47001
|
-
return
|
|
47768
|
+
return EXIT_OK11;
|
|
47002
47769
|
}
|
|
47003
47770
|
async function commitPlanningTransition(args) {
|
|
47004
|
-
const metadataPath3 =
|
|
47771
|
+
const metadataPath3 = path66.join(
|
|
47005
47772
|
args.rootDir,
|
|
47006
47773
|
".mancode",
|
|
47007
47774
|
"workflows",
|
|
47008
47775
|
args.taskId,
|
|
47009
47776
|
"metadata.json"
|
|
47010
47777
|
);
|
|
47011
|
-
const specPath =
|
|
47778
|
+
const specPath = path66.join(args.rootDir, ".mancode", "memory", "spec.md");
|
|
47012
47779
|
let originalMetadata;
|
|
47013
47780
|
let originalSpec;
|
|
47014
47781
|
try {
|
|
47015
|
-
originalMetadata = await
|
|
47782
|
+
originalMetadata = await readFile47(metadataPath3, "utf-8");
|
|
47016
47783
|
originalSpec = await readOptionalText2(specPath);
|
|
47017
47784
|
} catch (error) {
|
|
47018
47785
|
return error instanceof Error ? `unable to prepare planning transition: ${error.message}` : "unable to prepare planning transition";
|
|
47019
47786
|
}
|
|
47020
47787
|
try {
|
|
47021
47788
|
await updateWorkflow(args.rootDir, args.taskId, args.workflowPatch);
|
|
47022
|
-
await
|
|
47789
|
+
await writeFile47(
|
|
47023
47790
|
args.statePath,
|
|
47024
47791
|
`${JSON.stringify(args.nextState, null, 2)}
|
|
47025
47792
|
`,
|
|
@@ -47033,9 +47800,9 @@ async function commitPlanningTransition(args) {
|
|
|
47033
47800
|
return null;
|
|
47034
47801
|
} catch (error) {
|
|
47035
47802
|
const rollback = await Promise.allSettled([
|
|
47036
|
-
|
|
47037
|
-
|
|
47038
|
-
originalSpec === null ?
|
|
47803
|
+
writeFile47(metadataPath3, originalMetadata, "utf-8"),
|
|
47804
|
+
writeFile47(args.statePath, args.originalState, "utf-8"),
|
|
47805
|
+
originalSpec === null ? rm22(specPath, { force: true }) : writeFile47(specPath, originalSpec, "utf-8")
|
|
47039
47806
|
]);
|
|
47040
47807
|
const message = error instanceof Error ? error.message : "planning transition failed";
|
|
47041
47808
|
return rollback.some((result2) => result2.status === "rejected") ? `${message}; rollback was incomplete` : message;
|
|
@@ -47043,7 +47810,7 @@ async function commitPlanningTransition(args) {
|
|
|
47043
47810
|
}
|
|
47044
47811
|
async function readOptionalText2(filePath) {
|
|
47045
47812
|
try {
|
|
47046
|
-
return await
|
|
47813
|
+
return await readFile47(filePath, "utf-8");
|
|
47047
47814
|
} catch (error) {
|
|
47048
47815
|
if (isNodeError10(error) && error.code === "ENOENT") return null;
|
|
47049
47816
|
throw error;
|
|
@@ -47051,10 +47818,10 @@ async function readOptionalText2(filePath) {
|
|
|
47051
47818
|
}
|
|
47052
47819
|
async function restoreOptionalText(filePath, content) {
|
|
47053
47820
|
if (content === null) {
|
|
47054
|
-
await
|
|
47821
|
+
await rm22(filePath, { force: true });
|
|
47055
47822
|
return;
|
|
47056
47823
|
}
|
|
47057
|
-
await
|
|
47824
|
+
await writeFile47(filePath, content, "utf-8");
|
|
47058
47825
|
}
|
|
47059
47826
|
function readActiveSoloPlan(value) {
|
|
47060
47827
|
if (!value || typeof value !== "object") return null;
|
|
@@ -47072,11 +47839,11 @@ async function workflowList(rootDir, options) {
|
|
|
47072
47839
|
const views = attachActiveChildren(workflows);
|
|
47073
47840
|
if (options.json) {
|
|
47074
47841
|
console.log(JSON.stringify(views, null, 2));
|
|
47075
|
-
return
|
|
47842
|
+
return EXIT_OK11;
|
|
47076
47843
|
}
|
|
47077
47844
|
if (workflows.length === 0) {
|
|
47078
47845
|
console.log("No workflows.");
|
|
47079
|
-
return
|
|
47846
|
+
return EXIT_OK11;
|
|
47080
47847
|
}
|
|
47081
47848
|
const inProgress = workflows.filter((w) => w.status === "in_progress").length;
|
|
47082
47849
|
console.log(
|
|
@@ -47086,7 +47853,7 @@ async function workflowList(rootDir, options) {
|
|
|
47086
47853
|
for (const meta of views) {
|
|
47087
47854
|
console.log(formatWorkflowRow(meta));
|
|
47088
47855
|
}
|
|
47089
|
-
return
|
|
47856
|
+
return EXIT_OK11;
|
|
47090
47857
|
}
|
|
47091
47858
|
async function workflowShow(rootDir, taskId, options) {
|
|
47092
47859
|
if (!taskId) {
|
|
@@ -47123,7 +47890,7 @@ async function workflowShow(rootDir, taskId, options) {
|
|
|
47123
47890
|
2
|
|
47124
47891
|
)
|
|
47125
47892
|
);
|
|
47126
|
-
return
|
|
47893
|
+
return EXIT_OK11;
|
|
47127
47894
|
}
|
|
47128
47895
|
console.log(`Workflow: ${meta.taskId}`);
|
|
47129
47896
|
console.log(`Task: ${meta.task}`);
|
|
@@ -47155,7 +47922,7 @@ async function workflowShow(rootDir, taskId, options) {
|
|
|
47155
47922
|
}
|
|
47156
47923
|
}
|
|
47157
47924
|
}
|
|
47158
|
-
return
|
|
47925
|
+
return EXIT_OK11;
|
|
47159
47926
|
}
|
|
47160
47927
|
async function workflowClean(rootDir, options) {
|
|
47161
47928
|
const workflows = await listWorkflows(rootDir);
|
|
@@ -47223,7 +47990,7 @@ async function workflowClean(rootDir, options) {
|
|
|
47223
47990
|
} else {
|
|
47224
47991
|
console.log(`Removed ${removed.length} workflow(s).`);
|
|
47225
47992
|
}
|
|
47226
|
-
return
|
|
47993
|
+
return EXIT_OK11;
|
|
47227
47994
|
}
|
|
47228
47995
|
function formatWorkflowRow(meta) {
|
|
47229
47996
|
const stepMax = maxWorkflowStep(meta.mode);
|
|
@@ -47693,8 +48460,24 @@ program.command("manps [area]").description("Run deterministic preseason health
|
|
|
47693
48460
|
const code = await manps(process.cwd(), area ?? "all", options);
|
|
47694
48461
|
process.exitCode = code;
|
|
47695
48462
|
});
|
|
47696
|
-
program.command("
|
|
47697
|
-
|
|
48463
|
+
var designProgram = program.command("design").description("Inspect and configure project UI design policy");
|
|
48464
|
+
designProgram.command("status").description("Show the configured and effective project design policy").option("--json", "Output as JSON (for scripts)").action(async (options) => {
|
|
48465
|
+
process.exitCode = await designStatus(process.cwd(), options);
|
|
48466
|
+
});
|
|
48467
|
+
designProgram.command("context").description("Emit bounded UI design context for coding agents").option("--json", "Output as JSON (for scripts)").action(async (options) => {
|
|
48468
|
+
process.exitCode = await designContext(process.cwd(), options);
|
|
48469
|
+
});
|
|
48470
|
+
designProgram.command("configure").description("CAS-update the optional project design policy").requiredOption(
|
|
48471
|
+
"--expected-revision <n>",
|
|
48472
|
+
"Current policy revision; use 0 when absent"
|
|
48473
|
+
).option("--preset <preset>", "preserve, refine, or experimental").option("--icons <policy>", "existing-first or lucide").option("--emoji <policy>", "allow or forbid-as-interface-icon").option("--motion <policy>", "minimal or purposeful").option("--browser-validation <mode>", "off, when-available, or required").option("--confirm-experimental", "Explicitly allow the experimental preset").option("--json", "Output as JSON (for scripts)").action(async (options) => {
|
|
48474
|
+
process.exitCode = await designConfigure(process.cwd(), options);
|
|
48475
|
+
});
|
|
48476
|
+
designProgram.command("disable").description("Disable the project design policy without deleting it").requiredOption("--expected-revision <n>", "Current policy revision").option("--json", "Output as JSON (for scripts)").action(async (options) => {
|
|
48477
|
+
process.exitCode = await designDisable(process.cwd(), options);
|
|
48478
|
+
});
|
|
48479
|
+
program.command("refresh-style").description("Refresh project profile and rescan applicable design tokens").option("--root <path>", "Repository-relative UI project root").action(async (options) => {
|
|
48480
|
+
const code = await refreshStyle(process.cwd(), options);
|
|
47698
48481
|
process.exitCode = code;
|
|
47699
48482
|
});
|
|
47700
48483
|
program.command("refresh-project").description(
|