Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# Changelog
## Unreleased

- **archify v3.0.1.** `vendor/archify` moves from v3.0.0 to v3.0.1, commit `2ab3cae`, by `bin/archify-sync.mjs`. Release notes: https://github.com/tt-a1i/archify/releases/tag/v3.0.1
- **The archify workflow stops at the pushed branch.** The scheduled run on 2026-09-28 vendored archify v3.0.0, pushed `archify/v3.0.0` and then failed at `gh pr create`: GitHub Actions may not open pull requests in this repository. The workflow now pushes the branch, leaves a notice that links the compare page and exits 0. It repeats the notice each week until the branch is merged, and it no longer asks for the `pull-requests` permission. `docs/archify.md` says to open the PR by hand.
- **Chart bars are square at both ends (#162).** The engine painted every `bar` row with `border-radius:6px 6px 0 0`, so a column was rounded on its value end and an `hbar` bar on its top corners, and each read as a tab. `template.html` now paints no radius on a bar: every chart form (`bar`, `hbar`, a `compare` series, the template bars) is square by default, and a row that sets `radius` rounds all four corners. SKILL.md's row table and `docs/charts.md` say so. Deck and library html rebuilt. Gates: test/chart.test.mjs asserts that the chart rows and every template's rows carry no one-sided radius, and renders the chart forms and the chart templates in Chromium to check that each bar is square and that no mark draws a one-sided radius.
- **Undo and Delete buttons in the HUD.** Undo (⌘Z) and delete (⌫) were keys only, so a phone could neither take back an edit nor remove a row or a slide (#167). The edit group now carries an Undo button (Lucide `undo-2`) and a Delete button (Lucide `trash-2`) on every pointer, after duplicate. Each runs the code its key runs in the same place: the browser's text undo and delete while a row is being edited, `sheetKey()` in the contact sheet, `undo()` and the new `delSel()` (the canvas key's own body, moved into a function both share) on the canvas. Undo is disabled while the undo stack is empty; Delete is disabled with no selection on the canvas, and in the sheet with no selection or one slide left. Neither appears in the present-mode pill. The HUD manifest in `docs/editor.md` gains `undobtn` and `delbtn`. Guarded by `test/hud.test.mjs` and a tap-only test in `test/touch.test.mjs`.
Expand Down
4 changes: 2 additions & 2 deletions docs/archify.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# archify

decklet ships [archify](https://github.com/tt-a1i/archify) (MIT, tt-a1i) at **v3.0.0** in `vendor/archify`. archify turns a typed JSON spec into one standalone, explorable HTML diagram: architecture, workflow, sequence, data flow and lifecycle, with its own validator and export to PNG, SVG and WebM.
decklet ships [archify](https://github.com/tt-a1i/archify) (MIT, tt-a1i) at **v3.0.1** in `vendor/archify`. archify turns a typed JSON spec into one standalone, explorable HTML diagram: architecture, workflow, sequence, data flow and lifecycle, with its own validator and export to PNG, SVG and WebM.

## Figure or archify

Expand Down Expand Up @@ -32,7 +32,7 @@ To move the pin, run one command:

```bash
node bin/archify-sync.mjs # the latest release
node bin/archify-sync.mjs --tag v3.0.0 # one tag, forward or back
node bin/archify-sync.mjs --tag v3.0.1 # one tag, forward or back
node bin/archify-sync.mjs --check # exit 1 when a newer release is out
```

Expand Down
8 changes: 4 additions & 4 deletions vendor/archify.lock.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"repo": "tt-a1i/archify",
"tag": "v3.0.0",
"commit": "9286c3b9c2cef359e98586b420d769d87bcb163f",
"zipSha256": "e30f65ddab8bbb0c467fa4be5bccf7e3853bd3ee86e8338f31e102037496be18",
"treeSha256": "05ecbd8434825106e8a5284ef3f1a61f0bd3f9f375554a9e31795c67e304ea7e"
"tag": "v3.0.1",
"commit": "2ab3cae7ac2c2a55d7386ca789d03c4fcd31816c",
"zipSha256": "b0b23bd28db314f04ca8ab9620fe20f8c1ac6474a3546bd8fe4679508aa1b7f5",
"treeSha256": "3026a902111b9a6540b26f1b413ebef599aaa580aa134d929fe01cdf8494edf1"
}
7 changes: 2 additions & 5 deletions vendor/archify/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ For a real codebase, read [Repository authoring](references/repository-authoring

When the user supplies a frozen candidate, run `finalize` first as one CLI invocation. Its passing receipt completes the automated gates; follow any visual review recommendation under Delivery before claiming visual quality. For repair, follow step 5.

The optional update check never delays `finalize`; see Update awareness.
`finalize` includes a bounded update check in its delivery receipt; see Update awareness.

## Fast authoring path

Expand All @@ -43,10 +43,7 @@ Use this path for ordinary generation. Read branch references only when their st

## Update awareness

After the first candidate exists, a harness with true parallel tool calls may run `scripts/check-update.mjs` once alongside `finalize`. Otherwise skip it without delaying delivery.

- For `silent`, continue without mentioning the update check.
- For `update_available`, read `references/update-awareness.md`, follow it, then continue the requested task.
`finalize` and standalone `deliver` include `update` in their receipts. Do not run a separate check for the same delivery. If `update.noticeRequired` is true, read `references/update-awareness.md` and keep one update line in your final response to the user, even after a quality gate fails. For a task with several diagrams, mention the update once in the final response. Snooze or ignore a reminder only when the user explicitly asks; never install or update on your own initiative.

Before the first candidate, use the authoring references and relevant repository source, not Archify implementation or tests. Inspect Archify implementation if diagnostics remain unactionable after focused repairs.

Expand Down
2 changes: 1 addition & 1 deletion vendor/archify/assets/template.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="generator" content="archify 3.0.0">
<meta name="generator" content="archify 3.0.1">
<meta name="archify-reader-contract" content="declared-wide-v1">
<title>[PROJECT NAME] Architecture Diagram</title>
<script>
Expand Down
74 changes: 45 additions & 29 deletions vendor/archify/bin/archify.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -4163,7 +4163,7 @@ function commandRender(args) {
if (result.status !== 0) exitFrom(result);
}

function reportArtifactFailure({ command, json, stage, type, input, output, error, diagnostics = [], status = 1, checker, receiptId, provenance }) {
function reportArtifactFailure({ command, json, stage, type, input, output, error, diagnostics = [], status = 1, checker, receiptId, provenance, update }) {
const receipt = {
schemaVersion: 1,
ok: false,
Expand All @@ -4177,9 +4177,13 @@ function reportArtifactFailure({ command, json, stage, type, input, output, erro
diagnostics,
...(provenance ? { provenance } : {}),
...(checker ? { checker } : {}),
...(update ? { update } : {}),
};
if (json) console.log(JSON.stringify(receipt, null, 2));
else console.error(formatDiagnostics(error, diagnostics));
else {
console.error(formatDiagnostics(error, diagnostics));
if (update?.noticeRequired) console.log(update.noticeText);
}
process.exitCode = status;
}

Expand Down Expand Up @@ -4319,16 +4323,18 @@ async function commandDeliver(args) {
releaseRegularFileBinding,
};
const receiptId = randomUUID();
let updateCheck;
let deliveryOwnership;
let recoveryRequired = false;
let stagingDirectory;
let stagingIdentity;
let deliveryAliasOutput;
const reportDeliveryFailure = (options) => {
const reportDeliveryFailure = async (options) => {
const ownership = deliveryOwnership;
deliveryOwnership = undefined;
const recorded = writeDeliveryFailureReceipt({
...options,
...(updateCheck ? { update: await updateCheck } : {}),
pathsAlias,
receiptId,
ownership,
Expand All @@ -4343,6 +4349,10 @@ async function commandDeliver(args) {
recoveryRequired = true;
}
};
const reportPreparedArtifactFailure = async (options) => reportArtifactFailure({
...options,
...(updateCheck ? { update: await updateCheck } : {}),
});
const inputPath = path.resolve(input);
let specification;
let diagram;
Expand All @@ -4351,7 +4361,7 @@ async function commandDeliver(args) {
diagram = JSON.parse(specification.toString('utf8'));
} catch (error) {
const repair = inputDiagnostic(error, inputPath);
reportDeliveryFailure({
await reportDeliveryFailure({
json,
stage: 'input',
type,
Expand Down Expand Up @@ -4402,9 +4412,9 @@ async function commandDeliver(args) {
})],
};
if (outputPath) {
reportDeliveryFailure(failure);
await reportDeliveryFailure(failure);
} else {
reportArtifactFailure({ ...failure, command: 'deliver', receiptId });
await reportPreparedArtifactFailure({ ...failure, command: 'deliver', receiptId });
}
return;
}
Expand All @@ -4413,7 +4423,7 @@ async function commandDeliver(args) {
fs.mkdirSync(outputDirectory, { recursive: true });
} catch (error) {
const message = `Could not create delivery directory "${outputDirectory}": ${error.message}`;
reportDeliveryFailure({
await reportDeliveryFailure({
json,
stage: 'prepare',
type,
Expand Down Expand Up @@ -4466,9 +4476,9 @@ async function commandDeliver(args) {
})],
};
if (error?.code === 'ARCHIFY_SIDECAR_NAMESPACE_INDETERMINATE') {
reportArtifactFailure({ ...failure, command: 'deliver', receiptId });
await reportPreparedArtifactFailure({ ...failure, command: 'deliver', receiptId });
} else {
reportDeliveryFailure(failure);
await reportDeliveryFailure(failure);
}
return;
}
Expand Down Expand Up @@ -4506,8 +4516,10 @@ async function commandDeliver(args) {
outputPath = artifactCapture.commitPath;
provenancePath = provenanceCapture.commitPath;
outputDirectory = path.dirname(outputPath);
const { startDeliveryUpdateCheck } = await import('./delivery-update.mjs');
updateCheck = startDeliveryUpdateCheck();
} catch (error) {
reportArtifactFailure({
await reportPreparedArtifactFailure({
command: 'deliver', json, stage: 'prepare', type, input: inputPath, output: outputPath, receiptId,
error: error.message,
diagnostics: error.archifyDiagnostics || [diagnostic({
Expand All @@ -4532,7 +4544,7 @@ async function commandDeliver(args) {
stagingIdentity = staging.identity;
} catch (error) {
const message = `Could not create a delivery candidate beside "${outputPath}": ${error.message}`;
reportDeliveryFailure({
await reportDeliveryFailure({
json,
stage: 'prepare',
type,
Expand Down Expand Up @@ -4586,7 +4598,7 @@ async function commandDeliver(args) {
} catch (error) {
const message = `Could not start delivery for "${outputPath}": ${error.message}`;
const recorded = error.deliveryFailureRecord;
reportArtifactFailure({
await reportPreparedArtifactFailure({
command: 'deliver', json, stage: 'prepare', type, input: inputPath, output: outputPath, receiptId,
error: message,
...(recorded ? { provenance: recorded.status } : {}),
Expand Down Expand Up @@ -4625,7 +4637,7 @@ async function commandDeliver(args) {
releaseError = cause;
}
deliveryOwnership = undefined;
reportArtifactFailure({
await reportPreparedArtifactFailure({
command: 'deliver', json, stage: 'prepare', type, input: inputPath, output: outputPath, receiptId,
error: error.message,
diagnostics: [
Expand Down Expand Up @@ -4653,7 +4665,7 @@ async function commandDeliver(args) {
// The lock is the remaining fail-closed barrier. Do not write failure
// provenance or release it after journal rollback itself became unsafe.
deliveryOwnership = undefined;
reportArtifactFailure({
await reportPreparedArtifactFailure({
command: 'deliver', json, stage: 'prepare', type, input: inputPath, output: outputPath, receiptId,
error: `Could not persist the delivery attempt before rendering: ${error.message}`,
diagnostics: [deliveryJournalRecoveryDiagnostic(outputPath, error)],
Expand All @@ -4668,14 +4680,14 @@ async function commandDeliver(args) {
recoveryDirectory: stagingDirectory,
recoverableBackups: [],
};
reportArtifactFailure({
await reportPreparedArtifactFailure({
command: 'deliver', json, stage: 'prepare', type, input: inputPath, output: outputPath, receiptId,
error: `Could not persist the delivery attempt before rendering: ${error.message}`,
diagnostics: [deliveryLockFailureDiagnostic(outputPath, error)],
});
return;
}
reportDeliveryFailure({
await reportDeliveryFailure({
json, stage: 'prepare', type, input: inputPath, output: outputPath,
error: 'Could not persist the delivery attempt before rendering.',
diagnostics: [diagnostic({
Expand All @@ -4700,7 +4712,7 @@ async function commandDeliver(args) {
);
} catch (error) {
const message = `Could not freeze the delivery specification: ${error.message}`;
reportDeliveryFailure({
await reportDeliveryFailure({
json,
stage: 'prepare',
type,
Expand All @@ -4724,7 +4736,7 @@ async function commandDeliver(args) {
});
if (render.status !== 0) {
const failure = rendererFailure(render);
reportDeliveryFailure({
await reportDeliveryFailure({
json,
stage: 'render',
type,
Expand Down Expand Up @@ -4760,7 +4772,7 @@ async function commandDeliver(args) {
} catch {
checker = { ok: false, file: outputPath, diagnostic: check.stdout.trim() };
}
reportDeliveryFailure({
await reportDeliveryFailure({
json,
stage: 'check',
type,
Expand All @@ -4779,7 +4791,7 @@ async function commandDeliver(args) {
result = JSON.parse(check.stdout);
} catch (error) {
const message = `Could not parse the successful artifact-check receipt: ${error.message}`;
reportDeliveryFailure({
await reportDeliveryFailure({
json,
stage: 'receipt',
type,
Expand All @@ -4800,7 +4812,7 @@ async function commandDeliver(args) {
artifact = fs.readFileSync(candidatePath);
} catch (error) {
const message = `Could not read the verified delivery candidate: ${error.message}`;
reportDeliveryFailure({
await reportDeliveryFailure({
json,
stage: 'receipt',
type,
Expand All @@ -4821,7 +4833,7 @@ async function commandDeliver(args) {
sourceEvidence = sourceEvidenceFromArtifact(artifact);
} catch (error) {
const message = `Could not read the repository evidence receipt: ${error.message}`;
reportDeliveryFailure({
await reportDeliveryFailure({
json,
stage: 'receipt',
type,
Expand Down Expand Up @@ -4893,7 +4905,7 @@ async function commandDeliver(args) {
// cleanup must not claim a candidate that could not be bound here.
}
} catch (error) {
reportDeliveryFailure({
await reportDeliveryFailure({
json,
stage: 'commit',
type,
Expand Down Expand Up @@ -4928,7 +4940,7 @@ async function commandDeliver(args) {
otherOutputPaths: [currentOutputPath],
});
} catch (error) {
reportDeliveryFailure({
await reportDeliveryFailure({
json,
stage: 'commit',
type,
Expand Down Expand Up @@ -4974,7 +4986,7 @@ async function commandDeliver(args) {
// barrier around retained backups and any claimant we did not create.
// Do not write failure provenance or release ownership here.
deliveryOwnership = undefined;
reportArtifactFailure({
await reportPreparedArtifactFailure({
command: 'deliver', json, stage: 'commit', type, input: inputPath, output: outputPath, receiptId,
error: message,
diagnostics: [
Expand All @@ -4995,7 +5007,7 @@ async function commandDeliver(args) {
releaseError = cause;
}
deliveryOwnership = undefined;
reportArtifactFailure({
await reportPreparedArtifactFailure({
command: 'deliver', json, stage: 'commit', type, input: inputPath, output: outputPath, receiptId,
error: message,
diagnostics: [
Expand All @@ -5007,14 +5019,14 @@ async function commandDeliver(args) {
}
if (error.deliveryOwnershipCode === 'delivery/ownership-lost') {
deliveryOwnership = undefined;
reportArtifactFailure({
await reportPreparedArtifactFailure({
command: 'deliver', json, stage: 'commit', type, input: inputPath, output: outputPath, receiptId,
error: message,
diagnostics: [deliveryLockFailureDiagnostic(outputPath, error)],
});
return;
}
reportDeliveryFailure({
await reportDeliveryFailure({
json,
stage: 'commit',
type,
Expand Down Expand Up @@ -5050,7 +5062,7 @@ async function commandDeliver(args) {
};
}
const message = `Delivery committed, but its lock could not be released for "${outputPath}": ${error.message}`;
reportArtifactFailure({
await reportPreparedArtifactFailure({
command: 'deliver', json, stage: 'release', type, input: inputPath, output: outputPath, receiptId,
error: message,
diagnostics: [deliveryLockFailureDiagnostic(outputPath, error)],
Expand All @@ -5075,6 +5087,8 @@ async function commandDeliver(args) {
}
}

receipt.update = await updateCheck;

if (json) {
console.log(JSON.stringify(receipt, null, 2));
} else {
Expand All @@ -5084,6 +5098,7 @@ async function commandDeliver(args) {
: '';
console.log(`${receipt.validation.checksPassed}/${receipt.validation.checkCount} artifact checks; composition ${receipt.validation.compositionProfile}: ${receipt.validation.compositionStatus}${engineering}; sha256 ${receipt.artifact.sha256.slice(0, 12)}`);
if (receipt.open?.status === 'opened') console.log(`opened ${outputPath}`);
if (receipt.update.noticeRequired) console.log(receipt.update.noticeText);
}
} finally {
if (deliveryOwnership) {
Expand Down Expand Up @@ -5718,6 +5733,7 @@ async function commandFinalize(rawArgs) {
console.log(`gates ${Object.entries(result.summary.gates).map(([stage, status]) => `${stage}:${status}`).join(' ')}`);
console.log(`receipt ${result.summary.evidence.receipt}`);
console.log(`perceptual visual review ${result.summary.visualReview}`);
if (result.summary.update?.noticeRequired) console.log(result.summary.update.noticeText);
}
process.exitCode = result.exitCode;
}
Expand Down
Loading
Loading