rvlib-shipkit 1.4.0 → 1.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/CHANGELOG.md +68 -0
- package/README.md +17 -17
- package/package.json +3 -2
- package/src/check.ts +68 -95
- package/src/checks/SK001-package-json-shape.check.ts +6 -2
- package/src/checks/SK002-contracts-fulfillness.check.ts +4 -0
- package/src/checks/SK003-claude-md-shape.check.ts +5 -1
- package/src/checks/SK004-gitignore-policy.check.ts +7 -4
- package/src/checks/SK005-rvlib-versions.check.ts +53 -21
- package/src/checks/SK006-npm-publish-safety.check.ts +4 -0
- package/src/checks/SK007-github-visibility.check.ts +4 -2
- package/src/checks/SK008-reviewer-agent.check.ts +6 -4
- package/src/checks/SK009-commit-ai-tells.check.ts +4 -2
- package/src/checks/SK010-undeclared-unit.check.ts +4 -0
- package/src/checks/SK011-sibling-unit-ranges.check.ts +4 -0
- package/src/checks/SK012-config-barrel-import.check.ts +5 -1
- package/src/checks/SK013-one-way-in-policy.check.ts +7 -3
- package/src/checks/SK014-prose-ste.check.ts +4 -0
- package/src/checks/SK015-nested-repo.check.ts +4 -2
- package/src/checks/SK016-legacy-check-shapes.check.ts +13 -12
- package/src/checks/SK017-vscode-hub-task.check.ts +22 -7
- package/src/checks/SK018-test-files-run.check.ts +6 -2
- package/src/checks/SK019-tests-run-in-units.check.ts +8 -4
- package/src/checks/SK020-self-spawning-check.check.ts +4 -0
- package/src/checks/SK022-machine-runs-the-pin.check.ts +6 -4
- package/src/checks/SK024-identity-colors.check.ts +5 -3
- package/src/checks/SK025-release-drift.check.ts +4 -5
- package/src/checks/SK026-asks-autoclose.check.ts +4 -4
- package/src/checks/SK027-agent-wiki-links.check.ts +4 -1
- package/src/checks/SK028-readme.check.ts +5 -1
- package/src/checks/SK029-explicit-check-files.check.ts +95 -0
- package/src/cli/cmd_Asks.ts +5 -5
- package/src/cli/cmd_Assets.ts +7 -7
- package/src/cli/cmd_Bump.ts +12 -11
- package/src/cli/cmd_Check.ts +8 -7
- package/src/cli/cmd_Checks.ts +7 -6
- package/src/cli/cmd_Ci.ts +12 -11
- package/src/cli/cmd_Commands.ts +16 -13
- package/src/cli/cmd_ConfigKeys.ts +7 -6
- package/src/cli/cmd_Contracts.ts +3 -3
- package/src/cli/cmd_CrossRepoActivity.ts +6 -5
- package/src/cli/cmd_Fleet.ts +9 -7
- package/src/cli/cmd_GlobalProcesses.ts +116 -4
- package/src/cli/cmd_Home.ts +23 -17
- package/src/cli/cmd_Hooks.ts +6 -5
- package/src/cli/cmd_Init.ts +5 -4
- package/src/cli/cmd_Keys.ts +8 -7
- package/src/cli/cmd_Mv.ts +7 -6
- package/src/cli/cmd_Needs.ts +4 -3
- package/src/cli/cmd_Overview.ts +4 -3
- package/src/cli/cmd_Pb.ts +2 -2
- package/src/cli/cmd_Planned.ts +6 -5
- package/src/cli/cmd_Prose.ts +5 -5
- package/src/cli/cmd_Reflect.ts +7 -7
- package/src/cli/cmd_Release.ts +6 -5
- package/src/cli/cmd_Releases.ts +5 -4
- package/src/cli/cmd_Serve.ts +4 -3
- package/src/cli/cmd_Smoke.ts +5 -4
- package/src/cli/cmd_Start.ts +7 -6
- package/src/cli/cmd_Status.ts +4 -3
- package/src/cli/cmd_Tui.ts +3 -2
- package/src/cli/cmd_When.ts +71 -0
- package/src/cli/cmd_Wiki.ts +4 -4
- package/src/cli.ts +7 -2
- package/src/collections/checks.ts +2 -0
- package/src/collections/collection-types.ts +9 -4
- package/src/core/canonical-scripts.ts +1 -1
- package/src/core/check-runner.ts +37 -20
- package/src/core/config-rewrite.ts +37 -24
- package/src/core/discover-checks.ts +23 -2
- package/src/core/legacy-shapes.ts +39 -10
- package/src/core/one-way-in-policy.ts +2 -2
- package/src/core/outcome-words.ts +18 -2
- package/src/core/port-check-cli.ts +52 -0
- package/src/core/port-check-file.ts +295 -0
- package/src/core/port-check-files.ts +31 -0
- package/src/core/retention.ts +0 -14
- package/src/core/run-check.ts +12 -9
- package/src/core/run-ci.ts +8 -4
- package/src/core/run-fix.ts +30 -23
- package/src/core/run-fixers.ts +42 -5
- package/src/core/runs-matrix.ts +179 -0
- package/src/core/runs.ts +242 -0
- package/src/core/update-policy.ts +20 -0
- package/src/core/when-block.ts +29 -30
- package/src/core/when.ts +41 -103
- package/src/core/wire.ts +10 -14
- package/src/fleet/scan-fleet.ts +20 -4
- package/src/fleet/update-fleet.ts +6 -6
- package/src/home/home-launchd.ts +20 -4
- package/src/home/home-routes.ts +12 -1
- package/src/home/hubs.ts +5 -5
- package/src/home/pm.ts +8 -0
- package/src/home/run-pm.ts +1 -0
- package/src/home/serve-web.ts +2 -2
- package/src/home/supervise.ts +24 -1
- package/src/hooks/run-hooks.ts +48 -4
- package/src/init-repo.ts +6 -6
- package/src/ledger/gate-checks.ts +113 -59
- package/src/ledger/git-key.ts +5 -1
- package/src/ledger/ledger.ts +5 -5
- package/src/ledger/toolchain-identity.ts +45 -27
- package/src/plan/repo-source.ts +18 -39
- package/src/release/run-release.ts +5 -0
- package/src/repo-config.ts +30 -55
- package/src/rules/rule.ts +2 -2
- package/src/scaffold/files/agent-coding.md +1 -1
- package/src/scaffold/files/agent-index.md +1 -1
- package/src/scaffold/files/verify-skill.md +2 -2
- package/src/serve/hub-app/activity-st.ts +5 -4
- package/src/serve/hub-app/activity-view.tsx +1 -1
- package/src/serve/hub-app/admin-view.tsx +13 -11
- package/src/serve/hub-app/check-view.tsx +66 -46
- package/src/serve/hub-app/check-words.ts +1 -11
- package/src/serve/hub-app/checks-svc.ts +14 -35
- package/src/serve/hub-app/col-tables-view.tsx +13 -6
- package/src/serve/hub-app/cols-svc.ts +5 -4
- package/src/serve/hub-app/dock-st.ts +3 -2
- package/src/serve/hub-app/dock-view.tsx +36 -0
- package/src/serve/hub-app/dock.css +6 -0
- package/src/serve/hub-app/float-cards.tsx +30 -0
- package/src/serve/hub-app/floating.tsx +41 -4
- package/src/serve/hub-app/git-st.ts +42 -0
- package/src/serve/hub-app/git-view.tsx +61 -0
- package/src/serve/hub-app/hash-route.ts +45 -1
- package/src/serve/hub-app/header-bar.tsx +62 -72
- package/src/serve/hub-app/health-svc.ts +3 -2
- package/src/serve/hub-app/home-st.ts +14 -2
- package/src/serve/hub-app/home-strip.css +43 -8
- package/src/serve/hub-app/home-strip.tsx +111 -47
- package/src/serve/hub-app/home.html +1 -0
- package/src/serve/hub-app/hub-app.tsx +14 -4
- package/src/serve/hub-app/hub-types.ts +5 -2
- package/src/serve/hub-app/hub.css +65 -43
- package/src/serve/hub-app/icons.tsx +11 -0
- package/src/serve/hub-app/index.html +1 -0
- package/src/serve/hub-app/keys.ts +5 -2
- package/src/serve/hub-app/live-svc.ts +3 -2
- package/src/serve/hub-app/machine-st.ts +18 -22
- package/src/serve/hub-app/plan-view.tsx +51 -0
- package/src/serve/hub-app/planned-st.ts +9 -4
- package/src/serve/hub-app/processes-view.tsx +38 -0
- package/src/serve/hub-app/projects-svc.ts +15 -10
- package/src/serve/hub-app/prose-hits-st.ts +3 -2
- package/src/serve/hub-app/reach.ts +36 -0
- package/src/serve/hub-app/readme-svc.ts +3 -2
- package/src/serve/hub-app/repo-sections.ts +117 -0
- package/src/serve/hub-app/repo-st.ts +46 -9
- package/src/serve/hub-app/sidebar.tsx +12 -37
- package/src/serve/hub-app/timeline-svc.ts +3 -2
- package/src/serve/hub-app/tree-build.ts +149 -155
- package/src/serve/hub-app/tree-row.tsx +39 -9
- package/src/serve/hub-app/tree-svc.ts +70 -49
- package/src/serve/hub-app/when-view.tsx +89 -0
- package/src/serve/hub-app/when.css +17 -0
- package/src/serve/hub-runtime.ts +3 -16
- package/src/serve/run-serve.ts +1 -1
- package/src/serve/serve-hub.ts +4 -14
- package/src/serve/hub-app/processes-svc.ts +0 -63
- package/src/serve/hub-app/repo-sections.tsx +0 -61
- package/src/serve/repo-processes.ts +0 -89
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,71 @@
|
|
|
1
|
+
## 1.5.0
|
|
2
|
+
|
|
3
|
+
- **Every check declares where it runs and how it caches, with no default.** A check file carries `runs` (`onPreCommit`, `onCi`, `onFull`, `onRelease`, `onHealth`, `onSave`, `onClock`), `cache` (`files`, `reads`, `ttl`, `fact` or `never`, each with its one parameter), `fix` (`none`, `ci` or `manual`, the function itself is now `repair`) and `applies`. `check()` refuses a missing key, a retired key (`when`, `inputs`, `ttl`, `never`, `every`, `cron`, `whenInactive`, `planOff`, `cacheKey`) and the combinations that contradict each other. The gate, the fix pass, the release preflight and the planner read the declared axes; a release never applies a check repair. Every built-in carries its own placement: SK024, SK017 and SK028 run in the health pass only, and SK005, SK006, SK011, SK014, SK016 and SK022 are out of the quick gate. A check file that does not load is one failing row instead of a dead inventory.
|
|
4
|
+
|
|
5
|
+
- **SK029 ports a check file still in the retired shape.** Its repair writes `runs`, `cache`, `fix` and `applies` with the values the old keys resolved to, so the check runs where it ran, and the fix pass of `sk ci` applies it: a repo is carried across by its first gate.
|
|
6
|
+
|
|
7
|
+
- **A repo only turns a check off.** `off: { <id>: '<why>' }` in `repo.config.ts` replaces the `when` map; `defineRepo` refuses every `when` word but `off:<why>`, and SK029 ports that and `ruleExempt` into `off`. The hub's switch on a check page writes it.
|
|
8
|
+
|
|
9
|
+
- **The pre-commit hook runs the checks declaring `onPreCommit`**, in process on the working tree, under a budget of at most 100ms each; a failure refuses the commit. `sk hooks list` names them. The whole hook warns past 1s.
|
|
10
|
+
|
|
11
|
+
- **`sk when` and the when page show what runs when**: the legend of every context and value, then every check on every context. `--only onCi` keeps what the quick gate runs.
|
|
12
|
+
|
|
13
|
+
- **The hub tree has four sections where it had checks.** contracts (⌥K), shipkit checks (⌥S), repo checks (⌥C) and secrets (⌥X) are top rows, each with its own red count, and their rows sit straight under them, one indent less. shipkit checks and repo checks open the checks table showing only their own checks (`#page:checks:shipkit`, `#page:checks:repo`).
|
|
14
|
+
|
|
15
|
+
- **A check page lists where the check runs, one line per context.** Commit, ci, full, release, health, save, clock, fix and cache each show the declared value and what it means, in the words of the `sk when` legend. A context that does not run the check stays dim. The switch that turns the check off in this repo, with its reason, sits under that list.
|
|
16
|
+
|
|
17
|
+
- **The tree drops the gray ci, release, health word on a check row.** A check declares seven contexts now, which one word could not say. The row's tooltip lists every context that runs it (`runs on ci · full · release · health · save moved`), and the label gets the width back. A check that no context runs reads off.
|
|
18
|
+
|
|
19
|
+
- **A link button copies the page's url.** At the bottom right of the dock bar, it shows the url on hover and copies it on click. The app window has no url bar.
|
|
20
|
+
|
|
21
|
+
- **Fix: the repo tree's scrollbar is a thin bar.** In the macOS app it drew a wide dark band beside the tree; it is now a 6px thumb on a transparent track, and the rows sit closer to it.
|
|
22
|
+
|
|
23
|
+
- **The tree gives its width back to the labels.** A row's duration is a small clock now, tinted by the same tone table, with the figure in its tooltip. The indent per level and the space around the chevrons are a little smaller.
|
|
24
|
+
|
|
25
|
+
- **The command index is lean.** Every command's `description` is one short line (at most 100 characters, a test holds it), and the long text moved to `details`, which `--help` still prints. `shipkit commands` renders each signature with its flags inline, but no longer a line per flag, and every example uses `sk`, which is also the name `--help` shows. The generated index went from 33 KB to 17 KB.
|
|
26
|
+
|
|
27
|
+
- **`sk`, the short name.** The package ships a second bin, `sk`, the same cli as `shipkit`.
|
|
28
|
+
|
|
29
|
+
- **The fix pass is skipped over a tree it already left clean.** When HEAD, every uncommitted file, the toolchain and the fixer commands are the same as at the last pass that rewrote nothing, the formatter and import fixers do not run again. That was the whole wait before the first line of `shipkit ci`. CI never skips.
|
|
30
|
+
|
|
31
|
+
- **Every gate line says where its answer came from.** A check that ran ends its first line with `(ran 6.4s)`, one replayed from the cache with `(cached, 3h old, 6.4s saved)`, and a world check with `(ran 40ms, kept 1h more)` or `(cached, 2m old, kept 23h more)`. Before, a rule check that ran said nothing and a cached one never said how old its answer was.
|
|
32
|
+
|
|
33
|
+
- **Fix: a repo that `bun link`s a package replays from the cache.** A package linked outside the repo made every check "never cached", so a repo linking its toolchain re-ran everything on every gate. The link target is now keyed by its content (each file's path, size and bytes, symlinks followed, its own installs), so an edit there still moves the key and an untouched one replays. A linked tree that cannot be read keys nothing.
|
|
34
|
+
|
|
35
|
+
- **`shipkit gp start|stop|restart <id>`.** The overview's switches for a global process, from a terminal: pm takes the switch, and the command follows pm's status until the probe settles it. It exits 0 once the process is up (down for stop), and 1 with its note and its last log lines when it crashed or stayed down.
|
|
36
|
+
|
|
37
|
+
- **Widgets are asked for only by a visible overview.** The page polled `/api/home/widgets.json` from every page, hidden tabs and app windows included, so the daemon rendered every widget around the clock. A widget that samples another machine over ssh kept sampling it all day. A repo page or a hidden tab now asks for none, and the daemon stops rendering 30 s after the last read.
|
|
38
|
+
|
|
39
|
+
- **Removed: `serve.processes`.** A hub no longer supervises processes of its own: declare each one as a global process in a `<name>.shipkit.ts` file (`export default globalProcess({...})`), which pm runs. `defineRepo` refuses the old key and says so. The hub routes `/api/processes.json` and `/api/processes/act`, the header switches and the `process logs` retention store go with it.
|
|
40
|
+
|
|
41
|
+
- **A repo's plan, git and reflections are sections of its tree.** `plan` (⌥N) lists what the machine runs there and when, with run now. `git` (⌥G) shows the branch against its upstream, what is not committed and the commits of the week, with VS Code and Fork, from a new daemon route `/api/home/git.json?repo=`. `reflections` (⌥F) left the checks section for one of their own, one row each.
|
|
42
|
+
|
|
43
|
+
- **A repo's global processes are a section of its tree.** `processes` (⌥P) sits after `runs`, one row per process the repo declares, coloured by its state. The section opens a page with one card per process (its actions, its description as markdown, its log), and a row opens its own card, lit. A new resource kind, `process`, and a new address, `#page:processes[:<id>]`.
|
|
44
|
+
|
|
45
|
+
- **A repo page is not a box, each group is one.** A check, test, admin, runs or item page sits on the page background, and each group it holds (the facts, a titled section, the command, the admin rows, the runs list) is one lighter box.
|
|
46
|
+
|
|
47
|
+
- **A process menu shows its description as markdown, on the right.** The menu a process chip opens is two panels: its actions on the left, its `description` rendered as markdown on the right with its note and last log line, selectable, so a dev login written there is one click away. A process with nothing to say draws the actions alone.
|
|
48
|
+
|
|
49
|
+
- **Fix: a search reads every row, and a filtered tree says what it hides.** With the severity group on `needs` or `red`, a repo with few of them showed empty sections with no chevron and a search that found nothing. A search now ignores the group (`TreeSvc.visible`), and while the group hides rows a line under the tree counts them and shows all on a click (`TreeSvc.hidden`).
|
|
50
|
+
|
|
51
|
+
- **A process chip opens a menu instead of starting or stopping.** A click on a global process chip in the top bar opens its menu: start or stop, restart, open in a browser tab, in Chrome or as an app, its declared actions and take over. The chips sit right after the repo's name, and the spinner and `check…` sit at the right end before the editor icons.
|
|
52
|
+
|
|
53
|
+
- **The machine not answering is said once.** When the daemon, pm or the web does not answer, one card under the strip says so, with what hangs, what runs it and that the page comes back by itself; the daemon and pm down together share that card. The project list, the dock, a repo's trouble card and every repo pane keep what they last read and add no error line of their own. The bottom right toast is gone. `reach` and `ownTrouble` in `reach.ts` are the one reading of the web's tagged 502 and of a fetch with no answer. A route that fails while the daemon answers still shows its own error. The page stays drawn meanwhile: a repo keeps its last screen, since its hub's state is unknown rather than down, and the overview draws what it last had; a wait panel shows only when nothing was ever read.
|
|
54
|
+
|
|
55
|
+
- **Fix: pm kills a child that stopped answering, and its agent is never disk throttled.** A child whose pid lives but has not answered its probe for 90 s is hung: pm writes a WARN line to `pm.log`, sends SIGTERM then SIGKILL, and starts it again through the crash backoff (`hangMs` and `say` on a `ProcSpec`, `CHILD_HANG_MS`). A daemon had sat `starting` for an hour with its port open. The LaunchAgent now carries `ProcessType` Interactive: with none, launchd throttles the disk reads of pm and of every child it starts, and under a busy disk the daemon's boot reads of its sqlite store took minutes. Run `shipkit pm install` once to rewrite an installed agent. That install no longer strands the machine without pm: `launchctl bootout` returns before launchd lets go of the label, and the bootstrap right after it could fail with exit 5 once the old agent was gone. It is retried for 5 s (`BOOTSTRAP_TRIES`), and a final failure says pm is not loaded.
|
|
56
|
+
|
|
57
|
+
- **A readme section, and switching repo keeps the section open.** `readme` is the first row of a repo's left pane (⌥E, `#page:readme`). Selecting another repo opens the section the one you left showed; a repo already on a page of that section keeps it, and one without that section opens its README. `sectionOfSel` and `openSection` in `repo-sections.ts` light the rows and drive the switch, and `HashSel` gains `{ t: 'readme' }`.
|
|
58
|
+
|
|
59
|
+
- **A repo page's left pane is one tree whose top rows are its sections.** checks, runs, asks, tests, media, wikis and admin keep their icon, count, ⌥ key and lit state; a click opens the section's page, and only the chevron, the right arrow or a search unfolds it. Under them: the check origins with reflections, secrets and contracts under checks, one row per ask with the `done` archive, one row per test file, the assets with the workflow and post groups under media, one row per wiki. `KIND_SECTION` gives every resource kind one home, and a section the repo does not draw still gets a row when a resource lives in it (`buildTree` replaces `buildPathTree` and `buildTypeTree`). The by path and by type tabs, the `(?)` legend and the total are gone: each kind glyph names its kind in its tooltip, and the filter matches paths. The severity group sits beside the filter and narrows the section counts too. A search unfolds every section with a match and hides the rest; clearing it restores the folds. The planning line moved to the top of the checks page. `repo-sections.tsx` is `repo-sections.ts`.
|
|
60
|
+
|
|
61
|
+
- **The top bar carries no trouble text and no run buttons.** The hub's trouble and the machine's (a crashed child of pm, a crashed global process, a failed poll) are cards floating at the top right, just under the bar, full text, nothing drawn while all is well (`FloatCards`). The running command is a spinner with its words in a tooltip that opens at once, and nothing shows while idle. The health pass and the gate sit behind one small `check…` button, in a popover (`Pop` in floating.tsx) that Escape or a click outside closes. The standalone hub header gets the same.
|
|
62
|
+
|
|
63
|
+
- **The strip over a repo starts its global processes.** One chip per process the shown repo declares in its `.shipkit.ts` files: its dot and label, a click starts or stops it, and `↗` opens its url while it runs. pm runs them, so the chips show whether the repo's hub answers or not.
|
|
64
|
+
|
|
65
|
+
- **Fix: SK017 removes a `👁 TSC` watcher that runs `tsgo`.** The rule matched only a `tsc` binary, so a repo whose watcher had moved to tsgo kept it beside the gate's typecheck. A tsgo task under another label is still left alone. A wrapper that started only the TSC task goes with it, since it would open with the folder and start nothing.
|
|
66
|
+
|
|
67
|
+
- **Fix: a semver pin under a `bun link` moves when a release ships.** SK005 and `shipkit fleet` read the linked source, always the newest, so a repo pinned at 1.3.0 read current and a fresh clone kept installing 1.3.0. A pinned dep whose node_modules entry is a symlink is now judged by the pin's floor (`pinFloor`, `isLinkedInstall`). Behind, SK005 moves the pin through its guarded update, keeps its style, runs `bun link <name>` after it and FAILs when the link does not come back. The fleet row names it `pin 1.3.0 → 1.4.0 (linked, stale pin)`, `FleetDep` gains `linkedInstall` and `at`, and `fleet --update` reads the move off the pin (`judgedVersion`). A `link:` spec is judged as before.
|
|
68
|
+
|
|
1
69
|
## 1.4.0
|
|
2
70
|
|
|
3
71
|
- **Fix: `shipkit gui` wears the house mark from any directory.** The app took its icon from cwd, so a run outside every house repo rebuilt `Shipkit.app` with no icon. The house now comes from cwd, else from the installed pm agent's `WorkingDirectory` (`installedHouseRoot`, `guiRoot`), and never from cwd itself.
|
package/README.md
CHANGED
|
@@ -18,7 +18,7 @@ export default defineRepo({
|
|
|
18
18
|
})
|
|
19
19
|
```
|
|
20
20
|
|
|
21
|
-
Everything the gate runs beyond the floor is a CHECK, and a check needs no config at all: drop a `<name>.check.ts` file anywhere and `
|
|
21
|
+
Everything the gate runs beyond the floor is a CHECK, and a check needs no config at all: drop a `<name>.check.ts` file anywhere and `sk ci`, `sk check`, `sk checks` and the hub discover it.
|
|
22
22
|
|
|
23
23
|
```ts
|
|
24
24
|
// e2e.check.ts
|
|
@@ -35,46 +35,46 @@ export default check({
|
|
|
35
35
|
## CLI
|
|
36
36
|
|
|
37
37
|
```
|
|
38
|
-
|
|
38
|
+
sk ci commit gate: floor (lint/typecheck/test/imports/cycles —
|
|
39
39
|
scripts win, imports/cycles/typecheck fill from bundled
|
|
40
40
|
tools with zero config, gaps print visibly) + contracts
|
|
41
41
|
+ your checks, parallel DAG; refreshes STATUS.md
|
|
42
42
|
[--bail --skip g --only id --json]
|
|
43
|
-
|
|
44
|
-
|
|
43
|
+
sk contracts release-contract fulfillness alone [--venue v --json]
|
|
44
|
+
sk check periodic health: the built-in checks + every *.check.ts in
|
|
45
45
|
the repo, auto-discovered + TTL-cached
|
|
46
46
|
[--json --fresh --frozen --fix [SK### …]]
|
|
47
47
|
--fix applies check autofixes then re-runs them; --frozen =
|
|
48
48
|
self-maintaining checks (rvlib self-update) report only
|
|
49
|
-
|
|
49
|
+
sk checks the inventory: every check, where it runs, blocks or warns,
|
|
50
50
|
and how it caches. --fixable = what repairs itself,
|
|
51
51
|
with its owning doc [--json --md --out]
|
|
52
|
-
|
|
52
|
+
sk tui live dashboard: build steps + every other check + panels
|
|
53
53
|
the repo injects via repo.config tui.panels
|
|
54
|
-
|
|
55
|
-
|
|
54
|
+
sk asks human action queue: list · ask "<title>" · asks check (auto-close)
|
|
55
|
+
sk needs everything blocked on a human, red/yellow by collection
|
|
56
56
|
report-only, exit 0 always [--json]
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
57
|
+
sk wiki serve|lint — live md link-graph + orphan/dangling-ref lint
|
|
58
|
+
sk mv rename an md page + its sibling dir, sweeping every ref
|
|
59
|
+
sk assets serve|fill|add|gen|identity|check — the asset atelier
|
|
60
60
|
(declare kinds in .shipkit/assets/kit.ts, roll, curate, ship)
|
|
61
|
-
|
|
61
|
+
sk pb collection <name> — scaffold a PocketBase collection's UI
|
|
62
62
|
folder (columns/card/grid/form/index) from the app's
|
|
63
63
|
generated pb types, create-only [--dry-run]
|
|
64
|
-
|
|
64
|
+
sk smoke browser pass over a DEPLOYED web app, read only: login
|
|
65
65
|
through the app's own form, every route in repo.config
|
|
66
66
|
`smoke`, screenshots, console/network problems, the host
|
|
67
67
|
quota headers, a detail page per `open` link. Exit code =
|
|
68
68
|
failed routes. Needs playwright in the repo
|
|
69
69
|
[--base <url> --routes /a,/b]
|
|
70
|
-
|
|
71
|
-
|
|
70
|
+
sk serve the repo's ONE server: hub page, wikis, studio, status
|
|
71
|
+
sk reflect your prompts across every Claude Code session of a repo:
|
|
72
72
|
all config roots, queued-mid-run ones included, harness
|
|
73
73
|
noise out, chronological md corpus for a retrospective
|
|
74
74
|
[repo…] [--short --out <dir> --json]
|
|
75
|
-
|
|
75
|
+
sk init scaffold config + scripts, print the resolved floor
|
|
76
76
|
[--bin <cli.ts path> for in-repo-source consumers]
|
|
77
|
-
|
|
77
|
+
sk start ensure <root>/<name> + its CLAUDE.md include; prints the dir
|
|
78
78
|
```
|
|
79
79
|
|
|
80
80
|
Output is a stable line protocol — `ok:` / `WARN` / `FAIL:` / `skip:` with indented `fix:` pointers — exit 0/1. Greppable by humans, parseable by agents, `--json` where structure helps.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "rvlib-shipkit",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.5.0",
|
|
4
4
|
"funding": "https://github.com/sponsors/rvion",
|
|
5
5
|
"description": "All-in-one repo companion: ci gate (task DAG), auto-discovered health checks, release-contract fulfillness, asks queue, md-wiki tools, asset atelier, live tui",
|
|
6
6
|
"license": "MIT",
|
|
@@ -11,7 +11,8 @@
|
|
|
11
11
|
"CHANGELOG.md"
|
|
12
12
|
],
|
|
13
13
|
"bin": {
|
|
14
|
-
"shipkit": "./src/cli.ts"
|
|
14
|
+
"shipkit": "./src/cli.ts",
|
|
15
|
+
"sk": "./src/cli.ts"
|
|
15
16
|
},
|
|
16
17
|
"exports": {
|
|
17
18
|
".": "./src/shipkit.ts",
|
package/src/check.ts
CHANGED
|
@@ -14,14 +14,14 @@
|
|
|
14
14
|
// `cmd` argv, a subprocess, exit code is truth
|
|
15
15
|
//
|
|
16
16
|
// What a check declares about ITSELF is what every surface reads: `blocking`
|
|
17
|
-
// (can it stop you),
|
|
18
|
-
//
|
|
19
|
-
//
|
|
20
|
-
//
|
|
17
|
+
// (can it stop you), `runs` (every context it runs in), `cache` (how its
|
|
18
|
+
// answer is kept), `fix` (which command applies its repair), `applies` (does
|
|
19
|
+
// this repo give it work), `deps` (what must pass first). Every one of them is
|
|
20
|
+
// explicit, with no default (core/runs.ts). The file's own path joins its
|
|
21
|
+
// cache key automatically, so nothing declares its own code.
|
|
21
22
|
import type { CheckCtx } from './core/check-ctx.ts'
|
|
22
|
-
import {
|
|
23
|
-
import {
|
|
24
|
-
import { FOREVER, parseDuration, type Line } from './core/wire.ts'
|
|
23
|
+
import { cacheProblem, combinationProblem, runsProblem, type Applies, type CacheDecl, type FixWhen, type Runs } from './core/runs.ts'
|
|
24
|
+
import { type Line } from './core/wire.ts'
|
|
25
25
|
import type { RepoConfig } from './repo-config.ts'
|
|
26
26
|
|
|
27
27
|
export { defineScan, mdPages, packageJson, type MdPage, type PackageJson, type Scan } from './scan.ts'
|
|
@@ -77,7 +77,7 @@ export type CheckDef = {
|
|
|
77
77
|
* gate asks "is my change good" and builds, `shipkit check` asks "is
|
|
78
78
|
* this repo healthy" and reports, and a tool chain has no business in
|
|
79
79
|
* the second question. A floor slot derives it, a file declares it, and
|
|
80
|
-
* it takes the 600s ceiling rather than the 120s one. `
|
|
80
|
+
* it takes the 600s ceiling rather than the 120s one. its `runs` say
|
|
81
81
|
* TIME (always, release, health, off). A build step on `health` is an
|
|
82
82
|
* opt in one: the gate parks it and `shipkit ci --with <id>` runs it. */
|
|
83
83
|
build?: boolean
|
|
@@ -85,74 +85,34 @@ export type CheckDef = {
|
|
|
85
85
|
* so a check naming none is a root of it, and a dep doubles as the race
|
|
86
86
|
* guard between two checks that touch one file. */
|
|
87
87
|
deps?: string[]
|
|
88
|
-
/** WHERE
|
|
89
|
-
*
|
|
90
|
-
*
|
|
91
|
-
|
|
92
|
-
/**
|
|
93
|
-
*
|
|
94
|
-
*
|
|
95
|
-
*
|
|
96
|
-
*
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
*
|
|
104
|
-
*
|
|
105
|
-
|
|
106
|
-
/** a DECIDED never-cacheable, with the reason. Says somebody looked and
|
|
107
|
-
* no key can describe this, which takes it off the burn-down list. */
|
|
108
|
-
never?: string
|
|
88
|
+
/** WHERE IT RUNS, every context explicit, no default (core/runs.ts owns
|
|
89
|
+
* the meaning of each key and each value). A repo moves a check it does
|
|
90
|
+
* not own OFF with `off` in repo.config.ts, never elsewhere. */
|
|
91
|
+
runs: Runs
|
|
92
|
+
/** HOW ITS ANSWER IS KEPT, one variant, every parameter explicit:
|
|
93
|
+
* `files` (keyed on these paths), `reads` (keyed on what the body read),
|
|
94
|
+
* `ttl` (a world answer that keeps a span), `fact` (a decided value, once
|
|
95
|
+
* per key), `never` (with the reason). The file's own path joins every
|
|
96
|
+
* key automatically, so nothing declares its own code. */
|
|
97
|
+
cache: CacheDecl
|
|
98
|
+
/** which command applies `repair`: `'none'` (no repair), `'ci'` (the
|
|
99
|
+
* gate's fix pass and `shipkit check --fix`), `'manual'` (only
|
|
100
|
+
* `shipkit check --fix <id>`) */
|
|
101
|
+
fix: FixWhen
|
|
102
|
+
/** whether this repo gives the check anything to do: `'always'`, or a
|
|
103
|
+
* pure function of { root, config } returning the reason it does not
|
|
104
|
+
* (the row is then n/a in every context), or null */
|
|
105
|
+
applies: Applies
|
|
109
106
|
/** it REWRITES the repo while it runs (updates a dependency, untracks a
|
|
110
107
|
* file) unless the run is frozen, so a frozen run asks it a different
|
|
111
108
|
* question: only a check declaring this carries `frozen` in its cache
|
|
112
|
-
* key,
|
|
113
|
-
* a normal one. Declared, never guessed from the body. */
|
|
109
|
+
* key. Declared, never guessed from the body. */
|
|
114
110
|
writes?: boolean
|
|
115
|
-
/**
|
|
116
|
-
*
|
|
117
|
-
*
|
|
118
|
-
*
|
|
119
|
-
|
|
120
|
-
* change only. Or a PURE function of its last result (`status`, `at`, `streak`
|
|
121
|
-
* of that same status) and whether the repo is active, returning any of
|
|
122
|
-
* those: `(last) => (last?.status === 'fail' ? '1h' : '7d')`. A lambda
|
|
123
|
-
* that throws is an error row on the planned page, and the check runs on
|
|
124
|
-
* change only. Absent: its `ttl`, else a build step or a check keyed on
|
|
125
|
-
* its files waits for a save. A repo check nothing can key runs about
|
|
126
|
-
* once a day until it declares one, and a built-in never may: `shipkit
|
|
127
|
-
* keys --burn-down` names both. */
|
|
128
|
-
every?: Every
|
|
129
|
-
/** a time of day or week for the rare check that needs one, as five cron
|
|
130
|
-
* fields in local time (`'0 9 * * 1'`, Mondays at 9). Never with `every`. */
|
|
131
|
-
cron?: string
|
|
132
|
-
/** what a due check does while its repo is inactive (no agent session in
|
|
133
|
-
* it, VS Code does not have it open, it is not flagged active): `'wait'`
|
|
134
|
-
* turns it late and runs it once the repo is active again, `'run'` runs
|
|
135
|
-
* it on time anyway (a credential probe, an api key that must keep
|
|
136
|
-
* working). A pure function of the last result may choose. Default
|
|
137
|
-
* `'wait'`. */
|
|
138
|
-
whenInactive?: WhenInactiveDecl
|
|
139
|
-
/** why this repo gives the check nothing to do on a clock, or null: the
|
|
140
|
-
* plan leaves it out there (no row, no timer), and a gate or a health
|
|
141
|
-
* pass still runs it. Read at every reload of the repo's checks, so a
|
|
142
|
-
* file that gives it work (an ask with a probe, a release unit) plans it
|
|
143
|
-
* again. Cheap and pure over the repo's files and config */
|
|
144
|
-
planOff?: (env: CheckEnv) => string | null
|
|
145
|
-
/** cache-identity contribution for a `ttl` check whose verdict depends on
|
|
146
|
-
* config: a changed key busts the answer instantly instead of serving
|
|
147
|
-
* a stale cached assertion for the rest of the TTL. */
|
|
148
|
-
cacheKey?: (env: CheckEnv) => string
|
|
149
|
-
/** idempotent auto-repair, never interactive. `shipkit check --fix <id>`
|
|
150
|
-
* applies it, then re-runs the check. It gets the same `c` as the body,
|
|
151
|
-
* writes with `c.write` and `c.remove`, and is never cached. An `fs`
|
|
152
|
-
* import in the check file would keep an undeclared body off its reads
|
|
153
|
-
* (core/raw-access.ts). A repair that needs
|
|
154
|
-
* judgement stays a FAIL with a pointer. */
|
|
155
|
-
fix?: (c: CheckCtx) => FixResult | Promise<FixResult>
|
|
111
|
+
/** idempotent auto-repair, never interactive, required when `fix` is not
|
|
112
|
+
* `'none'`. It gets the same `c` as the body, writes with `c.write` and
|
|
113
|
+
* `c.remove`, and is never cached. A repair that needs judgement stays a
|
|
114
|
+
* FAIL with a pointer. */
|
|
115
|
+
repair?: (c: CheckCtx) => FixResult | Promise<FixResult>
|
|
156
116
|
/** wall clock ceiling in ms. A `cmd` check is killed with its whole
|
|
157
117
|
* process tree at the ceiling. */
|
|
158
118
|
timeoutMs?: number
|
|
@@ -160,7 +120,7 @@ export type CheckDef = {
|
|
|
160
120
|
* passes over it prints a WARN and reads yellow, and never blocks.
|
|
161
121
|
* Judged on the wall time of a run that measured, at the quick tier.
|
|
162
122
|
* Default 2000 for an in process body, 10000 for a build step, a `cmd`
|
|
163
|
-
* or a world probe (
|
|
123
|
+
* or a world probe (cache `ttl`, `fact` or `never`, core/budget.ts).
|
|
164
124
|
* The repo's `budgets` wins over it. */
|
|
165
125
|
budgetMs?: number
|
|
166
126
|
/** a label several checks share, so `--skip <group>` parks all of them
|
|
@@ -198,6 +158,19 @@ export function describeFirst(...candidates: (string | null | undefined)[]): str
|
|
|
198
158
|
throw new Error(`no description candidate passes the shape: ${candidates.map((d) => JSON.stringify(d)).join(', ')}`)
|
|
199
159
|
}
|
|
200
160
|
|
|
161
|
+
/** the keys the explicit declaration replaced, and what replaces each */
|
|
162
|
+
const RETIRED_KEYS: Record<string, string> = {
|
|
163
|
+
when: 'runs (every context explicit)',
|
|
164
|
+
every: 'runs.onClock { every, inactive }',
|
|
165
|
+
cron: 'runs.onClock { every: <cron>, inactive }',
|
|
166
|
+
whenInactive: 'runs.onClock.inactive',
|
|
167
|
+
planOff: 'applies',
|
|
168
|
+
inputs: "cache { by: 'files', inputs, key }",
|
|
169
|
+
ttl: "cache { by: 'ttl', span, key } or { by: 'fact', key }",
|
|
170
|
+
never: "cache { by: 'never', why }",
|
|
171
|
+
cacheKey: 'cache.key',
|
|
172
|
+
}
|
|
173
|
+
|
|
201
174
|
/** THE way a check file declares itself. It validates the shape at import
|
|
202
175
|
* time, so a malformed check dies when discovery loads it and never mid
|
|
203
176
|
* gate. The id, the title and the owner are filled in by discovery, which
|
|
@@ -208,20 +181,21 @@ export function check(d: CheckDef): CheckDef {
|
|
|
208
181
|
const bad = descriptionProblem(d.description)
|
|
209
182
|
if (bad != null) throw new Error(`check${name}: ${bad}`)
|
|
210
183
|
if (typeof d.blocking !== 'boolean')
|
|
211
|
-
throw new Error(`check${
|
|
184
|
+
throw new Error(`check${name}: blocking is required — true (about this repo, it stops you) or false (about the world, it warns)`)
|
|
212
185
|
if (has('run') === has('cmd'))
|
|
213
|
-
throw new Error(`check${
|
|
214
|
-
const
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
if (
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
if (
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
}
|
|
186
|
+
throw new Error(`check${name}: declare exactly one body, \`run\` (in process) or \`cmd\` (argv)`)
|
|
187
|
+
const raw = d as unknown as Record<string, unknown>
|
|
188
|
+
const retired = Object.keys(RETIRED_KEYS).filter((k) => raw[k] !== undefined)
|
|
189
|
+
if (retired.length > 0) throw new Error(`check${name}: ${retired.map((k) => `\`${k}\` is retired, declare ${RETIRED_KEYS[k]}`).join('; ')} (build/shipkit/runs.md)`)
|
|
190
|
+
if (typeof raw.fix === 'function') throw new Error(`check${name}: \`fix\` is now the word 'none' | 'ci' | 'manual', and the function is \`repair\` (build/shipkit/runs.md)`)
|
|
191
|
+
const runs = runsProblem(d.runs)
|
|
192
|
+
if (runs != null) throw new Error(`check${name}: ${runs}`)
|
|
193
|
+
const cache = cacheProblem(d.cache)
|
|
194
|
+
if (cache != null) throw new Error(`check${name}: ${cache}`)
|
|
195
|
+
if (d.applies !== 'always' && typeof d.applies !== 'function')
|
|
196
|
+
throw new Error(`check${name}: applies is required: 'always', or a function of { root, config } returning why this repo gives it nothing to do, or null`)
|
|
197
|
+
const whole = combinationProblem({ runs: d.runs, cache: d.cache, fix: d.fix, repair: d.repair, build: d.build === true, body: has('run') ? 'run' : 'cmd', blocking: d.blocking })
|
|
198
|
+
if (whole != null) throw new Error(`check${name}: ${whole}`)
|
|
225
199
|
return d
|
|
226
200
|
}
|
|
227
201
|
|
|
@@ -233,7 +207,7 @@ export function check(d: CheckDef): CheckDef {
|
|
|
233
207
|
|
|
234
208
|
export type TaskDef = {
|
|
235
209
|
/** the name every surface uses: the gate line, `--only`, `--skip`, a
|
|
236
|
-
* `deps` entry,
|
|
210
|
+
* `deps` entry, an `off` key and the ledger row. Unique in the repo. */
|
|
237
211
|
id: string
|
|
238
212
|
/** one line stating what must be true (the shape: descriptionProblem).
|
|
239
213
|
* A floor slot and a unit test check get theirs from the
|
|
@@ -255,7 +229,7 @@ export type TaskDef = {
|
|
|
255
229
|
/** a label several tasks share, so `--skip <group>` parks all of them at
|
|
256
230
|
* once (a local bench, a slow integration tier). */
|
|
257
231
|
group?: string
|
|
258
|
-
/** DEPRECATED, read
|
|
232
|
+
/** DEPRECATED, read as every gate axis false: out of the gate until
|
|
259
233
|
* `--with <id>` names it. */
|
|
260
234
|
optIn?: boolean
|
|
261
235
|
/** wall clock ceiling in ms, default 600000 for a build step. One that
|
|
@@ -333,13 +307,12 @@ export type Rule = {
|
|
|
333
307
|
|
|
334
308
|
// ── running a body, and what every line it prints carries ────────────────
|
|
335
309
|
|
|
336
|
-
/** the config part of a check's cache identity
|
|
337
|
-
*
|
|
338
|
-
*
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
return at.at === 'off' ? `${key ?? ''}|exempt:${at.reason ?? ''}` : `${key ?? ''}|when:${at.at}`
|
|
310
|
+
/** the config part of a check's cache identity: its declared key, and the
|
|
311
|
+
* reason it is off. Turning a check off, or editing why, asks the question
|
|
312
|
+
* again rather than serving the answer from before. Where it runs is not
|
|
313
|
+
* part of it: the answer to one question does not depend on who asks. */
|
|
314
|
+
export function checkCacheExtra(key: string | undefined, off: string | null): string | undefined {
|
|
315
|
+
return off == null ? key : `${key ?? ''}|exempt:${off}`
|
|
343
316
|
}
|
|
344
317
|
|
|
345
318
|
/** THE one way to run an in-process body (the check suite and the `--fix`
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
// what it read: package.json, the probes below, the test file listing, and
|
|
6
6
|
// whatever the floor resolution read.
|
|
7
7
|
//
|
|
8
|
-
// It also enforces the package.json half of ONE WAY IN (build/shipkit.md):
|
|
8
|
+
// It also enforces the package.json half of ONE WAY IN (build/shipkit/one-way-in.md):
|
|
9
9
|
// `test`, `lint` and `typecheck` ROUTE to `shipkit ci --only <id>` and the
|
|
10
10
|
// tool body they used to hold sits at `<id>:raw`. That is what makes a cache
|
|
11
11
|
// worth having: `bun run test` is the reflex, and the reflex has to land in
|
|
@@ -197,12 +197,16 @@ export const packageJsonShape = check({
|
|
|
197
197
|
title: 'package.json',
|
|
198
198
|
description: 'package.json routes lint, typecheck and test through the gate',
|
|
199
199
|
owner: OWNER,
|
|
200
|
+
runs: { onPreCommit: false, onCi: true, onFull: true, onRelease: true, onHealth: true, onSave: 'moved', onClock: false },
|
|
201
|
+
cache: { by: 'reads' },
|
|
202
|
+
fix: 'ci',
|
|
203
|
+
applies: 'always',
|
|
200
204
|
run: (c) => evaluatePackageJson(c),
|
|
201
205
|
// mechanical repairs only: field flips + scripts whose canonical body the
|
|
202
206
|
// vocabulary page states. Bodies it does NOT state (assets, comfy:up) are
|
|
203
207
|
// named in the summary, never invented. rvlib-* roots untouched — their
|
|
204
208
|
// license/private are publish decisions.
|
|
205
|
-
|
|
209
|
+
repair: (c): FixResult => {
|
|
206
210
|
const raw = c.read('package.json')
|
|
207
211
|
if (raw == null) return { changed: false, summary: 'no package.json — nothing to fix' }
|
|
208
212
|
if (rootPublishesNpm(c.config)) return { changed: false, summary: 'published to npm: its package.json is its public contract, never rewritten' }
|
|
@@ -16,6 +16,10 @@ export const contractsFulfillness = check({
|
|
|
16
16
|
owner: 'meta/contracts.md',
|
|
17
17
|
// keyed on what the contracts read: each artifact, each detector, and each
|
|
18
18
|
// folder a glob walked through `c.entries`, a gitignored one included
|
|
19
|
+
runs: { onPreCommit: false, onCi: true, onFull: true, onRelease: true, onHealth: true, onSave: 'moved', onClock: false },
|
|
20
|
+
cache: { by: 'reads' },
|
|
21
|
+
fix: 'none',
|
|
22
|
+
applies: 'always',
|
|
19
23
|
run: async (c) => {
|
|
20
24
|
applyContractsResult(c, await c.use(contractsResult), contractsFulfillness)
|
|
21
25
|
},
|
|
@@ -20,6 +20,10 @@ export const claudeMdShape = check({
|
|
|
20
20
|
owner: 'meta/agent-folder.md',
|
|
21
21
|
// keyed on what it reads: CLAUDE.md and whether agent/index.md exists. The
|
|
22
22
|
// gitignore probe runs git, so an answer that took it is never stored
|
|
23
|
+
runs: { onPreCommit: { budgetMs: 40 }, onCi: true, onFull: true, onRelease: true, onHealth: true, onSave: 'moved', onClock: false },
|
|
24
|
+
cache: { by: 'reads' },
|
|
25
|
+
fix: 'ci',
|
|
26
|
+
applies: 'always',
|
|
23
27
|
run: async (c) => {
|
|
24
28
|
const hasAgent = c.exists('agent/index.md')
|
|
25
29
|
const claude = c.read('CLAUDE.md')
|
|
@@ -53,7 +57,7 @@ export const claudeMdShape = check({
|
|
|
53
57
|
// CLAUDE.md would lint green with the base include forever missing,
|
|
54
58
|
// trading a loud FAIL for a permanent silent gap. Creation and prose
|
|
55
59
|
// relocation stay human/machine-local (`shipkit start --include`).
|
|
56
|
-
|
|
60
|
+
repair: (c): FixResult => {
|
|
57
61
|
if (!c.exists('agent/index.md')) return { changed: false, summary: 'no agent/index.md — nothing mechanical to fix' }
|
|
58
62
|
const cur = c.read('CLAUDE.md')
|
|
59
63
|
if (cur == null) return { changed: false, summary: 'CLAUDE.md missing — creation needs the base include (shipkit start <name> writes it), not autofixable' }
|
|
@@ -205,11 +205,14 @@ export const gitignorePolicy = check({
|
|
|
205
205
|
title: '.gitignore',
|
|
206
206
|
description: 'the managed .gitignore block keeps private contract folders out of git',
|
|
207
207
|
owner: 'meta/contracts.md',
|
|
208
|
-
// .gitignore plus what git currently TRACKS and IGNORES, which the tree
|
|
209
|
-
// carries and no read set records (the header says why)
|
|
210
|
-
inputs: ['.'],
|
|
211
208
|
// it untracks generated files (a commit) unless the run is frozen
|
|
212
209
|
writes: true,
|
|
210
|
+
runs: { onPreCommit: false, onCi: true, onFull: true, onRelease: true, onHealth: true, onSave: 'moved', onClock: false },
|
|
211
|
+
// .gitignore plus what git currently TRACKS and IGNORES, which the tree
|
|
212
|
+
// carries and no read set records (the header says why)
|
|
213
|
+
cache: { by: 'files', inputs: ['.'], key: null },
|
|
214
|
+
fix: 'ci',
|
|
215
|
+
applies: 'always',
|
|
213
216
|
run: async (c) => {
|
|
214
217
|
// a generated path still in the index is the half-applied state the
|
|
215
218
|
// managed block cannot fix on its own
|
|
@@ -278,7 +281,7 @@ export const gitignorePolicy = check({
|
|
|
278
281
|
}
|
|
279
282
|
c.ok(`.gitignore policy block current, ${claimed.length + backProbes.size} patterns verified against git`)
|
|
280
283
|
},
|
|
281
|
-
|
|
284
|
+
repair: async (c): Promise<FixResult> => {
|
|
282
285
|
// the move first: it writes the new block itself, before any folder moves
|
|
283
286
|
const moved = process.env.SHIPKIT_FROZEN === '1' ? null : migrateLayout(c.root, { config: c.config, renderGitignore: (t, legacy, cfg) => renderPolicy(t, cfg ?? c.config, legacy) })
|
|
284
287
|
const layout = moved == null ? null
|