muse-crew 0.14.4 → 0.14.6
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/AGENTS.md +1 -1
- package/API.md +61 -7
- package/docs/decisions/AGENTS.md +3 -0
- package/docs/decisions/publish-path.md +244 -1
- package/docs/guide.md +42 -6
- package/docs/publish-unknown-recovery.md +28 -113
- package/docs/publish-verification.md +148 -445
- package/docs/release-integrity.md +5 -3
- package/docs/reviews/critic-0145.md +106 -0
- package/lib/AGENTS.md +4 -8
- package/lib/advance-publish-base.js +3 -3
- package/lib/compose-evidence-caption.js +1 -2
- package/lib/compute-publish-diff.js +113 -15
- package/lib/crew-api.js +855 -725
- package/lib/publish-note-vocabulary.js +137 -24
- package/lib/schema.sql +19 -0
- package/package.json +1 -1
- package/seed/AGENTS.md +1 -0
- package/seed/cron-body-ack-scan.md +44 -0
- package/seed/cron-body-template.md +65 -65
- package/seed/crons.json +12 -0
- package/workflows/bugfix.js +146 -740
- package/workflows/chore.js +146 -740
- package/workflows/crew-dispatch.js +36 -0
- package/workflows/crew-init.js +23 -0
- package/workflows/crew-uninstall.js +7 -4
- package/workflows/standard.js +146 -763
- package/lib/build-readback-request.js +0 -140
- package/lib/classify-publish-absence.js +0 -462
- package/lib/publish-content.js +0 -154
- package/lib/readback-disk.js +0 -195
- package/lib/retry-publish.js +0 -405
- package/lib/verify-publish.js +0 -414
|
@@ -50,6 +50,42 @@ const MAX_TASKS_PER_POLL = inputs.maxTasksPerPoll || 6;
|
|
|
50
50
|
// inputs.registry. Fall back to the agent() load only when the caller
|
|
51
51
|
// predates the registry — slow, but never broken.
|
|
52
52
|
var registryResult = inputs.registry;
|
|
53
|
+
// Nested-registry seam (2026-09-20): a malformed nested registry object
|
|
54
|
+
// (e.g. a workflow key mapping to null/undefined, or a steps entry without
|
|
55
|
+
// a name) used to die deep in the lookup tables with a cryptic TypeError
|
|
56
|
+
// ("cannot convert 'null' or 'undefined' to object"). Validate the shape
|
|
57
|
+
// deterministically first; a malformed registry falls back to the slow
|
|
58
|
+
// agent load with a loud log, exactly like a missing one — the defect is
|
|
59
|
+
// named, never a crash.
|
|
60
|
+
function validateRegistry(reg) {
|
|
61
|
+
var wfNames = ["standard", "bugfix", "chore", "docs", "upgrade"];
|
|
62
|
+
if (!reg || typeof reg !== "object" || Array.isArray(reg)) {
|
|
63
|
+
return { ok: false, reason: "registry is missing or not an object" };
|
|
64
|
+
}
|
|
65
|
+
for (var i = 0; i < wfNames.length; i++) {
|
|
66
|
+
var wf = reg[wfNames[i]];
|
|
67
|
+
if (!wf || typeof wf !== "object") {
|
|
68
|
+
return { ok: false, reason: "workflow '" + wfNames[i] + "' is missing or not an object" };
|
|
69
|
+
}
|
|
70
|
+
if (!Array.isArray(wf.steps)) {
|
|
71
|
+
return { ok: false, reason: "workflow '" + wfNames[i] + "' has no steps array" };
|
|
72
|
+
}
|
|
73
|
+
for (var j = 0; j < wf.steps.length; j++) {
|
|
74
|
+
if (!wf.steps[j] || typeof wf.steps[j].name !== "string") {
|
|
75
|
+
return { ok: false, reason: "workflow '" + wfNames[i] + "' step " + j + " has no name" };
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
if (typeof wf.reworkTarget !== "string") {
|
|
79
|
+
return { ok: false, reason: "workflow '" + wfNames[i] + "' has no reworkTarget string" };
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return { ok: true };
|
|
83
|
+
}
|
|
84
|
+
var registryCheck = validateRegistry(registryResult);
|
|
85
|
+
if (!registryCheck.ok) {
|
|
86
|
+
log("WARNING: registry failed shape validation (" + registryCheck.reason + ") — falling back to slow registry load");
|
|
87
|
+
registryResult = null;
|
|
88
|
+
}
|
|
53
89
|
if (!registryResult) {
|
|
54
90
|
log("WARNING: no registry in args — falling back to slow registry load");
|
|
55
91
|
registryResult = await agent(
|
package/workflows/crew-init.js
CHANGED
|
@@ -58,6 +58,29 @@ if (!crewHome) throw new Error("crewHome is required — e.g. ~/workspace/.crew
|
|
|
58
58
|
// create projects later via crew-api.js). One without the other is an error.
|
|
59
59
|
if (!!dashboardSlug !== !!dashboardRepoPath) throw new Error("dashboardSlug and dashboardRepoPath must be provided together, or neither (omit both for a CLI-only install without a dashboard)");
|
|
60
60
|
|
|
61
|
+
// ── Cron id override validation (2026-09-20, 0.14.6 REVIEW) ──
|
|
62
|
+
// Uninstall's discovery fallback only recognizes live ids that start with
|
|
63
|
+
// a manifest entry id + "-" (crew-poll-, crew-ack-scan-,
|
|
64
|
+
// crew-update-watch-). An override that breaks that convention would
|
|
65
|
+
// survive uninstall if .cron-registry.json were ever lost — so overrides
|
|
66
|
+
// must keep the manifest-id prefix. Fail closed at init, before any cron
|
|
67
|
+
// is created.
|
|
68
|
+
for (const manifestId of Object.keys(cronIds)) {
|
|
69
|
+
const liveId = cronIds[manifestId];
|
|
70
|
+
if (typeof liveId !== "string" || !liveId.startsWith(manifestId + "-")) {
|
|
71
|
+
return {
|
|
72
|
+
__hatchWorkflowControl: "blocked",
|
|
73
|
+
result: {
|
|
74
|
+
blocked_reason: "Invalid cronIds override",
|
|
75
|
+
message: "cronIds[\"" + manifestId + "\"] must start with \"" + manifestId + "-\" — got " +
|
|
76
|
+
JSON.stringify(liveId) + ". Uninstall's discovery fallback only recognizes live ids under " +
|
|
77
|
+
"the manifest-id prefix; an arbitrary id could survive uninstall if the cron registry " +
|
|
78
|
+
"were lost. Re-run init with a prefixed id."
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
61
84
|
const orchDir = crewHome + "/.orchestration";
|
|
62
85
|
|
|
63
86
|
// ── Dependency node_modules resolution (clean-room defect 2026-09-16) ──
|
|
@@ -158,11 +158,14 @@ try {
|
|
|
158
158
|
"Steps:\n" +
|
|
159
159
|
"1. Registry: if " + sq(crewHomeExpanded + "/.cron-registry.json") + " exists, read it\n" +
|
|
160
160
|
" and take its crons[].id list as registry candidates.\n" +
|
|
161
|
-
"2. Discovery: call cron_list. For every job whose id starts with
|
|
161
|
+
"2. Discovery: call cron_list. For every job whose id starts with one of\n" +
|
|
162
|
+
" 'crew-poll-', 'crew-ack-scan-', or 'crew-update-watch-' (the three\n" +
|
|
163
|
+
" seed/crons.json manifest entry ids, each suffixed with the instance id),\n" +
|
|
162
164
|
" call cron_view and keep it as a discovery candidate when the job body\n" +
|
|
163
|
-
" contains the crewHome string '" + crewHomeExpanded + "' (the
|
|
164
|
-
"
|
|
165
|
-
" is never a live crew job
|
|
165
|
+
" contains the crewHome string '" + crewHomeExpanded + "' (the cron body templates\n" +
|
|
166
|
+
" embed the crew home path). A bare manifest id ('crew-poll', 'crew-ack-scan',\n" +
|
|
167
|
+
" 'crew-update-watch') with no instance suffix is never a live crew job —\n" +
|
|
168
|
+
" never remove it.\n" +
|
|
166
169
|
"3. Removal list = registry candidates ∪ discovery candidates, deduped.\n" +
|
|
167
170
|
" SAFETY: remove only jobs on this list. When in doubt about any job, fail\n" +
|
|
168
171
|
" closed (passed: false) instead of guessing.\n" +
|