@galda/cli 0.10.104 → 0.10.105
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/app/index.html +50 -28
- package/package.json +1 -1
package/app/index.html
CHANGED
|
@@ -2235,6 +2235,19 @@
|
|
|
2235
2235
|
/* Changed/Tests aligns with the request TEXT, not the number/chevron — same 18px
|
|
2236
2236
|
the fold body below uses, so both sit under the same column (Masa 2026-07-29). */
|
|
2237
2237
|
.redesign .rqit .rqev{font-size:12px;color:var(--ink3);margin:5px 0 0;padding-left:18px}
|
|
2238
|
+
/* Canonical requirement coverage: one compact ledger, not three competing
|
|
2239
|
+
interpretations. Status is text + a small rule/mark (no badge surface),
|
|
2240
|
+
and Manager checks stay visually distinct from worker claims. */
|
|
2241
|
+
.redesign .rqcov{display:flex;flex-direction:column;margin-top:2px}
|
|
2242
|
+
.redesign .rqcov-row{padding:11px 0;border-top:1px solid var(--hair)}
|
|
2243
|
+
.redesign .rqcov-row:first-child{padding-top:0;border-top:0}
|
|
2244
|
+
.redesign .rqcov-main{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:14px;align-items:baseline}
|
|
2245
|
+
.redesign .rqcov-text{font-size:13.5px;line-height:1.55;color:var(--ink)}
|
|
2246
|
+
.redesign .rqcov-state{font:600 10px/1.4 var(--mono);letter-spacing:.02em;color:var(--ink3);white-space:nowrap}
|
|
2247
|
+
.redesign .rqcov-state.verified{color:var(--green)}
|
|
2248
|
+
.redesign .rqcov-state.failed{color:var(--danger)}
|
|
2249
|
+
.redesign .rqcov-detail{margin-top:5px;font-size:11.5px;line-height:1.55;color:var(--ink3)}
|
|
2250
|
+
.redesign .rqcov-detail b{font-weight:600;color:var(--ink2)}
|
|
2238
2251
|
/* A long ask folds with the SAME .lacc pulldown Activity/Conversation use — chevron on
|
|
2239
2252
|
the peek line, body is the genuine rest (no duplicate, no trailing "…": Masa
|
|
2240
2253
|
2026-07-29 flagged both the vertical anchor line and the "…" as unnecessary — the
|
|
@@ -9473,6 +9486,33 @@ function latestGoalRunForOutcome(goalId, tasks, outcome){
|
|
|
9473
9486
|
note: prev.run?.note ? `${note} ${prev.run.note}` : note,
|
|
9474
9487
|
};
|
|
9475
9488
|
}
|
|
9489
|
+
function canonicalRequirementCoverage(goal, tasks){
|
|
9490
|
+
const requirements = Array.isArray(goal?.requirements) ? goal.requirements.filter((r) => r?.id && r?.text) : [];
|
|
9491
|
+
if (!requirements.length) {
|
|
9492
|
+
return (tasks || []).filter((t) => t.goalId === goal?.id && (t.detail || t.title) && (!t.reply || !t.replyFrom || t.replyFrom === 'you'))
|
|
9493
|
+
.sort((a, b) => (a.num ?? 0) - (b.num ?? 0))
|
|
9494
|
+
.map((t) => ({ id: `legacy-task-${t.id}`, text: String((t.reply ? t.detail : t.title) ?? t.title ?? '').replace(/\s+/g, ' ').trim(), coverage: 'unverified', legacy: true }));
|
|
9495
|
+
}
|
|
9496
|
+
const attemptOrder = new Map((goal.attempts || []).map((attempt, index) => [attempt.id, index]));
|
|
9497
|
+
const evidence = Array.isArray(goal.requirementEvidence) ? goal.requirementEvidence : [];
|
|
9498
|
+
return requirements.map((requirement) => {
|
|
9499
|
+
const rows = evidence.filter((row) => row?.requirementId === requirement.id)
|
|
9500
|
+
.sort((a, b) => (attemptOrder.get(a.attemptId) ?? -1) - (attemptOrder.get(b.attemptId) ?? -1));
|
|
9501
|
+
const latestAttemptId = rows.at(-1)?.attemptId;
|
|
9502
|
+
const latestRows = latestAttemptId ? rows.filter((row) => row.attemptId === latestAttemptId) : [];
|
|
9503
|
+
const statuses = latestRows.map((row) => row.coverage);
|
|
9504
|
+
const coverage = statuses.includes('failed') ? 'failed'
|
|
9505
|
+
: statuses.includes('verified') ? 'verified'
|
|
9506
|
+
: statuses.length && statuses.every((status) => status === 'not-applicable') ? 'not-applicable'
|
|
9507
|
+
: 'unverified';
|
|
9508
|
+
const claims = [...new Set(latestRows.map((row) => row.claim).filter(Boolean))];
|
|
9509
|
+
const workerEvidence = [...new Set(latestRows.map((row) => row.workerEvidence || row.evidence).filter(Boolean))];
|
|
9510
|
+
const checks = latestRows.flatMap((row) => Array.isArray(row.checks) ? row.checks : [])
|
|
9511
|
+
.filter((check) => Array.isArray(check.requirementIds) && check.requirementIds.includes(requirement.id));
|
|
9512
|
+
const checkFacts = [...new Set(checks.map((check) => `${check.kind}: ${check.status}`))];
|
|
9513
|
+
return { id: requirement.id, text: requirement.text, coverage, claims, workerEvidence, checkFacts, attemptId: latestAttemptId ?? null };
|
|
9514
|
+
});
|
|
9515
|
+
}
|
|
9476
9516
|
// One digest-row → one See-all card item. Extracted from saRows (2026-07-24) so a single
|
|
9477
9517
|
// "Needs you" goal can be opened as the SAME review card (saLedgerRows solo mode) — the card's
|
|
9478
9518
|
// whole shape (Request/Result/Proof/Activity, empty sections auto-hidden) is reused verbatim.
|
|
@@ -9522,10 +9562,7 @@ function saRowFromDigest(r, gs, ts){
|
|
|
9522
9562
|
// simply omit it, so the UI remains backward compatible during rollout.
|
|
9523
9563
|
attempt: g?.reviewAttempt ?? null,
|
|
9524
9564
|
unmappedChangedFiles: outcome?.unmappedChangedFiles ?? [],
|
|
9525
|
-
|
|
9526
|
-
requirementCoverage: ts.filter((t) => t.goalId === g?.id && (t.detail || t.title)).sort((a, b) => (a.num ?? 0) - (b.num ?? 0)).map((t) => ({ text: String((t.reply ? t.detail : t.title) ?? t.title ?? '').replace(/\s+/g, ' ').trim(), taskStatus: t.status, evidenceStatus: t.requirementEvidence?.requirements?.[0]?.status ?? null })),
|
|
9527
|
-
requirementEvidence: outcome?.requirementEvidence?.requirements ?? [],
|
|
9528
|
-
requirementCoverage: ts.filter((t) => t.goalId === g?.id && (t.detail || t.title) && (!t.reply || !t.replyFrom || t.replyFrom === 'you')).sort((a, b) => (a.num ?? 0) - (b.num ?? 0)).map((t) => ({ text: String((t.reply ? t.detail : t.title) ?? t.title ?? '').replace(/\s+/g, ' ').trim(), status: t.status })),
|
|
9565
|
+
requirementCoverage: canonicalRequirementCoverage(g, ts),
|
|
9529
9566
|
did, siblings, risk: g?.risk ?? null,
|
|
9530
9567
|
verificationInfraError: g?.verificationInfraError ?? r.verificationInfraError ?? null,
|
|
9531
9568
|
prNote: g?.prNote ?? null,
|
|
@@ -10081,31 +10118,18 @@ function saItemHtml(it, i){
|
|
|
10081
10118
|
const reqSec = reqStackRows
|
|
10082
10119
|
? `<section class="rsec rreq" data-reqmsgs="${gk}"><div class="rsec-h">Request</div><div class="rqlist">${reqStackRows}</div></section>`
|
|
10083
10120
|
: '';
|
|
10084
|
-
const reqVerify = it.requirementVerification;
|
|
10085
|
-
const reqVerifyParts = [
|
|
10086
|
-
reqVerify?.proof?.verified ? 'Independent proof recorded' : reqVerify?.proof ? 'Proof recorded' : '',
|
|
10087
|
-
reqVerify?.run?.url ? `Open it: ${reqVerify.run.url}` : '',
|
|
10088
|
-
Array.isArray(reqVerify?.changedFiles) && reqVerify.changedFiles.length ? `Files: ${reqVerify.changedFiles.join(' · ')}` : '',
|
|
10089
|
-
].filter(Boolean);
|
|
10090
|
-
const reqVerifySec = reqVerifyParts.length ? `<section class="rsec"><div class="rsec-h">Requirement verification</div><p class="rbody v">${esc(reqVerifyParts.join(' · '))}</p></section>` : '';
|
|
10091
10121
|
const coverage = (it.requirementCoverage || []).filter((r) => r.text);
|
|
10092
|
-
// For one requirement copied from Request, its status is useful but the full
|
|
10093
|
-
// sentence is not. Multiple or narrowed requirements retain their text.
|
|
10094
|
-
const coverageIsSingleRequest = coverage.length === 1
|
|
10095
|
-
&& String(coverage[0].text).replace(/\s+/g, ' ').trim() === requestText;
|
|
10096
10122
|
const coverageRows = coverage.map((r) => {
|
|
10097
|
-
const
|
|
10098
|
-
const
|
|
10099
|
-
|
|
10100
|
-
|
|
10101
|
-
|
|
10102
|
-
|
|
10103
|
-
|
|
10104
|
-
|
|
10105
|
-
const tone = entry.status === 'addressed' ? 'ok' : entry.status === 'partial' ? '' : 'dim';
|
|
10106
|
-
return `<p class="rbody v"><b class="${tone}">${esc(entry.status)}</b> · ${esc(entry.evidence || entry.id)}</p>`;
|
|
10123
|
+
const labels = { verified: 'Verified', failed: 'Failed', 'not-applicable': 'Not applicable', unverified: 'Not verified' };
|
|
10124
|
+
const details = [
|
|
10125
|
+
r.legacy ? 'Legacy item — no canonical evidence was recorded' : '',
|
|
10126
|
+
r.checkFacts?.length ? `Manager: ${r.checkFacts.join(' · ')}` : '',
|
|
10127
|
+
r.claims?.length ? `Worker claim: ${r.claims.join(', ')}` : '',
|
|
10128
|
+
r.workerEvidence?.length ? r.workerEvidence.join(' · ') : '',
|
|
10129
|
+
].filter(Boolean);
|
|
10130
|
+
return `<div class="rqcov-row" data-requirement-id="${esc(r.id)}"><div class="rqcov-main"><div class="rqcov-text">${esc(r.text)}</div><span class="rqcov-state ${esc(r.coverage)}">${esc(labels[r.coverage] || labels.unverified)}</span></div>${details.length ? `<div class="rqcov-detail">${details.map((detail, index) => index === 0 ? esc(detail) : `<br>${esc(detail)}`).join('')}</div>` : ''}</div>`;
|
|
10107
10131
|
}).join('');
|
|
10108
|
-
const
|
|
10132
|
+
const coverageSec = coverageRows ? `<section class="rsec"><div class="rsec-h">Requirement coverage</div><div class="rqcov">${coverageRows}</div></section>` : '';
|
|
10109
10133
|
// ── Open it (Masa 2026-07-22): a plain section in the card's own typography — the same
|
|
10110
10134
|
// heading + body shape as Request and Result, not a chip in another vocabulary. The
|
|
10111
10135
|
// address the worker declared IS the control (press it → the process starts on demand →
|
|
@@ -10355,8 +10379,6 @@ function saItemHtml(it, i){
|
|
|
10355
10379
|
${S('Open it', openBody + infraBody)}
|
|
10356
10380
|
${S('What to check', checkBody)}
|
|
10357
10381
|
${coverageSec}
|
|
10358
|
-
${evidenceSec}
|
|
10359
|
-
${reqVerifySec}
|
|
10360
10382
|
${S('Run state', interruptedBody)}
|
|
10361
10383
|
${S('PR', prRepairBody)}
|
|
10362
10384
|
${S('Also carries', carriesBody)}
|
package/package.json
CHANGED