mancode 0.4.2 → 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 +63 -6
- package/README.md +43 -6
- package/dist/{chunk-LYRYNJHW.js → chunk-73F46VQM.js} +3 -1
- package/dist/chunk-73F46VQM.js.map +1 -0
- package/dist/cli.js +1425 -661
- package/dist/cli.js.map +1 -1
- package/dist/{v3-adapter-E6VEEDCF.js → v3-adapter-7XYKHGTB.js} +2 -2
- package/package.json +1 -1
- package/dist/chunk-LYRYNJHW.js.map +0 -1
- /package/dist/{v3-adapter-E6VEEDCF.js.map → v3-adapter-7XYKHGTB.js.map} +0 -0
package/dist/cli.js
CHANGED
|
@@ -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";
|
|
@@ -401,7 +401,7 @@ async function inspectMancodeLayout(projectRoot) {
|
|
|
401
401
|
]);
|
|
402
402
|
const v3AuthorityPathsPresent = (await Promise.all(
|
|
403
403
|
V3_AUTHORITY_PATHS.map(
|
|
404
|
-
async (
|
|
404
|
+
async (relativePath2) => await lstatOrNull(path.join(mancodeRoot, relativePath2)) === null ? null : relativePath2
|
|
405
405
|
)
|
|
406
406
|
)).filter(
|
|
407
407
|
(value) => value !== null
|
|
@@ -436,9 +436,9 @@ async function scanLegacyEntry(root, legacyPath) {
|
|
|
436
436
|
};
|
|
437
437
|
}
|
|
438
438
|
async function describeNode(target) {
|
|
439
|
-
const
|
|
440
|
-
if (
|
|
441
|
-
if (
|
|
439
|
+
const stat5 = await lstatOrNull(target);
|
|
440
|
+
if (stat5 === null) return null;
|
|
441
|
+
if (stat5.isFile()) {
|
|
442
442
|
const contents = await readFile(target);
|
|
443
443
|
return {
|
|
444
444
|
kind: "file",
|
|
@@ -446,7 +446,7 @@ async function describeNode(target) {
|
|
|
446
446
|
digest: sha256(contents)
|
|
447
447
|
};
|
|
448
448
|
}
|
|
449
|
-
if (
|
|
449
|
+
if (stat5.isSymbolicLink()) {
|
|
450
450
|
const link = await readlink(target);
|
|
451
451
|
return {
|
|
452
452
|
kind: "symlink",
|
|
@@ -454,7 +454,7 @@ async function describeNode(target) {
|
|
|
454
454
|
digest: sha256(Buffer.from(link, "utf8"))
|
|
455
455
|
};
|
|
456
456
|
}
|
|
457
|
-
if (!
|
|
457
|
+
if (!stat5.isDirectory()) {
|
|
458
458
|
return {
|
|
459
459
|
kind: "other",
|
|
460
460
|
hasBusinessContent: true,
|
|
@@ -4464,8 +4464,8 @@ async function unlinkIfExists(target) {
|
|
|
4464
4464
|
}
|
|
4465
4465
|
}
|
|
4466
4466
|
async function assertSafeStateDirectory(target) {
|
|
4467
|
-
const
|
|
4468
|
-
if (!
|
|
4467
|
+
const stat5 = await lstat2(target);
|
|
4468
|
+
if (!stat5.isDirectory() || stat5.isSymbolicLink()) {
|
|
4469
4469
|
throw new Error("MANCODE_TRANSPORT_AUTHORITY_STATE_UNSAFE");
|
|
4470
4470
|
}
|
|
4471
4471
|
}
|
|
@@ -9293,13 +9293,13 @@ function parseArtifacts(value) {
|
|
|
9293
9293
|
["relativePath", "classification", "includeInPromotion", "contentDigest"],
|
|
9294
9294
|
"quarantine artifact"
|
|
9295
9295
|
);
|
|
9296
|
-
const
|
|
9296
|
+
const relativePath2 = assertSafeSharedRelativePath(
|
|
9297
9297
|
item.relativePath
|
|
9298
9298
|
);
|
|
9299
|
-
if (paths.has(
|
|
9299
|
+
if (paths.has(relativePath2)) {
|
|
9300
9300
|
throw new Error("quarantine artifacts must not repeat a relativePath");
|
|
9301
9301
|
}
|
|
9302
|
-
paths.add(
|
|
9302
|
+
paths.add(relativePath2);
|
|
9303
9303
|
if (typeof item.classification !== "string" || !ARTIFACT_CLASSES.has(item.classification)) {
|
|
9304
9304
|
throw new Error("quarantine artifact classification is invalid");
|
|
9305
9305
|
}
|
|
@@ -9311,7 +9311,7 @@ function parseArtifacts(value) {
|
|
|
9311
9311
|
throw new Error("MANCODE_RAW_ARTIFACT_CANNOT_BE_PROMOTED");
|
|
9312
9312
|
}
|
|
9313
9313
|
return {
|
|
9314
|
-
relativePath,
|
|
9314
|
+
relativePath: relativePath2,
|
|
9315
9315
|
classification,
|
|
9316
9316
|
includeInPromotion: item.includeInPromotion,
|
|
9317
9317
|
contentDigest: parseDigestOrNull3(
|
|
@@ -9881,7 +9881,7 @@ async function activateLegacyMigration(input) {
|
|
|
9881
9881
|
for (const action of payload.actions.filter(
|
|
9882
9882
|
(action2) => action2.kind === "v3_adapter_file"
|
|
9883
9883
|
)) {
|
|
9884
|
-
const { applyV3AdapterFilePlan: applyV3AdapterFilePlan2 } = await import("./v3-adapter-
|
|
9884
|
+
const { applyV3AdapterFilePlan: applyV3AdapterFilePlan2 } = await import("./v3-adapter-7XYKHGTB.js");
|
|
9885
9885
|
await applyV3AdapterFilePlan2(root, action);
|
|
9886
9886
|
}
|
|
9887
9887
|
journal = await completeActivationStep(
|
|
@@ -10899,14 +10899,14 @@ function renderBlockedTask(loaded, aliases, allocator, now, blockers) {
|
|
|
10899
10899
|
function buildQuarantineCandidate(loaded, candidate, quarantineId, now) {
|
|
10900
10900
|
const entityFiles = candidateEntityFiles(candidate);
|
|
10901
10901
|
const artifacts = [
|
|
10902
|
-
...entityFiles.map(({ relativePath, content }) => ({
|
|
10903
|
-
relativePath,
|
|
10902
|
+
...entityFiles.map(({ relativePath: relativePath2, content }) => ({
|
|
10903
|
+
relativePath: relativePath2,
|
|
10904
10904
|
classification: "authority",
|
|
10905
10905
|
includeInPromotion: true,
|
|
10906
10906
|
contentDigest: digestText(content)
|
|
10907
10907
|
})),
|
|
10908
|
-
...loaded.sourceFiles.filter((file) => file.relativePath.startsWith("artifacts/")).map(({ relativePath, content }) => ({
|
|
10909
|
-
relativePath,
|
|
10908
|
+
...loaded.sourceFiles.filter((file) => file.relativePath.startsWith("artifacts/")).map(({ relativePath: relativePath2, content }) => ({
|
|
10909
|
+
relativePath: relativePath2,
|
|
10910
10910
|
classification: "human_view",
|
|
10911
10911
|
includeInPromotion: true,
|
|
10912
10912
|
contentDigest: digestText(content)
|
|
@@ -10934,8 +10934,8 @@ function buildSourceOnlyQuarantine(loaded, quarantineId, now) {
|
|
|
10934
10934
|
purpose: "legacy_migration",
|
|
10935
10935
|
sourceTaskRef: null,
|
|
10936
10936
|
candidateTaskRef: { namespace: "local", taskId: quarantineId },
|
|
10937
|
-
artifacts: loaded.sourceFiles.map(({ relativePath, content }) => ({
|
|
10938
|
-
relativePath,
|
|
10937
|
+
artifacts: loaded.sourceFiles.map(({ relativePath: relativePath2, content }) => ({
|
|
10938
|
+
relativePath: relativePath2,
|
|
10939
10939
|
classification: "authority",
|
|
10940
10940
|
includeInPromotion: false,
|
|
10941
10941
|
contentDigest: digestText(content)
|
|
@@ -11377,16 +11377,16 @@ function assertLegacyTaskId(value) {
|
|
|
11377
11377
|
throw new Error("MANCODE_MIGRATION_LEGACY_TASK_ID_UNSAFE");
|
|
11378
11378
|
}
|
|
11379
11379
|
}
|
|
11380
|
-
async function readLegacyText(projectRoot,
|
|
11381
|
-
const value = await readLegacyTextOrNull(projectRoot,
|
|
11380
|
+
async function readLegacyText(projectRoot, relativePath2) {
|
|
11381
|
+
const value = await readLegacyTextOrNull(projectRoot, relativePath2);
|
|
11382
11382
|
if (value === null) {
|
|
11383
11383
|
throw new Error("MANCODE_MIGRATION_LEGACY_ENTITY_MISSING");
|
|
11384
11384
|
}
|
|
11385
11385
|
return value;
|
|
11386
11386
|
}
|
|
11387
|
-
async function readLegacyTextOrNull(projectRoot,
|
|
11387
|
+
async function readLegacyTextOrNull(projectRoot, relativePath2) {
|
|
11388
11388
|
const root = path18.join(path18.resolve(projectRoot), ".mancode");
|
|
11389
|
-
const segments = safeSegments(
|
|
11389
|
+
const segments = safeSegments(relativePath2);
|
|
11390
11390
|
await assertSafeDirectory(root);
|
|
11391
11391
|
let directory = root;
|
|
11392
11392
|
for (const segment of segments.slice(0, -1)) {
|
|
@@ -11412,8 +11412,8 @@ async function readLegacyTextOrNull(projectRoot, relativePath) {
|
|
|
11412
11412
|
}
|
|
11413
11413
|
return content;
|
|
11414
11414
|
}
|
|
11415
|
-
async function assertLegacyTextUnchanged(projectRoot,
|
|
11416
|
-
const actual = await readLegacyText(projectRoot,
|
|
11415
|
+
async function assertLegacyTextUnchanged(projectRoot, relativePath2, expected) {
|
|
11416
|
+
const actual = await readLegacyText(projectRoot, relativePath2);
|
|
11417
11417
|
if (actual !== expected) {
|
|
11418
11418
|
throw new Error("MANCODE_LEGACY_TREE_CHANGED_DURING_SCAN");
|
|
11419
11419
|
}
|
|
@@ -11428,16 +11428,16 @@ async function readSafeDirectoryOrEmpty(target) {
|
|
|
11428
11428
|
}
|
|
11429
11429
|
}
|
|
11430
11430
|
async function assertSafeDirectory(target) {
|
|
11431
|
-
const
|
|
11432
|
-
if (!
|
|
11431
|
+
const stat5 = await lstat5(target);
|
|
11432
|
+
if (!stat5.isDirectory() || stat5.isSymbolicLink()) {
|
|
11433
11433
|
throw new Error("MANCODE_MIGRATION_LEGACY_PATH_UNSAFE");
|
|
11434
11434
|
}
|
|
11435
11435
|
}
|
|
11436
|
-
function safeSegments(
|
|
11437
|
-
if (!
|
|
11436
|
+
function safeSegments(relativePath2) {
|
|
11437
|
+
if (!relativePath2 || path18.isAbsolute(relativePath2) || relativePath2.includes("\0")) {
|
|
11438
11438
|
throw new Error("MANCODE_MIGRATION_LEGACY_PATH_UNSAFE");
|
|
11439
11439
|
}
|
|
11440
|
-
const segments =
|
|
11440
|
+
const segments = relativePath2.split(path18.sep);
|
|
11441
11441
|
if (segments.some((segment) => !segment || segment === "." || segment === "..")) {
|
|
11442
11442
|
throw new Error("MANCODE_MIGRATION_LEGACY_PATH_UNSAFE");
|
|
11443
11443
|
}
|
|
@@ -11620,15 +11620,15 @@ function assertClaimMatchesStore(store, claim) {
|
|
|
11620
11620
|
return claim;
|
|
11621
11621
|
}
|
|
11622
11622
|
async function assertSafeClaimFile(target) {
|
|
11623
|
-
const
|
|
11624
|
-
if (!
|
|
11623
|
+
const stat5 = await lstat6(target);
|
|
11624
|
+
if (!stat5.isFile() || stat5.isSymbolicLink()) {
|
|
11625
11625
|
throw new Error("MANCODE_CLAIM_PATH_UNSAFE");
|
|
11626
11626
|
}
|
|
11627
11627
|
}
|
|
11628
11628
|
async function assertSafeClaimDirectory(store) {
|
|
11629
11629
|
const directory = claimDirectory(store);
|
|
11630
|
-
const
|
|
11631
|
-
if (!
|
|
11630
|
+
const stat5 = await lstat6(directory);
|
|
11631
|
+
if (!stat5.isDirectory() || stat5.isSymbolicLink()) {
|
|
11632
11632
|
throw new Error("MANCODE_CLAIM_PATH_UNSAFE");
|
|
11633
11633
|
}
|
|
11634
11634
|
}
|
|
@@ -11760,14 +11760,14 @@ async function atomicWriteHandoff(store, handoff) {
|
|
|
11760
11760
|
await assertSafeHandoffFile(target);
|
|
11761
11761
|
}
|
|
11762
11762
|
async function assertSafeHandoffFile(target) {
|
|
11763
|
-
const
|
|
11764
|
-
if (!
|
|
11763
|
+
const stat5 = await lstat7(target);
|
|
11764
|
+
if (!stat5.isFile() || stat5.isSymbolicLink()) {
|
|
11765
11765
|
throw new Error("MANCODE_HANDOFF_PATH_UNSAFE");
|
|
11766
11766
|
}
|
|
11767
11767
|
}
|
|
11768
11768
|
async function assertSafeHandoffDirectory(store) {
|
|
11769
|
-
const
|
|
11770
|
-
if (!
|
|
11769
|
+
const stat5 = await lstat7(handoffDirectory(store));
|
|
11770
|
+
if (!stat5.isDirectory() || stat5.isSymbolicLink()) {
|
|
11771
11771
|
throw new Error("MANCODE_HANDOFF_PATH_UNSAFE");
|
|
11772
11772
|
}
|
|
11773
11773
|
}
|
|
@@ -13737,7 +13737,7 @@ async function upgradeV3Adapters(input) {
|
|
|
13737
13737
|
if (unfinished.length > 0) {
|
|
13738
13738
|
throw new Error("MANCODE_ADAPTER_UPGRADE_OPERATION_PENDING");
|
|
13739
13739
|
}
|
|
13740
|
-
const actualVersions = await import("./v3-adapter-
|
|
13740
|
+
const actualVersions = await import("./v3-adapter-7XYKHGTB.js").then(
|
|
13741
13741
|
({ inspectV3AdapterVersions: inspectV3AdapterVersions2 }) => inspectV3AdapterVersions2(
|
|
13742
13742
|
root,
|
|
13743
13743
|
managedAdapterNames(project.manifest.managedAdapters)
|
|
@@ -14216,8 +14216,8 @@ async function removeAdapterUpgradePreview(root, operationId) {
|
|
|
14216
14216
|
async function readAdapterUpgradePreview(root, operationId) {
|
|
14217
14217
|
const target = adapterUpgradePreviewPath(root, operationId);
|
|
14218
14218
|
try {
|
|
14219
|
-
const
|
|
14220
|
-
if (!
|
|
14219
|
+
const stat5 = await lstat10(target);
|
|
14220
|
+
if (!stat5.isFile() || stat5.isSymbolicLink()) {
|
|
14221
14221
|
throw new Error("MANCODE_ADAPTER_UPGRADE_PREVIEW_INVALID");
|
|
14222
14222
|
}
|
|
14223
14223
|
return parseAdapterUpgradePreview(
|
|
@@ -14297,8 +14297,8 @@ async function assertStagedAdapterFiles(root, preview, plans) {
|
|
|
14297
14297
|
if (!target.startsWith(`${root}${path24.sep}`)) {
|
|
14298
14298
|
throw new Error("MANCODE_ADAPTER_UPGRADE_PREVIEW_INVALID");
|
|
14299
14299
|
}
|
|
14300
|
-
const
|
|
14301
|
-
if (!
|
|
14300
|
+
const stat5 = await lstat10(target);
|
|
14301
|
+
if (!stat5.isFile() || stat5.isSymbolicLink()) {
|
|
14302
14302
|
throw new Error("MANCODE_ADAPTER_UPGRADE_PREVIEW_INVALID");
|
|
14303
14303
|
}
|
|
14304
14304
|
if (await readFile23(target, "utf8") !== plan.targetContent) {
|
|
@@ -14648,7 +14648,8 @@ trigger: <\u5177\u4F53\u4E8B\u5B9E>
|
|
|
14648
14648
|
- **\u7CBE\u786E\u5339\u914D**\u5DF2\u6709\u98CE\u683C\u3001\u547D\u540D\u3001\u6A21\u5F0F \u2014 \u5373\u4F7F\u4F60\u4E0D\u8BA4\u540C
|
|
14649
14649
|
- \u6539\u52A8\u5B64\u7ACB\u4E86\u67D0\u4E2A import / \u53D8\u91CF / \u51FD\u6570 \u2192 \u79FB\u9664\u5B83
|
|
14650
14650
|
- \u4E0D\u79FB\u9664\u6539\u52A8\u524D\u5C31\u5B58\u5728\u7684\u6B7B\u4EE3\u7801\uFF08\u63D0\u4E00\u53E5\u5C31\u884C\uFF09
|
|
14651
|
-
- \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
|
|
14652
14653
|
|
|
14653
14654
|
---
|
|
14654
14655
|
|
|
@@ -15806,6 +15807,7 @@ var DEFAULT_CONFIG = {
|
|
|
15806
15807
|
};
|
|
15807
15808
|
var EMPTY_STYLE_TOKENS = {
|
|
15808
15809
|
version: "1.0.0",
|
|
15810
|
+
scopeRoot: ".",
|
|
15809
15811
|
lastScanned: null,
|
|
15810
15812
|
colors: {},
|
|
15811
15813
|
fonts: {},
|
|
@@ -16268,8 +16270,14 @@ function renderModeSkill(mode, commandPrefix = "$") {
|
|
|
16268
16270
|
"is the smallest useful diff?",
|
|
16269
16271
|
"",
|
|
16270
16272
|
"Read `.mancode/project-profile.json` before choosing tools or validation.",
|
|
16271
|
-
"
|
|
16272
|
-
"
|
|
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.",
|
|
16273
16281
|
"",
|
|
16274
16282
|
meta.workflow
|
|
16275
16283
|
].join("\n");
|
|
@@ -16648,7 +16656,7 @@ var MODE_META = {
|
|
|
16648
16656
|
"",
|
|
16649
16657
|
"- Keep the diff narrow.",
|
|
16650
16658
|
"- Reuse existing functions, components, styles, and dependencies.",
|
|
16651
|
-
"- 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.",
|
|
16652
16660
|
"- Verify with the narrowest meaningful test, lint, build, or smoke check.",
|
|
16653
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.",
|
|
16654
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."
|
|
@@ -16700,7 +16708,7 @@ function renderProjectContext(state, tokens, profile, options) {
|
|
|
16700
16708
|
...state?.activeSoloPlan?.taskId ? [
|
|
16701
16709
|
`- Active solo plan: ${state.activeSoloPlan.taskId} (plan v${state.activeSoloPlan.planVersion ?? 1}); read its requirements.md and plan.md before implementation.`
|
|
16702
16710
|
] : [],
|
|
16703
|
-
"- 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."
|
|
16704
16712
|
].join("\n");
|
|
16705
16713
|
}
|
|
16706
16714
|
function renderPracticeRules() {
|
|
@@ -16737,7 +16745,7 @@ function renderAesthetics(tokens) {
|
|
|
16737
16745
|
"## mancode Aesthetics",
|
|
16738
16746
|
"",
|
|
16739
16747
|
lowConfidence,
|
|
16740
|
-
"- 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."
|
|
16741
16749
|
].join("\n");
|
|
16742
16750
|
}
|
|
16743
16751
|
const lines = ["## mancode Aesthetics", ""];
|
|
@@ -16749,7 +16757,7 @@ function renderAesthetics(tokens) {
|
|
|
16749
16757
|
if (components) lines.push(`- Components: ${components}`);
|
|
16750
16758
|
if (cssVariables) lines.push(`- CSS variables: ${cssVariables}`);
|
|
16751
16759
|
lines.push(
|
|
16752
|
-
"- 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."
|
|
16753
16761
|
);
|
|
16754
16762
|
return lines.join("\n");
|
|
16755
16763
|
}
|
|
@@ -17118,7 +17126,7 @@ function renderSoloRule() {
|
|
|
17118
17126
|
"",
|
|
17119
17127
|
"- Keep the diff narrow.",
|
|
17120
17128
|
"- Reuse existing functions, components, styles, and dependencies.",
|
|
17121
|
-
"- 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.",
|
|
17122
17130
|
"- Verify with the narrowest meaningful test, lint, build, or smoke check.",
|
|
17123
17131
|
"- Perform one bounded self-check limited to the current diff. Do not start another reviewer, create a review artifact, or repeat the review.",
|
|
17124
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.",
|
|
@@ -18167,9 +18175,9 @@ async function previewV3TaskPromotion(input) {
|
|
|
18167
18175
|
purpose: "publish_promote",
|
|
18168
18176
|
sourceTaskRef,
|
|
18169
18177
|
candidateTaskRef: sourceTaskRef,
|
|
18170
|
-
artifacts: Object.entries(contents).map(([
|
|
18171
|
-
relativePath,
|
|
18172
|
-
classification:
|
|
18178
|
+
artifacts: Object.entries(contents).map(([relativePath2, content]) => ({
|
|
18179
|
+
relativePath: relativePath2,
|
|
18180
|
+
classification: relativePath2 === "plan.md" ? "human_view" : "authority",
|
|
18173
18181
|
includeInPromotion: true,
|
|
18174
18182
|
contentDigest: digestCanonicalJson({ content })
|
|
18175
18183
|
})),
|
|
@@ -18697,9 +18705,9 @@ function buildPromotionRecoveryPayload(input) {
|
|
|
18697
18705
|
function prepareQuarantine(input) {
|
|
18698
18706
|
const contents = destinationAuthorityContents(input.entities);
|
|
18699
18707
|
const artifacts = Object.entries(contents).map(
|
|
18700
|
-
([
|
|
18701
|
-
relativePath,
|
|
18702
|
-
classification:
|
|
18708
|
+
([relativePath2, content]) => ({
|
|
18709
|
+
relativePath: relativePath2,
|
|
18710
|
+
classification: relativePath2 === "plan.md" ? "human_view" : "authority",
|
|
18703
18711
|
includeInPromotion: true,
|
|
18704
18712
|
contentDigest: digestCanonicalJson({ content })
|
|
18705
18713
|
})
|
|
@@ -21568,7 +21576,7 @@ function parseGitRefTaskBundleArtifact(value) {
|
|
|
21568
21576
|
if (!isBundleArtifactKind(value.kind)) {
|
|
21569
21577
|
throw new Error("git-ref task bundle artifact kind is invalid");
|
|
21570
21578
|
}
|
|
21571
|
-
const
|
|
21579
|
+
const relativePath2 = assertSafeSharedRelativePath(
|
|
21572
21580
|
value.relativePath
|
|
21573
21581
|
);
|
|
21574
21582
|
const content = parseJsonValue(
|
|
@@ -21586,7 +21594,7 @@ function parseGitRefTaskBundleArtifact(value) {
|
|
|
21586
21594
|
if (contentDigest !== digestCanonicalJson(content)) {
|
|
21587
21595
|
throw new Error("MANCODE_TRANSPORT_BUNDLE_ARTIFACT_DIGEST_MISMATCH");
|
|
21588
21596
|
}
|
|
21589
|
-
return { kind: value.kind, relativePath, content, contentDigest };
|
|
21597
|
+
return { kind: value.kind, relativePath: relativePath2, content, contentDigest };
|
|
21590
21598
|
}
|
|
21591
21599
|
function parseJsonValue(value, label, depth = 0) {
|
|
21592
21600
|
if (depth > MAX_JSON_DEPTH) {
|
|
@@ -23319,11 +23327,11 @@ async function readQuarantinedGitRefTaskBundle(projectRoot, remoteRevision, task
|
|
|
23319
23327
|
}
|
|
23320
23328
|
return matches[0] ?? null;
|
|
23321
23329
|
}
|
|
23322
|
-
function artifact(kind,
|
|
23330
|
+
function artifact(kind, relativePath2, value) {
|
|
23323
23331
|
const content = JSON.parse(JSON.stringify(value));
|
|
23324
23332
|
return {
|
|
23325
23333
|
kind,
|
|
23326
|
-
relativePath,
|
|
23334
|
+
relativePath: relativePath2,
|
|
23327
23335
|
content,
|
|
23328
23336
|
contentDigest: digestCanonicalJson(content)
|
|
23329
23337
|
};
|
|
@@ -23670,13 +23678,13 @@ async function applyJournal(projectRoot, journal) {
|
|
|
23670
23678
|
"workflows",
|
|
23671
23679
|
journal.targetBundle.taskRef.taskId
|
|
23672
23680
|
]);
|
|
23673
|
-
for (const [
|
|
23681
|
+
for (const [relativePath2, content] of target) {
|
|
23674
23682
|
await replaceVerifiedFile(
|
|
23675
23683
|
taskRoot2,
|
|
23676
|
-
|
|
23684
|
+
relativePath2,
|
|
23677
23685
|
content,
|
|
23678
|
-
predecessor.get(
|
|
23679
|
-
|
|
23686
|
+
predecessor.get(relativePath2) ?? null,
|
|
23687
|
+
relativePath2 === "metadata.json" ? pendingMetadataContent : null
|
|
23680
23688
|
);
|
|
23681
23689
|
}
|
|
23682
23690
|
for (const optional of ["plan.md", "summary.md"]) {
|
|
@@ -23814,18 +23822,18 @@ function serializeArtifact(artifact2) {
|
|
|
23814
23822
|
return `${JSON.stringify(artifact2.content, null, 2)}
|
|
23815
23823
|
`;
|
|
23816
23824
|
}
|
|
23817
|
-
async function replaceVerifiedFile(taskRoot2,
|
|
23818
|
-
const target = safeTaskPath(taskRoot2,
|
|
23825
|
+
async function replaceVerifiedFile(taskRoot2, relativePath2, targetContent, predecessorContent, alternatePredecessorContent) {
|
|
23826
|
+
const target = safeTaskPath(taskRoot2, relativePath2);
|
|
23819
23827
|
await ensureSafeDirectory(
|
|
23820
23828
|
taskRoot2,
|
|
23821
|
-
path42.dirname(
|
|
23829
|
+
path42.dirname(relativePath2).split(path42.sep)
|
|
23822
23830
|
);
|
|
23823
23831
|
const current = await readSafeFileOrNull(target);
|
|
23824
|
-
if (contentMatches(
|
|
23825
|
-
if (current !== null && !contentMatches(
|
|
23832
|
+
if (contentMatches(relativePath2, current, targetContent)) return;
|
|
23833
|
+
if (current !== null && !contentMatches(relativePath2, current, predecessorContent) && !contentMatches(relativePath2, current, alternatePredecessorContent)) {
|
|
23826
23834
|
throw new Error("MANCODE_SPLIT_BRAIN");
|
|
23827
23835
|
}
|
|
23828
|
-
if (current === null && (predecessorContent !== null || alternatePredecessorContent !== null) &&
|
|
23836
|
+
if (current === null && (predecessorContent !== null || alternatePredecessorContent !== null) && relativePath2 !== "summary.md") {
|
|
23829
23837
|
throw new Error("MANCODE_SPLIT_BRAIN");
|
|
23830
23838
|
}
|
|
23831
23839
|
const temporary = path42.join(
|
|
@@ -23835,9 +23843,9 @@ async function replaceVerifiedFile(taskRoot2, relativePath, targetContent, prede
|
|
|
23835
23843
|
await writeFile36(temporary, targetContent, { encoding: "utf8", flag: "wx" });
|
|
23836
23844
|
await replaceFileAtomically(temporary, target);
|
|
23837
23845
|
}
|
|
23838
|
-
function contentMatches(
|
|
23846
|
+
function contentMatches(relativePath2, current, expected) {
|
|
23839
23847
|
if (current === null || expected === null) return current === expected;
|
|
23840
|
-
if (!
|
|
23848
|
+
if (!relativePath2.endsWith(".json")) return current === expected;
|
|
23841
23849
|
try {
|
|
23842
23850
|
return digestCanonicalJson(JSON.parse(current)) === digestCanonicalJson(JSON.parse(expected));
|
|
23843
23851
|
} catch {
|
|
@@ -23871,8 +23879,8 @@ function bundleMetadata(bundle) {
|
|
|
23871
23879
|
}
|
|
23872
23880
|
return parseWorkflowMetadata(artifact2.content);
|
|
23873
23881
|
}
|
|
23874
|
-
async function removeVerifiedFile(taskRoot2,
|
|
23875
|
-
const target = safeTaskPath(taskRoot2,
|
|
23882
|
+
async function removeVerifiedFile(taskRoot2, relativePath2, predecessorContent) {
|
|
23883
|
+
const target = safeTaskPath(taskRoot2, relativePath2);
|
|
23876
23884
|
const current = await readSafeFileOrNull(target);
|
|
23877
23885
|
if (current === null) return;
|
|
23878
23886
|
if (predecessorContent === null || current !== predecessorContent) {
|
|
@@ -23916,8 +23924,8 @@ async function ensureSafeDirectory(root, segments) {
|
|
|
23916
23924
|
}
|
|
23917
23925
|
}
|
|
23918
23926
|
}
|
|
23919
|
-
function safeTaskPath(taskRoot2,
|
|
23920
|
-
const target = path42.resolve(taskRoot2,
|
|
23927
|
+
function safeTaskPath(taskRoot2, relativePath2) {
|
|
23928
|
+
const target = path42.resolve(taskRoot2, relativePath2);
|
|
23921
23929
|
const relative = path42.relative(taskRoot2, target);
|
|
23922
23930
|
if (!relative || relative.startsWith("..") || path42.isAbsolute(relative)) {
|
|
23923
23931
|
throw new Error("MANCODE_ARTIFACT_PATH_UNSAFE");
|
|
@@ -25297,15 +25305,692 @@ function parseExpectedRevision2(value) {
|
|
|
25297
25305
|
return Number.isSafeInteger(parsed) ? parsed : null;
|
|
25298
25306
|
}
|
|
25299
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
|
+
|
|
25300
25985
|
// src/commands/init.ts
|
|
25301
25986
|
import { promises as fs4 } from "fs";
|
|
25302
25987
|
import os from "os";
|
|
25303
|
-
import
|
|
25304
|
-
import
|
|
25988
|
+
import path51 from "path";
|
|
25989
|
+
import process6 from "process";
|
|
25305
25990
|
|
|
25306
25991
|
// src/installers/platform-status.ts
|
|
25307
25992
|
import { promises as fs } from "fs";
|
|
25308
|
-
import
|
|
25993
|
+
import path46 from "path";
|
|
25309
25994
|
async function checkPlatformStatus(rootDir, platform, installed) {
|
|
25310
25995
|
const readiness = await checkPlatformReadiness(rootDir, platform);
|
|
25311
25996
|
return {
|
|
@@ -25322,13 +26007,13 @@ async function checkPlatformReadiness(rootDir, platform) {
|
|
|
25322
26007
|
if (platform === "claude-code") {
|
|
25323
26008
|
const [hasSoloSkill, registered, hasHookFiles] = await Promise.all([
|
|
25324
26009
|
fileMatches(
|
|
25325
|
-
|
|
26010
|
+
path46.join(rootDir, ".claude", "skills", "solo", "SKILL.md"),
|
|
25326
26011
|
(content) => isGeneratedClaudeSkill(content, "solo")
|
|
25327
26012
|
),
|
|
25328
26013
|
claudeHooksRegistered(rootDir),
|
|
25329
26014
|
pathsExist([
|
|
25330
|
-
|
|
25331
|
-
|
|
26015
|
+
path46.join(rootDir, ".mancode", "hooks", "session-start.mjs"),
|
|
26016
|
+
path46.join(rootDir, ".mancode", "hooks", "user-prompt-submit.mjs")
|
|
25332
26017
|
])
|
|
25333
26018
|
]);
|
|
25334
26019
|
const present = hasSoloSkill && registered && hasHookFiles;
|
|
@@ -25344,7 +26029,7 @@ async function checkPlatformReadiness(rootDir, platform) {
|
|
|
25344
26029
|
if (platform === "cursor") {
|
|
25345
26030
|
const hasCoreRules = await allManagedSkills(
|
|
25346
26031
|
MANCODE_CURSOR_CORE_RULE_FILES.map(
|
|
25347
|
-
(file) =>
|
|
26032
|
+
(file) => path46.join(rootDir, ".cursor", "rules", file)
|
|
25348
26033
|
),
|
|
25349
26034
|
[CURSOR_RULE_MANAGED_MARKER]
|
|
25350
26035
|
);
|
|
@@ -25359,13 +26044,13 @@ async function checkPlatformReadiness(rootDir, platform) {
|
|
|
25359
26044
|
const [hasRules, hasCommands] = await Promise.all([
|
|
25360
26045
|
allManagedSkills(
|
|
25361
26046
|
MANCODE_CURSOR_RULE_FILES.map(
|
|
25362
|
-
(file) =>
|
|
26047
|
+
(file) => path46.join(rootDir, ".cursor", "rules", file)
|
|
25363
26048
|
),
|
|
25364
26049
|
[CURSOR_RULE_MANAGED_MARKER]
|
|
25365
26050
|
),
|
|
25366
26051
|
allManagedSkills(
|
|
25367
26052
|
MODE_NAMES.map(
|
|
25368
|
-
(mode) =>
|
|
26053
|
+
(mode) => path46.join(rootDir, ".cursor", "commands", `${mode}.md`)
|
|
25369
26054
|
),
|
|
25370
26055
|
[MODE_FILE_MANAGED_MARKER]
|
|
25371
26056
|
)
|
|
@@ -25378,7 +26063,7 @@ async function checkPlatformReadiness(rootDir, platform) {
|
|
|
25378
26063
|
};
|
|
25379
26064
|
}
|
|
25380
26065
|
if (platform === "codex") {
|
|
25381
|
-
const hasBlock2 = await fileHasManagedBlock(
|
|
26066
|
+
const hasBlock2 = await fileHasManagedBlock(path46.join(rootDir, "AGENTS.md"));
|
|
25382
26067
|
if (!hasBlock2) {
|
|
25383
26068
|
return {
|
|
25384
26069
|
present: false,
|
|
@@ -25395,9 +26080,9 @@ async function checkPlatformReadiness(rootDir, platform) {
|
|
|
25395
26080
|
readyDetail: "managed block present"
|
|
25396
26081
|
};
|
|
25397
26082
|
}
|
|
25398
|
-
const skillsDir =
|
|
26083
|
+
const skillsDir = path46.join(rootDir, ".agents", "skills");
|
|
25399
26084
|
const hasSkills = await allManagedSkills(
|
|
25400
|
-
MODE_NAMES.map((mode) =>
|
|
26085
|
+
MODE_NAMES.map((mode) => path46.join(skillsDir, mode, "SKILL.md")),
|
|
25401
26086
|
MANCODE_AGENT_SKILL_MARKERS
|
|
25402
26087
|
);
|
|
25403
26088
|
return {
|
|
@@ -25409,7 +26094,7 @@ async function checkPlatformReadiness(rootDir, platform) {
|
|
|
25409
26094
|
}
|
|
25410
26095
|
if (platform === "zcode") {
|
|
25411
26096
|
const hasBlock2 = await fileHasManagedBlock(
|
|
25412
|
-
|
|
26097
|
+
path46.join(rootDir, "AGENTS.md"),
|
|
25413
26098
|
ZCODE_MANCODE_START_MARKER,
|
|
25414
26099
|
ZCODE_MANCODE_END_MARKER
|
|
25415
26100
|
);
|
|
@@ -25429,9 +26114,9 @@ async function checkPlatformReadiness(rootDir, platform) {
|
|
|
25429
26114
|
readyDetail: "managed block present"
|
|
25430
26115
|
};
|
|
25431
26116
|
}
|
|
25432
|
-
const skillsDir =
|
|
26117
|
+
const skillsDir = path46.join(rootDir, ".agents", "skills");
|
|
25433
26118
|
const hasSkills = await allManagedSkills(
|
|
25434
|
-
MODE_NAMES.map((mode) =>
|
|
26119
|
+
MODE_NAMES.map((mode) => path46.join(skillsDir, mode, "SKILL.md")),
|
|
25435
26120
|
MANCODE_AGENT_SKILL_MARKERS
|
|
25436
26121
|
);
|
|
25437
26122
|
return {
|
|
@@ -25442,7 +26127,7 @@ async function checkPlatformReadiness(rootDir, platform) {
|
|
|
25442
26127
|
};
|
|
25443
26128
|
}
|
|
25444
26129
|
const hasBlock = await fileHasManagedBlock(
|
|
25445
|
-
|
|
26130
|
+
path46.join(rootDir, ".github", "copilot-instructions.md")
|
|
25446
26131
|
);
|
|
25447
26132
|
if (!hasBlock) {
|
|
25448
26133
|
return {
|
|
@@ -25453,9 +26138,9 @@ async function checkPlatformReadiness(rootDir, platform) {
|
|
|
25453
26138
|
};
|
|
25454
26139
|
}
|
|
25455
26140
|
if (!await isPlatformMinimal(rootDir, "copilot")) {
|
|
25456
|
-
const promptsDir =
|
|
26141
|
+
const promptsDir = path46.join(rootDir, ".github", "prompts");
|
|
25457
26142
|
const hasPrompts = await allManagedSkills(
|
|
25458
|
-
MODE_NAMES.map((mode) =>
|
|
26143
|
+
MODE_NAMES.map((mode) => path46.join(promptsDir, `${mode}.prompt.md`)),
|
|
25459
26144
|
[MODE_FILE_MANAGED_MARKER]
|
|
25460
26145
|
);
|
|
25461
26146
|
return {
|
|
@@ -25488,13 +26173,13 @@ async function allManagedSkills(paths, markers) {
|
|
|
25488
26173
|
async function claudeFullContentReady(rootDir) {
|
|
25489
26174
|
const skillChecks = MVP2_SKILLS.map(
|
|
25490
26175
|
(skill) => fileMatches(
|
|
25491
|
-
|
|
26176
|
+
path46.join(rootDir, ".claude", "skills", skill.name, "SKILL.md"),
|
|
25492
26177
|
(content) => isGeneratedClaudeSkill(content, skill.name)
|
|
25493
26178
|
)
|
|
25494
26179
|
);
|
|
25495
26180
|
const agentChecks = ALL_AGENTS.map(
|
|
25496
26181
|
(agent) => fileMatches(
|
|
25497
|
-
|
|
26182
|
+
path46.join(rootDir, ".claude", "agents", `${agent.name}.md`),
|
|
25498
26183
|
(content) => isGeneratedClaudeAgent(content, agent.name)
|
|
25499
26184
|
)
|
|
25500
26185
|
);
|
|
@@ -25522,13 +26207,13 @@ async function fileHasAnyMarker(filePath, needles) {
|
|
|
25522
26207
|
async function isPlatformMinimal(rootDir, platform) {
|
|
25523
26208
|
try {
|
|
25524
26209
|
const raw = await fs.readFile(
|
|
25525
|
-
|
|
26210
|
+
path46.join(rootDir, ".mancode", "config.json"),
|
|
25526
26211
|
"utf-8"
|
|
25527
26212
|
);
|
|
25528
26213
|
const config = JSON.parse(raw);
|
|
25529
|
-
if (!
|
|
26214
|
+
if (!isRecord7(config.platformOptions)) return false;
|
|
25530
26215
|
const options = config.platformOptions[platform];
|
|
25531
|
-
return
|
|
26216
|
+
return isRecord7(options) && options.minimal === true;
|
|
25532
26217
|
} catch {
|
|
25533
26218
|
return false;
|
|
25534
26219
|
}
|
|
@@ -25544,7 +26229,7 @@ async function fileHasManagedBlock(filePath, startMarker = DEFAULT_MANCODE_START
|
|
|
25544
26229
|
async function claudeHooksRegistered(rootDir) {
|
|
25545
26230
|
try {
|
|
25546
26231
|
const raw = await fs.readFile(
|
|
25547
|
-
|
|
26232
|
+
path46.join(rootDir, ".claude", "settings.json"),
|
|
25548
26233
|
"utf-8"
|
|
25549
26234
|
);
|
|
25550
26235
|
const settings = JSON.parse(raw);
|
|
@@ -25554,9 +26239,9 @@ async function claudeHooksRegistered(rootDir) {
|
|
|
25554
26239
|
}
|
|
25555
26240
|
}
|
|
25556
26241
|
function hooksRegistered(settings) {
|
|
25557
|
-
if (!
|
|
26242
|
+
if (!isRecord7(settings)) return false;
|
|
25558
26243
|
const hooks = settings.hooks;
|
|
25559
|
-
if (!
|
|
26244
|
+
if (!isRecord7(hooks)) return false;
|
|
25560
26245
|
return hasHookCommand(hooks.SessionStart, ".mancode/hooks/session-start.mjs") && hasHookCommand(
|
|
25561
26246
|
hooks.UserPromptSubmit,
|
|
25562
26247
|
".mancode/hooks/user-prompt-submit.mjs"
|
|
@@ -25565,9 +26250,9 @@ function hooksRegistered(settings) {
|
|
|
25565
26250
|
function hasHookCommand(value, needle) {
|
|
25566
26251
|
if (!Array.isArray(value)) return false;
|
|
25567
26252
|
return value.some((group) => {
|
|
25568
|
-
if (!
|
|
26253
|
+
if (!isRecord7(group) || !Array.isArray(group.hooks)) return false;
|
|
25569
26254
|
return group.hooks.some((hook) => {
|
|
25570
|
-
if (!
|
|
26255
|
+
if (!isRecord7(hook) || typeof hook.command !== "string") return false;
|
|
25571
26256
|
return hook.command.includes(needle);
|
|
25572
26257
|
});
|
|
25573
26258
|
});
|
|
@@ -25580,15 +26265,15 @@ async function pathExists4(p) {
|
|
|
25580
26265
|
return false;
|
|
25581
26266
|
}
|
|
25582
26267
|
}
|
|
25583
|
-
function
|
|
26268
|
+
function isRecord7(value) {
|
|
25584
26269
|
return typeof value === "object" && value !== null;
|
|
25585
26270
|
}
|
|
25586
26271
|
|
|
25587
26272
|
// src/system/detect-team.ts
|
|
25588
26273
|
import { execFile as execFile6 } from "child_process";
|
|
25589
26274
|
import { access as access2 } from "fs/promises";
|
|
25590
|
-
import
|
|
25591
|
-
import
|
|
26275
|
+
import path47 from "path";
|
|
26276
|
+
import process3 from "process";
|
|
25592
26277
|
import { promisify as promisify6 } from "util";
|
|
25593
26278
|
var execFileAsync = promisify6(execFile6);
|
|
25594
26279
|
var NO_TEAM = {
|
|
@@ -25598,7 +26283,7 @@ var NO_TEAM = {
|
|
|
25598
26283
|
hasRemote: false
|
|
25599
26284
|
};
|
|
25600
26285
|
var GIT_ENV = {
|
|
25601
|
-
...
|
|
26286
|
+
...process3.env,
|
|
25602
26287
|
GIT_PAGER: "cat",
|
|
25603
26288
|
PAGER: "cat",
|
|
25604
26289
|
GIT_TERMINAL_PROMPT: "0"
|
|
@@ -25697,7 +26382,7 @@ async function anyPathExists(projectRoot, candidates) {
|
|
|
25697
26382
|
const results = await Promise.all(
|
|
25698
26383
|
candidates.map(async (candidate) => {
|
|
25699
26384
|
try {
|
|
25700
|
-
await access2(
|
|
26385
|
+
await access2(path47.join(projectRoot, candidate));
|
|
25701
26386
|
return true;
|
|
25702
26387
|
} catch {
|
|
25703
26388
|
return false;
|
|
@@ -25720,10 +26405,10 @@ function emptySignals(isGitRepository) {
|
|
|
25720
26405
|
|
|
25721
26406
|
// src/system/detect.ts
|
|
25722
26407
|
import { execFile as execFile7 } from "child_process";
|
|
25723
|
-
import
|
|
26408
|
+
import process4 from "process";
|
|
25724
26409
|
import { promisify as promisify7 } from "util";
|
|
25725
26410
|
var execFileAsync2 = promisify7(execFile7);
|
|
25726
|
-
async function detectSystemDeps(env =
|
|
26411
|
+
async function detectSystemDeps(env = process4.env) {
|
|
25727
26412
|
try {
|
|
25728
26413
|
await execFileAsync2("git", ["--version"], {
|
|
25729
26414
|
env,
|
|
@@ -25738,18 +26423,18 @@ async function detectSystemDeps(env = process3.env) {
|
|
|
25738
26423
|
// src/system/init-onboarding.ts
|
|
25739
26424
|
import { execFileSync } from "child_process";
|
|
25740
26425
|
import { promises as fs2 } from "fs";
|
|
25741
|
-
import
|
|
25742
|
-
import
|
|
26426
|
+
import path48 from "path";
|
|
26427
|
+
import process5 from "process";
|
|
25743
26428
|
import { stdin, stdout } from "process";
|
|
25744
26429
|
import { createInterface } from "readline/promises";
|
|
25745
26430
|
var ALL_PLATFORMS = Object.keys(PLATFORM_INSTALLERS);
|
|
25746
26431
|
var cachedNativeSystemLocale;
|
|
25747
|
-
function detectInitLocale(override, environment =
|
|
26432
|
+
function detectInitLocale(override, environment = process5.env, systemLocale = Intl.DateTimeFormat().resolvedOptions().locale, nativeLocale) {
|
|
25748
26433
|
if (override) return parseLocale(override);
|
|
25749
26434
|
const resolvedNativeLocale = nativeLocale === void 0 ? getNativeSystemLocale() : nativeLocale;
|
|
25750
26435
|
return parseLocale(resolvedNativeLocale) ?? detectEnvironmentLocale(environment) ?? parseLocale(systemLocale) ?? "en";
|
|
25751
26436
|
}
|
|
25752
|
-
function detectNativeSystemLocale(platform =
|
|
26437
|
+
function detectNativeSystemLocale(platform = process5.platform, runCommand = runLocaleCommand) {
|
|
25753
26438
|
if (platform === "darwin") {
|
|
25754
26439
|
const languages = runCommand("defaults", ["read", "-g", "AppleLanguages"]);
|
|
25755
26440
|
const primaryLanguage = parsePrimaryAppleLanguage(languages);
|
|
@@ -25833,7 +26518,7 @@ function parsePlatformSelection(value) {
|
|
|
25833
26518
|
}
|
|
25834
26519
|
return [...new Set(choices)];
|
|
25835
26520
|
}
|
|
25836
|
-
async function detectPlatformHints(rootDir, environment =
|
|
26521
|
+
async function detectPlatformHints(rootDir, environment = process5.env) {
|
|
25837
26522
|
const hints = /* @__PURE__ */ new Set();
|
|
25838
26523
|
if (environment.CLAUDECODE || environment.CLAUDE_CODE)
|
|
25839
26524
|
hints.add("claude-code");
|
|
@@ -25841,17 +26526,17 @@ async function detectPlatformHints(rootDir, environment = process4.env) {
|
|
|
25841
26526
|
if (environment.CURSOR_TRACE_ID) hints.add("cursor");
|
|
25842
26527
|
if (environment.COPILOT_AGENT || environment.GITHUB_COPILOT)
|
|
25843
26528
|
hints.add("copilot");
|
|
25844
|
-
const
|
|
26529
|
+
const exists2 = async (relative) => {
|
|
25845
26530
|
try {
|
|
25846
|
-
await fs2.access(
|
|
26531
|
+
await fs2.access(path48.join(rootDir, relative));
|
|
25847
26532
|
return true;
|
|
25848
26533
|
} catch {
|
|
25849
26534
|
return false;
|
|
25850
26535
|
}
|
|
25851
26536
|
};
|
|
25852
|
-
if (await
|
|
25853
|
-
if (await
|
|
25854
|
-
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");
|
|
25855
26540
|
return ALL_PLATFORMS.filter((platform) => hints.has(platform));
|
|
25856
26541
|
}
|
|
25857
26542
|
function createTerminalPrompter() {
|
|
@@ -25919,10 +26604,10 @@ function createTerminalPrompter() {
|
|
|
25919
26604
|
|
|
25920
26605
|
// src/system/scan-aesthetics.ts
|
|
25921
26606
|
import { promises as fs3 } from "fs";
|
|
25922
|
-
import
|
|
26607
|
+
import path49 from "path";
|
|
25923
26608
|
var MAX_COMPONENT_SCAN_DEPTH = 12;
|
|
25924
26609
|
var MAX_COMPONENT_FILES = 2e3;
|
|
25925
|
-
async function scanAesthetics(projectRoot, uiLibrary = null) {
|
|
26610
|
+
async function scanAesthetics(projectRoot, uiLibrary = null, scopeRoot = ".") {
|
|
25926
26611
|
const sourceFiles = [];
|
|
25927
26612
|
const configResult = await findTailwindConfig(projectRoot);
|
|
25928
26613
|
let colors = {};
|
|
@@ -25955,12 +26640,13 @@ async function scanAesthetics(projectRoot, uiLibrary = null) {
|
|
|
25955
26640
|
} else if (await hasTailwindDep(projectRoot) || uiLibrary) {
|
|
25956
26641
|
matchLevel = "low";
|
|
25957
26642
|
}
|
|
25958
|
-
if (uiLibrary && await pathExists5(
|
|
26643
|
+
if (uiLibrary && await pathExists5(path49.join(projectRoot, "package.json"))) {
|
|
25959
26644
|
sourceFiles.push("package.json");
|
|
25960
26645
|
}
|
|
25961
26646
|
sourceFiles.push(...cssScan.sourceFiles);
|
|
25962
26647
|
return {
|
|
25963
26648
|
version: "1.0.0",
|
|
26649
|
+
scopeRoot,
|
|
25964
26650
|
lastScanned: (/* @__PURE__ */ new Date()).toISOString(),
|
|
25965
26651
|
colors,
|
|
25966
26652
|
fonts,
|
|
@@ -25980,7 +26666,7 @@ async function findTailwindConfig(projectRoot) {
|
|
|
25980
26666
|
"tailwind.config.mjs"
|
|
25981
26667
|
];
|
|
25982
26668
|
for (const name of candidates) {
|
|
25983
|
-
const absPath =
|
|
26669
|
+
const absPath = path49.join(projectRoot, name);
|
|
25984
26670
|
if (await pathExists5(absPath)) {
|
|
25985
26671
|
return { absPath, relPath: name };
|
|
25986
26672
|
}
|
|
@@ -26207,7 +26893,7 @@ async function scanComponents(projectRoot) {
|
|
|
26207
26893
|
const names = /* @__PURE__ */ new Set();
|
|
26208
26894
|
let visitedFiles = 0;
|
|
26209
26895
|
for (const relRoot of roots) {
|
|
26210
|
-
const absRoot =
|
|
26896
|
+
const absRoot = path49.join(projectRoot, relRoot);
|
|
26211
26897
|
if (!await pathExists5(absRoot)) continue;
|
|
26212
26898
|
visitedFiles = await collectComponentNames(absRoot, names, 0, visitedFiles);
|
|
26213
26899
|
if (visitedFiles >= MAX_COMPONENT_FILES) break;
|
|
@@ -26227,7 +26913,7 @@ async function collectComponentNames(dir, names, depth, visitedFiles) {
|
|
|
26227
26913
|
}
|
|
26228
26914
|
for (const entry of entries) {
|
|
26229
26915
|
if (fileCount >= MAX_COMPONENT_FILES) return fileCount;
|
|
26230
|
-
const abs =
|
|
26916
|
+
const abs = path49.join(dir, entry);
|
|
26231
26917
|
let info;
|
|
26232
26918
|
try {
|
|
26233
26919
|
info = await fs3.lstat(abs);
|
|
@@ -26248,7 +26934,7 @@ async function collectComponentNames(dir, names, depth, visitedFiles) {
|
|
|
26248
26934
|
""
|
|
26249
26935
|
);
|
|
26250
26936
|
if (base === "index") {
|
|
26251
|
-
base =
|
|
26937
|
+
base = path49.basename(dir);
|
|
26252
26938
|
}
|
|
26253
26939
|
if (base.startsWith(".")) continue;
|
|
26254
26940
|
const componentName = toPascalCase(base);
|
|
@@ -26270,7 +26956,7 @@ async function scanCssVariables(projectRoot) {
|
|
|
26270
26956
|
const variables = {};
|
|
26271
26957
|
const sourceFiles = [];
|
|
26272
26958
|
for (const relPath of candidates) {
|
|
26273
|
-
const absPath =
|
|
26959
|
+
const absPath = path49.join(projectRoot, relPath);
|
|
26274
26960
|
if (!await pathExists5(absPath)) continue;
|
|
26275
26961
|
const content = await fs3.readFile(absPath, "utf-8");
|
|
26276
26962
|
const found = extractCssVariables(content);
|
|
@@ -26316,7 +27002,7 @@ function toPascalCase(value) {
|
|
|
26316
27002
|
async function hasTailwindDep(projectRoot) {
|
|
26317
27003
|
try {
|
|
26318
27004
|
const raw = await fs3.readFile(
|
|
26319
|
-
|
|
27005
|
+
path49.join(projectRoot, "package.json"),
|
|
26320
27006
|
"utf-8"
|
|
26321
27007
|
);
|
|
26322
27008
|
const pkg = JSON.parse(raw);
|
|
@@ -26341,15 +27027,15 @@ async function pathExists5(p) {
|
|
|
26341
27027
|
|
|
26342
27028
|
// src/context/greenfield-init.ts
|
|
26343
27029
|
import {
|
|
26344
|
-
lstat as
|
|
26345
|
-
mkdir as
|
|
26346
|
-
readFile as
|
|
27030
|
+
lstat as lstat20,
|
|
27031
|
+
mkdir as mkdir34,
|
|
27032
|
+
readFile as readFile38,
|
|
26347
27033
|
rename as rename10,
|
|
26348
|
-
rm as
|
|
26349
|
-
writeFile as
|
|
27034
|
+
rm as rm18,
|
|
27035
|
+
writeFile as writeFile39
|
|
26350
27036
|
} from "fs/promises";
|
|
26351
|
-
import
|
|
26352
|
-
var JOURNAL_RELATIVE_DIRECTORY =
|
|
27037
|
+
import path50 from "path";
|
|
27038
|
+
var JOURNAL_RELATIVE_DIRECTORY = path50.join(
|
|
26353
27039
|
"local",
|
|
26354
27040
|
"runtime",
|
|
26355
27041
|
"initialization"
|
|
@@ -26372,7 +27058,7 @@ async function stageGreenfieldInitialization(input) {
|
|
|
26372
27058
|
normalized.operationId
|
|
26373
27059
|
);
|
|
26374
27060
|
try {
|
|
26375
|
-
await
|
|
27061
|
+
await mkdir34(stagingRoot);
|
|
26376
27062
|
} catch (error) {
|
|
26377
27063
|
if (isAlreadyExists22(error)) {
|
|
26378
27064
|
throw new Error("MANCODE_GREENFIELD_STAGING_EXISTS");
|
|
@@ -26398,7 +27084,7 @@ async function stageGreenfieldInitialization(input) {
|
|
|
26398
27084
|
operationId: normalized.operationId,
|
|
26399
27085
|
workspaceId: normalized.workspaceId,
|
|
26400
27086
|
state: "staged",
|
|
26401
|
-
stagingDirectoryName:
|
|
27087
|
+
stagingDirectoryName: path50.basename(stagingRoot),
|
|
26402
27088
|
targetDirectoryName: ".mancode",
|
|
26403
27089
|
manifestDigest: digestCanonicalJson(manifest),
|
|
26404
27090
|
configDigest: digestCanonicalJson(config),
|
|
@@ -26429,7 +27115,7 @@ async function stageGreenfieldInitialization(input) {
|
|
|
26429
27115
|
return journal;
|
|
26430
27116
|
}
|
|
26431
27117
|
async function publishGreenfieldInitialization(input) {
|
|
26432
|
-
const root =
|
|
27118
|
+
const root = path50.resolve(input.projectRoot);
|
|
26433
27119
|
assertUlid(input.operationId, "greenfield operationId");
|
|
26434
27120
|
const stagingRoot = greenfieldStagingPath(root, input.operationId);
|
|
26435
27121
|
const targetRoot = greenfieldTargetPath(root);
|
|
@@ -26464,10 +27150,10 @@ async function initializeGreenfield(input, publication) {
|
|
|
26464
27150
|
}
|
|
26465
27151
|
function greenfieldStagingPath(projectRoot, operationId) {
|
|
26466
27152
|
assertUlid(operationId, "greenfield operationId");
|
|
26467
|
-
return
|
|
27153
|
+
return path50.join(path50.resolve(projectRoot), `.mancode.init-${operationId}`);
|
|
26468
27154
|
}
|
|
26469
27155
|
function greenfieldTargetPath(projectRoot) {
|
|
26470
|
-
return
|
|
27156
|
+
return path50.join(path50.resolve(projectRoot), ".mancode");
|
|
26471
27157
|
}
|
|
26472
27158
|
function parseGreenfieldInitializationJournal(value) {
|
|
26473
27159
|
assertRecord(value, "greenfield initialization journal");
|
|
@@ -26603,7 +27289,7 @@ async function finishPublishedInitialization(input, stagedJournal) {
|
|
|
26603
27289
|
activatedAt: (input.now ?? /* @__PURE__ */ new Date()).toISOString()
|
|
26604
27290
|
};
|
|
26605
27291
|
assertSchemaManifestTransition(manifest, activeManifest);
|
|
26606
|
-
await writeJson(
|
|
27292
|
+
await writeJson(path50.join(targetRoot, "schema.json"), activeManifest);
|
|
26607
27293
|
throwIfOperationCrashInjected(
|
|
26608
27294
|
"greenfield_initialize",
|
|
26609
27295
|
"activate-v3-manifest"
|
|
@@ -26619,46 +27305,46 @@ async function finishPublishedInitialization(input, stagedJournal) {
|
|
|
26619
27305
|
}
|
|
26620
27306
|
async function writeGreenfieldLayout(stagingRoot, manifest, config, policy, projectFacts, journal) {
|
|
26621
27307
|
await Promise.all([
|
|
26622
|
-
|
|
26623
|
-
|
|
27308
|
+
mkdir34(path50.join(stagingRoot, "shared", "context"), { recursive: true }),
|
|
27309
|
+
mkdir34(path50.join(stagingRoot, "shared", "memory", "decisions"), {
|
|
26624
27310
|
recursive: true
|
|
26625
27311
|
}),
|
|
26626
|
-
|
|
27312
|
+
mkdir34(path50.join(stagingRoot, "shared", "team", "actors"), {
|
|
26627
27313
|
recursive: true
|
|
26628
27314
|
}),
|
|
26629
|
-
|
|
27315
|
+
mkdir34(path50.join(stagingRoot, "shared", "team", "handoffs"), {
|
|
26630
27316
|
recursive: true
|
|
26631
27317
|
}),
|
|
26632
|
-
|
|
27318
|
+
mkdir34(path50.join(stagingRoot, "shared", "team", "events"), {
|
|
26633
27319
|
recursive: true
|
|
26634
27320
|
}),
|
|
26635
|
-
|
|
27321
|
+
mkdir34(path50.join(stagingRoot, "shared", "team", "transport"), {
|
|
26636
27322
|
recursive: true
|
|
26637
27323
|
}),
|
|
26638
|
-
|
|
26639
|
-
|
|
27324
|
+
mkdir34(path50.join(stagingRoot, "local", "sessions"), { recursive: true }),
|
|
27325
|
+
mkdir34(path50.join(stagingRoot, JOURNAL_RELATIVE_DIRECTORY), {
|
|
26640
27326
|
recursive: true
|
|
26641
27327
|
}),
|
|
26642
|
-
|
|
26643
|
-
|
|
26644
|
-
|
|
26645
|
-
|
|
26646
|
-
|
|
26647
|
-
|
|
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), {
|
|
26648
27334
|
recursive: true
|
|
26649
27335
|
})
|
|
26650
27336
|
]);
|
|
26651
27337
|
await Promise.all([
|
|
26652
|
-
writeJson(
|
|
26653
|
-
writeJson(
|
|
26654
|
-
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),
|
|
26655
27341
|
writeJson(
|
|
26656
|
-
|
|
27342
|
+
path50.join(stagingRoot, "shared", "context", "project.json"),
|
|
26657
27343
|
projectFacts
|
|
26658
27344
|
),
|
|
26659
27345
|
writeJson(journalPath2(stagingRoot, journal.operationId), journal),
|
|
26660
|
-
|
|
26661
|
-
|
|
27346
|
+
writeFile39(
|
|
27347
|
+
path50.join(stagingRoot, ".gitignore"),
|
|
26662
27348
|
`${V3_IGNORE.join("\n")}
|
|
26663
27349
|
`,
|
|
26664
27350
|
{ encoding: "utf8", flag: "wx" }
|
|
@@ -26667,14 +27353,14 @@ async function writeGreenfieldLayout(stagingRoot, manifest, config, policy, proj
|
|
|
26667
27353
|
}
|
|
26668
27354
|
async function readGreenfieldJournal(root, operationId) {
|
|
26669
27355
|
try {
|
|
26670
|
-
const raw = await
|
|
27356
|
+
const raw = await readFile38(journalPath2(root, operationId), "utf8");
|
|
26671
27357
|
const journal = parseGreenfieldInitializationJournal(JSON.parse(raw));
|
|
26672
27358
|
if (journal.operationId !== operationId) {
|
|
26673
27359
|
throw new Error("MANCODE_GREENFIELD_JOURNAL_CORRUPT");
|
|
26674
27360
|
}
|
|
26675
27361
|
return journal;
|
|
26676
27362
|
} catch (error) {
|
|
26677
|
-
if (error instanceof SyntaxError ||
|
|
27363
|
+
if (error instanceof SyntaxError || isNotFound28(error)) {
|
|
26678
27364
|
throw new Error("MANCODE_GREENFIELD_JOURNAL_CORRUPT");
|
|
26679
27365
|
}
|
|
26680
27366
|
throw error;
|
|
@@ -26683,10 +27369,10 @@ async function readGreenfieldJournal(root, operationId) {
|
|
|
26683
27369
|
async function readManifest(root) {
|
|
26684
27370
|
try {
|
|
26685
27371
|
return parseSchemaManifest(
|
|
26686
|
-
JSON.parse(await
|
|
27372
|
+
JSON.parse(await readFile38(path50.join(root, "schema.json"), "utf8"))
|
|
26687
27373
|
);
|
|
26688
27374
|
} catch (error) {
|
|
26689
|
-
if (error instanceof SyntaxError ||
|
|
27375
|
+
if (error instanceof SyntaxError || isNotFound28(error)) {
|
|
26690
27376
|
throw new Error("MANCODE_GREENFIELD_REPAIR_REQUIRED");
|
|
26691
27377
|
}
|
|
26692
27378
|
throw error;
|
|
@@ -26721,7 +27407,7 @@ async function readConfig(root) {
|
|
|
26721
27407
|
try {
|
|
26722
27408
|
config = parseProjectConfig(
|
|
26723
27409
|
JSON.parse(
|
|
26724
|
-
await
|
|
27410
|
+
await readFile38(path50.join(root, "shared", "config.json"), "utf8")
|
|
26725
27411
|
)
|
|
26726
27412
|
);
|
|
26727
27413
|
} catch (error) {
|
|
@@ -26737,8 +27423,8 @@ async function readPolicy(root) {
|
|
|
26737
27423
|
try {
|
|
26738
27424
|
policy = parseTeamPolicy(
|
|
26739
27425
|
JSON.parse(
|
|
26740
|
-
await
|
|
26741
|
-
|
|
27426
|
+
await readFile38(
|
|
27427
|
+
path50.join(root, "shared", "team", "policy.json"),
|
|
26742
27428
|
"utf8"
|
|
26743
27429
|
)
|
|
26744
27430
|
)
|
|
@@ -26755,14 +27441,14 @@ async function readProjectFactsAt(root) {
|
|
|
26755
27441
|
try {
|
|
26756
27442
|
return parseProjectFacts(
|
|
26757
27443
|
JSON.parse(
|
|
26758
|
-
await
|
|
26759
|
-
|
|
27444
|
+
await readFile38(
|
|
27445
|
+
path50.join(root, "shared", "context", "project.json"),
|
|
26760
27446
|
"utf8"
|
|
26761
27447
|
)
|
|
26762
27448
|
)
|
|
26763
27449
|
);
|
|
26764
27450
|
} catch (error) {
|
|
26765
|
-
if (error instanceof SyntaxError ||
|
|
27451
|
+
if (error instanceof SyntaxError || isNotFound28(error)) {
|
|
26766
27452
|
throw new Error("MANCODE_GREENFIELD_REPAIR_REQUIRED");
|
|
26767
27453
|
}
|
|
26768
27454
|
throw error;
|
|
@@ -26795,7 +27481,7 @@ function normalizeInput(input) {
|
|
|
26795
27481
|
parseSchemaManifest(manifest);
|
|
26796
27482
|
return {
|
|
26797
27483
|
...input,
|
|
26798
|
-
projectRoot:
|
|
27484
|
+
projectRoot: path50.resolve(input.projectRoot),
|
|
26799
27485
|
projectConfig: config,
|
|
26800
27486
|
teamPolicy: policy,
|
|
26801
27487
|
projectFacts: input.projectFacts === void 0 ? void 0 : parseProjectFacts(input.projectFacts)
|
|
@@ -26893,16 +27579,16 @@ function initializationProjectFacts(input, now) {
|
|
|
26893
27579
|
}
|
|
26894
27580
|
function journalPath2(root, operationId) {
|
|
26895
27581
|
assertUlid(operationId, "greenfield operationId");
|
|
26896
|
-
return
|
|
27582
|
+
return path50.join(root, JOURNAL_RELATIVE_DIRECTORY, `${operationId}.json`);
|
|
26897
27583
|
}
|
|
26898
27584
|
async function writeJson(target, value) {
|
|
26899
|
-
const directory =
|
|
26900
|
-
await
|
|
26901
|
-
const temporary =
|
|
27585
|
+
const directory = path50.dirname(target);
|
|
27586
|
+
await mkdir34(directory, { recursive: true });
|
|
27587
|
+
const temporary = path50.join(
|
|
26902
27588
|
directory,
|
|
26903
|
-
`.${
|
|
27589
|
+
`.${path50.basename(target)}.${process.pid}.${Date.now()}.tmp`
|
|
26904
27590
|
);
|
|
26905
|
-
await
|
|
27591
|
+
await writeFile39(temporary, `${JSON.stringify(value, null, 2)}
|
|
26906
27592
|
`, {
|
|
26907
27593
|
encoding: "utf8",
|
|
26908
27594
|
flag: "wx"
|
|
@@ -26926,13 +27612,13 @@ function isState(value) {
|
|
|
26926
27612
|
}
|
|
26927
27613
|
async function lstatOrNull4(target) {
|
|
26928
27614
|
try {
|
|
26929
|
-
return await
|
|
27615
|
+
return await lstat20(target);
|
|
26930
27616
|
} catch (error) {
|
|
26931
|
-
if (
|
|
27617
|
+
if (isNotFound28(error)) return null;
|
|
26932
27618
|
throw error;
|
|
26933
27619
|
}
|
|
26934
27620
|
}
|
|
26935
|
-
function
|
|
27621
|
+
function isNotFound28(error) {
|
|
26936
27622
|
return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
|
|
26937
27623
|
}
|
|
26938
27624
|
function isAlreadyExists22(error) {
|
|
@@ -27003,7 +27689,7 @@ async function initializeV3Project(input) {
|
|
|
27003
27689
|
}
|
|
27004
27690
|
|
|
27005
27691
|
// src/commands/init.ts
|
|
27006
|
-
var
|
|
27692
|
+
var EXIT_OK2 = 0;
|
|
27007
27693
|
var EXIT_ALREADY_INITIALIZED = 1;
|
|
27008
27694
|
var EXIT_NOT_A_PROJECT_DIR = 2;
|
|
27009
27695
|
var EXIT_USER_CANCEL = 3;
|
|
@@ -27014,15 +27700,15 @@ function resolveInitAuthority(options) {
|
|
|
27014
27700
|
if (options.v3 || options.fromCli) return "v3";
|
|
27015
27701
|
return "legacy";
|
|
27016
27702
|
}
|
|
27017
|
-
async function init(rootDir =
|
|
27703
|
+
async function init(rootDir = process6.cwd(), options = {}) {
|
|
27018
27704
|
if (options.v3 && options.legacy) {
|
|
27019
27705
|
console.error("\u2717 --v3 and --legacy cannot be used together.");
|
|
27020
27706
|
return EXIT_INIT_FAILED;
|
|
27021
27707
|
}
|
|
27022
27708
|
const authority = resolveInitAuthority(options);
|
|
27023
|
-
const mancodeDir =
|
|
27024
|
-
const stateFile =
|
|
27025
|
-
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");
|
|
27026
27712
|
const wasInitialized = await pathExists6(stateFile);
|
|
27027
27713
|
let mutationSnapshots = [];
|
|
27028
27714
|
let directorySnapshots = [];
|
|
@@ -27090,7 +27776,7 @@ async function init(rootDir = process5.cwd(), options = {}) {
|
|
|
27090
27776
|
}
|
|
27091
27777
|
return initializeV3(rootDir, options);
|
|
27092
27778
|
}
|
|
27093
|
-
const isGitRepo = await pathExists6(
|
|
27779
|
+
const isGitRepo = await pathExists6(path51.join(rootDir, ".git"));
|
|
27094
27780
|
const hasManifest = await hasProjectManifest(rootDir);
|
|
27095
27781
|
let isGenericProject = false;
|
|
27096
27782
|
if (!isGitRepo && !hasManifest) {
|
|
@@ -27208,8 +27894,8 @@ async function init(rootDir = process5.cwd(), options = {}) {
|
|
|
27208
27894
|
const managedFiles = getInitManagedFilePaths(rootDir, selectedPlatforms);
|
|
27209
27895
|
mutationSnapshots = await snapshotFiles(managedFiles);
|
|
27210
27896
|
directorySnapshots = await snapshotDirectories(managedFiles, [
|
|
27211
|
-
|
|
27212
|
-
|
|
27897
|
+
path51.join(mancodeDir, "workflows"),
|
|
27898
|
+
path51.join(mancodeDir, "preseason-reports")
|
|
27213
27899
|
]);
|
|
27214
27900
|
const team = await detectTeamStatus(rootDir);
|
|
27215
27901
|
const platformMinimal = Object.fromEntries(
|
|
@@ -27270,7 +27956,7 @@ async function init(rootDir = process5.cwd(), options = {}) {
|
|
|
27270
27956
|
`;
|
|
27271
27957
|
await fs4.writeFile(stateFile, stateContent, "utf-8");
|
|
27272
27958
|
await fs4.writeFile(
|
|
27273
|
-
|
|
27959
|
+
path51.join(mancodeDir, "project-profile.json"),
|
|
27274
27960
|
`${JSON.stringify(profile, null, 2)}
|
|
27275
27961
|
`,
|
|
27276
27962
|
"utf-8"
|
|
@@ -27307,7 +27993,7 @@ async function init(rootDir = process5.cwd(), options = {}) {
|
|
|
27307
27993
|
)
|
|
27308
27994
|
);
|
|
27309
27995
|
const tokens = await scanAesthetics(rootDir, uiLibrary);
|
|
27310
|
-
const tokensPath =
|
|
27996
|
+
const tokensPath = path51.join(
|
|
27311
27997
|
mancodeDir,
|
|
27312
27998
|
"aesthetics",
|
|
27313
27999
|
"style-tokens.json"
|
|
@@ -27442,7 +28128,7 @@ async function init(rootDir = process5.cwd(), options = {}) {
|
|
|
27442
28128
|
)
|
|
27443
28129
|
);
|
|
27444
28130
|
}
|
|
27445
|
-
return
|
|
28131
|
+
return EXIT_OK2;
|
|
27446
28132
|
} catch (err) {
|
|
27447
28133
|
await restoreFiles(mutationSnapshots);
|
|
27448
28134
|
await removeNewEmptyDirectories(directorySnapshots);
|
|
@@ -27471,7 +28157,7 @@ async function initializeV3(rootDir, options) {
|
|
|
27471
28157
|
);
|
|
27472
28158
|
return EXIT_INIT_FAILED;
|
|
27473
28159
|
}
|
|
27474
|
-
const schemaPath =
|
|
28160
|
+
const schemaPath = path51.join(rootDir, ".mancode", "schema.json");
|
|
27475
28161
|
let existingV3 = false;
|
|
27476
28162
|
let registeredAdapters = /* @__PURE__ */ new Set();
|
|
27477
28163
|
if (await pathExists6(schemaPath)) {
|
|
@@ -27560,7 +28246,7 @@ async function initializeV3(rootDir, options) {
|
|
|
27560
28246
|
} else {
|
|
27561
28247
|
console.log(` mancode bootstrap: ${selectedPlatforms.join(", ")}`);
|
|
27562
28248
|
}
|
|
27563
|
-
return
|
|
28249
|
+
return EXIT_OK2;
|
|
27564
28250
|
} catch (error) {
|
|
27565
28251
|
printV3InitError(error);
|
|
27566
28252
|
return EXIT_INIT_FAILED;
|
|
@@ -27574,7 +28260,7 @@ function printV3InitError(error) {
|
|
|
27574
28260
|
}
|
|
27575
28261
|
}
|
|
27576
28262
|
async function updateConfigOptions(mancodeDir, patch, preserveInstalledPlatforms) {
|
|
27577
|
-
const configPath =
|
|
28263
|
+
const configPath = path51.join(mancodeDir, "config.json");
|
|
27578
28264
|
let config = {};
|
|
27579
28265
|
try {
|
|
27580
28266
|
config = JSON.parse(await fs4.readFile(configPath, "utf-8"));
|
|
@@ -27583,7 +28269,7 @@ async function updateConfigOptions(mancodeDir, patch, preserveInstalledPlatforms
|
|
|
27583
28269
|
const existingPlatforms = Array.isArray(config.platforms) ? config.platforms.filter(
|
|
27584
28270
|
(platform) => typeof platform === "string"
|
|
27585
28271
|
) : [];
|
|
27586
|
-
const existingPlatformOptions =
|
|
28272
|
+
const existingPlatformOptions = isRecord8(config.platformOptions) ? config.platformOptions : {};
|
|
27587
28273
|
const definedPatch = Object.fromEntries(
|
|
27588
28274
|
Object.entries(patch).filter(([, value]) => value !== void 0)
|
|
27589
28275
|
);
|
|
@@ -27607,7 +28293,7 @@ async function updateConfigOptions(mancodeDir, patch, preserveInstalledPlatforms
|
|
|
27607
28293
|
async function readExistingInitPreferences(mancodeDir) {
|
|
27608
28294
|
try {
|
|
27609
28295
|
const config = JSON.parse(
|
|
27610
|
-
await fs4.readFile(
|
|
28296
|
+
await fs4.readFile(path51.join(mancodeDir, "config.json"), "utf-8")
|
|
27611
28297
|
);
|
|
27612
28298
|
const preferences = {
|
|
27613
28299
|
platforms: Array.isArray(config.platforms) ? config.platforms.filter(
|
|
@@ -27621,10 +28307,10 @@ async function readExistingInitPreferences(mancodeDir) {
|
|
|
27621
28307
|
if (config.teamMode === "auto" || config.teamMode === "on" || config.teamMode === "off") {
|
|
27622
28308
|
preferences.teamMode = config.teamMode;
|
|
27623
28309
|
}
|
|
27624
|
-
if (
|
|
28310
|
+
if (isRecord8(config.platformOptions)) {
|
|
27625
28311
|
for (const platform of preferences.platforms) {
|
|
27626
28312
|
const platformOptions = config.platformOptions[platform];
|
|
27627
|
-
if (
|
|
28313
|
+
if (isRecord8(platformOptions) && platformOptions.minimal === true) {
|
|
27628
28314
|
preferences.minimalByPlatform[platform] = true;
|
|
27629
28315
|
}
|
|
27630
28316
|
}
|
|
@@ -27673,13 +28359,13 @@ async function selectInitPlatforms(input) {
|
|
|
27673
28359
|
}
|
|
27674
28360
|
async function hasProjectManifest(rootDir) {
|
|
27675
28361
|
for (const name of PROJECT_MANIFESTS) {
|
|
27676
|
-
if (await pathExists6(
|
|
28362
|
+
if (await pathExists6(path51.join(rootDir, name))) return true;
|
|
27677
28363
|
}
|
|
27678
28364
|
return false;
|
|
27679
28365
|
}
|
|
27680
28366
|
async function canInitializeGenericProject(rootDir) {
|
|
27681
|
-
const resolved =
|
|
27682
|
-
if (resolved ===
|
|
28367
|
+
const resolved = path51.resolve(rootDir);
|
|
28368
|
+
if (resolved === path51.parse(resolved).root || resolved === path51.resolve(os.homedir())) {
|
|
27683
28369
|
return { ok: false, reason: "unsafe" };
|
|
27684
28370
|
}
|
|
27685
28371
|
try {
|
|
@@ -27693,11 +28379,11 @@ async function canInitializeGenericProject(rootDir) {
|
|
|
27693
28379
|
}
|
|
27694
28380
|
}
|
|
27695
28381
|
async function validateV3CliProjectBoundary(rootDir, options, locale, legacyInitialized) {
|
|
27696
|
-
const isGitRepo = await pathExists6(
|
|
28382
|
+
const isGitRepo = await pathExists6(path51.join(rootDir, ".git"));
|
|
27697
28383
|
const hasManifest = await hasProjectManifest(rootDir);
|
|
27698
28384
|
if (isGitRepo || hasManifest) return null;
|
|
27699
28385
|
const v3Initialized = await pathExists6(
|
|
27700
|
-
|
|
28386
|
+
path51.join(rootDir, ".mancode", "schema.json")
|
|
27701
28387
|
);
|
|
27702
28388
|
const legacyAuthorityPresent = legacyInitialized || (await scanLegacyAuthority(rootDir)).authorityPresent;
|
|
27703
28389
|
const genericSafety = await canInitializeGenericProject(rootDir);
|
|
@@ -27826,7 +28512,7 @@ function getInitManagedFilePaths(rootDir, platforms) {
|
|
|
27826
28512
|
files.push(`.github/prompts/${mode}.prompt.md`);
|
|
27827
28513
|
}
|
|
27828
28514
|
}
|
|
27829
|
-
return [...new Set(files.map((file) =>
|
|
28515
|
+
return [...new Set(files.map((file) => path51.join(rootDir, file)))];
|
|
27830
28516
|
}
|
|
27831
28517
|
async function snapshotFiles(filePaths) {
|
|
27832
28518
|
return Promise.all(
|
|
@@ -27845,10 +28531,10 @@ async function snapshotFiles(filePaths) {
|
|
|
27845
28531
|
async function snapshotDirectories(filePaths, additionalDirectories = []) {
|
|
27846
28532
|
const directories = new Set(additionalDirectories);
|
|
27847
28533
|
for (const filePath of filePaths) {
|
|
27848
|
-
let current =
|
|
27849
|
-
while (current !==
|
|
28534
|
+
let current = path51.dirname(filePath);
|
|
28535
|
+
while (current !== path51.dirname(current)) {
|
|
27850
28536
|
directories.add(current);
|
|
27851
|
-
current =
|
|
28537
|
+
current = path51.dirname(current);
|
|
27852
28538
|
}
|
|
27853
28539
|
}
|
|
27854
28540
|
return Promise.all(
|
|
@@ -27864,7 +28550,7 @@ async function restoreFiles(snapshots) {
|
|
|
27864
28550
|
await fs4.rm(snapshot.filePath, { force: true });
|
|
27865
28551
|
continue;
|
|
27866
28552
|
}
|
|
27867
|
-
await fs4.mkdir(
|
|
28553
|
+
await fs4.mkdir(path51.dirname(snapshot.filePath), { recursive: true });
|
|
27868
28554
|
await fs4.writeFile(snapshot.filePath, snapshot.content, "utf-8");
|
|
27869
28555
|
}
|
|
27870
28556
|
}
|
|
@@ -27877,7 +28563,7 @@ async function removeNewEmptyDirectories(snapshots) {
|
|
|
27877
28563
|
}
|
|
27878
28564
|
}
|
|
27879
28565
|
}
|
|
27880
|
-
function
|
|
28566
|
+
function isRecord8(value) {
|
|
27881
28567
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
27882
28568
|
}
|
|
27883
28569
|
function isNodeError6(error) {
|
|
@@ -27931,15 +28617,15 @@ async function pathExists6(p) {
|
|
|
27931
28617
|
|
|
27932
28618
|
// src/commands/install.ts
|
|
27933
28619
|
import { promises as fs5 } from "fs";
|
|
27934
|
-
import
|
|
27935
|
-
import
|
|
27936
|
-
var
|
|
27937
|
-
var
|
|
28620
|
+
import path52 from "path";
|
|
28621
|
+
import process7 from "process";
|
|
28622
|
+
var EXIT_OK3 = 0;
|
|
28623
|
+
var EXIT_NOT_INITIALIZED2 = 1;
|
|
27938
28624
|
var EXIT_UNSUPPORTED_PLATFORM = 2;
|
|
27939
28625
|
var EXIT_INSTALL_FAILED = 3;
|
|
27940
|
-
async function install(rootDir =
|
|
27941
|
-
const stateFile =
|
|
27942
|
-
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");
|
|
27943
28629
|
if (await pathExists7(v3SchemaFile)) {
|
|
27944
28630
|
return installV3(rootDir, platform, options);
|
|
27945
28631
|
}
|
|
@@ -27953,7 +28639,7 @@ async function install(rootDir = process6.cwd(), platform = "claude-code", optio
|
|
|
27953
28639
|
if (!await pathExists7(stateFile)) {
|
|
27954
28640
|
console.error("\u2717 mancode not initialized.");
|
|
27955
28641
|
console.error(" Run `mancode init` first.");
|
|
27956
|
-
return
|
|
28642
|
+
return EXIT_NOT_INITIALIZED2;
|
|
27957
28643
|
}
|
|
27958
28644
|
const installer = getPlatformInstaller(platform);
|
|
27959
28645
|
if (!installer) {
|
|
@@ -27986,7 +28672,7 @@ async function install(rootDir = process6.cwd(), platform = "claude-code", optio
|
|
|
27986
28672
|
`\u2139\uFE0F ${formatPlatformName(platform)} adapter already installed.`
|
|
27987
28673
|
);
|
|
27988
28674
|
console.log(" Run with --force to reinstall.");
|
|
27989
|
-
return
|
|
28675
|
+
return EXIT_OK3;
|
|
27990
28676
|
}
|
|
27991
28677
|
console.log(
|
|
27992
28678
|
`\u2139\uFE0F ${formatPlatformName(platform)} adapter already installed; switching to minimal install.`
|
|
@@ -28028,7 +28714,7 @@ async function install(rootDir = process6.cwd(), platform = "claude-code", optio
|
|
|
28028
28714
|
})
|
|
28029
28715
|
});
|
|
28030
28716
|
console.log(`\u2713 ${formatPlatformName(platform)} adapter installed.`);
|
|
28031
|
-
return
|
|
28717
|
+
return EXIT_OK3;
|
|
28032
28718
|
}
|
|
28033
28719
|
async function installV3(rootDir, platform, options) {
|
|
28034
28720
|
const installer = getPlatformInstaller(platform);
|
|
@@ -28050,7 +28736,7 @@ async function installV3(rootDir, platform, options) {
|
|
|
28050
28736
|
for (const entry of staged.modeEntries) {
|
|
28051
28737
|
console.log(` ${entry.stagingTarget}`);
|
|
28052
28738
|
}
|
|
28053
|
-
return
|
|
28739
|
+
return EXIT_OK3;
|
|
28054
28740
|
}
|
|
28055
28741
|
if (project.manifest.activationState !== "v3_active") {
|
|
28056
28742
|
throw new Error("MANCODE_V3_ADAPTER_INSTALL_REQUIRES_ACTIVE");
|
|
@@ -28083,7 +28769,7 @@ async function installV3(rootDir, platform, options) {
|
|
|
28083
28769
|
);
|
|
28084
28770
|
for (const target of installed.filePlans)
|
|
28085
28771
|
console.log(` ${target.target}`);
|
|
28086
|
-
return
|
|
28772
|
+
return EXIT_OK3;
|
|
28087
28773
|
} catch (err) {
|
|
28088
28774
|
const message = err instanceof Error ? err.message : String(err);
|
|
28089
28775
|
console.error(
|
|
@@ -28100,7 +28786,7 @@ function printUnsupportedPlatform(platform) {
|
|
|
28100
28786
|
}
|
|
28101
28787
|
}
|
|
28102
28788
|
async function readConfig2(rootDir) {
|
|
28103
|
-
const configPath =
|
|
28789
|
+
const configPath = path52.join(rootDir, ".mancode", "config.json");
|
|
28104
28790
|
try {
|
|
28105
28791
|
const raw = await fs5.readFile(configPath, "utf-8");
|
|
28106
28792
|
return { config: JSON.parse(raw), valid: true };
|
|
@@ -28115,7 +28801,7 @@ function isNodeError7(err) {
|
|
|
28115
28801
|
return err instanceof Error && "code" in err;
|
|
28116
28802
|
}
|
|
28117
28803
|
async function updateConfig(rootDir, config) {
|
|
28118
|
-
const configPath =
|
|
28804
|
+
const configPath = path52.join(rootDir, ".mancode", "config.json");
|
|
28119
28805
|
const content = `${JSON.stringify(config, null, 2)}
|
|
28120
28806
|
`;
|
|
28121
28807
|
await fs5.writeFile(configPath, content, "utf-8");
|
|
@@ -28130,28 +28816,28 @@ function withDefaultConfig(config, fallbackPlatform) {
|
|
|
28130
28816
|
return {
|
|
28131
28817
|
...merged,
|
|
28132
28818
|
platforms,
|
|
28133
|
-
hooks:
|
|
28134
|
-
logging:
|
|
28819
|
+
hooks: isRecord9(config.hooks) ? config.hooks : DEFAULT_CONFIG.hooks,
|
|
28820
|
+
logging: isRecord9(config.logging) ? config.logging : DEFAULT_CONFIG.logging
|
|
28135
28821
|
};
|
|
28136
28822
|
}
|
|
28137
28823
|
function updatePlatformOptions(value, platform, options) {
|
|
28138
|
-
const platformOptions =
|
|
28824
|
+
const platformOptions = isRecord9(value) ? { ...value } : {};
|
|
28139
28825
|
const existing = platformOptions[platform];
|
|
28140
28826
|
platformOptions[platform] = {
|
|
28141
|
-
...
|
|
28827
|
+
...isRecord9(existing) ? existing : {},
|
|
28142
28828
|
minimal: options.minimal === true
|
|
28143
28829
|
};
|
|
28144
28830
|
return platformOptions;
|
|
28145
28831
|
}
|
|
28146
28832
|
function readConfiguredMinimal(value, platform) {
|
|
28147
|
-
if (!
|
|
28833
|
+
if (!isRecord9(value)) return false;
|
|
28148
28834
|
const platformOptions = value[platform];
|
|
28149
|
-
return
|
|
28835
|
+
return isRecord9(platformOptions) && platformOptions.minimal === true;
|
|
28150
28836
|
}
|
|
28151
28837
|
async function readStatePlatform(rootDir) {
|
|
28152
28838
|
try {
|
|
28153
28839
|
const raw = await fs5.readFile(
|
|
28154
|
-
|
|
28840
|
+
path52.join(rootDir, ".mancode", "state.json"),
|
|
28155
28841
|
"utf-8"
|
|
28156
28842
|
);
|
|
28157
28843
|
const state = JSON.parse(raw);
|
|
@@ -28168,17 +28854,17 @@ async function pathExists7(p) {
|
|
|
28168
28854
|
return false;
|
|
28169
28855
|
}
|
|
28170
28856
|
}
|
|
28171
|
-
function
|
|
28857
|
+
function isRecord9(value) {
|
|
28172
28858
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
28173
28859
|
}
|
|
28174
28860
|
|
|
28175
28861
|
// src/commands/list-platforms.ts
|
|
28176
28862
|
import { promises as fs6 } from "fs";
|
|
28177
|
-
import
|
|
28178
|
-
import
|
|
28179
|
-
var
|
|
28180
|
-
async function listPlatforms(rootDir =
|
|
28181
|
-
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"))) {
|
|
28182
28868
|
return listV3Platforms(rootDir);
|
|
28183
28869
|
}
|
|
28184
28870
|
const installed = new Set(await readInstalledPlatforms(rootDir));
|
|
@@ -28189,7 +28875,7 @@ async function listPlatforms(rootDir = process7.cwd()) {
|
|
|
28189
28875
|
console.log(formatPlatformLine(platform, installed.has(platform.name)));
|
|
28190
28876
|
}
|
|
28191
28877
|
console.log("");
|
|
28192
|
-
return
|
|
28878
|
+
return EXIT_OK4;
|
|
28193
28879
|
}
|
|
28194
28880
|
async function listV3Platforms(rootDir) {
|
|
28195
28881
|
const platforms = getPlatformInstallers();
|
|
@@ -28209,12 +28895,12 @@ async function listV3Platforms(rootDir) {
|
|
|
28209
28895
|
);
|
|
28210
28896
|
}
|
|
28211
28897
|
console.log("");
|
|
28212
|
-
return
|
|
28898
|
+
return EXIT_OK4;
|
|
28213
28899
|
}
|
|
28214
28900
|
async function readInstalledPlatforms(rootDir) {
|
|
28215
28901
|
try {
|
|
28216
28902
|
const raw = await fs6.readFile(
|
|
28217
|
-
|
|
28903
|
+
path53.join(rootDir, ".mancode", "config.json"),
|
|
28218
28904
|
"utf-8"
|
|
28219
28905
|
);
|
|
28220
28906
|
const config = JSON.parse(raw);
|
|
@@ -28246,8 +28932,8 @@ function describePlatform(platform) {
|
|
|
28246
28932
|
}
|
|
28247
28933
|
|
|
28248
28934
|
// src/commands/manps.ts
|
|
28249
|
-
import { access as access4, readFile as
|
|
28250
|
-
import
|
|
28935
|
+
import { access as access4, readFile as readFile40 } from "fs/promises";
|
|
28936
|
+
import path55 from "path";
|
|
28251
28937
|
import { createInterface as createInterface2 } from "readline/promises";
|
|
28252
28938
|
|
|
28253
28939
|
// src/system/preseason.ts
|
|
@@ -28256,14 +28942,14 @@ import { createHash as createHash8 } from "crypto";
|
|
|
28256
28942
|
import { existsSync, readFileSync } from "fs";
|
|
28257
28943
|
import {
|
|
28258
28944
|
access as access3,
|
|
28259
|
-
lstat as
|
|
28260
|
-
mkdir as
|
|
28261
|
-
readFile as
|
|
28945
|
+
lstat as lstat21,
|
|
28946
|
+
mkdir as mkdir35,
|
|
28947
|
+
readFile as readFile39,
|
|
28262
28948
|
readdir as readdir18,
|
|
28263
28949
|
rename as rename11,
|
|
28264
|
-
writeFile as
|
|
28950
|
+
writeFile as writeFile40
|
|
28265
28951
|
} from "fs/promises";
|
|
28266
|
-
import
|
|
28952
|
+
import path54 from "path";
|
|
28267
28953
|
var PRESEASON_AREAS = [
|
|
28268
28954
|
"all",
|
|
28269
28955
|
"deps",
|
|
@@ -28328,7 +29014,7 @@ var SCANNERS = [
|
|
|
28328
29014
|
{
|
|
28329
29015
|
name: "aesthetic-drift",
|
|
28330
29016
|
areas: ["all"],
|
|
28331
|
-
scan: ({ projectRoot, files }) => scanAestheticDrift(projectRoot, files)
|
|
29017
|
+
scan: ({ projectRoot, files, pkg }) => scanAestheticDrift(projectRoot, files, pkg)
|
|
28332
29018
|
},
|
|
28333
29019
|
{
|
|
28334
29020
|
name: "architecture",
|
|
@@ -28343,10 +29029,10 @@ async function runPreseasonScan(projectRoot, area = "all", options = {}) {
|
|
|
28343
29029
|
const needsFiles = normalizedArea === "all" || normalizedArea === "dead-code" || normalizedArea === "config";
|
|
28344
29030
|
const files = needsFiles ? await listProjectFiles(projectRoot) : [];
|
|
28345
29031
|
const issues = (await scanArea(projectRoot, normalizedArea, pkg, files)).slice(0, 20);
|
|
28346
|
-
const storageRoot = options.storageRoot ??
|
|
28347
|
-
const reportDir =
|
|
28348
|
-
await
|
|
28349
|
-
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");
|
|
28350
29036
|
const reportPath = await allocateReportPath(
|
|
28351
29037
|
reportDir,
|
|
28352
29038
|
`${generatedAt.replace(/[:.]/g, "-")}-${normalizedArea}`
|
|
@@ -28360,9 +29046,9 @@ async function runPreseasonScan(projectRoot, area = "all", options = {}) {
|
|
|
28360
29046
|
issueDbPath
|
|
28361
29047
|
};
|
|
28362
29048
|
const database = await buildIssueDatabase(projectRoot, report);
|
|
28363
|
-
await
|
|
28364
|
-
await
|
|
28365
|
-
|
|
29049
|
+
await writeFile40(reportPath, renderPreseasonReport(report), "utf-8");
|
|
29050
|
+
await writeFile40(
|
|
29051
|
+
path54.join(storageRoot, "preseason-report.md"),
|
|
28366
29052
|
renderPreseasonReport(report),
|
|
28367
29053
|
"utf-8"
|
|
28368
29054
|
);
|
|
@@ -28370,7 +29056,7 @@ async function runPreseasonScan(projectRoot, area = "all", options = {}) {
|
|
|
28370
29056
|
return report;
|
|
28371
29057
|
}
|
|
28372
29058
|
async function runPreseasonRemediation(projectRoot, issues, options = {}) {
|
|
28373
|
-
const issueDbPath = options.issueDbPath ??
|
|
29059
|
+
const issueDbPath = options.issueDbPath ?? path54.join(projectRoot, ".mancode", "preseason-issues.json");
|
|
28374
29060
|
const database = await readIssueDatabase(issueDbPath);
|
|
28375
29061
|
const keys = new Set(issues.map((issue) => issueKey(issue)));
|
|
28376
29062
|
const targets = database.issues.filter(
|
|
@@ -28448,7 +29134,7 @@ async function runPreseasonRemediation(projectRoot, issues, options = {}) {
|
|
|
28448
29134
|
write2(" Decision: skipped.");
|
|
28449
29135
|
}
|
|
28450
29136
|
database.updatedAt = now;
|
|
28451
|
-
await
|
|
29137
|
+
await writeFile40(
|
|
28452
29138
|
issueDbPath,
|
|
28453
29139
|
`${JSON.stringify(database, null, 2)}
|
|
28454
29140
|
`,
|
|
@@ -28480,7 +29166,7 @@ async function scanArea(projectRoot, area, pkg, files) {
|
|
|
28480
29166
|
async function allocateReportPath(reportDir, baseName) {
|
|
28481
29167
|
for (let attempt = 0; attempt < 1e3; attempt++) {
|
|
28482
29168
|
const suffix = attempt === 0 ? "" : `-${attempt + 1}`;
|
|
28483
|
-
const candidate =
|
|
29169
|
+
const candidate = path54.join(reportDir, `${baseName}${suffix}.md`);
|
|
28484
29170
|
if (!existsSync(candidate)) return candidate;
|
|
28485
29171
|
}
|
|
28486
29172
|
throw new Error(`unable to allocate preseason report path: ${baseName}`);
|
|
@@ -28529,18 +29215,18 @@ async function walk(root, current, results, depth) {
|
|
|
28529
29215
|
}
|
|
28530
29216
|
for (const entry of entries) {
|
|
28531
29217
|
if (IGNORE_DIRS.has(entry)) continue;
|
|
28532
|
-
const abs =
|
|
28533
|
-
const rel =
|
|
29218
|
+
const abs = path54.join(current, entry);
|
|
29219
|
+
const rel = path54.relative(root, abs);
|
|
28534
29220
|
let info;
|
|
28535
29221
|
try {
|
|
28536
|
-
info = await
|
|
29222
|
+
info = await lstat21(abs);
|
|
28537
29223
|
} catch {
|
|
28538
29224
|
continue;
|
|
28539
29225
|
}
|
|
28540
29226
|
if (info.isSymbolicLink()) continue;
|
|
28541
29227
|
if (info.isDirectory()) {
|
|
28542
29228
|
await walk(root, abs, results, depth + 1);
|
|
28543
|
-
} else if (SOURCE_EXTENSIONS.has(
|
|
29229
|
+
} else if (SOURCE_EXTENSIONS.has(path54.extname(entry)) || entry === "package.json") {
|
|
28544
29230
|
results.push(rel);
|
|
28545
29231
|
if (results.length >= MAX_PROJECT_FILES) return;
|
|
28546
29232
|
}
|
|
@@ -28548,7 +29234,7 @@ async function walk(root, current, results, depth) {
|
|
|
28548
29234
|
}
|
|
28549
29235
|
async function readPackageJson(projectRoot) {
|
|
28550
29236
|
try {
|
|
28551
|
-
const raw = await
|
|
29237
|
+
const raw = await readFile39(path54.join(projectRoot, "package.json"), "utf-8");
|
|
28552
29238
|
return JSON.parse(raw);
|
|
28553
29239
|
} catch {
|
|
28554
29240
|
return null;
|
|
@@ -28641,7 +29327,7 @@ function scanTodos(projectRoot, files) {
|
|
|
28641
29327
|
const matches = [];
|
|
28642
29328
|
for (const file of files) {
|
|
28643
29329
|
if (matches.length >= 7) break;
|
|
28644
|
-
const abs =
|
|
29330
|
+
const abs = path54.join(projectRoot, file);
|
|
28645
29331
|
matches.push(...readTodoIssues(abs, file, matches.length));
|
|
28646
29332
|
}
|
|
28647
29333
|
return matches.slice(0, 7);
|
|
@@ -28682,7 +29368,7 @@ function scanTestGaps(files) {
|
|
|
28682
29368
|
if (sourceFiles.length === 0) return [];
|
|
28683
29369
|
const tests = new Set(files.filter((file) => file.startsWith("tests/")));
|
|
28684
29370
|
const missing = sourceFiles.filter((file) => {
|
|
28685
|
-
const base =
|
|
29371
|
+
const base = path54.basename(file).replace(/\.(ts|tsx|js|jsx)$/, "");
|
|
28686
29372
|
return !Array.from(tests).some((test) => test.includes(base));
|
|
28687
29373
|
}).slice(0, 4);
|
|
28688
29374
|
return missing.map((file, index) => ({
|
|
@@ -28691,13 +29377,13 @@ function scanTestGaps(files) {
|
|
|
28691
29377
|
type: "tests",
|
|
28692
29378
|
title: "Core source file has no obvious test",
|
|
28693
29379
|
file,
|
|
28694
|
-
detail: `No matching test file was found for ${
|
|
29380
|
+
detail: `No matching test file was found for ${path54.basename(file)}.`,
|
|
28695
29381
|
recommendation: "Add focused coverage for the public behavior or document why this module is exercised indirectly."
|
|
28696
29382
|
}));
|
|
28697
29383
|
}
|
|
28698
29384
|
function scanConfig(projectRoot, files) {
|
|
28699
29385
|
const issues = [];
|
|
28700
|
-
if (!files.includes(".gitignore") && !pathExistsSync(
|
|
29386
|
+
if (!files.includes(".gitignore") && !pathExistsSync(path54.join(projectRoot, ".gitignore"))) {
|
|
28701
29387
|
issues.push({
|
|
28702
29388
|
id: "config-gitignore",
|
|
28703
29389
|
severity: "P1",
|
|
@@ -28708,7 +29394,7 @@ function scanConfig(projectRoot, files) {
|
|
|
28708
29394
|
recommendation: "Add a .gitignore that excludes dependencies, build output, coverage, and local env files."
|
|
28709
29395
|
});
|
|
28710
29396
|
}
|
|
28711
|
-
if (!files.includes(".editorconfig") && !pathExistsSync(
|
|
29397
|
+
if (!files.includes(".editorconfig") && !pathExistsSync(path54.join(projectRoot, ".editorconfig"))) {
|
|
28712
29398
|
issues.push({
|
|
28713
29399
|
id: "config-editorconfig",
|
|
28714
29400
|
severity: "P2",
|
|
@@ -28721,13 +29407,13 @@ function scanConfig(projectRoot, files) {
|
|
|
28721
29407
|
}
|
|
28722
29408
|
return issues;
|
|
28723
29409
|
}
|
|
28724
|
-
function scanAestheticDrift(projectRoot, files) {
|
|
29410
|
+
function scanAestheticDrift(projectRoot, files, pkg) {
|
|
28725
29411
|
const issues = [];
|
|
28726
29412
|
const frontendFiles = files.filter((file) => /\.(tsx|jsx|css)$/.test(file));
|
|
28727
29413
|
for (const file of frontendFiles) {
|
|
28728
29414
|
let content;
|
|
28729
29415
|
try {
|
|
28730
|
-
content = readFileSyncSafe(
|
|
29416
|
+
content = readFileSyncSafe(path54.join(projectRoot, file));
|
|
28731
29417
|
} catch {
|
|
28732
29418
|
continue;
|
|
28733
29419
|
}
|
|
@@ -28744,10 +29430,41 @@ function scanAestheticDrift(projectRoot, files) {
|
|
|
28744
29430
|
break;
|
|
28745
29431
|
}
|
|
28746
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
|
+
}
|
|
28747
29445
|
return issues;
|
|
28748
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
|
+
}
|
|
28749
29466
|
async function scanArchitecture(projectRoot) {
|
|
28750
|
-
const localBinary =
|
|
29467
|
+
const localBinary = path54.join(
|
|
28751
29468
|
projectRoot,
|
|
28752
29469
|
"node_modules",
|
|
28753
29470
|
".bin",
|
|
@@ -28795,7 +29512,7 @@ async function hasDependencyCruiserConfig(projectRoot) {
|
|
|
28795
29512
|
"dependency-cruiser.config.mjs"
|
|
28796
29513
|
];
|
|
28797
29514
|
const results = await Promise.all(
|
|
28798
|
-
files.map((file) => pathExists9(
|
|
29515
|
+
files.map((file) => pathExists9(path54.join(projectRoot, file)))
|
|
28799
29516
|
);
|
|
28800
29517
|
return results.some(Boolean);
|
|
28801
29518
|
}
|
|
@@ -28863,15 +29580,15 @@ function parseDepcruiseJson(output) {
|
|
|
28863
29580
|
}
|
|
28864
29581
|
}
|
|
28865
29582
|
function extractDepcruiseViolations(value) {
|
|
28866
|
-
if (!
|
|
28867
|
-
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 : [];
|
|
28868
29585
|
return rawViolations.map((violation) => normalizeDepcruiseViolation(violation)).filter(
|
|
28869
29586
|
(violation) => violation !== null
|
|
28870
29587
|
);
|
|
28871
29588
|
}
|
|
28872
29589
|
function normalizeDepcruiseViolation(value) {
|
|
28873
|
-
if (!
|
|
28874
|
-
const rule =
|
|
29590
|
+
if (!isRecord10(value)) return null;
|
|
29591
|
+
const rule = isRecord10(value.rule) ? value.rule : {};
|
|
28875
29592
|
const from = typeof value.from === "string" ? value.from : "";
|
|
28876
29593
|
const to = typeof value.to === "string" ? value.to : void 0;
|
|
28877
29594
|
const ruleName = typeof rule.name === "string" ? rule.name : typeof value.name === "string" ? value.name : "unnamed-rule";
|
|
@@ -28901,9 +29618,9 @@ function inferCommands(pkg) {
|
|
|
28901
29618
|
return ["lint", "test", "build"].filter((name) => scripts[name]).map((name) => `npm run ${name}`);
|
|
28902
29619
|
}
|
|
28903
29620
|
async function buildIssueDatabase(projectRoot, report) {
|
|
28904
|
-
const reportRef =
|
|
29621
|
+
const reportRef = path54.relative(projectRoot, report.reportPath);
|
|
28905
29622
|
const run = {
|
|
28906
|
-
id:
|
|
29623
|
+
id: path54.basename(report.reportPath, ".md"),
|
|
28907
29624
|
generatedAt: report.generatedAt,
|
|
28908
29625
|
area: report.area,
|
|
28909
29626
|
reportPath: reportRef,
|
|
@@ -28945,7 +29662,7 @@ async function buildIssueDatabase(projectRoot, report) {
|
|
|
28945
29662
|
async function readIssueDatabase(issueDbPath) {
|
|
28946
29663
|
let raw;
|
|
28947
29664
|
try {
|
|
28948
|
-
raw = await
|
|
29665
|
+
raw = await readFile39(issueDbPath, "utf-8");
|
|
28949
29666
|
} catch (err) {
|
|
28950
29667
|
if (isNodeError8(err) && err.code === "ENOENT") {
|
|
28951
29668
|
return emptyIssueDatabase();
|
|
@@ -28966,7 +29683,7 @@ async function readIssueDatabase(issueDbPath) {
|
|
|
28966
29683
|
}
|
|
28967
29684
|
async function writeJsonAtomic3(file, value) {
|
|
28968
29685
|
const tmp = `${file}.tmp-${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
28969
|
-
await
|
|
29686
|
+
await writeFile40(tmp, `${JSON.stringify(value, null, 2)}
|
|
28970
29687
|
`, "utf-8");
|
|
28971
29688
|
await rename11(tmp, file);
|
|
28972
29689
|
}
|
|
@@ -29009,20 +29726,20 @@ function compareIssueRecords(a, b) {
|
|
|
29009
29726
|
}
|
|
29010
29727
|
async function applySafeRemediation(projectRoot, issue) {
|
|
29011
29728
|
if (issue.id === "config-gitignore" && issue.file === ".gitignore") {
|
|
29012
|
-
const gitignorePath =
|
|
29729
|
+
const gitignorePath = path54.join(projectRoot, ".gitignore");
|
|
29013
29730
|
if (pathExistsSync(gitignorePath)) {
|
|
29014
29731
|
return { applied: false };
|
|
29015
29732
|
}
|
|
29016
|
-
await
|
|
29733
|
+
await writeFile40(gitignorePath, `${DEFAULT_GITIGNORE}
|
|
29017
29734
|
`, "utf-8");
|
|
29018
29735
|
return { applied: true, action: "created .gitignore" };
|
|
29019
29736
|
}
|
|
29020
29737
|
if (issue.id === "config-editorconfig" && issue.file === ".editorconfig") {
|
|
29021
|
-
const editorconfigPath =
|
|
29738
|
+
const editorconfigPath = path54.join(projectRoot, ".editorconfig");
|
|
29022
29739
|
if (pathExistsSync(editorconfigPath)) {
|
|
29023
29740
|
return { applied: false };
|
|
29024
29741
|
}
|
|
29025
|
-
await
|
|
29742
|
+
await writeFile40(editorconfigPath, `${DEFAULT_EDITORCONFIG}
|
|
29026
29743
|
`, "utf-8");
|
|
29027
29744
|
return { applied: true, action: "created .editorconfig" };
|
|
29028
29745
|
}
|
|
@@ -29058,10 +29775,10 @@ async function inferSafePackageScript(projectRoot, scriptName) {
|
|
|
29058
29775
|
}
|
|
29059
29776
|
}
|
|
29060
29777
|
async function addPackageScript(projectRoot, scriptName, script) {
|
|
29061
|
-
const packagePath =
|
|
29778
|
+
const packagePath = path54.join(projectRoot, "package.json");
|
|
29062
29779
|
let pkg;
|
|
29063
29780
|
try {
|
|
29064
|
-
pkg = JSON.parse(await
|
|
29781
|
+
pkg = JSON.parse(await readFile39(packagePath, "utf-8"));
|
|
29065
29782
|
} catch {
|
|
29066
29783
|
return false;
|
|
29067
29784
|
}
|
|
@@ -29071,7 +29788,7 @@ async function addPackageScript(projectRoot, scriptName, script) {
|
|
|
29071
29788
|
...scripts,
|
|
29072
29789
|
[scriptName]: script
|
|
29073
29790
|
};
|
|
29074
|
-
await
|
|
29791
|
+
await writeFile40(packagePath, `${JSON.stringify(pkg, null, 2)}
|
|
29075
29792
|
`, "utf-8");
|
|
29076
29793
|
return true;
|
|
29077
29794
|
}
|
|
@@ -29161,17 +29878,17 @@ async function pathExists9(file) {
|
|
|
29161
29878
|
function isNodeError8(err) {
|
|
29162
29879
|
return err instanceof Error && "code" in err;
|
|
29163
29880
|
}
|
|
29164
|
-
function
|
|
29881
|
+
function isRecord10(value) {
|
|
29165
29882
|
return typeof value === "object" && value !== null;
|
|
29166
29883
|
}
|
|
29167
29884
|
|
|
29168
29885
|
// src/commands/manps.ts
|
|
29169
|
-
var
|
|
29170
|
-
var
|
|
29886
|
+
var EXIT_OK5 = 0;
|
|
29887
|
+
var EXIT_NOT_INITIALIZED3 = 1;
|
|
29171
29888
|
var EXIT_SCAN_FAILED = 2;
|
|
29172
29889
|
var EXIT_INVALID_ARG = 3;
|
|
29173
29890
|
async function manps(rootDir, area = "all", options = {}) {
|
|
29174
|
-
const v3SchemaPath =
|
|
29891
|
+
const v3SchemaPath = path55.join(rootDir, ".mancode", "schema.json");
|
|
29175
29892
|
const v3Activation = await readV3ActivationState(v3SchemaPath);
|
|
29176
29893
|
if (v3Activation !== null && v3Activation !== "v3_active" && v3Activation !== "dual_read") {
|
|
29177
29894
|
const message = `manps is unavailable while mancode activation is ${v3Activation}`;
|
|
@@ -29184,7 +29901,7 @@ async function manps(rootDir, area = "all", options = {}) {
|
|
|
29184
29901
|
return EXIT_SCAN_FAILED;
|
|
29185
29902
|
}
|
|
29186
29903
|
const v3Initialized = v3Activation === "v3_active";
|
|
29187
|
-
const initialized = v3Initialized || await pathExists10(
|
|
29904
|
+
const initialized = v3Initialized || await pathExists10(path55.join(rootDir, ".mancode", "state.json"));
|
|
29188
29905
|
if (!initialized) {
|
|
29189
29906
|
if (options.json) {
|
|
29190
29907
|
console.log(JSON.stringify({ error: "not initialized" }, null, 2));
|
|
@@ -29192,12 +29909,12 @@ async function manps(rootDir, area = "all", options = {}) {
|
|
|
29192
29909
|
console.error("\u2717 mancode not initialized.");
|
|
29193
29910
|
console.error(" Run `mancode init` first.");
|
|
29194
29911
|
}
|
|
29195
|
-
return
|
|
29912
|
+
return EXIT_NOT_INITIALIZED3;
|
|
29196
29913
|
}
|
|
29197
29914
|
let report;
|
|
29198
29915
|
try {
|
|
29199
29916
|
report = await runPreseasonScan(rootDir, area, {
|
|
29200
|
-
storageRoot: v3Initialized ?
|
|
29917
|
+
storageRoot: v3Initialized ? path55.join(rootDir, ".mancode", "local") : void 0
|
|
29201
29918
|
});
|
|
29202
29919
|
} catch (err) {
|
|
29203
29920
|
const message = err instanceof Error ? err.message : String(err);
|
|
@@ -29255,7 +29972,7 @@ async function manps(rootDir, area = "all", options = {}) {
|
|
|
29255
29972
|
}
|
|
29256
29973
|
if (options.json) {
|
|
29257
29974
|
console.log(JSON.stringify({ ...report, remediation }, null, 2));
|
|
29258
|
-
return
|
|
29975
|
+
return EXIT_OK5;
|
|
29259
29976
|
}
|
|
29260
29977
|
const p0 = report.issues.filter((issue) => issue.severity === "P0").length;
|
|
29261
29978
|
const p1 = report.issues.filter((issue) => issue.severity === "P1").length;
|
|
@@ -29266,8 +29983,8 @@ async function manps(rootDir, area = "all", options = {}) {
|
|
|
29266
29983
|
console.log(
|
|
29267
29984
|
`Issues: ${report.issues.length} total (P0 ${p0}, P1 ${p1}, P2 ${p2})`
|
|
29268
29985
|
);
|
|
29269
|
-
console.log(`Report: ${
|
|
29270
|
-
console.log(`Issue DB: ${
|
|
29986
|
+
console.log(`Report: ${path55.relative(rootDir, report.reportPath)}`);
|
|
29987
|
+
console.log(`Issue DB: ${path55.relative(rootDir, report.issueDbPath)}`);
|
|
29271
29988
|
if (report.issues.length > 0) {
|
|
29272
29989
|
console.log("");
|
|
29273
29990
|
for (const issue of report.issues.slice(0, 7)) {
|
|
@@ -29283,10 +30000,10 @@ async function manps(rootDir, area = "all", options = {}) {
|
|
|
29283
30000
|
console.log(` Skipped: ${remediation.skipped}`);
|
|
29284
30001
|
console.log(` Fixed: ${remediation.fixed}`);
|
|
29285
30002
|
console.log(
|
|
29286
|
-
` Issue DB: ${
|
|
30003
|
+
` Issue DB: ${path55.relative(rootDir, remediation.issueDbPath)}`
|
|
29287
30004
|
);
|
|
29288
30005
|
}
|
|
29289
|
-
return
|
|
30006
|
+
return EXIT_OK5;
|
|
29290
30007
|
}
|
|
29291
30008
|
async function runRemediation(rootDir, report, options, silent = false) {
|
|
29292
30009
|
const write2 = silent ? () => {
|
|
@@ -29344,7 +30061,7 @@ async function readV3ActivationState(schemaPath) {
|
|
|
29344
30061
|
if (!await pathExists10(schemaPath)) return null;
|
|
29345
30062
|
try {
|
|
29346
30063
|
const manifest = parseSchemaManifest(
|
|
29347
|
-
JSON.parse(await
|
|
30064
|
+
JSON.parse(await readFile40(schemaPath, "utf8"))
|
|
29348
30065
|
);
|
|
29349
30066
|
return manifest.activationState;
|
|
29350
30067
|
} catch {
|
|
@@ -29353,9 +30070,9 @@ async function readV3ActivationState(schemaPath) {
|
|
|
29353
30070
|
}
|
|
29354
30071
|
|
|
29355
30072
|
// src/commands/migrate.ts
|
|
29356
|
-
import { readFile as
|
|
29357
|
-
import
|
|
29358
|
-
var
|
|
30073
|
+
import { readFile as readFile41 } from "fs/promises";
|
|
30074
|
+
import path56 from "path";
|
|
30075
|
+
var EXIT_OK6 = 0;
|
|
29359
30076
|
var EXIT_INVALID_ARG2 = 2;
|
|
29360
30077
|
var EXIT_MIGRATION_BLOCKED = 3;
|
|
29361
30078
|
async function migrateContext(rootDir, options) {
|
|
@@ -29367,7 +30084,7 @@ async function migrateContext(rootDir, options) {
|
|
|
29367
30084
|
options.rollback !== void 0
|
|
29368
30085
|
].filter(Boolean).length;
|
|
29369
30086
|
if (selected !== 1) {
|
|
29370
|
-
return
|
|
30087
|
+
return printError2(
|
|
29371
30088
|
options.json,
|
|
29372
30089
|
"MANCODE_MIGRATION_ARGUMENT_INVALID",
|
|
29373
30090
|
"Choose exactly one migration operation.",
|
|
@@ -29376,16 +30093,16 @@ async function migrateContext(rootDir, options) {
|
|
|
29376
30093
|
}
|
|
29377
30094
|
try {
|
|
29378
30095
|
if (options.dryRun) {
|
|
29379
|
-
return
|
|
30096
|
+
return printResult2(options.json, await dryRunLegacyMigration(rootDir));
|
|
29380
30097
|
}
|
|
29381
30098
|
if (options.stage) {
|
|
29382
|
-
return
|
|
30099
|
+
return printResult2(
|
|
29383
30100
|
options.json,
|
|
29384
30101
|
await stageLegacyMigration({ projectRoot: rootDir })
|
|
29385
30102
|
);
|
|
29386
30103
|
}
|
|
29387
30104
|
if (options.status) {
|
|
29388
|
-
return
|
|
30105
|
+
return printResult2(options.json, {
|
|
29389
30106
|
schemaVersion: 1,
|
|
29390
30107
|
stages: await listMigrationStages(rootDir)
|
|
29391
30108
|
});
|
|
@@ -29396,7 +30113,7 @@ async function migrateContext(rootDir, options) {
|
|
|
29396
30113
|
assertUlid(options.session, "migration activation session");
|
|
29397
30114
|
if (options.rollback !== void 0) {
|
|
29398
30115
|
assertUlid(options.rollback, "migration rollback operation");
|
|
29399
|
-
return
|
|
30116
|
+
return printResult2(
|
|
29400
30117
|
options.json,
|
|
29401
30118
|
await rollbackLegacyMigration({
|
|
29402
30119
|
projectRoot: rootDir,
|
|
@@ -29407,7 +30124,7 @@ async function migrateContext(rootDir, options) {
|
|
|
29407
30124
|
);
|
|
29408
30125
|
}
|
|
29409
30126
|
const stageId = await selectStageId(rootDir, options.stageId);
|
|
29410
|
-
return
|
|
30127
|
+
return printResult2(
|
|
29411
30128
|
options.json,
|
|
29412
30129
|
await activateLegacyMigration({
|
|
29413
30130
|
projectRoot: rootDir,
|
|
@@ -29419,9 +30136,9 @@ async function migrateContext(rootDir, options) {
|
|
|
29419
30136
|
})
|
|
29420
30137
|
);
|
|
29421
30138
|
} catch (error) {
|
|
29422
|
-
return
|
|
30139
|
+
return printError2(
|
|
29423
30140
|
options.json,
|
|
29424
|
-
|
|
30141
|
+
errorCode4(error),
|
|
29425
30142
|
error instanceof Error ? error.message : "Migration failed.",
|
|
29426
30143
|
EXIT_MIGRATION_BLOCKED
|
|
29427
30144
|
);
|
|
@@ -29441,11 +30158,11 @@ async function migrateContextResolve(rootDir, legacyTaskId, options) {
|
|
|
29441
30158
|
ownerActorId: owner,
|
|
29442
30159
|
implementationScope
|
|
29443
30160
|
});
|
|
29444
|
-
return
|
|
30161
|
+
return printResult2(options.json, result2);
|
|
29445
30162
|
} catch (error) {
|
|
29446
|
-
return
|
|
30163
|
+
return printError2(
|
|
29447
30164
|
options.json,
|
|
29448
|
-
|
|
30165
|
+
errorCode4(error),
|
|
29449
30166
|
error instanceof Error ? error.message : "Migration resolution failed.",
|
|
29450
30167
|
EXIT_MIGRATION_BLOCKED
|
|
29451
30168
|
);
|
|
@@ -29480,14 +30197,14 @@ async function readScopeFile(rootDir, file) {
|
|
|
29480
30197
|
if (!file.trim() || file.includes("\0")) {
|
|
29481
30198
|
throw new Error("MANCODE_MIGRATION_SCOPE_FILE_INVALID");
|
|
29482
30199
|
}
|
|
29483
|
-
const resolved =
|
|
29484
|
-
const relative =
|
|
29485
|
-
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)) {
|
|
29486
30203
|
throw new Error("MANCODE_MIGRATION_SCOPE_FILE_INVALID");
|
|
29487
30204
|
}
|
|
29488
30205
|
try {
|
|
29489
30206
|
return JSON.parse(
|
|
29490
|
-
await
|
|
30207
|
+
await readFile41(resolved, "utf8")
|
|
29491
30208
|
);
|
|
29492
30209
|
} catch (error) {
|
|
29493
30210
|
if (error instanceof SyntaxError) {
|
|
@@ -29496,15 +30213,15 @@ async function readScopeFile(rootDir, file) {
|
|
|
29496
30213
|
throw error;
|
|
29497
30214
|
}
|
|
29498
30215
|
}
|
|
29499
|
-
function
|
|
30216
|
+
function printResult2(json, result2) {
|
|
29500
30217
|
if (json) {
|
|
29501
30218
|
console.log(JSON.stringify(result2, null, 2));
|
|
29502
30219
|
} else {
|
|
29503
30220
|
console.log(JSON.stringify(result2, null, 2));
|
|
29504
30221
|
}
|
|
29505
|
-
return
|
|
30222
|
+
return EXIT_OK6;
|
|
29506
30223
|
}
|
|
29507
|
-
function
|
|
30224
|
+
function printError2(json, code, message, exitCode) {
|
|
29508
30225
|
const result2 = { schemaVersion: 1, error: { code, message } };
|
|
29509
30226
|
if (json) {
|
|
29510
30227
|
console.log(JSON.stringify(result2, null, 2));
|
|
@@ -29514,7 +30231,7 @@ function printError(json, code, message, exitCode) {
|
|
|
29514
30231
|
}
|
|
29515
30232
|
return exitCode;
|
|
29516
30233
|
}
|
|
29517
|
-
function
|
|
30234
|
+
function errorCode4(error) {
|
|
29518
30235
|
if (error instanceof Error && error.message.startsWith("MANCODE_")) {
|
|
29519
30236
|
return error.message.split(":", 1)[0] ?? "MANCODE_MIGRATION_FAILED";
|
|
29520
30237
|
}
|
|
@@ -29587,12 +30304,12 @@ async function runOperationMutation(rootDir, operationId, options, mode) {
|
|
|
29587
30304
|
}
|
|
29588
30305
|
|
|
29589
30306
|
// src/context/project-policy-upgrade.ts
|
|
29590
|
-
import { lstat as
|
|
29591
|
-
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";
|
|
29592
30309
|
var UPGRADE_OPERATION = "project_policy_upgrade";
|
|
29593
30310
|
async function dryRunProjectPolicyUpgrade(input) {
|
|
29594
30311
|
assertPolicyVersion(input.policyVersion);
|
|
29595
|
-
const root =
|
|
30312
|
+
const root = path57.resolve(input.projectRoot);
|
|
29596
30313
|
const project = await new V3ContextStore(root).readProjectSnapshot();
|
|
29597
30314
|
const beforeDigest = digestManifest(project.manifest);
|
|
29598
30315
|
const now = input.now ?? /* @__PURE__ */ new Date();
|
|
@@ -29636,7 +30353,7 @@ async function dryRunProjectPolicyUpgrade(input) {
|
|
|
29636
30353
|
async function upgradeProjectPolicy(input) {
|
|
29637
30354
|
assertPolicyVersion(input.policyVersion);
|
|
29638
30355
|
assertUlid(input.sessionId, "project policy upgrade sessionId");
|
|
29639
|
-
const root =
|
|
30356
|
+
const root = path57.resolve(input.projectRoot);
|
|
29640
30357
|
const now = input.now ?? /* @__PURE__ */ new Date();
|
|
29641
30358
|
const operationId = input.operationId;
|
|
29642
30359
|
if (operationId === void 0) {
|
|
@@ -29846,7 +30563,7 @@ async function collectUpgradeBlockers(root, project) {
|
|
|
29846
30563
|
try {
|
|
29847
30564
|
await assertUpgradePreflight(root, project);
|
|
29848
30565
|
} catch (error) {
|
|
29849
|
-
blockers.push(
|
|
30566
|
+
blockers.push(errorCode5(error));
|
|
29850
30567
|
}
|
|
29851
30568
|
return [...new Set(blockers)];
|
|
29852
30569
|
}
|
|
@@ -29890,24 +30607,24 @@ function buildV2Manifest(manifest, operationId) {
|
|
|
29890
30607
|
return candidate;
|
|
29891
30608
|
}
|
|
29892
30609
|
async function readSchemaContent(root) {
|
|
29893
|
-
return
|
|
30610
|
+
return readFile42(path57.join(root, ".mancode", "schema.json"), "utf8");
|
|
29894
30611
|
}
|
|
29895
30612
|
async function writeSchemaContent(root, operationId, content) {
|
|
29896
|
-
const directory =
|
|
29897
|
-
const target =
|
|
29898
|
-
const
|
|
29899
|
-
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()) {
|
|
29900
30617
|
throw new Error("MANCODE_ARTIFACT_PATH_UNSAFE");
|
|
29901
30618
|
}
|
|
29902
|
-
const temporary =
|
|
30619
|
+
const temporary = path57.join(
|
|
29903
30620
|
directory,
|
|
29904
30621
|
`.schema.json.${operationId}.${process.pid}.tmp`
|
|
29905
30622
|
);
|
|
29906
|
-
await
|
|
30623
|
+
await writeFile41(temporary, content, { encoding: "utf8", flag: "wx" });
|
|
29907
30624
|
try {
|
|
29908
30625
|
await replaceFileAtomically(temporary, target);
|
|
29909
30626
|
} catch (error) {
|
|
29910
|
-
await
|
|
30627
|
+
await rm19(temporary, { force: true });
|
|
29911
30628
|
throw error;
|
|
29912
30629
|
}
|
|
29913
30630
|
}
|
|
@@ -29968,22 +30685,22 @@ function assertPolicyVersion(value) {
|
|
|
29968
30685
|
);
|
|
29969
30686
|
}
|
|
29970
30687
|
}
|
|
29971
|
-
function
|
|
30688
|
+
function errorCode5(error) {
|
|
29972
30689
|
return error instanceof Error && error.message.startsWith("MANCODE_") ? error.message.split(":", 1)[0] ?? "MANCODE_PROJECT_UPGRADE_BLOCKED" : "MANCODE_PROJECT_UPGRADE_BLOCKED";
|
|
29973
30690
|
}
|
|
29974
30691
|
async function releaseLocks3(locks) {
|
|
29975
30692
|
await Promise.allSettled([...locks].reverse().map((lock) => lock.release()));
|
|
29976
30693
|
}
|
|
29977
30694
|
function projectUpgradePreviewRoot(root, operationId) {
|
|
29978
|
-
return
|
|
30695
|
+
return path57.join(root, ".mancode", "staging", "project-upgrade", operationId);
|
|
29979
30696
|
}
|
|
29980
30697
|
async function stageProjectPolicyUpgrade(root, receipt, manifestContent) {
|
|
29981
30698
|
const directory = projectUpgradePreviewRoot(root, receipt.operationId);
|
|
29982
|
-
const receiptPath =
|
|
29983
|
-
const manifestPath =
|
|
29984
|
-
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 });
|
|
29985
30702
|
try {
|
|
29986
|
-
await
|
|
30703
|
+
await mkdir36(directory);
|
|
29987
30704
|
} catch (error) {
|
|
29988
30705
|
if (isAlreadyExists23(error)) {
|
|
29989
30706
|
throw new Error("MANCODE_PROJECT_UPGRADE_PREVIEW_EXISTS");
|
|
@@ -29991,25 +30708,25 @@ async function stageProjectPolicyUpgrade(root, receipt, manifestContent) {
|
|
|
29991
30708
|
throw error;
|
|
29992
30709
|
}
|
|
29993
30710
|
try {
|
|
29994
|
-
await
|
|
30711
|
+
await writeFile41(receiptPath, `${JSON.stringify(receipt, null, 2)}
|
|
29995
30712
|
`, {
|
|
29996
30713
|
encoding: "utf8",
|
|
29997
30714
|
flag: "wx"
|
|
29998
30715
|
});
|
|
29999
|
-
await
|
|
30716
|
+
await writeFile41(manifestPath, manifestContent, {
|
|
30000
30717
|
encoding: "utf8",
|
|
30001
30718
|
flag: "wx"
|
|
30002
30719
|
});
|
|
30003
30720
|
} catch (error) {
|
|
30004
|
-
await
|
|
30721
|
+
await rm19(directory, { recursive: true, force: true });
|
|
30005
30722
|
throw error;
|
|
30006
30723
|
}
|
|
30007
30724
|
}
|
|
30008
30725
|
async function assertProjectPolicyUpgradePreview(root, operationId, project) {
|
|
30009
30726
|
const directory = projectUpgradePreviewRoot(root, operationId);
|
|
30010
30727
|
const [receiptContent, manifestContent] = await Promise.all([
|
|
30011
|
-
readSafePreviewFile(
|
|
30012
|
-
readSafePreviewFile(
|
|
30728
|
+
readSafePreviewFile(path57.join(directory, "preview.json")),
|
|
30729
|
+
readSafePreviewFile(path57.join(directory, "schema.json"))
|
|
30013
30730
|
]);
|
|
30014
30731
|
let receipt;
|
|
30015
30732
|
try {
|
|
@@ -30032,13 +30749,13 @@ async function assertProjectPolicyUpgradePreview(root, operationId, project) {
|
|
|
30032
30749
|
}
|
|
30033
30750
|
async function readSafePreviewFile(target) {
|
|
30034
30751
|
try {
|
|
30035
|
-
const
|
|
30036
|
-
if (!
|
|
30752
|
+
const stat5 = await lstat22(target);
|
|
30753
|
+
if (!stat5.isFile() || stat5.isSymbolicLink()) {
|
|
30037
30754
|
throw new Error("MANCODE_PROJECT_UPGRADE_PREVIEW_INVALID");
|
|
30038
30755
|
}
|
|
30039
|
-
return
|
|
30756
|
+
return readFile42(target, "utf8");
|
|
30040
30757
|
} catch (error) {
|
|
30041
|
-
if (
|
|
30758
|
+
if (isNotFound29(error)) {
|
|
30042
30759
|
throw new Error("MANCODE_PROJECT_UPGRADE_PREVIEW_REQUIRED");
|
|
30043
30760
|
}
|
|
30044
30761
|
throw error;
|
|
@@ -30071,7 +30788,7 @@ function parseProjectPolicyUpgradePreviewReceipt(value) {
|
|
|
30071
30788
|
createdAt: record.createdAt
|
|
30072
30789
|
};
|
|
30073
30790
|
}
|
|
30074
|
-
function
|
|
30791
|
+
function isNotFound29(error) {
|
|
30075
30792
|
return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
|
|
30076
30793
|
}
|
|
30077
30794
|
function isAlreadyExists23(error) {
|
|
@@ -30125,22 +30842,22 @@ async function projectUpgrade(rootDir, options) {
|
|
|
30125
30842
|
// src/commands/refresh-project.ts
|
|
30126
30843
|
import { randomUUID } from "crypto";
|
|
30127
30844
|
import { promises as fs7 } from "fs";
|
|
30128
|
-
import
|
|
30129
|
-
import
|
|
30130
|
-
var
|
|
30131
|
-
var
|
|
30845
|
+
import path58 from "path";
|
|
30846
|
+
import process9 from "process";
|
|
30847
|
+
var EXIT_OK7 = 0;
|
|
30848
|
+
var EXIT_NOT_INITIALIZED4 = 1;
|
|
30132
30849
|
var EXIT_CORRUPT_STATE = 2;
|
|
30133
30850
|
var EXIT_REFRESH_FAILED = 3;
|
|
30134
|
-
async function refreshProject(rootDir =
|
|
30135
|
-
const mancodeDir =
|
|
30136
|
-
const statePath =
|
|
30137
|
-
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"))) {
|
|
30138
30855
|
return refreshV3Project(rootDir);
|
|
30139
30856
|
}
|
|
30140
30857
|
if (!await pathExists11(statePath)) {
|
|
30141
30858
|
console.error("\u2717 mancode not initialized.");
|
|
30142
30859
|
console.error(" Run `mancode init` first.");
|
|
30143
|
-
return
|
|
30860
|
+
return EXIT_NOT_INITIALIZED4;
|
|
30144
30861
|
}
|
|
30145
30862
|
const state = await readRequiredState(statePath);
|
|
30146
30863
|
if (!state) {
|
|
@@ -30153,12 +30870,12 @@ async function refreshProject(rootDir = process8.cwd()) {
|
|
|
30153
30870
|
const [profile, team, hasGit, hasManifest] = await Promise.all([
|
|
30154
30871
|
detectProjectProfile(rootDir),
|
|
30155
30872
|
detectTeamStatus(rootDir),
|
|
30156
|
-
pathExists11(
|
|
30873
|
+
pathExists11(path58.join(rootDir, ".git")),
|
|
30157
30874
|
hasProjectManifest2(rootDir)
|
|
30158
30875
|
]);
|
|
30159
30876
|
const uiLibrary = primaryUiLibrary(profile);
|
|
30160
30877
|
const stack = [...profile.languages, ...profile.frameworks];
|
|
30161
|
-
const config = await readJson2(
|
|
30878
|
+
const config = await readJson2(path58.join(mancodeDir, "config.json"));
|
|
30162
30879
|
const configuredTeam = config.forceTeamMode === true ? true : config.teamMode === "on" ? true : config.teamMode === "off" ? false : team.isTeam;
|
|
30163
30880
|
const nextState = {
|
|
30164
30881
|
...state,
|
|
@@ -30170,7 +30887,7 @@ async function refreshProject(rootDir = process8.cwd()) {
|
|
|
30170
30887
|
};
|
|
30171
30888
|
await writeProjectFacts2(
|
|
30172
30889
|
statePath,
|
|
30173
|
-
|
|
30890
|
+
path58.join(mancodeDir, "project-profile.json"),
|
|
30174
30891
|
`${JSON.stringify(nextState, null, 2)}
|
|
30175
30892
|
`,
|
|
30176
30893
|
`${JSON.stringify(profile, null, 2)}
|
|
@@ -30198,7 +30915,7 @@ async function refreshProject(rootDir = process8.cwd()) {
|
|
|
30198
30915
|
console.log(
|
|
30199
30916
|
" Run `mancode refresh-style` if UI files or dependencies changed."
|
|
30200
30917
|
);
|
|
30201
|
-
return
|
|
30918
|
+
return EXIT_OK7;
|
|
30202
30919
|
} catch (error) {
|
|
30203
30920
|
const message = error instanceof Error ? error.message : String(error);
|
|
30204
30921
|
console.error(`\u2717 Project refresh failed: ${message}`);
|
|
@@ -30228,7 +30945,7 @@ async function refreshV3Project(rootDir) {
|
|
|
30228
30945
|
console.log(
|
|
30229
30946
|
" mancode adapters remain unchanged because their bootstrap is static."
|
|
30230
30947
|
);
|
|
30231
|
-
return
|
|
30948
|
+
return EXIT_OK7;
|
|
30232
30949
|
} catch (error) {
|
|
30233
30950
|
const message = error instanceof Error ? error.message : String(error);
|
|
30234
30951
|
console.error(`\u2717 mancode project facts refresh failed: ${message}`);
|
|
@@ -30237,7 +30954,7 @@ async function refreshV3Project(rootDir) {
|
|
|
30237
30954
|
}
|
|
30238
30955
|
async function hasProjectManifest2(rootDir) {
|
|
30239
30956
|
for (const manifest of PROJECT_MANIFESTS) {
|
|
30240
|
-
if (await pathExists11(
|
|
30957
|
+
if (await pathExists11(path58.join(rootDir, manifest))) return true;
|
|
30241
30958
|
}
|
|
30242
30959
|
return false;
|
|
30243
30960
|
}
|
|
@@ -30303,9 +31020,9 @@ async function readOptionalText(filePath) {
|
|
|
30303
31020
|
}
|
|
30304
31021
|
}
|
|
30305
31022
|
function temporaryPath(filePath) {
|
|
30306
|
-
return
|
|
30307
|
-
|
|
30308
|
-
`.${
|
|
31023
|
+
return path58.join(
|
|
31024
|
+
path58.dirname(filePath),
|
|
31025
|
+
`.${path58.basename(filePath)}.${process9.pid}.${randomUUID()}.tmp`
|
|
30309
31026
|
);
|
|
30310
31027
|
}
|
|
30311
31028
|
async function refreshStaticPlatforms(rootDir, config, fallbackPlatform, stack, uiLibrary, profile) {
|
|
@@ -30334,14 +31051,14 @@ function configuredPlatforms(config, fallbackPlatform) {
|
|
|
30334
31051
|
);
|
|
30335
31052
|
}
|
|
30336
31053
|
function platformIsMinimal(config, platform) {
|
|
30337
|
-
if (!
|
|
31054
|
+
if (!isRecord11(config.platformOptions)) return false;
|
|
30338
31055
|
const options = config.platformOptions[platform];
|
|
30339
|
-
return
|
|
31056
|
+
return isRecord11(options) && options.minimal === true;
|
|
30340
31057
|
}
|
|
30341
31058
|
async function readJson2(filePath) {
|
|
30342
31059
|
try {
|
|
30343
31060
|
const value = JSON.parse(await fs7.readFile(filePath, "utf-8"));
|
|
30344
|
-
return
|
|
31061
|
+
return isRecord11(value) ? value : {};
|
|
30345
31062
|
} catch {
|
|
30346
31063
|
return {};
|
|
30347
31064
|
}
|
|
@@ -30351,14 +31068,14 @@ async function readRequiredState(filePath) {
|
|
|
30351
31068
|
try {
|
|
30352
31069
|
const raw = await fs7.readFile(filePath, "utf-8");
|
|
30353
31070
|
const parsed = JSON.parse(raw);
|
|
30354
|
-
if (!
|
|
31071
|
+
if (!isRecord11(parsed)) return null;
|
|
30355
31072
|
state = parsed;
|
|
30356
31073
|
} catch {
|
|
30357
31074
|
return null;
|
|
30358
31075
|
}
|
|
30359
31076
|
return typeof state.version === "string" && typeof state.currentMode === "string" && typeof state.platform === "string" ? state : null;
|
|
30360
31077
|
}
|
|
30361
|
-
function
|
|
31078
|
+
function isRecord11(value) {
|
|
30362
31079
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
30363
31080
|
}
|
|
30364
31081
|
function isNodeError9(error) {
|
|
@@ -30375,52 +31092,62 @@ async function pathExists11(filePath) {
|
|
|
30375
31092
|
|
|
30376
31093
|
// src/commands/refresh-style.ts
|
|
30377
31094
|
import { promises as fs8 } from "fs";
|
|
30378
|
-
import
|
|
30379
|
-
import
|
|
30380
|
-
var
|
|
30381
|
-
var
|
|
31095
|
+
import path59 from "path";
|
|
31096
|
+
import process10 from "process";
|
|
31097
|
+
var EXIT_OK8 = 0;
|
|
31098
|
+
var EXIT_NOT_INITIALIZED5 = 1;
|
|
30382
31099
|
var EXIT_V3_REFRESH_FAILED = 2;
|
|
30383
|
-
async function refreshStyle(rootDir =
|
|
30384
|
-
const
|
|
30385
|
-
if (
|
|
30386
|
-
|
|
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);
|
|
30387
31109
|
}
|
|
30388
31110
|
if (!await pathExists12(stateFile)) {
|
|
30389
31111
|
console.error("\u2717 mancode not initialized.");
|
|
30390
31112
|
console.error(" Run `mancode init` first.");
|
|
30391
|
-
return
|
|
31113
|
+
return EXIT_NOT_INITIALIZED5;
|
|
30392
31114
|
}
|
|
30393
31115
|
console.log("\u2713 \u5237\u65B0\u9879\u76EE profile...");
|
|
30394
31116
|
const profile = await detectProjectProfile(rootDir);
|
|
30395
|
-
const profilePath =
|
|
31117
|
+
const profilePath = path59.join(rootDir, ".mancode", "project-profile.json");
|
|
30396
31118
|
await fs8.writeFile(
|
|
30397
31119
|
profilePath,
|
|
30398
31120
|
`${JSON.stringify(profile, null, 2)}
|
|
30399
31121
|
`,
|
|
30400
31122
|
"utf-8"
|
|
30401
31123
|
);
|
|
30402
|
-
const
|
|
31124
|
+
const scanProfile = scanTarget.scopeRoot === "." ? profile : await detectProjectProfile(scanTarget.root);
|
|
31125
|
+
const uiLibraryHint = primaryUiLibrary(scanProfile);
|
|
30403
31126
|
await refreshLegacyStateContext(rootDir, profile, uiLibraryHint);
|
|
30404
31127
|
console.log(
|
|
30405
31128
|
` \u7C7B\u578B: ${profile.projectKind} | UI: ${profile.uiAssets} | \u6D4F\u89C8\u5668: ${profile.browserAutomation}`
|
|
30406
31129
|
);
|
|
30407
|
-
if (
|
|
31130
|
+
if (scanProfile.uiAssets !== "detected") {
|
|
30408
31131
|
console.log(
|
|
30409
31132
|
"\u2139\uFE0F No UI assets detected in project profile. Skipping style scan."
|
|
30410
31133
|
);
|
|
30411
31134
|
console.log(" Updated .mancode/project-profile.json.");
|
|
30412
31135
|
await printStaticPlatformRefreshHint(rootDir);
|
|
30413
|
-
return
|
|
31136
|
+
return EXIT_OK8;
|
|
30414
31137
|
}
|
|
30415
31138
|
console.log("\u2713 \u626B\u63CF\u9879\u76EE\u8BBE\u8BA1 token...");
|
|
30416
|
-
const tokens = await scanAesthetics(
|
|
30417
|
-
|
|
31139
|
+
const tokens = await scanAesthetics(
|
|
31140
|
+
scanTarget.root,
|
|
31141
|
+
uiLibraryHint,
|
|
31142
|
+
scanTarget.scopeRoot
|
|
31143
|
+
);
|
|
31144
|
+
const tokensPath = path59.join(
|
|
30418
31145
|
rootDir,
|
|
30419
31146
|
".mancode",
|
|
30420
31147
|
"aesthetics",
|
|
30421
31148
|
"style-tokens.json"
|
|
30422
31149
|
);
|
|
30423
|
-
await fs8.mkdir(
|
|
31150
|
+
await fs8.mkdir(path59.dirname(tokensPath), { recursive: true });
|
|
30424
31151
|
await fs8.writeFile(
|
|
30425
31152
|
tokensPath,
|
|
30426
31153
|
`${JSON.stringify(tokens, null, 2)}
|
|
@@ -30433,7 +31160,7 @@ async function refreshStyle(rootDir = process9.cwd()) {
|
|
|
30433
31160
|
"\u5DF2\u66F4\u65B0 .mancode/project-profile.json \u548C .mancode/aesthetics/style-tokens.json"
|
|
30434
31161
|
);
|
|
30435
31162
|
await printStaticPlatformRefreshHint(rootDir);
|
|
30436
|
-
return
|
|
31163
|
+
return EXIT_OK8;
|
|
30437
31164
|
}
|
|
30438
31165
|
function printAestheticsSummary(tokens) {
|
|
30439
31166
|
console.log("");
|
|
@@ -30474,7 +31201,7 @@ function printAestheticsSummary(tokens) {
|
|
|
30474
31201
|
console.log(` \u5339\u914D\u5EA6: ${tokens.matchLevel}`);
|
|
30475
31202
|
}
|
|
30476
31203
|
}
|
|
30477
|
-
async function refreshV3Style(rootDir) {
|
|
31204
|
+
async function refreshV3Style(rootDir, scanRoot, scopeRoot) {
|
|
30478
31205
|
try {
|
|
30479
31206
|
const project = await new V3ContextStore(rootDir).readProjectSnapshot();
|
|
30480
31207
|
if (project.manifest.activationState !== "v3_active") {
|
|
@@ -30482,7 +31209,8 @@ async function refreshV3Style(rootDir) {
|
|
|
30482
31209
|
}
|
|
30483
31210
|
console.log("\u2713 \u5237\u65B0 mancode \u9879\u76EE profile...");
|
|
30484
31211
|
const profile = await detectProjectProfile(rootDir);
|
|
30485
|
-
const
|
|
31212
|
+
const scanProfile = scopeRoot === "." ? profile : await detectProjectProfile(scanRoot);
|
|
31213
|
+
const uiLibraryHint = primaryUiLibrary(scanProfile);
|
|
30486
31214
|
await writeProjectFacts(
|
|
30487
31215
|
rootDir,
|
|
30488
31216
|
createProjectFacts(profile, {
|
|
@@ -30492,24 +31220,24 @@ async function refreshV3Style(rootDir) {
|
|
|
30492
31220
|
console.log(
|
|
30493
31221
|
` \u7C7B\u578B: ${profile.projectKind} | UI: ${profile.uiAssets} | \u6D4F\u89C8\u5668: ${profile.browserAutomation}`
|
|
30494
31222
|
);
|
|
30495
|
-
const tokensPath =
|
|
31223
|
+
const tokensPath = path59.join(
|
|
30496
31224
|
rootDir,
|
|
30497
31225
|
".mancode",
|
|
30498
31226
|
"local",
|
|
30499
31227
|
"cache",
|
|
30500
31228
|
"style-tokens.json"
|
|
30501
31229
|
);
|
|
30502
|
-
if (
|
|
31230
|
+
if (scanProfile.uiAssets !== "detected") {
|
|
30503
31231
|
await fs8.rm(tokensPath, { force: true });
|
|
30504
31232
|
console.log(
|
|
30505
31233
|
"\u2139\uFE0F No UI assets detected in project profile. Skipping style scan."
|
|
30506
31234
|
);
|
|
30507
31235
|
console.log(" Updated mancode project facts.");
|
|
30508
|
-
return
|
|
31236
|
+
return EXIT_OK8;
|
|
30509
31237
|
}
|
|
30510
31238
|
console.log("\u2713 \u626B\u63CF\u9879\u76EE\u8BBE\u8BA1 token...");
|
|
30511
|
-
const tokens = await scanAesthetics(
|
|
30512
|
-
await fs8.mkdir(
|
|
31239
|
+
const tokens = await scanAesthetics(scanRoot, uiLibraryHint, scopeRoot);
|
|
31240
|
+
await fs8.mkdir(path59.dirname(tokensPath), { recursive: true });
|
|
30513
31241
|
await fs8.writeFile(
|
|
30514
31242
|
tokensPath,
|
|
30515
31243
|
`${JSON.stringify(tokens, null, 2)}
|
|
@@ -30521,7 +31249,7 @@ async function refreshV3Style(rootDir) {
|
|
|
30521
31249
|
console.log(
|
|
30522
31250
|
"\u5DF2\u66F4\u65B0 .mancode/shared/context/project.json \u548C .mancode/local/cache/style-tokens.json"
|
|
30523
31251
|
);
|
|
30524
|
-
return
|
|
31252
|
+
return EXIT_OK8;
|
|
30525
31253
|
} catch (error) {
|
|
30526
31254
|
const message = error instanceof Error ? error.message : String(error);
|
|
30527
31255
|
console.error(`\u2717 mancode style refresh failed: ${message}`);
|
|
@@ -30543,7 +31271,7 @@ async function printStaticPlatformRefreshHint(rootDir) {
|
|
|
30543
31271
|
);
|
|
30544
31272
|
}
|
|
30545
31273
|
async function refreshLegacyStateContext(rootDir, profile, uiLibrary) {
|
|
30546
|
-
const statePath =
|
|
31274
|
+
const statePath = path59.join(rootDir, ".mancode", "state.json");
|
|
30547
31275
|
try {
|
|
30548
31276
|
const state = JSON.parse(await fs8.readFile(statePath, "utf-8"));
|
|
30549
31277
|
const stack = [...profile.languages, ...profile.frameworks];
|
|
@@ -30567,7 +31295,7 @@ async function refreshLegacyStateContext(rootDir, profile, uiLibrary) {
|
|
|
30567
31295
|
async function readInstalledPlatforms2(rootDir) {
|
|
30568
31296
|
try {
|
|
30569
31297
|
const raw = await fs8.readFile(
|
|
30570
|
-
|
|
31298
|
+
path59.join(rootDir, ".mancode", "config.json"),
|
|
30571
31299
|
"utf-8"
|
|
30572
31300
|
);
|
|
30573
31301
|
const config = JSON.parse(raw);
|
|
@@ -30586,12 +31314,32 @@ async function pathExists12(p) {
|
|
|
30586
31314
|
return false;
|
|
30587
31315
|
}
|
|
30588
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
|
+
}
|
|
30589
31337
|
|
|
30590
31338
|
// src/commands/status.ts
|
|
30591
31339
|
import { spawn } from "child_process";
|
|
30592
31340
|
import { promises as fs9 } from "fs";
|
|
30593
|
-
import
|
|
30594
|
-
import
|
|
31341
|
+
import path60 from "path";
|
|
31342
|
+
import process11 from "process";
|
|
30595
31343
|
|
|
30596
31344
|
// src/team/assessment.ts
|
|
30597
31345
|
function assessTeam(input) {
|
|
@@ -30742,19 +31490,19 @@ function assertTimestamp3(value) {
|
|
|
30742
31490
|
|
|
30743
31491
|
// src/commands/status.ts
|
|
30744
31492
|
var HOOK_ESTIMATE_TIMEOUT_MS = 2e3;
|
|
30745
|
-
var
|
|
30746
|
-
var
|
|
31493
|
+
var EXIT_OK9 = 0;
|
|
31494
|
+
var EXIT_NOT_INITIALIZED6 = 1;
|
|
30747
31495
|
var EXIT_CORRUPT_STATE2 = 2;
|
|
30748
|
-
async function status(rootDir =
|
|
30749
|
-
const stateFile =
|
|
30750
|
-
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");
|
|
30751
31499
|
if (await pathExists13(v3SchemaFile)) {
|
|
30752
31500
|
return statusV3(rootDir, options);
|
|
30753
31501
|
}
|
|
30754
31502
|
if (!await pathExists13(stateFile)) {
|
|
30755
31503
|
console.error("\u2717 mancode not initialized.");
|
|
30756
31504
|
console.error(" Run `mancode init` to get started.");
|
|
30757
|
-
return
|
|
31505
|
+
return EXIT_NOT_INITIALIZED6;
|
|
30758
31506
|
}
|
|
30759
31507
|
let state;
|
|
30760
31508
|
try {
|
|
@@ -30811,7 +31559,7 @@ async function status(rootDir = process10.cwd(), options = {}) {
|
|
|
30811
31559
|
} else {
|
|
30812
31560
|
printText(result2);
|
|
30813
31561
|
}
|
|
30814
|
-
return
|
|
31562
|
+
return EXIT_OK9;
|
|
30815
31563
|
}
|
|
30816
31564
|
async function statusV3(rootDir, options) {
|
|
30817
31565
|
try {
|
|
@@ -30952,7 +31700,7 @@ async function statusV3(rootDir, options) {
|
|
|
30952
31700
|
} else {
|
|
30953
31701
|
printV3Text(result2);
|
|
30954
31702
|
}
|
|
30955
|
-
return
|
|
31703
|
+
return EXIT_OK9;
|
|
30956
31704
|
} catch (error) {
|
|
30957
31705
|
const message = error instanceof Error ? error.message : String(error);
|
|
30958
31706
|
console.error("\u2717 .mancode/schema.json is corrupt or incomplete.");
|
|
@@ -30981,7 +31729,7 @@ function toContinuityStatus(result2) {
|
|
|
30981
31729
|
};
|
|
30982
31730
|
}
|
|
30983
31731
|
async function readV3StatusSession(rootDir) {
|
|
30984
|
-
const sessionId =
|
|
31732
|
+
const sessionId = process11.env.MANCODE_SESSION_ID;
|
|
30985
31733
|
if (sessionId === void 0 || !sessionId) return null;
|
|
30986
31734
|
try {
|
|
30987
31735
|
assertUlid(sessionId, "status sessionId");
|
|
@@ -30992,10 +31740,10 @@ async function readV3StatusSession(rootDir) {
|
|
|
30992
31740
|
}
|
|
30993
31741
|
async function shouldRefreshProject(rootDir, state) {
|
|
30994
31742
|
if (state.projectMode !== "generic") return false;
|
|
30995
|
-
const hasGit = await pathExists13(
|
|
31743
|
+
const hasGit = await pathExists13(path60.join(rootDir, ".git"));
|
|
30996
31744
|
if (hasGit) return true;
|
|
30997
31745
|
for (const manifest of PROJECT_MANIFESTS) {
|
|
30998
|
-
if (await pathExists13(
|
|
31746
|
+
if (await pathExists13(path60.join(rootDir, manifest))) return true;
|
|
30999
31747
|
}
|
|
31000
31748
|
return false;
|
|
31001
31749
|
}
|
|
@@ -31039,19 +31787,19 @@ async function getCurrentWorkflow(rootDir, taskId) {
|
|
|
31039
31787
|
}
|
|
31040
31788
|
async function getProjectName(rootDir) {
|
|
31041
31789
|
try {
|
|
31042
|
-
const raw = await fs9.readFile(
|
|
31790
|
+
const raw = await fs9.readFile(path60.join(rootDir, "package.json"), "utf-8");
|
|
31043
31791
|
const pkg = JSON.parse(raw);
|
|
31044
31792
|
if (pkg.name && typeof pkg.name === "string") {
|
|
31045
31793
|
return pkg.name;
|
|
31046
31794
|
}
|
|
31047
31795
|
} catch {
|
|
31048
31796
|
}
|
|
31049
|
-
return
|
|
31797
|
+
return path60.basename(rootDir);
|
|
31050
31798
|
}
|
|
31051
31799
|
async function readConfig3(rootDir) {
|
|
31052
31800
|
try {
|
|
31053
31801
|
const raw = await fs9.readFile(
|
|
31054
|
-
|
|
31802
|
+
path60.join(rootDir, ".mancode", "config.json"),
|
|
31055
31803
|
"utf-8"
|
|
31056
31804
|
);
|
|
31057
31805
|
return JSON.parse(raw);
|
|
@@ -31079,9 +31827,9 @@ function getEffectiveTeamStatus(state, config, detected) {
|
|
|
31079
31827
|
}
|
|
31080
31828
|
async function checkHooks(rootDir) {
|
|
31081
31829
|
const [sessionStart, userPromptSubmit, registered] = await Promise.all([
|
|
31082
|
-
pathExists13(
|
|
31830
|
+
pathExists13(path60.join(rootDir, ".mancode", "hooks", "session-start.mjs")),
|
|
31083
31831
|
pathExists13(
|
|
31084
|
-
|
|
31832
|
+
path60.join(rootDir, ".mancode", "hooks", "user-prompt-submit.mjs")
|
|
31085
31833
|
),
|
|
31086
31834
|
isRegistered(rootDir)
|
|
31087
31835
|
]);
|
|
@@ -31090,7 +31838,7 @@ async function checkHooks(rootDir) {
|
|
|
31090
31838
|
async function isRegistered(rootDir) {
|
|
31091
31839
|
try {
|
|
31092
31840
|
const raw = await fs9.readFile(
|
|
31093
|
-
|
|
31841
|
+
path60.join(rootDir, ".claude", "settings.json"),
|
|
31094
31842
|
"utf-8"
|
|
31095
31843
|
);
|
|
31096
31844
|
const settings = JSON.parse(raw);
|
|
@@ -31100,9 +31848,9 @@ async function isRegistered(rootDir) {
|
|
|
31100
31848
|
}
|
|
31101
31849
|
}
|
|
31102
31850
|
function hooksRegistered2(settings) {
|
|
31103
|
-
if (!
|
|
31851
|
+
if (!isRecord12(settings)) return false;
|
|
31104
31852
|
const hooks = settings.hooks;
|
|
31105
|
-
if (!
|
|
31853
|
+
if (!isRecord12(hooks)) return false;
|
|
31106
31854
|
return hasHookCommand2(hooks.SessionStart, ".mancode/hooks/session-start.mjs") && hasHookCommand2(
|
|
31107
31855
|
hooks.UserPromptSubmit,
|
|
31108
31856
|
".mancode/hooks/user-prompt-submit.mjs"
|
|
@@ -31111,15 +31859,15 @@ function hooksRegistered2(settings) {
|
|
|
31111
31859
|
function hasHookCommand2(value, needle) {
|
|
31112
31860
|
if (!Array.isArray(value)) return false;
|
|
31113
31861
|
return value.some((group) => {
|
|
31114
|
-
if (!
|
|
31862
|
+
if (!isRecord12(group) || !Array.isArray(group.hooks)) return false;
|
|
31115
31863
|
return group.hooks.some((hook) => {
|
|
31116
|
-
if (!
|
|
31864
|
+
if (!isRecord12(hook) || typeof hook.command !== "string") return false;
|
|
31117
31865
|
return hook.command.includes(needle);
|
|
31118
31866
|
});
|
|
31119
31867
|
});
|
|
31120
31868
|
}
|
|
31121
31869
|
async function estimateHookInjection(rootDir) {
|
|
31122
|
-
const hookPath =
|
|
31870
|
+
const hookPath = path60.join(
|
|
31123
31871
|
rootDir,
|
|
31124
31872
|
".mancode",
|
|
31125
31873
|
"hooks",
|
|
@@ -31140,7 +31888,7 @@ async function estimateHookInjection(rootDir) {
|
|
|
31140
31888
|
}
|
|
31141
31889
|
function runHookEstimate(rootDir, hookPath) {
|
|
31142
31890
|
return new Promise((resolve, reject) => {
|
|
31143
|
-
const child = spawn(
|
|
31891
|
+
const child = spawn(process11.execPath, [hookPath], {
|
|
31144
31892
|
cwd: rootDir,
|
|
31145
31893
|
stdio: ["pipe", "pipe", "ignore"]
|
|
31146
31894
|
});
|
|
@@ -31338,7 +32086,7 @@ function formatTeamStatus(team) {
|
|
|
31338
32086
|
function workflowStepMax(mode) {
|
|
31339
32087
|
return maxWorkflowStep(mode);
|
|
31340
32088
|
}
|
|
31341
|
-
function
|
|
32089
|
+
function isRecord12(value) {
|
|
31342
32090
|
return typeof value === "object" && value !== null;
|
|
31343
32091
|
}
|
|
31344
32092
|
async function pathExists13(p) {
|
|
@@ -32616,8 +33364,8 @@ function assertPositiveRevision2(value, label) {
|
|
|
32616
33364
|
}
|
|
32617
33365
|
|
|
32618
33366
|
// src/team/git-ref-handoff-repair.ts
|
|
32619
|
-
import { lstat as
|
|
32620
|
-
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";
|
|
32621
33369
|
|
|
32622
33370
|
// src/team/git-ref-operation.ts
|
|
32623
33371
|
import { execFile as execFileCallback6 } from "child_process";
|
|
@@ -35195,7 +35943,7 @@ async function recoverGitRefHandoffRepairs(projectRoot) {
|
|
|
35195
35943
|
}
|
|
35196
35944
|
async function recoverGitRefHandoffRepair(projectRoot, operationId, transportReceipt) {
|
|
35197
35945
|
assertUlid(operationId, "git-ref handoff repair operationId");
|
|
35198
|
-
const root =
|
|
35946
|
+
const root = path61.resolve(projectRoot);
|
|
35199
35947
|
let journal = await requireJournal2(root, operationId);
|
|
35200
35948
|
if (journal.state === "committed" || journal.state === "aborted") {
|
|
35201
35949
|
return recoveryResult2(journal);
|
|
@@ -35274,7 +36022,7 @@ async function recoverGitRefHandoffRepair(projectRoot, operationId, transportRec
|
|
|
35274
36022
|
}
|
|
35275
36023
|
}
|
|
35276
36024
|
async function prepareHandoffRepairWhileTaskLocked(projectRoot, rawPrepared) {
|
|
35277
|
-
const root =
|
|
36025
|
+
const root = path61.resolve(projectRoot);
|
|
35278
36026
|
const prepared2 = parsePrepared2(rawPrepared);
|
|
35279
36027
|
const runtime = await readProjectRuntimeContext(root);
|
|
35280
36028
|
const previousMetadata = bundleMetadata2(prepared2.predecessorBundle);
|
|
@@ -35337,7 +36085,7 @@ async function restorePredecessorMetadata2(projectRoot, journal) {
|
|
|
35337
36085
|
);
|
|
35338
36086
|
}
|
|
35339
36087
|
async function replaceMetadataVerified(projectRoot, expected, targetMetadata, alternateExpected) {
|
|
35340
|
-
const target =
|
|
36088
|
+
const target = path61.join(
|
|
35341
36089
|
taskRootPath(projectRoot, targetMetadata.taskRef),
|
|
35342
36090
|
"metadata.json"
|
|
35343
36091
|
);
|
|
@@ -35463,7 +36211,7 @@ async function createJournal3(projectRoot, journal) {
|
|
|
35463
36211
|
await ensureJournalDirectory2(projectRoot);
|
|
35464
36212
|
const target = journalPath3(projectRoot, journal.operationId);
|
|
35465
36213
|
try {
|
|
35466
|
-
await
|
|
36214
|
+
await writeFile42(target, serialize13(journal), {
|
|
35467
36215
|
encoding: "utf8",
|
|
35468
36216
|
flag: "wx"
|
|
35469
36217
|
});
|
|
@@ -35482,10 +36230,10 @@ async function replaceJournal3(projectRoot, journal) {
|
|
|
35482
36230
|
async function requireJournal2(projectRoot, operationId) {
|
|
35483
36231
|
try {
|
|
35484
36232
|
return parseJournal3(
|
|
35485
|
-
JSON.parse(await
|
|
36233
|
+
JSON.parse(await readFile43(journalPath3(projectRoot, operationId), "utf8"))
|
|
35486
36234
|
);
|
|
35487
36235
|
} catch (error) {
|
|
35488
|
-
if (error instanceof SyntaxError ||
|
|
36236
|
+
if (error instanceof SyntaxError || isNotFound30(error)) {
|
|
35489
36237
|
throw new Error("MANCODE_HANDOFF_REPAIR_JOURNAL_NOT_FOUND");
|
|
35490
36238
|
}
|
|
35491
36239
|
throw error;
|
|
@@ -35496,7 +36244,7 @@ async function listJournals2(projectRoot) {
|
|
|
35496
36244
|
try {
|
|
35497
36245
|
entries = await readdir19(journalDirectory2(projectRoot));
|
|
35498
36246
|
} catch (error) {
|
|
35499
|
-
if (
|
|
36247
|
+
if (isNotFound30(error)) return [];
|
|
35500
36248
|
throw error;
|
|
35501
36249
|
}
|
|
35502
36250
|
const journals = [];
|
|
@@ -35505,8 +36253,8 @@ async function listJournals2(projectRoot) {
|
|
|
35505
36253
|
journals.push(
|
|
35506
36254
|
parseJournal3(
|
|
35507
36255
|
JSON.parse(
|
|
35508
|
-
await
|
|
35509
|
-
|
|
36256
|
+
await readFile43(
|
|
36257
|
+
path61.join(journalDirectory2(projectRoot), entry),
|
|
35510
36258
|
"utf8"
|
|
35511
36259
|
)
|
|
35512
36260
|
)
|
|
@@ -35516,43 +36264,43 @@ async function listJournals2(projectRoot) {
|
|
|
35516
36264
|
return journals;
|
|
35517
36265
|
}
|
|
35518
36266
|
async function readSafeFile2(target) {
|
|
35519
|
-
const before = await
|
|
36267
|
+
const before = await lstat23(target);
|
|
35520
36268
|
if (!before.isFile() || before.isSymbolicLink()) {
|
|
35521
36269
|
throw new Error("MANCODE_ARTIFACT_PATH_UNSAFE");
|
|
35522
36270
|
}
|
|
35523
|
-
const content = await
|
|
35524
|
-
const after = await
|
|
36271
|
+
const content = await readFile43(target, "utf8");
|
|
36272
|
+
const after = await lstat23(target);
|
|
35525
36273
|
if (!after.isFile() || after.isSymbolicLink() || before.dev !== after.dev || before.ino !== after.ino) {
|
|
35526
36274
|
throw new Error("MANCODE_ARTIFACT_PATH_UNSAFE");
|
|
35527
36275
|
}
|
|
35528
36276
|
return content;
|
|
35529
36277
|
}
|
|
35530
36278
|
async function atomicWrite2(target, content) {
|
|
35531
|
-
const temporary =
|
|
35532
|
-
|
|
35533
|
-
`.${
|
|
36279
|
+
const temporary = path61.join(
|
|
36280
|
+
path61.dirname(target),
|
|
36281
|
+
`.${path61.basename(target)}.${process.pid}.${Date.now()}.tmp`
|
|
35534
36282
|
);
|
|
35535
|
-
await
|
|
36283
|
+
await writeFile42(temporary, content, { encoding: "utf8", flag: "wx" });
|
|
35536
36284
|
await replaceFileAtomically(temporary, target);
|
|
35537
36285
|
}
|
|
35538
36286
|
async function ensureJournalDirectory2(projectRoot) {
|
|
35539
|
-
let current =
|
|
36287
|
+
let current = path61.resolve(projectRoot);
|
|
35540
36288
|
for (const segment of [".mancode", "local", "journals", "git-ref-handoff"]) {
|
|
35541
|
-
current =
|
|
36289
|
+
current = path61.join(current, segment);
|
|
35542
36290
|
try {
|
|
35543
|
-
await
|
|
36291
|
+
await mkdir37(current);
|
|
35544
36292
|
} catch (error) {
|
|
35545
36293
|
if (!isAlreadyExists24(error)) throw error;
|
|
35546
36294
|
}
|
|
35547
|
-
const entry = await
|
|
36295
|
+
const entry = await lstat23(current);
|
|
35548
36296
|
if (!entry.isDirectory() || entry.isSymbolicLink()) {
|
|
35549
36297
|
throw new Error("MANCODE_ARTIFACT_PATH_UNSAFE");
|
|
35550
36298
|
}
|
|
35551
36299
|
}
|
|
35552
36300
|
}
|
|
35553
36301
|
function journalDirectory2(projectRoot) {
|
|
35554
|
-
return
|
|
35555
|
-
|
|
36302
|
+
return path61.join(
|
|
36303
|
+
path61.resolve(projectRoot),
|
|
35556
36304
|
".mancode",
|
|
35557
36305
|
"local",
|
|
35558
36306
|
"journals",
|
|
@@ -35561,7 +36309,7 @@ function journalDirectory2(projectRoot) {
|
|
|
35561
36309
|
}
|
|
35562
36310
|
function journalPath3(projectRoot, operationId) {
|
|
35563
36311
|
assertUlid(operationId, "git-ref handoff repair operationId");
|
|
35564
|
-
return
|
|
36312
|
+
return path61.join(journalDirectory2(projectRoot), `${operationId}.json`);
|
|
35565
36313
|
}
|
|
35566
36314
|
function serialize13(value) {
|
|
35567
36315
|
return `${JSON.stringify(value, null, 2)}
|
|
@@ -35576,7 +36324,7 @@ function parseTimestamp15(value) {
|
|
|
35576
36324
|
function isAlreadyExists24(error) {
|
|
35577
36325
|
return typeof error === "object" && error !== null && "code" in error && error.code === "EEXIST";
|
|
35578
36326
|
}
|
|
35579
|
-
function
|
|
36327
|
+
function isNotFound30(error) {
|
|
35580
36328
|
return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
|
|
35581
36329
|
}
|
|
35582
36330
|
|
|
@@ -35660,8 +36408,8 @@ function parseReceipt(value) {
|
|
|
35660
36408
|
}
|
|
35661
36409
|
|
|
35662
36410
|
// src/team/policy-operation.ts
|
|
35663
|
-
import { lstat as
|
|
35664
|
-
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";
|
|
35665
36413
|
async function updateTeamPolicy(input) {
|
|
35666
36414
|
const operationId = input.operationId ?? createUlid();
|
|
35667
36415
|
const eventId = createUlid();
|
|
@@ -35672,7 +36420,7 @@ async function updateTeamPolicy(input) {
|
|
|
35672
36420
|
throw new Error("MANCODE_TEAM_POLICY_INVALID");
|
|
35673
36421
|
}
|
|
35674
36422
|
const now = input.now ?? /* @__PURE__ */ new Date();
|
|
35675
|
-
const root =
|
|
36423
|
+
const root = path62.resolve(input.projectRoot);
|
|
35676
36424
|
const runtime = await readProjectRuntimeContext(root);
|
|
35677
36425
|
const store = resolveCoordinationEntityHomeStore(
|
|
35678
36426
|
runtime.entityHomeStoreContext
|
|
@@ -35753,7 +36501,7 @@ async function applyTeamTransportSet(input, write2) {
|
|
|
35753
36501
|
}
|
|
35754
36502
|
const remote = transportRemote(input.mode, input.remote);
|
|
35755
36503
|
const now = input.now ?? /* @__PURE__ */ new Date();
|
|
35756
|
-
const root =
|
|
36504
|
+
const root = path62.resolve(input.projectRoot);
|
|
35757
36505
|
const runtime = await readProjectRuntimeContext(root);
|
|
35758
36506
|
const store = resolveCoordinationEntityHomeStore(
|
|
35759
36507
|
runtime.entityHomeStoreContext
|
|
@@ -35886,9 +36634,9 @@ async function assertTransportAuthorityEmpty(projectRoot, store) {
|
|
|
35886
36634
|
listClaims(store),
|
|
35887
36635
|
listHandoffs(store),
|
|
35888
36636
|
directoryHasEntries(taskHeadDirectory(store)),
|
|
35889
|
-
directoryHasEntries(
|
|
36637
|
+
directoryHasEntries(path62.join(store.root, "transport-migrations")),
|
|
35890
36638
|
directoryHasEntries(
|
|
35891
|
-
|
|
36639
|
+
path62.join(projectRoot, ".mancode", "shared", "team", "transport")
|
|
35892
36640
|
),
|
|
35893
36641
|
pathExists14(gitRefCachePath(projectRoot))
|
|
35894
36642
|
]);
|
|
@@ -35918,21 +36666,21 @@ function assertPositiveRevision5(value, label) {
|
|
|
35918
36666
|
}
|
|
35919
36667
|
}
|
|
35920
36668
|
function teamPolicyPath(projectRoot) {
|
|
35921
|
-
return
|
|
36669
|
+
return path62.join(projectRoot, ".mancode", "shared", "team", "policy.json");
|
|
35922
36670
|
}
|
|
35923
36671
|
function projectConfigPath(projectRoot) {
|
|
35924
|
-
return
|
|
36672
|
+
return path62.join(projectRoot, ".mancode", "shared", "config.json");
|
|
35925
36673
|
}
|
|
35926
36674
|
async function writeJsonAtomic4(target, value) {
|
|
35927
|
-
await
|
|
35928
|
-
await assertPlainDirectory(
|
|
36675
|
+
await mkdir38(path62.dirname(target), { recursive: true });
|
|
36676
|
+
await assertPlainDirectory(path62.dirname(target));
|
|
35929
36677
|
await assertPlainFileOrMissing(target);
|
|
35930
|
-
const temporary =
|
|
35931
|
-
|
|
35932
|
-
`.${
|
|
36678
|
+
const temporary = path62.join(
|
|
36679
|
+
path62.dirname(target),
|
|
36680
|
+
`.${path62.basename(target)}.${process.pid}.${createUlid()}.tmp`
|
|
35933
36681
|
);
|
|
35934
36682
|
try {
|
|
35935
|
-
await
|
|
36683
|
+
await writeFile43(temporary, `${JSON.stringify(value, null, 2)}
|
|
35936
36684
|
`, {
|
|
35937
36685
|
encoding: "utf8",
|
|
35938
36686
|
flag: "wx"
|
|
@@ -35944,61 +36692,61 @@ async function writeJsonAtomic4(target, value) {
|
|
|
35944
36692
|
}
|
|
35945
36693
|
}
|
|
35946
36694
|
async function assertPlainDirectory(target) {
|
|
35947
|
-
const entry = await
|
|
36695
|
+
const entry = await lstat24(target);
|
|
35948
36696
|
if (!entry.isDirectory() || entry.isSymbolicLink()) {
|
|
35949
36697
|
throw new Error("MANCODE_ARTIFACT_PATH_UNSAFE");
|
|
35950
36698
|
}
|
|
35951
36699
|
}
|
|
35952
36700
|
async function assertPlainFileOrMissing(target) {
|
|
35953
36701
|
try {
|
|
35954
|
-
const entry = await
|
|
36702
|
+
const entry = await lstat24(target);
|
|
35955
36703
|
if (!entry.isFile() || entry.isSymbolicLink()) {
|
|
35956
36704
|
throw new Error("MANCODE_ARTIFACT_PATH_UNSAFE");
|
|
35957
36705
|
}
|
|
35958
36706
|
} catch (error) {
|
|
35959
|
-
if (
|
|
36707
|
+
if (isNotFound31(error)) return;
|
|
35960
36708
|
throw error;
|
|
35961
36709
|
}
|
|
35962
36710
|
}
|
|
35963
36711
|
async function directoryHasEntries(target) {
|
|
35964
36712
|
try {
|
|
35965
|
-
const entry = await
|
|
36713
|
+
const entry = await lstat24(target);
|
|
35966
36714
|
if (!entry.isDirectory() || entry.isSymbolicLink()) {
|
|
35967
36715
|
throw new Error("MANCODE_ARTIFACT_PATH_UNSAFE");
|
|
35968
36716
|
}
|
|
35969
36717
|
return (await readdir20(target)).length > 0;
|
|
35970
36718
|
} catch (error) {
|
|
35971
|
-
if (
|
|
36719
|
+
if (isNotFound31(error)) return false;
|
|
35972
36720
|
throw error;
|
|
35973
36721
|
}
|
|
35974
36722
|
}
|
|
35975
36723
|
async function pathExists14(target) {
|
|
35976
36724
|
try {
|
|
35977
|
-
await
|
|
36725
|
+
await lstat24(target);
|
|
35978
36726
|
return true;
|
|
35979
36727
|
} catch (error) {
|
|
35980
|
-
if (
|
|
36728
|
+
if (isNotFound31(error)) return false;
|
|
35981
36729
|
throw error;
|
|
35982
36730
|
}
|
|
35983
36731
|
}
|
|
35984
36732
|
async function releaseLocks4(locks) {
|
|
35985
36733
|
await Promise.allSettled([...locks].reverse().map((lock) => lock.release()));
|
|
35986
36734
|
}
|
|
35987
|
-
function
|
|
36735
|
+
function isNotFound31(error) {
|
|
35988
36736
|
return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
|
|
35989
36737
|
}
|
|
35990
36738
|
|
|
35991
36739
|
// src/team/transport-migration-adapters.ts
|
|
35992
36740
|
import {
|
|
35993
|
-
lstat as
|
|
35994
|
-
mkdir as
|
|
35995
|
-
readFile as
|
|
36741
|
+
lstat as lstat25,
|
|
36742
|
+
mkdir as mkdir39,
|
|
36743
|
+
readFile as readFile44,
|
|
35996
36744
|
readdir as readdir21,
|
|
35997
36745
|
rename as rename12,
|
|
35998
36746
|
unlink as unlink4,
|
|
35999
|
-
writeFile as
|
|
36747
|
+
writeFile as writeFile44
|
|
36000
36748
|
} from "fs/promises";
|
|
36001
|
-
import
|
|
36749
|
+
import path63 from "path";
|
|
36002
36750
|
|
|
36003
36751
|
// src/team/transport-migration.ts
|
|
36004
36752
|
var DIGEST_PATTERN7 = /^sha256:[a-f0-9]{64}$/;
|
|
@@ -36961,7 +37709,7 @@ function parseTaskSnapshot(value) {
|
|
|
36961
37709
|
assertUlid(ownerActorId, "transport migration task ownerActorId");
|
|
36962
37710
|
}
|
|
36963
37711
|
const taskRevision = parsePositiveInteger5(value.taskRevision, "taskRevision");
|
|
36964
|
-
const ownershipEpoch =
|
|
37712
|
+
const ownershipEpoch = parseNonNegativeInteger3(
|
|
36965
37713
|
value.ownershipEpoch,
|
|
36966
37714
|
"ownershipEpoch"
|
|
36967
37715
|
);
|
|
@@ -37038,7 +37786,7 @@ function parsePositiveInteger5(value, label) {
|
|
|
37038
37786
|
}
|
|
37039
37787
|
return value;
|
|
37040
37788
|
}
|
|
37041
|
-
function
|
|
37789
|
+
function parseNonNegativeInteger3(value, label) {
|
|
37042
37790
|
if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 0) {
|
|
37043
37791
|
throw new Error(`${label} must be a non-negative integer`);
|
|
37044
37792
|
}
|
|
@@ -37070,7 +37818,7 @@ function compareUtf813(left, right) {
|
|
|
37070
37818
|
var STAGE_DIRECTORY = "transport-migrations";
|
|
37071
37819
|
var COLLECTIONS = ["claims", "handoffs", "task-heads"];
|
|
37072
37820
|
async function createTransportMigrationFileAdapters(input) {
|
|
37073
|
-
const projectRoot =
|
|
37821
|
+
const projectRoot = path63.resolve(input.projectRoot);
|
|
37074
37822
|
assertUlid(input.actorId, "transport migration adapter actorId");
|
|
37075
37823
|
if (input.operationId !== void 0) {
|
|
37076
37824
|
assertUlid(input.operationId, "transport migration adapter operationId");
|
|
@@ -37122,7 +37870,7 @@ async function createTransportMigrationFileAdapters(input) {
|
|
|
37122
37870
|
var FileSystemTransportMigrationConfigAdapter = class {
|
|
37123
37871
|
constructor(projectRoot, coordinationStore) {
|
|
37124
37872
|
this.coordinationStore = coordinationStore;
|
|
37125
|
-
this.projectRoot =
|
|
37873
|
+
this.projectRoot = path63.resolve(projectRoot);
|
|
37126
37874
|
}
|
|
37127
37875
|
projectRoot;
|
|
37128
37876
|
async read() {
|
|
@@ -37975,27 +38723,27 @@ async function publishMigrationActorProfiles(projectRoot, profiles) {
|
|
|
37975
38723
|
}
|
|
37976
38724
|
}
|
|
37977
38725
|
async function archiveLocalCoordinationCollections(store, operationId) {
|
|
37978
|
-
const archiveRoot =
|
|
38726
|
+
const archiveRoot = path63.join(
|
|
37979
38727
|
store.root,
|
|
37980
38728
|
STAGE_DIRECTORY,
|
|
37981
38729
|
"archive",
|
|
37982
38730
|
operationId
|
|
37983
38731
|
);
|
|
37984
|
-
await
|
|
38732
|
+
await mkdir39(archiveRoot, { recursive: true });
|
|
37985
38733
|
const directories = {
|
|
37986
38734
|
claims: claimDirectory(store),
|
|
37987
38735
|
handoffs: handoffDirectory(store),
|
|
37988
38736
|
"task-heads": taskHeadDirectory(store)
|
|
37989
38737
|
};
|
|
37990
38738
|
for (const name of COLLECTIONS) {
|
|
37991
|
-
const archived =
|
|
37992
|
-
const absent =
|
|
38739
|
+
const archived = path63.join(archiveRoot, name);
|
|
38740
|
+
const absent = path63.join(archiveRoot, `${name}.absent`);
|
|
37993
38741
|
if (await pathKind(archived) === "directory" || await pathKind(absent) === "file") {
|
|
37994
38742
|
continue;
|
|
37995
38743
|
}
|
|
37996
38744
|
const sourceKind = await pathKind(directories[name]);
|
|
37997
38745
|
if (sourceKind === null) {
|
|
37998
|
-
await
|
|
38746
|
+
await writeFile44(absent, "\n", { encoding: "utf8", flag: "wx" });
|
|
37999
38747
|
continue;
|
|
38000
38748
|
}
|
|
38001
38749
|
if (sourceKind !== "directory") {
|
|
@@ -38010,7 +38758,7 @@ async function listActorProfiles(projectRoot) {
|
|
|
38010
38758
|
try {
|
|
38011
38759
|
entries = await readdir21(directory);
|
|
38012
38760
|
} catch (error) {
|
|
38013
|
-
if (
|
|
38761
|
+
if (isNotFound32(error)) return [];
|
|
38014
38762
|
throw error;
|
|
38015
38763
|
}
|
|
38016
38764
|
const profiles = [];
|
|
@@ -38027,19 +38775,19 @@ async function listActorProfiles(projectRoot) {
|
|
|
38027
38775
|
return profiles;
|
|
38028
38776
|
}
|
|
38029
38777
|
async function listSharedTaskRefs(projectRoot) {
|
|
38030
|
-
const directory =
|
|
38778
|
+
const directory = path63.join(projectRoot, ".mancode", "shared", "workflows");
|
|
38031
38779
|
let entries;
|
|
38032
38780
|
try {
|
|
38033
38781
|
entries = await readdir21(directory);
|
|
38034
38782
|
} catch (error) {
|
|
38035
|
-
if (
|
|
38783
|
+
if (isNotFound32(error)) return [];
|
|
38036
38784
|
throw error;
|
|
38037
38785
|
}
|
|
38038
38786
|
const refs = [];
|
|
38039
38787
|
for (const taskId of entries.sort(compareUtf814)) {
|
|
38040
38788
|
assertUlid(taskId, "shared workflow directory");
|
|
38041
|
-
const
|
|
38042
|
-
if (!
|
|
38789
|
+
const stat5 = await lstat25(path63.join(directory, taskId));
|
|
38790
|
+
if (!stat5.isDirectory() || stat5.isSymbolicLink()) {
|
|
38043
38791
|
throw new Error("MANCODE_CONTEXT_PATH_UNSAFE");
|
|
38044
38792
|
}
|
|
38045
38793
|
refs.push({ namespace: "shared", taskId });
|
|
@@ -38050,7 +38798,7 @@ async function readTaskSnapshotOrNull(projectRoot, taskRef) {
|
|
|
38050
38798
|
try {
|
|
38051
38799
|
return await new V3ContextStore(projectRoot).readTaskSnapshot(taskRef);
|
|
38052
38800
|
} catch (error) {
|
|
38053
|
-
if (error instanceof Error && (error.message === "MANCODE_TASK_NOT_FOUND" ||
|
|
38801
|
+
if (error instanceof Error && (error.message === "MANCODE_TASK_NOT_FOUND" || isNotFound32(error))) {
|
|
38054
38802
|
return null;
|
|
38055
38803
|
}
|
|
38056
38804
|
throw error;
|
|
@@ -38112,7 +38860,7 @@ async function readStagedRecord(store, operationId) {
|
|
|
38112
38860
|
);
|
|
38113
38861
|
}
|
|
38114
38862
|
function stagedPath(store, operationId) {
|
|
38115
|
-
return
|
|
38863
|
+
return path63.join(
|
|
38116
38864
|
store.root,
|
|
38117
38865
|
STAGE_DIRECTORY,
|
|
38118
38866
|
"staged",
|
|
@@ -38120,7 +38868,7 @@ function stagedPath(store, operationId) {
|
|
|
38120
38868
|
);
|
|
38121
38869
|
}
|
|
38122
38870
|
function establishedPath(store, operationId) {
|
|
38123
|
-
return
|
|
38871
|
+
return path63.join(
|
|
38124
38872
|
store.root,
|
|
38125
38873
|
STAGE_DIRECTORY,
|
|
38126
38874
|
"established",
|
|
@@ -38128,12 +38876,12 @@ function establishedPath(store, operationId) {
|
|
|
38128
38876
|
);
|
|
38129
38877
|
}
|
|
38130
38878
|
function projectConfigPath2(projectRoot) {
|
|
38131
|
-
return
|
|
38879
|
+
return path63.join(projectRoot, ".mancode", "shared", "config.json");
|
|
38132
38880
|
}
|
|
38133
38881
|
async function readProjectConfigFile(projectRoot) {
|
|
38134
38882
|
try {
|
|
38135
38883
|
return parseProjectConfig(
|
|
38136
|
-
JSON.parse(await
|
|
38884
|
+
JSON.parse(await readFile44(projectConfigPath2(projectRoot), "utf8"))
|
|
38137
38885
|
);
|
|
38138
38886
|
} catch (error) {
|
|
38139
38887
|
if (error instanceof SyntaxError) {
|
|
@@ -38143,14 +38891,14 @@ async function readProjectConfigFile(projectRoot) {
|
|
|
38143
38891
|
}
|
|
38144
38892
|
}
|
|
38145
38893
|
async function writeJsonAtomic5(target, value) {
|
|
38146
|
-
await
|
|
38147
|
-
await assertPlainDirectory2(
|
|
38148
|
-
const temporary =
|
|
38149
|
-
|
|
38150
|
-
`.${
|
|
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`
|
|
38151
38899
|
);
|
|
38152
38900
|
try {
|
|
38153
|
-
await
|
|
38901
|
+
await writeFile44(temporary, serialize14(value), {
|
|
38154
38902
|
encoding: "utf8",
|
|
38155
38903
|
flag: "wx"
|
|
38156
38904
|
});
|
|
@@ -38161,10 +38909,10 @@ async function writeJsonAtomic5(target, value) {
|
|
|
38161
38909
|
}
|
|
38162
38910
|
}
|
|
38163
38911
|
async function writeJsonExclusiveOrEqual(target, value, parser, conflictCode) {
|
|
38164
|
-
await
|
|
38165
|
-
await assertPlainDirectory2(
|
|
38912
|
+
await mkdir39(path63.dirname(target), { recursive: true });
|
|
38913
|
+
await assertPlainDirectory2(path63.dirname(target));
|
|
38166
38914
|
try {
|
|
38167
|
-
await
|
|
38915
|
+
await writeFile44(target, serialize14(value), { encoding: "utf8", flag: "wx" });
|
|
38168
38916
|
} catch (error) {
|
|
38169
38917
|
if (!isAlreadyExists25(error)) throw error;
|
|
38170
38918
|
const existing = await readJsonOrNull5(target, parser, conflictCode);
|
|
@@ -38176,18 +38924,18 @@ async function writeJsonExclusiveOrEqual(target, value, parser, conflictCode) {
|
|
|
38176
38924
|
}
|
|
38177
38925
|
async function readJsonOrNull5(target, parser, corruptCode) {
|
|
38178
38926
|
try {
|
|
38179
|
-
const before = await
|
|
38927
|
+
const before = await lstat25(target);
|
|
38180
38928
|
if (!before.isFile() || before.isSymbolicLink()) {
|
|
38181
38929
|
throw new Error("MANCODE_TRANSPORT_MIGRATION_STAGE_UNSAFE");
|
|
38182
38930
|
}
|
|
38183
|
-
const parsed = parser(JSON.parse(await
|
|
38184
|
-
const after = await
|
|
38931
|
+
const parsed = parser(JSON.parse(await readFile44(target, "utf8")));
|
|
38932
|
+
const after = await lstat25(target);
|
|
38185
38933
|
if (!after.isFile() || after.isSymbolicLink() || before.dev !== after.dev || before.ino !== after.ino) {
|
|
38186
38934
|
throw new Error("MANCODE_TRANSPORT_MIGRATION_STAGE_UNSAFE");
|
|
38187
38935
|
}
|
|
38188
38936
|
return parsed;
|
|
38189
38937
|
} catch (error) {
|
|
38190
|
-
if (
|
|
38938
|
+
if (isNotFound32(error)) return null;
|
|
38191
38939
|
if (error instanceof SyntaxError) throw new Error(corruptCode);
|
|
38192
38940
|
throw error;
|
|
38193
38941
|
}
|
|
@@ -38239,19 +38987,19 @@ function requireRemote(value) {
|
|
|
38239
38987
|
}
|
|
38240
38988
|
async function pathKind(target) {
|
|
38241
38989
|
try {
|
|
38242
|
-
const
|
|
38243
|
-
if (
|
|
38244
|
-
if (
|
|
38245
|
-
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";
|
|
38246
38994
|
return "other";
|
|
38247
38995
|
} catch (error) {
|
|
38248
|
-
if (
|
|
38996
|
+
if (isNotFound32(error)) return null;
|
|
38249
38997
|
throw error;
|
|
38250
38998
|
}
|
|
38251
38999
|
}
|
|
38252
39000
|
async function assertPlainDirectory2(target) {
|
|
38253
|
-
const
|
|
38254
|
-
if (!
|
|
39001
|
+
const stat5 = await lstat25(target);
|
|
39002
|
+
if (!stat5.isDirectory() || stat5.isSymbolicLink()) {
|
|
38255
39003
|
throw new Error("MANCODE_TRANSPORT_MIGRATION_STAGE_UNSAFE");
|
|
38256
39004
|
}
|
|
38257
39005
|
}
|
|
@@ -38259,7 +39007,7 @@ async function unlinkIfExists2(target) {
|
|
|
38259
39007
|
try {
|
|
38260
39008
|
await unlink4(target);
|
|
38261
39009
|
} catch (error) {
|
|
38262
|
-
if (!
|
|
39010
|
+
if (!isNotFound32(error)) throw error;
|
|
38263
39011
|
}
|
|
38264
39012
|
}
|
|
38265
39013
|
function serialize14(value) {
|
|
@@ -38272,7 +39020,7 @@ function compareUtf814(left, right) {
|
|
|
38272
39020
|
function isAlreadyExists25(error) {
|
|
38273
39021
|
return typeof error === "object" && error !== null && "code" in error && error.code === "EEXIST";
|
|
38274
39022
|
}
|
|
38275
|
-
function
|
|
39023
|
+
function isNotFound32(error) {
|
|
38276
39024
|
return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
|
|
38277
39025
|
}
|
|
38278
39026
|
|
|
@@ -39681,12 +40429,12 @@ function parseActorId2(value) {
|
|
|
39681
40429
|
function parseHandoffId(value) {
|
|
39682
40430
|
return parseUlidArgument(value, "MANCODE_HANDOFF_ID_INVALID");
|
|
39683
40431
|
}
|
|
39684
|
-
function parseUlidArgument(value,
|
|
40432
|
+
function parseUlidArgument(value, errorCode6) {
|
|
39685
40433
|
try {
|
|
39686
40434
|
assertUlid(value, "value");
|
|
39687
40435
|
return value;
|
|
39688
40436
|
} catch {
|
|
39689
|
-
throw new Error(
|
|
40437
|
+
throw new Error(errorCode6);
|
|
39690
40438
|
}
|
|
39691
40439
|
}
|
|
39692
40440
|
function parseTransportMode3(value) {
|
|
@@ -39712,23 +40460,23 @@ function parsePositiveInteger6(value) {
|
|
|
39712
40460
|
}
|
|
39713
40461
|
|
|
39714
40462
|
// src/commands/uninstall.ts
|
|
39715
|
-
import { access as access5, readFile as
|
|
39716
|
-
import
|
|
39717
|
-
import
|
|
39718
|
-
var
|
|
39719
|
-
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;
|
|
39720
40468
|
var EXIT_UNSUPPORTED_PLATFORM2 = 2;
|
|
39721
40469
|
var EXIT_V3_AUTHORITY_PROTECTED = 3;
|
|
39722
|
-
async function uninstall(rootDir =
|
|
39723
|
-
const stateFile =
|
|
39724
|
-
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");
|
|
39725
40473
|
if (await pathExists15(v3SchemaFile)) {
|
|
39726
40474
|
return uninstallV3(rootDir, platform, options);
|
|
39727
40475
|
}
|
|
39728
40476
|
if (!await pathExists15(stateFile)) {
|
|
39729
40477
|
console.error("\u2717 mancode not initialized.");
|
|
39730
40478
|
console.error(" Run `mancode init` first.");
|
|
39731
|
-
return
|
|
40479
|
+
return EXIT_NOT_INITIALIZED7;
|
|
39732
40480
|
}
|
|
39733
40481
|
const removeAll = !platform || options.all;
|
|
39734
40482
|
if (platform) {
|
|
@@ -39753,7 +40501,7 @@ async function uninstall(rootDir = process11.cwd(), platform, options = {}) {
|
|
|
39753
40501
|
await uninstallPlatform(rootDir, platform ?? "claude-code");
|
|
39754
40502
|
}
|
|
39755
40503
|
console.log("\u2713 Uninstall complete.");
|
|
39756
|
-
return
|
|
40504
|
+
return EXIT_OK10;
|
|
39757
40505
|
}
|
|
39758
40506
|
async function uninstallV3(rootDir, platform, options) {
|
|
39759
40507
|
if (!platform || options.all) {
|
|
@@ -39784,7 +40532,7 @@ async function uninstallV3(rootDir, platform, options) {
|
|
|
39784
40532
|
console.log(
|
|
39785
40533
|
`\u2713 Removed ${formatPlatformName(platform)} mancode bootstrap.`
|
|
39786
40534
|
);
|
|
39787
|
-
return
|
|
40535
|
+
return EXIT_OK10;
|
|
39788
40536
|
} catch (error) {
|
|
39789
40537
|
const message = error instanceof Error ? error.message : String(error);
|
|
39790
40538
|
console.error(`\u2717 mancode bootstrap removal failed: ${message}`);
|
|
@@ -39812,7 +40560,7 @@ async function uninstallAll(rootDir) {
|
|
|
39812
40560
|
await uninstallPlatform(rootDir, p);
|
|
39813
40561
|
}
|
|
39814
40562
|
console.log("\u2713 Removing .mancode/ directory...");
|
|
39815
|
-
await
|
|
40563
|
+
await rm20(path64.join(rootDir, ".mancode"), {
|
|
39816
40564
|
recursive: true,
|
|
39817
40565
|
force: true
|
|
39818
40566
|
});
|
|
@@ -39822,10 +40570,10 @@ async function uninstallClaudeCode(rootDir) {
|
|
|
39822
40570
|
await cleanClaudeSettings(rootDir);
|
|
39823
40571
|
}
|
|
39824
40572
|
async function cleanClaudeSettings(rootDir) {
|
|
39825
|
-
const settingsPath =
|
|
40573
|
+
const settingsPath = path64.join(rootDir, ".claude", "settings.json");
|
|
39826
40574
|
let content;
|
|
39827
40575
|
try {
|
|
39828
|
-
content = await
|
|
40576
|
+
content = await readFile45(settingsPath, "utf-8");
|
|
39829
40577
|
} catch {
|
|
39830
40578
|
return;
|
|
39831
40579
|
}
|
|
@@ -39836,14 +40584,14 @@ async function cleanClaudeSettings(rootDir) {
|
|
|
39836
40584
|
return;
|
|
39837
40585
|
}
|
|
39838
40586
|
const cleanedHooks = {};
|
|
39839
|
-
if (
|
|
40587
|
+
if (isRecord13(settings.hooks)) {
|
|
39840
40588
|
for (const [event, value] of Object.entries(settings.hooks)) {
|
|
39841
40589
|
const cleaned = cleanClaudeHookValue(value);
|
|
39842
40590
|
if (cleaned !== void 0) cleanedHooks[event] = cleaned;
|
|
39843
40591
|
}
|
|
39844
40592
|
settings.hooks = Object.keys(cleanedHooks).length > 0 ? cleanedHooks : void 0;
|
|
39845
40593
|
}
|
|
39846
|
-
if (
|
|
40594
|
+
if (isRecord13(settings.skills)) {
|
|
39847
40595
|
const retainedSkills = Object.fromEntries(
|
|
39848
40596
|
Object.entries(settings.skills).filter(
|
|
39849
40597
|
([name, value]) => LEGACY_CLAUDE_SKILL_SETTINGS[name] !== value
|
|
@@ -39851,7 +40599,7 @@ async function cleanClaudeSettings(rootDir) {
|
|
|
39851
40599
|
);
|
|
39852
40600
|
settings.skills = Object.keys(retainedSkills).length > 0 ? retainedSkills : void 0;
|
|
39853
40601
|
}
|
|
39854
|
-
await
|
|
40602
|
+
await writeFile45(
|
|
39855
40603
|
settingsPath,
|
|
39856
40604
|
`${JSON.stringify(settings, null, 2)}
|
|
39857
40605
|
`,
|
|
@@ -39863,7 +40611,7 @@ function cleanClaudeHookValue(value) {
|
|
|
39863
40611
|
const entries2 = value.flatMap(cleanClaudeHookEntry);
|
|
39864
40612
|
return entries2.length > 0 ? entries2 : void 0;
|
|
39865
40613
|
}
|
|
39866
|
-
if (!
|
|
40614
|
+
if (!isRecord13(value)) return value;
|
|
39867
40615
|
if (Array.isArray(value.hooks) || typeof value.command === "string") {
|
|
39868
40616
|
const entries2 = cleanClaudeHookEntry(value);
|
|
39869
40617
|
return entries2.length > 0 ? entries2 : void 0;
|
|
@@ -39877,7 +40625,7 @@ function cleanClaudeHookValue(value) {
|
|
|
39877
40625
|
}
|
|
39878
40626
|
function cleanClaudeHookEntry(entry) {
|
|
39879
40627
|
if (Array.isArray(entry)) return entry.flatMap(cleanClaudeHookEntry);
|
|
39880
|
-
if (!
|
|
40628
|
+
if (!isRecord13(entry)) return [entry];
|
|
39881
40629
|
if (Array.isArray(entry.hooks)) {
|
|
39882
40630
|
const hooks = entry.hooks.filter((hook) => !isMancodeHookEntry(hook));
|
|
39883
40631
|
return hooks.length > 0 ? [{ ...entry, hooks }] : [];
|
|
@@ -39885,11 +40633,11 @@ function cleanClaudeHookEntry(entry) {
|
|
|
39885
40633
|
return isMancodeHookEntry(entry) ? [] : [entry];
|
|
39886
40634
|
}
|
|
39887
40635
|
function isMancodeHookEntry(value) {
|
|
39888
|
-
return
|
|
40636
|
+
return isRecord13(value) && typeof value.command === "string" && isGeneratedMancodeHookCommand(value.command);
|
|
39889
40637
|
}
|
|
39890
40638
|
function containsLegacyMancodeHookPath2(value) {
|
|
39891
40639
|
if (Array.isArray(value)) return value.some(containsLegacyMancodeHookPath2);
|
|
39892
|
-
if (!
|
|
40640
|
+
if (!isRecord13(value)) return false;
|
|
39893
40641
|
if (typeof value.command === "string" && value.command.includes(".mancode/hooks/")) {
|
|
39894
40642
|
return true;
|
|
39895
40643
|
}
|
|
@@ -39900,66 +40648,66 @@ async function uninstallCursor(rootDir) {
|
|
|
39900
40648
|
await removeCursorCommands(rootDir);
|
|
39901
40649
|
}
|
|
39902
40650
|
async function uninstallCodex(rootDir) {
|
|
39903
|
-
const agentsPath =
|
|
40651
|
+
const agentsPath = path64.join(rootDir, "AGENTS.md");
|
|
39904
40652
|
try {
|
|
39905
|
-
const content = await
|
|
40653
|
+
const content = await readFile45(agentsPath, "utf-8");
|
|
39906
40654
|
const cleaned = removeManagedBlock(content);
|
|
39907
40655
|
if (cleaned.trim()) {
|
|
39908
|
-
await
|
|
40656
|
+
await writeFile45(agentsPath, `${cleaned}
|
|
39909
40657
|
`, "utf-8");
|
|
39910
40658
|
} else {
|
|
39911
|
-
await
|
|
40659
|
+
await rm20(agentsPath, { force: true });
|
|
39912
40660
|
}
|
|
39913
40661
|
} catch {
|
|
39914
40662
|
}
|
|
39915
40663
|
await removeCodexSkills(rootDir);
|
|
39916
40664
|
}
|
|
39917
40665
|
async function uninstallCopilot(rootDir) {
|
|
39918
|
-
const instructionsPath =
|
|
40666
|
+
const instructionsPath = path64.join(
|
|
39919
40667
|
rootDir,
|
|
39920
40668
|
".github",
|
|
39921
40669
|
"copilot-instructions.md"
|
|
39922
40670
|
);
|
|
39923
40671
|
try {
|
|
39924
|
-
const content = await
|
|
40672
|
+
const content = await readFile45(instructionsPath, "utf-8");
|
|
39925
40673
|
const cleaned = removeManagedBlock(content);
|
|
39926
40674
|
if (cleaned.trim()) {
|
|
39927
|
-
await
|
|
40675
|
+
await writeFile45(instructionsPath, `${cleaned}
|
|
39928
40676
|
`, "utf-8");
|
|
39929
40677
|
} else {
|
|
39930
|
-
await
|
|
40678
|
+
await rm20(instructionsPath, { force: true });
|
|
39931
40679
|
}
|
|
39932
40680
|
} catch {
|
|
39933
40681
|
}
|
|
39934
40682
|
await removeCopilotPrompts(rootDir);
|
|
39935
40683
|
}
|
|
39936
40684
|
async function uninstallZcode(rootDir) {
|
|
39937
|
-
const agentsPath =
|
|
40685
|
+
const agentsPath = path64.join(rootDir, "AGENTS.md");
|
|
39938
40686
|
try {
|
|
39939
|
-
const content = await
|
|
40687
|
+
const content = await readFile45(agentsPath, "utf-8");
|
|
39940
40688
|
const cleaned = removeManagedBlock(
|
|
39941
40689
|
content,
|
|
39942
40690
|
ZCODE_MANCODE_START_MARKER,
|
|
39943
40691
|
ZCODE_MANCODE_END_MARKER
|
|
39944
40692
|
);
|
|
39945
40693
|
if (cleaned.trim()) {
|
|
39946
|
-
await
|
|
40694
|
+
await writeFile45(agentsPath, `${cleaned}
|
|
39947
40695
|
`, "utf-8");
|
|
39948
40696
|
} else {
|
|
39949
|
-
await
|
|
40697
|
+
await rm20(agentsPath, { force: true });
|
|
39950
40698
|
}
|
|
39951
40699
|
} catch {
|
|
39952
40700
|
}
|
|
39953
40701
|
await removeZcodeSkills(rootDir);
|
|
39954
40702
|
}
|
|
39955
40703
|
async function removeFromConfig(rootDir, platform) {
|
|
39956
|
-
const configPath =
|
|
40704
|
+
const configPath = path64.join(rootDir, ".mancode", "config.json");
|
|
39957
40705
|
try {
|
|
39958
|
-
const raw = await
|
|
40706
|
+
const raw = await readFile45(configPath, "utf-8");
|
|
39959
40707
|
const config = JSON.parse(raw);
|
|
39960
40708
|
if (Array.isArray(config.platforms)) {
|
|
39961
40709
|
config.platforms = config.platforms.filter((p) => p !== platform);
|
|
39962
|
-
if (
|
|
40710
|
+
if (isRecord13(config.platformOptions)) {
|
|
39963
40711
|
const platformOptions = Object.fromEntries(
|
|
39964
40712
|
Object.entries(config.platformOptions).filter(
|
|
39965
40713
|
([name]) => name !== platform
|
|
@@ -39967,7 +40715,7 @@ async function removeFromConfig(rootDir, platform) {
|
|
|
39967
40715
|
);
|
|
39968
40716
|
config.platformOptions = Object.keys(platformOptions).length > 0 ? platformOptions : void 0;
|
|
39969
40717
|
}
|
|
39970
|
-
await
|
|
40718
|
+
await writeFile45(
|
|
39971
40719
|
configPath,
|
|
39972
40720
|
`${JSON.stringify(config, null, 2)}
|
|
39973
40721
|
`,
|
|
@@ -39977,7 +40725,7 @@ async function removeFromConfig(rootDir, platform) {
|
|
|
39977
40725
|
} catch {
|
|
39978
40726
|
}
|
|
39979
40727
|
}
|
|
39980
|
-
function
|
|
40728
|
+
function isRecord13(value) {
|
|
39981
40729
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
39982
40730
|
}
|
|
39983
40731
|
async function pathExists15(p) {
|
|
@@ -39990,18 +40738,18 @@ async function pathExists15(p) {
|
|
|
39990
40738
|
}
|
|
39991
40739
|
|
|
39992
40740
|
// src/commands/version.ts
|
|
39993
|
-
import
|
|
40741
|
+
import process13 from "process";
|
|
39994
40742
|
function version() {
|
|
39995
|
-
const nodeVersion =
|
|
39996
|
-
const platform = `${
|
|
40743
|
+
const nodeVersion = process13.version;
|
|
40744
|
+
const platform = `${process13.platform}/${process13.arch}`;
|
|
39997
40745
|
console.log(`mancode/${VERSION}`);
|
|
39998
40746
|
console.log(`node/${nodeVersion.replace("v", "")}`);
|
|
39999
40747
|
console.log(platform);
|
|
40000
40748
|
}
|
|
40001
40749
|
|
|
40002
40750
|
// src/commands/workflow.ts
|
|
40003
|
-
import { access as access6, readFile as
|
|
40004
|
-
import
|
|
40751
|
+
import { access as access6, readFile as readFile47, rm as rm22, writeFile as writeFile47 } from "fs/promises";
|
|
40752
|
+
import path66 from "path";
|
|
40005
40753
|
|
|
40006
40754
|
// src/context/child-result-merge.ts
|
|
40007
40755
|
async function mergeV3ChildResult(input) {
|
|
@@ -43060,14 +43808,14 @@ function updateMetadata4(previous, verification, operationId, updatedAt) {
|
|
|
43060
43808
|
|
|
43061
43809
|
// src/context/workflow-create.ts
|
|
43062
43810
|
import {
|
|
43063
|
-
lstat as
|
|
43064
|
-
mkdir as
|
|
43065
|
-
readFile as
|
|
43811
|
+
lstat as lstat26,
|
|
43812
|
+
mkdir as mkdir40,
|
|
43813
|
+
readFile as readFile46,
|
|
43066
43814
|
rename as rename13,
|
|
43067
|
-
rm as
|
|
43068
|
-
writeFile as
|
|
43815
|
+
rm as rm21,
|
|
43816
|
+
writeFile as writeFile46
|
|
43069
43817
|
} from "fs/promises";
|
|
43070
|
-
import
|
|
43818
|
+
import path65 from "path";
|
|
43071
43819
|
|
|
43072
43820
|
// src/context/creation-resolution.ts
|
|
43073
43821
|
function resolveWorkflowCreation(request) {
|
|
@@ -43177,7 +43925,7 @@ function rejectConflict(provided, expected, label) {
|
|
|
43177
43925
|
|
|
43178
43926
|
// src/context/workflow-create.ts
|
|
43179
43927
|
async function createV3Workflow(input) {
|
|
43180
|
-
const projectRoot =
|
|
43928
|
+
const projectRoot = path65.resolve(requireProjectRoot2(input.projectRoot));
|
|
43181
43929
|
const task = requireText2(input.task, "workflow task");
|
|
43182
43930
|
const client = requireText2(input.client, "workflow client");
|
|
43183
43931
|
const now = input.now ?? /* @__PURE__ */ new Date();
|
|
@@ -43362,8 +44110,8 @@ async function createV3Workflow(input) {
|
|
|
43362
44110
|
throw new Error("MANCODE_REVISION_CONFLICT");
|
|
43363
44111
|
}
|
|
43364
44112
|
const taskParent = await ensureSafeTaskParent3(projectRoot, taskRef);
|
|
43365
|
-
const targetDirectory =
|
|
43366
|
-
stagingDirectory =
|
|
44113
|
+
const targetDirectory = path65.join(taskParent, taskRef.taskId);
|
|
44114
|
+
stagingDirectory = path65.join(
|
|
43367
44115
|
taskParent,
|
|
43368
44116
|
`.${taskRef.taskId}.${operationId}.staging`
|
|
43369
44117
|
);
|
|
@@ -43812,10 +44560,10 @@ async function ensureSafeTaskParent3(projectRoot, taskRef) {
|
|
|
43812
44560
|
const segments = [".mancode", taskRef.namespace, "workflows"];
|
|
43813
44561
|
let current = projectRoot;
|
|
43814
44562
|
for (const segment of segments) {
|
|
43815
|
-
current =
|
|
44563
|
+
current = path65.join(current, segment);
|
|
43816
44564
|
const existing = await lstatOrNull5(current);
|
|
43817
44565
|
if (existing === null) {
|
|
43818
|
-
await
|
|
44566
|
+
await mkdir40(current);
|
|
43819
44567
|
continue;
|
|
43820
44568
|
}
|
|
43821
44569
|
if (!existing.isDirectory() || existing.isSymbolicLink()) {
|
|
@@ -43828,7 +44576,7 @@ async function assertDirectoryAbsent(target, code) {
|
|
|
43828
44576
|
if (await lstatOrNull5(target) !== null) throw new Error(code);
|
|
43829
44577
|
}
|
|
43830
44578
|
async function writeStagedEntities(stagingDirectory, entities) {
|
|
43831
|
-
await
|
|
44579
|
+
await mkdir40(stagingDirectory);
|
|
43832
44580
|
await assertDirectory(stagingDirectory);
|
|
43833
44581
|
await Promise.all([
|
|
43834
44582
|
writeStagedJson(stagingDirectory, "metadata.json", entities.metadata),
|
|
@@ -43848,13 +44596,13 @@ async function writeStagedEntities(stagingDirectory, entities) {
|
|
|
43848
44596
|
}
|
|
43849
44597
|
async function writeStagedJson(stagingDirectory, fileName, value) {
|
|
43850
44598
|
await assertDirectory(stagingDirectory);
|
|
43851
|
-
const target =
|
|
43852
|
-
await
|
|
44599
|
+
const target = path65.join(stagingDirectory, fileName);
|
|
44600
|
+
await writeFile46(target, `${JSON.stringify(value, null, 2)}
|
|
43853
44601
|
`, {
|
|
43854
44602
|
encoding: "utf8",
|
|
43855
44603
|
flag: "wx"
|
|
43856
44604
|
});
|
|
43857
|
-
const entry = await
|
|
44605
|
+
const entry = await lstat26(target);
|
|
43858
44606
|
if (!entry.isFile() || entry.isSymbolicLink()) {
|
|
43859
44607
|
throw new Error("MANCODE_ARTIFACT_PATH_UNSAFE");
|
|
43860
44608
|
}
|
|
@@ -43886,13 +44634,13 @@ async function validateStagedEntities(stagingDirectory) {
|
|
|
43886
44634
|
});
|
|
43887
44635
|
}
|
|
43888
44636
|
async function readStagedJson(stagingDirectory, fileName, parser) {
|
|
43889
|
-
const target =
|
|
43890
|
-
const before = await
|
|
44637
|
+
const target = path65.join(stagingDirectory, fileName);
|
|
44638
|
+
const before = await lstat26(target);
|
|
43891
44639
|
if (!before.isFile() || before.isSymbolicLink()) {
|
|
43892
44640
|
throw new Error("MANCODE_ARTIFACT_PATH_UNSAFE");
|
|
43893
44641
|
}
|
|
43894
|
-
const parsed = parser(JSON.parse(await
|
|
43895
|
-
const after = await
|
|
44642
|
+
const parsed = parser(JSON.parse(await readFile46(target, "utf8")));
|
|
44643
|
+
const after = await lstat26(target);
|
|
43896
44644
|
if (!after.isFile() || after.isSymbolicLink() || before.dev !== after.dev || before.ino !== after.ino) {
|
|
43897
44645
|
throw new Error("MANCODE_ARTIFACT_PATH_UNSAFE");
|
|
43898
44646
|
}
|
|
@@ -43983,20 +44731,20 @@ async function abortPreparedCreate(store, journal, stagingDirectory, now) {
|
|
|
43983
44731
|
{ canAbort: true }
|
|
43984
44732
|
);
|
|
43985
44733
|
} finally {
|
|
43986
|
-
await
|
|
44734
|
+
await rm21(stagingDirectory, { recursive: true, force: true });
|
|
43987
44735
|
}
|
|
43988
44736
|
}
|
|
43989
44737
|
async function assertDirectory(target) {
|
|
43990
|
-
const entry = await
|
|
44738
|
+
const entry = await lstat26(target);
|
|
43991
44739
|
if (!entry.isDirectory() || entry.isSymbolicLink()) {
|
|
43992
44740
|
throw new Error("MANCODE_ARTIFACT_PATH_UNSAFE");
|
|
43993
44741
|
}
|
|
43994
44742
|
}
|
|
43995
44743
|
async function lstatOrNull5(target) {
|
|
43996
44744
|
try {
|
|
43997
|
-
return await
|
|
44745
|
+
return await lstat26(target);
|
|
43998
44746
|
} catch (error) {
|
|
43999
|
-
if (
|
|
44747
|
+
if (isNotFound33(error)) return null;
|
|
44000
44748
|
throw error;
|
|
44001
44749
|
}
|
|
44002
44750
|
}
|
|
@@ -44016,7 +44764,7 @@ function requireText2(value, label) {
|
|
|
44016
44764
|
}
|
|
44017
44765
|
return value.trim();
|
|
44018
44766
|
}
|
|
44019
|
-
function
|
|
44767
|
+
function isNotFound33(error) {
|
|
44020
44768
|
return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
|
|
44021
44769
|
}
|
|
44022
44770
|
|
|
@@ -44913,7 +45661,7 @@ function compareUtf817(left, right) {
|
|
|
44913
45661
|
|
|
44914
45662
|
// src/commands/requirements-input.ts
|
|
44915
45663
|
function normalizeRequirementsInput(value, requestedTaskRef, now = /* @__PURE__ */ new Date(), options = {}) {
|
|
44916
|
-
if (
|
|
45664
|
+
if (isRecord14(value) && "schemaVersion" in value) {
|
|
44917
45665
|
return parseRequirementsLedger(value);
|
|
44918
45666
|
}
|
|
44919
45667
|
const serialized = JSON.stringify(value);
|
|
@@ -44981,20 +45729,20 @@ function buildCanonicalRequirements(semantic, requestedTaskRef, now) {
|
|
|
44981
45729
|
contentDigest: requirementsLedgerDigest(draft)
|
|
44982
45730
|
});
|
|
44983
45731
|
}
|
|
44984
|
-
function
|
|
45732
|
+
function isRecord14(value) {
|
|
44985
45733
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
44986
45734
|
}
|
|
44987
45735
|
|
|
44988
45736
|
// src/commands/workflow.ts
|
|
44989
|
-
var
|
|
44990
|
-
var
|
|
45737
|
+
var EXIT_OK11 = 0;
|
|
45738
|
+
var EXIT_NOT_INITIALIZED8 = 1;
|
|
44991
45739
|
var EXIT_INVALID_ARG3 = 2;
|
|
44992
45740
|
async function workflow(rootDir, subcommand, args = [], options = {}) {
|
|
44993
45741
|
const v3Activation = await readV3ActivationState2(rootDir);
|
|
44994
45742
|
if (v3Activation === "v3_active") {
|
|
44995
45743
|
return workflowV3(rootDir, subcommand, args, options);
|
|
44996
45744
|
}
|
|
44997
|
-
if (!await pathExists16(
|
|
45745
|
+
if (!await pathExists16(path66.join(rootDir, ".mancode", "state.json"))) {
|
|
44998
45746
|
if (v3Activation !== null) {
|
|
44999
45747
|
return printV3Error(
|
|
45000
45748
|
options.json,
|
|
@@ -45008,7 +45756,7 @@ async function workflow(rootDir, subcommand, args = [], options = {}) {
|
|
|
45008
45756
|
console.error("\u2717 mancode not initialized.");
|
|
45009
45757
|
console.error(" Run `mancode init` to get started.");
|
|
45010
45758
|
}
|
|
45011
|
-
return
|
|
45759
|
+
return EXIT_NOT_INITIALIZED8;
|
|
45012
45760
|
}
|
|
45013
45761
|
switch (subcommand) {
|
|
45014
45762
|
case "create":
|
|
@@ -45124,7 +45872,7 @@ async function workflowListV3(rootDir, args, options) {
|
|
|
45124
45872
|
}
|
|
45125
45873
|
if (workflows.length === 0) {
|
|
45126
45874
|
console.log("No mancode workflows.");
|
|
45127
|
-
return
|
|
45875
|
+
return EXIT_OK11;
|
|
45128
45876
|
}
|
|
45129
45877
|
const active = workflows.filter(
|
|
45130
45878
|
(item) => ["in_progress", "planned", "blocked"].includes(item.status)
|
|
@@ -45136,7 +45884,7 @@ async function workflowListV3(rootDir, args, options) {
|
|
|
45136
45884
|
for (const metadata of workflows) {
|
|
45137
45885
|
console.log(formatV3WorkflowRow(metadata));
|
|
45138
45886
|
}
|
|
45139
|
-
return
|
|
45887
|
+
return EXIT_OK11;
|
|
45140
45888
|
} catch (error) {
|
|
45141
45889
|
return printV3Error(
|
|
45142
45890
|
options.json,
|
|
@@ -45194,7 +45942,7 @@ async function workflowShowV3(rootDir, args, options) {
|
|
|
45194
45942
|
if (snapshot.aggregateError !== null) {
|
|
45195
45943
|
console.log(`Aggregate: ${snapshot.aggregateError}`);
|
|
45196
45944
|
}
|
|
45197
|
-
return
|
|
45945
|
+
return EXIT_OK11;
|
|
45198
45946
|
} catch (error) {
|
|
45199
45947
|
return printV3Error(
|
|
45200
45948
|
options.json,
|
|
@@ -46086,8 +46834,8 @@ function parseV3ParticipantActorIds(values) {
|
|
|
46086
46834
|
return values;
|
|
46087
46835
|
}
|
|
46088
46836
|
async function readWorkflowInputFile(projectRoot, value) {
|
|
46089
|
-
const inputPath =
|
|
46090
|
-
return
|
|
46837
|
+
const inputPath = path66.isAbsolute(value) ? value : path66.resolve(projectRoot, value);
|
|
46838
|
+
return readFile47(inputPath, "utf8");
|
|
46091
46839
|
}
|
|
46092
46840
|
async function readWorkflowJsonInputFile(projectRoot, value) {
|
|
46093
46841
|
return JSON.parse(await readWorkflowInputFile(projectRoot, value));
|
|
@@ -46160,7 +46908,7 @@ async function readV3ActivationState2(rootDir) {
|
|
|
46160
46908
|
try {
|
|
46161
46909
|
const manifest = parseSchemaManifest(
|
|
46162
46910
|
JSON.parse(
|
|
46163
|
-
await
|
|
46911
|
+
await readFile47(path66.join(rootDir, ".mancode", "schema.json"), "utf8")
|
|
46164
46912
|
)
|
|
46165
46913
|
);
|
|
46166
46914
|
return manifest.activationState === "v3_active" ? "v3_active" : "other";
|
|
@@ -46205,21 +46953,21 @@ async function workflowRequirements(rootDir, args, options) {
|
|
|
46205
46953
|
"requirements can only be finalized for an in-progress man or manteam workflow at step 1 or 2"
|
|
46206
46954
|
);
|
|
46207
46955
|
}
|
|
46208
|
-
const workflowPath =
|
|
46209
|
-
const jsonPath =
|
|
46210
|
-
const markdownPath =
|
|
46211
|
-
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");
|
|
46212
46960
|
let originalJson;
|
|
46213
46961
|
let originalMarkdown;
|
|
46214
46962
|
let originalMetadata;
|
|
46215
46963
|
try {
|
|
46216
|
-
const inputPath =
|
|
46217
|
-
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");
|
|
46218
46966
|
const requirements = parseRequirementsLedger2(input);
|
|
46219
46967
|
[originalJson, originalMarkdown, originalMetadata] = await Promise.all([
|
|
46220
46968
|
readOptionalText2(jsonPath),
|
|
46221
46969
|
readOptionalText2(markdownPath),
|
|
46222
|
-
|
|
46970
|
+
readFile47(metadataPath3, "utf-8")
|
|
46223
46971
|
]);
|
|
46224
46972
|
await writeRequirementsArtifacts(rootDir, taskId, requirements);
|
|
46225
46973
|
await updateWorkflow(rootDir, taskId, {
|
|
@@ -46242,14 +46990,14 @@ async function workflowRequirements(rootDir, args, options) {
|
|
|
46242
46990
|
`Finalized requirements: ${taskId} (${requirementsAreReady2(requirements) ? "ready" : "needs_clarification"})`
|
|
46243
46991
|
);
|
|
46244
46992
|
}
|
|
46245
|
-
return
|
|
46993
|
+
return EXIT_OK11;
|
|
46246
46994
|
} catch (error) {
|
|
46247
46995
|
let rollbackIncomplete = false;
|
|
46248
46996
|
if (originalJson !== void 0 && originalMarkdown !== void 0 && originalMetadata !== void 0) {
|
|
46249
46997
|
const rollback = await Promise.allSettled([
|
|
46250
46998
|
restoreOptionalText(jsonPath, originalJson),
|
|
46251
46999
|
restoreOptionalText(markdownPath, originalMarkdown),
|
|
46252
|
-
|
|
47000
|
+
writeFile47(metadataPath3, originalMetadata, "utf-8")
|
|
46253
47001
|
]);
|
|
46254
47002
|
rollbackIncomplete = rollback.some(
|
|
46255
47003
|
(result2) => result2.status === "rejected"
|
|
@@ -46278,7 +47026,7 @@ async function workflowVerify(rootDir, args, options) {
|
|
|
46278
47026
|
return invalidArg(options, `verification not initialized: ${taskId}`);
|
|
46279
47027
|
}
|
|
46280
47028
|
outputVerificationLedger(ledger, options);
|
|
46281
|
-
return
|
|
47029
|
+
return EXIT_OK11;
|
|
46282
47030
|
}
|
|
46283
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") {
|
|
46284
47032
|
return invalidArg(
|
|
@@ -46337,7 +47085,7 @@ async function workflowVerify(rootDir, args, options) {
|
|
|
46337
47085
|
);
|
|
46338
47086
|
}
|
|
46339
47087
|
if (options.evidenceFile) {
|
|
46340
|
-
const evidencePath =
|
|
47088
|
+
const evidencePath = path66.isAbsolute(options.evidenceFile) ? options.evidenceFile : path66.resolve(rootDir, options.evidenceFile);
|
|
46341
47089
|
if (!await pathExists16(evidencePath)) {
|
|
46342
47090
|
return invalidArg(
|
|
46343
47091
|
options,
|
|
@@ -46387,7 +47135,7 @@ async function workflowVerify(rootDir, args, options) {
|
|
|
46387
47135
|
);
|
|
46388
47136
|
if (transitionError) return invalidArg(options, transitionError);
|
|
46389
47137
|
outputVerificationLedger(ledger, options);
|
|
46390
|
-
return
|
|
47138
|
+
return EXIT_OK11;
|
|
46391
47139
|
} catch (error) {
|
|
46392
47140
|
return invalidArg(
|
|
46393
47141
|
options,
|
|
@@ -46397,17 +47145,17 @@ async function workflowVerify(rootDir, args, options) {
|
|
|
46397
47145
|
}
|
|
46398
47146
|
async function commitVerificationTransition(rootDir, meta, ledger) {
|
|
46399
47147
|
const ledgerPath = verificationLedgerPath(rootDir, meta.taskId);
|
|
46400
|
-
const metadataPath3 =
|
|
47148
|
+
const metadataPath3 = path66.join(
|
|
46401
47149
|
rootDir,
|
|
46402
47150
|
".mancode",
|
|
46403
47151
|
"workflows",
|
|
46404
47152
|
meta.taskId,
|
|
46405
47153
|
"metadata.json"
|
|
46406
47154
|
);
|
|
46407
|
-
const specPath =
|
|
47155
|
+
const specPath = path66.join(rootDir, ".mancode", "memory", "spec.md");
|
|
46408
47156
|
const [originalLedger, originalMetadata, originalSpec] = await Promise.all([
|
|
46409
47157
|
readOptionalText2(ledgerPath),
|
|
46410
|
-
|
|
47158
|
+
readFile47(metadataPath3, "utf-8"),
|
|
46411
47159
|
readOptionalText2(specPath)
|
|
46412
47160
|
]);
|
|
46413
47161
|
const wasVerificationBlocked = meta.status === "blocked" && meta.blockingReason?.startsWith("[verification]");
|
|
@@ -46436,7 +47184,7 @@ async function commitVerificationTransition(rootDir, meta, ledger) {
|
|
|
46436
47184
|
} catch (error) {
|
|
46437
47185
|
const rollback = await Promise.allSettled([
|
|
46438
47186
|
restoreOptionalText(ledgerPath, originalLedger),
|
|
46439
|
-
|
|
47187
|
+
writeFile47(metadataPath3, originalMetadata, "utf-8"),
|
|
46440
47188
|
restoreOptionalText(specPath, originalSpec)
|
|
46441
47189
|
]);
|
|
46442
47190
|
const message = error instanceof Error ? error.message : "verification transition failed";
|
|
@@ -46471,7 +47219,7 @@ async function workflowReview(rootDir, args, options) {
|
|
|
46471
47219
|
if (!ledger)
|
|
46472
47220
|
return invalidArg(options, `review not initialized: ${taskId}`);
|
|
46473
47221
|
outputReviewLedger(ledger, options);
|
|
46474
|
-
return
|
|
47222
|
+
return EXIT_OK11;
|
|
46475
47223
|
}
|
|
46476
47224
|
if (meta.status !== "in_progress" || meta.currentStep < 6) {
|
|
46477
47225
|
return invalidArg(
|
|
@@ -46501,7 +47249,7 @@ async function workflowReview(rootDir, args, options) {
|
|
|
46501
47249
|
if (error) return invalidArg(options, error);
|
|
46502
47250
|
const ledger = await readReviewLedger(rootDir, taskId);
|
|
46503
47251
|
outputReviewLedger(ledger, options);
|
|
46504
|
-
return
|
|
47252
|
+
return EXIT_OK11;
|
|
46505
47253
|
} catch (error) {
|
|
46506
47254
|
return invalidArg(
|
|
46507
47255
|
options,
|
|
@@ -46558,7 +47306,7 @@ async function workflowReview(rootDir, args, options) {
|
|
|
46558
47306
|
);
|
|
46559
47307
|
}
|
|
46560
47308
|
outputReviewLedger(ledger, options);
|
|
46561
|
-
return
|
|
47309
|
+
return EXIT_OK11;
|
|
46562
47310
|
} catch (error) {
|
|
46563
47311
|
return invalidArg(
|
|
46564
47312
|
options,
|
|
@@ -46568,7 +47316,7 @@ async function workflowReview(rootDir, args, options) {
|
|
|
46568
47316
|
}
|
|
46569
47317
|
async function commitReviewSkip(rootDir, meta, reason) {
|
|
46570
47318
|
const ledgerPath = reviewLedgerPath(rootDir, meta.taskId);
|
|
46571
|
-
const metadataPath3 =
|
|
47319
|
+
const metadataPath3 = path66.join(
|
|
46572
47320
|
rootDir,
|
|
46573
47321
|
".mancode",
|
|
46574
47322
|
"workflows",
|
|
@@ -46577,7 +47325,7 @@ async function commitReviewSkip(rootDir, meta, reason) {
|
|
|
46577
47325
|
);
|
|
46578
47326
|
const [originalLedger, originalMetadata] = await Promise.all([
|
|
46579
47327
|
readOptionalText2(ledgerPath),
|
|
46580
|
-
|
|
47328
|
+
readFile47(metadataPath3, "utf-8")
|
|
46581
47329
|
]);
|
|
46582
47330
|
try {
|
|
46583
47331
|
await initializeSkippedReview(rootDir, meta.taskId, reason);
|
|
@@ -46588,7 +47336,7 @@ async function commitReviewSkip(rootDir, meta, reason) {
|
|
|
46588
47336
|
} catch (error) {
|
|
46589
47337
|
const rollback = await Promise.allSettled([
|
|
46590
47338
|
restoreOptionalText(ledgerPath, originalLedger),
|
|
46591
|
-
|
|
47339
|
+
writeFile47(metadataPath3, originalMetadata, "utf-8")
|
|
46592
47340
|
]);
|
|
46593
47341
|
const message = error instanceof Error ? error.message : "review skip failed";
|
|
46594
47342
|
return rollback.some((result2) => result2.status === "rejected") ? `${message}; rollback was incomplete` : message;
|
|
@@ -46648,7 +47396,7 @@ async function workflowCreate(rootDir, args, options) {
|
|
|
46648
47396
|
error instanceof Error ? error.message : "unable to create workflow"
|
|
46649
47397
|
);
|
|
46650
47398
|
}
|
|
46651
|
-
return
|
|
47399
|
+
return EXIT_OK11;
|
|
46652
47400
|
}
|
|
46653
47401
|
async function workflowUpdate(rootDir, taskId, options) {
|
|
46654
47402
|
if (!taskId) {
|
|
@@ -46783,7 +47531,7 @@ async function workflowUpdate(rootDir, taskId, options) {
|
|
|
46783
47531
|
} else {
|
|
46784
47532
|
console.log(`Updated workflow: ${taskId}`);
|
|
46785
47533
|
}
|
|
46786
|
-
return
|
|
47534
|
+
return EXIT_OK11;
|
|
46787
47535
|
}
|
|
46788
47536
|
async function workflowHandoff(rootDir, taskId, options) {
|
|
46789
47537
|
if (!taskId || !isValidWorkflowTaskId(taskId)) {
|
|
@@ -46808,18 +47556,18 @@ async function workflowHandoff(rootDir, taskId, options) {
|
|
|
46808
47556
|
"solo handoff requires an undecided in-progress workflow at step 4 with ready requirements"
|
|
46809
47557
|
);
|
|
46810
47558
|
}
|
|
46811
|
-
const workflowPath =
|
|
46812
|
-
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"))) {
|
|
46813
47561
|
return invalidArg(
|
|
46814
47562
|
options,
|
|
46815
47563
|
"solo handoff requires requirements.md and plan.md"
|
|
46816
47564
|
);
|
|
46817
47565
|
}
|
|
46818
|
-
const statePath =
|
|
47566
|
+
const statePath = path66.join(rootDir, ".mancode", "state.json");
|
|
46819
47567
|
let originalState;
|
|
46820
47568
|
let state;
|
|
46821
47569
|
try {
|
|
46822
|
-
originalState = await
|
|
47570
|
+
originalState = await readFile47(statePath, "utf-8");
|
|
46823
47571
|
state = JSON.parse(originalState);
|
|
46824
47572
|
} catch {
|
|
46825
47573
|
return invalidArg(
|
|
@@ -46880,7 +47628,7 @@ async function workflowHandoff(rootDir, taskId, options) {
|
|
|
46880
47628
|
} else {
|
|
46881
47629
|
console.log(`Handed off plan to solo: ${taskId}`);
|
|
46882
47630
|
}
|
|
46883
|
-
return
|
|
47631
|
+
return EXIT_OK11;
|
|
46884
47632
|
}
|
|
46885
47633
|
async function workflowCompleteHandoff(rootDir, taskId, options) {
|
|
46886
47634
|
const meta = await readWorkflow(rootDir, taskId);
|
|
@@ -46890,11 +47638,11 @@ async function workflowCompleteHandoff(rootDir, taskId, options) {
|
|
|
46890
47638
|
`workflow is not an active solo handoff: ${taskId}`
|
|
46891
47639
|
);
|
|
46892
47640
|
}
|
|
46893
|
-
const statePath =
|
|
47641
|
+
const statePath = path66.join(rootDir, ".mancode", "state.json");
|
|
46894
47642
|
let originalState;
|
|
46895
47643
|
let state;
|
|
46896
47644
|
try {
|
|
46897
|
-
originalState = await
|
|
47645
|
+
originalState = await readFile47(statePath, "utf-8");
|
|
46898
47646
|
state = JSON.parse(originalState);
|
|
46899
47647
|
} catch {
|
|
46900
47648
|
return invalidArg(
|
|
@@ -46932,7 +47680,7 @@ async function workflowCompleteHandoff(rootDir, taskId, options) {
|
|
|
46932
47680
|
} else {
|
|
46933
47681
|
console.log(`Completed solo handoff: ${taskId}`);
|
|
46934
47682
|
}
|
|
46935
|
-
return
|
|
47683
|
+
return EXIT_OK11;
|
|
46936
47684
|
}
|
|
46937
47685
|
async function workflowDecide(rootDir, taskId, options) {
|
|
46938
47686
|
if (!taskId || !isValidWorkflowTaskId(taskId)) {
|
|
@@ -46957,18 +47705,18 @@ async function workflowDecide(rootDir, taskId, options) {
|
|
|
46957
47705
|
`workflow is not ready for a plan-only decision: ${taskId}`
|
|
46958
47706
|
);
|
|
46959
47707
|
}
|
|
46960
|
-
const workflowPath =
|
|
46961
|
-
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"))) {
|
|
46962
47710
|
return invalidArg(
|
|
46963
47711
|
options,
|
|
46964
47712
|
"plan-only requires requirements.md and plan.md"
|
|
46965
47713
|
);
|
|
46966
47714
|
}
|
|
46967
|
-
const statePath =
|
|
47715
|
+
const statePath = path66.join(rootDir, ".mancode", "state.json");
|
|
46968
47716
|
let originalState;
|
|
46969
47717
|
let state;
|
|
46970
47718
|
try {
|
|
46971
|
-
originalState = await
|
|
47719
|
+
originalState = await readFile47(statePath, "utf-8");
|
|
46972
47720
|
state = JSON.parse(originalState);
|
|
46973
47721
|
} catch {
|
|
46974
47722
|
return invalidArg(
|
|
@@ -47017,28 +47765,28 @@ async function workflowDecide(rootDir, taskId, options) {
|
|
|
47017
47765
|
} else {
|
|
47018
47766
|
console.log(`Saved plan without execution: ${taskId}`);
|
|
47019
47767
|
}
|
|
47020
|
-
return
|
|
47768
|
+
return EXIT_OK11;
|
|
47021
47769
|
}
|
|
47022
47770
|
async function commitPlanningTransition(args) {
|
|
47023
|
-
const metadataPath3 =
|
|
47771
|
+
const metadataPath3 = path66.join(
|
|
47024
47772
|
args.rootDir,
|
|
47025
47773
|
".mancode",
|
|
47026
47774
|
"workflows",
|
|
47027
47775
|
args.taskId,
|
|
47028
47776
|
"metadata.json"
|
|
47029
47777
|
);
|
|
47030
|
-
const specPath =
|
|
47778
|
+
const specPath = path66.join(args.rootDir, ".mancode", "memory", "spec.md");
|
|
47031
47779
|
let originalMetadata;
|
|
47032
47780
|
let originalSpec;
|
|
47033
47781
|
try {
|
|
47034
|
-
originalMetadata = await
|
|
47782
|
+
originalMetadata = await readFile47(metadataPath3, "utf-8");
|
|
47035
47783
|
originalSpec = await readOptionalText2(specPath);
|
|
47036
47784
|
} catch (error) {
|
|
47037
47785
|
return error instanceof Error ? `unable to prepare planning transition: ${error.message}` : "unable to prepare planning transition";
|
|
47038
47786
|
}
|
|
47039
47787
|
try {
|
|
47040
47788
|
await updateWorkflow(args.rootDir, args.taskId, args.workflowPatch);
|
|
47041
|
-
await
|
|
47789
|
+
await writeFile47(
|
|
47042
47790
|
args.statePath,
|
|
47043
47791
|
`${JSON.stringify(args.nextState, null, 2)}
|
|
47044
47792
|
`,
|
|
@@ -47052,9 +47800,9 @@ async function commitPlanningTransition(args) {
|
|
|
47052
47800
|
return null;
|
|
47053
47801
|
} catch (error) {
|
|
47054
47802
|
const rollback = await Promise.allSettled([
|
|
47055
|
-
|
|
47056
|
-
|
|
47057
|
-
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")
|
|
47058
47806
|
]);
|
|
47059
47807
|
const message = error instanceof Error ? error.message : "planning transition failed";
|
|
47060
47808
|
return rollback.some((result2) => result2.status === "rejected") ? `${message}; rollback was incomplete` : message;
|
|
@@ -47062,7 +47810,7 @@ async function commitPlanningTransition(args) {
|
|
|
47062
47810
|
}
|
|
47063
47811
|
async function readOptionalText2(filePath) {
|
|
47064
47812
|
try {
|
|
47065
|
-
return await
|
|
47813
|
+
return await readFile47(filePath, "utf-8");
|
|
47066
47814
|
} catch (error) {
|
|
47067
47815
|
if (isNodeError10(error) && error.code === "ENOENT") return null;
|
|
47068
47816
|
throw error;
|
|
@@ -47070,10 +47818,10 @@ async function readOptionalText2(filePath) {
|
|
|
47070
47818
|
}
|
|
47071
47819
|
async function restoreOptionalText(filePath, content) {
|
|
47072
47820
|
if (content === null) {
|
|
47073
|
-
await
|
|
47821
|
+
await rm22(filePath, { force: true });
|
|
47074
47822
|
return;
|
|
47075
47823
|
}
|
|
47076
|
-
await
|
|
47824
|
+
await writeFile47(filePath, content, "utf-8");
|
|
47077
47825
|
}
|
|
47078
47826
|
function readActiveSoloPlan(value) {
|
|
47079
47827
|
if (!value || typeof value !== "object") return null;
|
|
@@ -47091,11 +47839,11 @@ async function workflowList(rootDir, options) {
|
|
|
47091
47839
|
const views = attachActiveChildren(workflows);
|
|
47092
47840
|
if (options.json) {
|
|
47093
47841
|
console.log(JSON.stringify(views, null, 2));
|
|
47094
|
-
return
|
|
47842
|
+
return EXIT_OK11;
|
|
47095
47843
|
}
|
|
47096
47844
|
if (workflows.length === 0) {
|
|
47097
47845
|
console.log("No workflows.");
|
|
47098
|
-
return
|
|
47846
|
+
return EXIT_OK11;
|
|
47099
47847
|
}
|
|
47100
47848
|
const inProgress = workflows.filter((w) => w.status === "in_progress").length;
|
|
47101
47849
|
console.log(
|
|
@@ -47105,7 +47853,7 @@ async function workflowList(rootDir, options) {
|
|
|
47105
47853
|
for (const meta of views) {
|
|
47106
47854
|
console.log(formatWorkflowRow(meta));
|
|
47107
47855
|
}
|
|
47108
|
-
return
|
|
47856
|
+
return EXIT_OK11;
|
|
47109
47857
|
}
|
|
47110
47858
|
async function workflowShow(rootDir, taskId, options) {
|
|
47111
47859
|
if (!taskId) {
|
|
@@ -47142,7 +47890,7 @@ async function workflowShow(rootDir, taskId, options) {
|
|
|
47142
47890
|
2
|
|
47143
47891
|
)
|
|
47144
47892
|
);
|
|
47145
|
-
return
|
|
47893
|
+
return EXIT_OK11;
|
|
47146
47894
|
}
|
|
47147
47895
|
console.log(`Workflow: ${meta.taskId}`);
|
|
47148
47896
|
console.log(`Task: ${meta.task}`);
|
|
@@ -47174,7 +47922,7 @@ async function workflowShow(rootDir, taskId, options) {
|
|
|
47174
47922
|
}
|
|
47175
47923
|
}
|
|
47176
47924
|
}
|
|
47177
|
-
return
|
|
47925
|
+
return EXIT_OK11;
|
|
47178
47926
|
}
|
|
47179
47927
|
async function workflowClean(rootDir, options) {
|
|
47180
47928
|
const workflows = await listWorkflows(rootDir);
|
|
@@ -47242,7 +47990,7 @@ async function workflowClean(rootDir, options) {
|
|
|
47242
47990
|
} else {
|
|
47243
47991
|
console.log(`Removed ${removed.length} workflow(s).`);
|
|
47244
47992
|
}
|
|
47245
|
-
return
|
|
47993
|
+
return EXIT_OK11;
|
|
47246
47994
|
}
|
|
47247
47995
|
function formatWorkflowRow(meta) {
|
|
47248
47996
|
const stepMax = maxWorkflowStep(meta.mode);
|
|
@@ -47712,8 +48460,24 @@ program.command("manps [area]").description("Run deterministic preseason health
|
|
|
47712
48460
|
const code = await manps(process.cwd(), area ?? "all", options);
|
|
47713
48461
|
process.exitCode = code;
|
|
47714
48462
|
});
|
|
47715
|
-
program.command("
|
|
47716
|
-
|
|
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);
|
|
47717
48481
|
process.exitCode = code;
|
|
47718
48482
|
});
|
|
47719
48483
|
program.command("refresh-project").description(
|