@mutmutco/claude-plugin 4.6.40 → 4.6.41
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/cli/dist/main.cjs
CHANGED
|
@@ -22569,7 +22569,10 @@ async function boardDoctor(options, deps = {}) {
|
|
|
22569
22569
|
const holderProvenDead = Boolean(
|
|
22570
22570
|
evidence.marker && evidence.sessionState === "dead" && isHostSessionId(evidence.marker.session) && !evidence.openPr && !evidence.branch
|
|
22571
22571
|
);
|
|
22572
|
-
const freshMarker = evidence.
|
|
22572
|
+
const freshMarker = evidence.marker ? !claimStampStaleness(evidence.marker, {
|
|
22573
|
+
activityAt: [evidence.lastCommentAt],
|
|
22574
|
+
sessionState: evidence.sessionState
|
|
22575
|
+
}).stale : false;
|
|
22573
22576
|
const bits = [
|
|
22574
22577
|
evidence.marker ? `claim marker ${describeClaimMarker(evidence.marker)} ${formatClaimAge(evidence.markerAgeMs)} old` + (evidence.sessionState ? `; local session ${evidence.sessionState}` : "") : evidence.failed.includes("comments") ? "claim marker unreadable" : "no claim marker",
|
|
22575
22578
|
evidence.openPr,
|
|
@@ -23809,6 +23812,9 @@ function parseClaimReleases(body) {
|
|
|
23809
23812
|
}
|
|
23810
23813
|
return out;
|
|
23811
23814
|
}
|
|
23815
|
+
function isClaimStampComment(body) {
|
|
23816
|
+
return parseClaimMarkers(body).length > 0 || parseClaimReleases(body).length > 0;
|
|
23817
|
+
}
|
|
23812
23818
|
function renderClaimReleaseBody(release) {
|
|
23813
23819
|
return `Released by \`${formatSessionIdentity(release)}\` at ${release.ts}.
|
|
23814
23820
|
|
|
@@ -23859,19 +23865,27 @@ function boardItemClaim(item) {
|
|
|
23859
23865
|
function claimStampStaleness(marker, evidence = {}, now = Date.now()) {
|
|
23860
23866
|
const times = [marker.ts, ...evidence.activityAt ?? []].map((t) => t ? Date.parse(t) : Number.NaN);
|
|
23861
23867
|
const idleMs = now - Math.max(...times.filter(Number.isFinite));
|
|
23862
|
-
return { stale:
|
|
23868
|
+
if (evidence.sessionState === "live") return { stale: false, idleMs };
|
|
23869
|
+
if (evidence.linkedWork) return { stale: false, idleMs };
|
|
23870
|
+
return { stale: evidence.sessionState === "dead" || idleMs >= CLAIM_STAMP_IDLE_MS, idleMs };
|
|
23863
23871
|
}
|
|
23864
23872
|
function workIsLive(at, now = Date.now()) {
|
|
23865
23873
|
const idle = now - Date.parse(at ?? "");
|
|
23866
23874
|
return !Number.isFinite(idle) || idle < CLAIM_STAMP_IDLE_MS;
|
|
23867
23875
|
}
|
|
23868
23876
|
function claimFromMarker(item, marker, linked = {}, now = Date.now()) {
|
|
23877
|
+
const sessionState = linked.sessionState ?? probeLocalClaimSession(marker);
|
|
23869
23878
|
return {
|
|
23870
23879
|
marker,
|
|
23871
23880
|
holder: describeClaimMarker(marker),
|
|
23872
23881
|
ageMs: now - Date.parse(marker.ts),
|
|
23873
23882
|
currentlyClaimed: item.assignees.length > 0 && item.status === "In Progress",
|
|
23874
|
-
...
|
|
23883
|
+
...sessionState ? { sessionState } : {},
|
|
23884
|
+
...claimStampStaleness(marker, {
|
|
23885
|
+
activityAt: [...linked.activityAt ?? []],
|
|
23886
|
+
linkedWork: linked.linkedWork,
|
|
23887
|
+
...sessionState ? { sessionState } : {}
|
|
23888
|
+
}, now)
|
|
23875
23889
|
};
|
|
23876
23890
|
}
|
|
23877
23891
|
function latestClaimMarkerAuthor(comments) {
|
|
@@ -23883,14 +23897,15 @@ function latestClaimMarkerAuthor(comments) {
|
|
|
23883
23897
|
}
|
|
23884
23898
|
return void 0;
|
|
23885
23899
|
}
|
|
23886
|
-
function classifyClaimableMarker(comments, actor, now = Date.now(), activityAt = [], viewerLogin) {
|
|
23900
|
+
function classifyClaimableMarker(comments, actor, now = Date.now(), activityAt = [], viewerLogin, sessionState) {
|
|
23887
23901
|
const marker = comments ? latestClaimMarker(comments) : void 0;
|
|
23888
23902
|
if (!marker) return { verdict: "claimable" };
|
|
23889
23903
|
const markerBy = comments ? latestClaimMarkerAuthor(comments) : void 0;
|
|
23890
|
-
|
|
23904
|
+
const state = sessionState ?? probeLocalClaimSession(marker);
|
|
23905
|
+
if (isSeatClaimMarker(marker, actor, { viewerLogin: viewerLogin ?? markerBy, markerBy, now, sessionState: state })) {
|
|
23891
23906
|
return { verdict: "owned", holder: describeClaimMarker(marker) };
|
|
23892
23907
|
}
|
|
23893
|
-
if (!claimStampStaleness(marker, { activityAt }, now).stale) {
|
|
23908
|
+
if (!claimStampStaleness(marker, { activityAt, sessionState: state }, now).stale) {
|
|
23894
23909
|
return { verdict: "taken", holder: describeClaimMarker(marker) };
|
|
23895
23910
|
}
|
|
23896
23911
|
return { verdict: "claimable" };
|
|
@@ -23945,10 +23960,12 @@ async function markStaleClaimStamps(scope, readComments, options = {}) {
|
|
|
23945
23960
|
markerBy: markerBy ?? (bucket === "userOwned" ? item.assignees[0] : void 0),
|
|
23946
23961
|
now
|
|
23947
23962
|
});
|
|
23963
|
+
const sessionState = (options.probeSessionState ?? probeLocalClaimSession)(marker);
|
|
23948
23964
|
const prs = (options.pullRequests ?? []).filter((pr) => pr.closesIssues.some((ref) => ref.toLowerCase() === item.ref.toLowerCase()));
|
|
23949
23965
|
item.claim = claimFromMarker(item, marker, {
|
|
23950
23966
|
activityAt: prs.map((pr) => pr.updatedAt),
|
|
23951
|
-
linkedWork: prs.some((pr) => !pr.updatedAt)
|
|
23967
|
+
linkedWork: prs.some((pr) => !pr.updatedAt),
|
|
23968
|
+
...sessionState ? { sessionState } : {}
|
|
23952
23969
|
}, now);
|
|
23953
23970
|
if (ownSeat && bucket !== "userOwned" && bucket !== "claimable") {
|
|
23954
23971
|
kept.pop();
|
|
@@ -24020,9 +24037,25 @@ async function demoteLiveClaimedClaimables(scope, client, actor = describeSessio
|
|
|
24020
24037
|
var CLAIM_SESSION_ACTIVITY_MS = 30 * 6e4;
|
|
24021
24038
|
var CLAIM_SESSION_PROBE_CACHE_MS = 6e4;
|
|
24022
24039
|
var claimSessionProbeCache = /* @__PURE__ */ new Map();
|
|
24023
|
-
function
|
|
24040
|
+
function scanSessionTranscripts(root, matches, now) {
|
|
24041
|
+
const pending = [root];
|
|
24042
|
+
while (pending.length) {
|
|
24043
|
+
const dir = pending.pop();
|
|
24044
|
+
for (const entry of (0, import_node_fs18.readdirSync)(dir, { withFileTypes: true })) {
|
|
24045
|
+
const path2 = (0, import_node_path15.join)(dir, entry.name);
|
|
24046
|
+
if (entry.isDirectory()) pending.push(path2);
|
|
24047
|
+
else if (entry.isFile() && matches(entry.name.toLowerCase())) {
|
|
24048
|
+
return now - (0, import_node_fs18.statSync)(path2).mtimeMs <= CLAIM_SESSION_ACTIVITY_MS ? "live" : "dead";
|
|
24049
|
+
}
|
|
24050
|
+
}
|
|
24051
|
+
}
|
|
24052
|
+
return "dead";
|
|
24053
|
+
}
|
|
24054
|
+
function probeLocalClaimSession(marker, now = Date.now(), roots = {}) {
|
|
24024
24055
|
if (!isHostSessionId(marker.session) || !marker.host || marker.host.toLowerCase() !== (0, import_node_os11.hostname)().toLowerCase()) return void 0;
|
|
24025
|
-
|
|
24056
|
+
const surface = marker.surface?.toLowerCase() ?? "";
|
|
24057
|
+
const kind = surface.startsWith("claude") ? "claude" : surface.startsWith("jerv") || surface.startsWith("pi") ? "jerv" : void 0;
|
|
24058
|
+
if (!kind) return void 0;
|
|
24026
24059
|
const cacheKey = `${marker.host.toLowerCase()}/${marker.session}`;
|
|
24027
24060
|
const cached = claimSessionProbeCache.get(cacheKey);
|
|
24028
24061
|
if (cached && now - cached.checkedAt <= CLAIM_SESSION_PROBE_CACHE_MS) return cached.state;
|
|
@@ -24030,21 +24063,10 @@ function probeLocalClaimSession(marker, now = Date.now()) {
|
|
|
24030
24063
|
claimSessionProbeCache.set(cacheKey, { checkedAt: now, state });
|
|
24031
24064
|
return state;
|
|
24032
24065
|
};
|
|
24033
|
-
|
|
24034
|
-
|
|
24035
|
-
const
|
|
24036
|
-
|
|
24037
|
-
while (pending.length) {
|
|
24038
|
-
const dir = pending.pop();
|
|
24039
|
-
for (const entry of (0, import_node_fs18.readdirSync)(dir, { withFileTypes: true })) {
|
|
24040
|
-
const path2 = (0, import_node_path15.join)(dir, entry.name);
|
|
24041
|
-
if (entry.isDirectory()) pending.push(path2);
|
|
24042
|
-
else if (entry.isFile() && entry.name.toLowerCase() === wanted) {
|
|
24043
|
-
return remember(now - (0, import_node_fs18.statSync)(path2).mtimeMs <= CLAIM_SESSION_ACTIVITY_MS ? "live" : "dead");
|
|
24044
|
-
}
|
|
24045
|
-
}
|
|
24046
|
-
}
|
|
24047
|
-
return remember("dead");
|
|
24066
|
+
try {
|
|
24067
|
+
const session = marker.session.toLowerCase();
|
|
24068
|
+
const state = kind === "claude" ? scanSessionTranscripts(roots.claude ?? (0, import_node_path15.join)((0, import_node_os11.homedir)(), ".claude", "projects"), (name) => name === `${session}.jsonl`, now) : scanSessionTranscripts(roots.jerv ?? (0, import_node_path15.join)((0, import_node_os11.homedir)(), ".jerv", "agent", "sessions"), (name) => name.endsWith(`_${session}.jsonl`), now);
|
|
24069
|
+
return remember(state);
|
|
24048
24070
|
} catch {
|
|
24049
24071
|
return remember("unverifiable");
|
|
24050
24072
|
}
|
|
@@ -24092,7 +24114,7 @@ async function gatherClaimLiveness(client, repo, number, fetchOpenPulls) {
|
|
|
24092
24114
|
out.marker = latestClaimMarker(rows);
|
|
24093
24115
|
if (!out.marker) out.releasedAt = latestClaimRelease(rows)?.ts;
|
|
24094
24116
|
for (let i = comments.length - 1; i >= 0; i -= 1) {
|
|
24095
|
-
if (comments[i].created_at && !
|
|
24117
|
+
if (comments[i].created_at && !isClaimStampComment(rows[i].body)) {
|
|
24096
24118
|
out.lastCommentAt = comments[i].created_at;
|
|
24097
24119
|
break;
|
|
24098
24120
|
}
|
|
@@ -24167,7 +24189,7 @@ function liveEvidenceLines(evidence, repo) {
|
|
|
24167
24189
|
if (evidence.marker && evidence.sessionState === "live") {
|
|
24168
24190
|
live.push(`claim session ${describeClaimMarker(evidence.marker)} has recent local transcript activity`);
|
|
24169
24191
|
} else if (evidence.marker && evidence.sessionState !== "dead") {
|
|
24170
|
-
const { stale, idleMs } = claimStampStaleness(evidence.marker, { activityAt: [evidence.lastCommentAt] });
|
|
24192
|
+
const { stale, idleMs } = claimStampStaleness(evidence.marker, { activityAt: [evidence.lastCommentAt], sessionState: evidence.sessionState });
|
|
24171
24193
|
const marker = describeClaimMarker(evidence.marker);
|
|
24172
24194
|
if (!stale) {
|
|
24173
24195
|
live.push(evidence.lastCommentAt && Date.parse(evidence.lastCommentAt) > Date.parse(evidence.marker.ts) ? `claim marker from ${marker} is ${formatClaimAge(evidence.markerAgeMs)} old but the issue was commented ${formatClaimAge(idleMs)} ago (session not locally probeable)` : `claim marker from ${marker} is only ${formatClaimAge(evidence.markerAgeMs)} old (session not locally probeable)`);
|
|
@@ -24261,7 +24283,7 @@ async function checkLaneContest(client, item, actor = describeSessionIdentity(),
|
|
|
24261
24283
|
}
|
|
24262
24284
|
}
|
|
24263
24285
|
const carry = staleWorkLines(evidence);
|
|
24264
|
-
const staleStamp = !contested && !resume && !ownSeat && evidence.marker ? `stale claim stamp ${describeClaimMarker(evidence.marker)} (idle ${formatClaimAge(claimStampStaleness(evidence.marker, { activityAt: [evidence.lastCommentAt] }).idleMs)})${carry.length ? `; continue its ${carry.join(" and ")}` : ""}` : void 0;
|
|
24286
|
+
const staleStamp = !contested && !resume && !ownSeat && evidence.marker ? `stale claim stamp ${describeClaimMarker(evidence.marker)} (idle ${formatClaimAge(claimStampStaleness(evidence.marker, { activityAt: [evidence.lastCommentAt], sessionState: evidence.sessionState }).idleMs)})${carry.length ? `; continue its ${carry.join(" and ")}` : ""}` : void 0;
|
|
24265
24287
|
return {
|
|
24266
24288
|
contested,
|
|
24267
24289
|
live,
|
|
@@ -28505,10 +28527,10 @@ var rollout_plan_default = {
|
|
|
28505
28527
|
note: "The v4.0.0 stamp happens at cut time (D6e #4463); until then the candidate is the origin/development head artifacts (built cli/dist + npm pack), identity proven by dist content hash (D6a)."
|
|
28506
28528
|
},
|
|
28507
28529
|
baseline: {
|
|
28508
|
-
version: "4.6.
|
|
28509
|
-
tag: "v4.6.
|
|
28510
|
-
commit: "
|
|
28511
|
-
npm: "@mutmutco/cli@4.6.
|
|
28530
|
+
version: "4.6.41",
|
|
28531
|
+
tag: "v4.6.41",
|
|
28532
|
+
commit: "2cf5b22abb64",
|
|
28533
|
+
npm: "@mutmutco/cli@4.6.41"
|
|
28512
28534
|
},
|
|
28513
28535
|
exitCriterion: "fleet-n-of-n",
|
|
28514
28536
|
hubOnlyShortcut: "forbidden",
|
|
@@ -28525,14 +28547,14 @@ var rollout_plan_default = {
|
|
|
28525
28547
|
repo: "mutmutco/mmi-hub",
|
|
28526
28548
|
role: "canary",
|
|
28527
28549
|
schedule: "train",
|
|
28528
|
-
v3Target: "v4.6.
|
|
28550
|
+
v3Target: "v4.6.41"
|
|
28529
28551
|
}
|
|
28530
28552
|
],
|
|
28531
28553
|
rollbackTrigger: "Any red inside the post-contract soak window: `devops train gate` FAIL attributable to the v4 doors, Hub endpoint health probe failure, a pre-v4 client admitted instead of receiving actionable HTTP 426, or npm consumer install/doctor failure on the v4-only dist.",
|
|
28532
28554
|
rollback: {
|
|
28533
28555
|
independent: true,
|
|
28534
|
-
mechanism: "npm dist-tag latest -> 4.6.
|
|
28535
|
-
v3Target: "v4.6.
|
|
28556
|
+
mechanism: "npm dist-tag latest -> 4.6.41 and redeploy the Hub Lambda from tag v4.6.41 (2cf5b22abb64); installed clients repair via `mmi-cli doctor`. No other cohort is touched.",
|
|
28557
|
+
v3Target: "v4.6.41 (@mutmutco/cli@4.6.41, tag commit 2cf5b22abb64 \u2014 last known-good release carrying the repo-index v4-only contract)"
|
|
28536
28558
|
}
|
|
28537
28559
|
},
|
|
28538
28560
|
{
|
package/cli/package.json
CHANGED
package/package.json
CHANGED
|
@@ -15,7 +15,7 @@ The server exposes `/health` and `/module.js`. Register the module's bundle URL,
|
|
|
15
15
|
1. **Single source of truth:** the source folder of `packages/mmwork-ds` in `mutmutco/MM-Work`, owned by the MM-Work Design Lead (tokens, layers, component bundle, component docs, `DESIGN.md` and its `design.json` sidecar). Never edit the kit or its copies here; a missing piece or variant is built there first, or requested via kit MCP `request_piece`.
|
|
16
16
|
2. **MM Artifact on Live Docs:** Live Docs (`Canlı belgeler / MM-Work`) displays document `3a5c79df-5274-40ad-a1b5-a75e67a74dac` (ATOMIC, module `mm-work-kit`), an MM Artifact in the `design-system` format rebuilt from the kit source on every kit release: Overview, Guide (kit README + `DESIGN.md`), Tokens, Atoms, Molecules, Organisms, Templates and Files. Browse it to see every piece live.
|
|
17
17
|
3. **Impeccable knows Atomic Design at boot:** `impeccable context` loads `PRODUCT.md`, `DESIGN.md` and the `design.json` sidecar in `.impeccable`, which carry the Atomic Design contract 1.1.0: `Atoms -> Molecules -> Organisms -> Templates -> Pages`, upward-only composition enforced by `npm --prefix module run lint` (or `npm run lint` inside `module/`; `mmwork-check-ui` and `mmwork-check-i18n` are bins of `@mutmutco/mmwork-ds`, so a bare `npx mmwork-check-ui` outside that project's installed `node_modules` is resolved as a package name and 404s). Pages arrange exported `@mutmutco/mmwork-ds` pieces around one template and never paint custom controls, raw `<button>`/`<input>`, `mw-*` classes, inline visual styles or raw hex/px values.
|
|
18
|
-
4. **Automatic propagation:** on every kit release the Hub kit-adopt workflow opens an adoption PR here that bumps `@mutmutco/mmwork-ds`, runs `mmwork-sync-impeccable`, and writes `DESIGN.md`, the `.impeccable` design manifest and `.impeccable/config.json` (`hook.enabled: true`) at the repository root, and deletes any stale copies under `module/`. These files are kit-owned: do not hand-edit them, and keep them committed even if `.impeccable/` is ignored (the adoption PR force-stages them).
|
|
18
|
+
4. **Automatic propagation:** on every kit release the Hub kit-adopt workflow opens an adoption PR here that bumps `@mutmutco/mmwork-ds`, runs `mmwork-sync-impeccable`, and writes `DESIGN.md`, the `.impeccable` design manifest and `.impeccable/config.json` (`hook.enabled: true`) at the repository root, and deletes any stale copies under `module/`. These files are kit-owned: do not hand-edit them, and keep them committed even if `.impeccable/` is ignored (the adoption PR force-stages them). The adoption PR and any `kit-adopt` failure issue are Hub-owned — merge the PR or leave it for the Hub's scheduled reconcile, and leave failure issues open and unedited; a hand-closed unmerged adoption PR strands the operation until an explicit `--recover-closed-pr` dispatch retires it.
|
|
19
19
|
5. **Root only:** `PRODUCT.md`, `DESIGN.md`, the `.impeccable` design manifest and `.impeccable/config.json` live only at this repository's root, never duplicated under `module/`; a copy there makes Impeccable treat `module/` as a separate root without `PRODUCT.md` and the config. Run `impeccable context` from the root. Any suite-wide propagation of these files needs an explicit intercom ACK handshake with the MM-Work Design Lead naming the files written and removed, `impeccable context` + `impeccable doctor --json` verification, and the issue/PR reference.
|
|
20
20
|
6. **Front-loaded harmony (owner, 2026-10-25; Hub#8837 / MM-Work#7668):** design work runs one workflow — Front-Loaded Impeccable v4.7.0 + MM Artifacts + Live Docs (`Canlı belgeler`, `3a5c79df-5274-40ad-a1b5-a75e67a74dac`) + Atomic Design Kit (`@mutmutco/mmwork-ds`). The former local stage skill is retired; preview and verify through these tools only.
|
|
21
21
|
|