pi-career 0.2.0 → 0.3.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 +28 -2
- package/NOTICE +1 -1
- package/README.md +72 -40
- package/SECURITY.md +7 -7
- package/dist/index.js +1406 -296
- package/docs/application-workspaces.md +6 -5
- package/docs/career-run-roadmap.md +37 -27
- package/docs/design.md +24 -19
- package/docs/native-dependency-inventory.md +1 -1
- package/docs/product-flow.md +11 -6
- package/docs/releasing.md +55 -32
- package/docs/variant-save-workflow.md +303 -0
- package/package.json +6 -1
- package/skills/career-core/SKILL.md +52 -133
- package/skills/career-core/references/cli-contract.md +6 -6
package/docs/releasing.md
CHANGED
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
# Release process
|
|
2
2
|
|
|
3
|
-
This document defines the bounded trusted-publishing
|
|
3
|
+
This document defines the bounded trusted-publishing process for the next explicitly authorized pi-career release and records the historical `v0.1.0` and `v0.2.0` outcomes. In the instructions below, `<version>` is the exact package version without `v`, `<tag>` is `v<version>`, and `<sha>` is the full frozen candidate commit.
|
|
4
4
|
|
|
5
5
|
## Release boundary
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
One coordinated release may create exactly:
|
|
8
8
|
|
|
9
|
-
1. one public `pi-career
|
|
10
|
-
2. one annotated, unsigned
|
|
9
|
+
1. one public `pi-career@<version>` npm package on `https://registry.npmjs.org/`;
|
|
10
|
+
2. one annotated, unsigned `<tag>` Git tag pointing to the exact published commit; and
|
|
11
11
|
3. one GitHub Release for that tag with notes derived from the finalized [`CHANGELOG.md`](../CHANGELOG.md) entry.
|
|
12
12
|
|
|
13
13
|
The npm package must be the native-free allowlisted artifact verified by `npm run check:package`. It contains the Pi extension, generated PDF worker, Agent Skill, and documentation. It must contain no `runtime/`, native executable, `node_modules`, Pi peer package contents, production dependency tree, lifecycle download/build hook, or publication script.
|
|
14
14
|
|
|
15
|
-
Career Core distribution remains external. The candidate pins exact [`@revazi/career@0.
|
|
15
|
+
Career Core distribution remains external. The candidate pins exact [`@revazi/career@0.2.0`](https://www.npmjs.com/package/@revazi/career/v/0.2.0); its reviewed launcher owns native target/libc, package metadata, provenance, file invariants, size, format, architecture, and SHA-256 verification. Pi-career supports only its six macOS/Linux targets and must not copy those algorithms or artifacts. Pi-career validates the exact ordered six-package v2 launcher manifest, declared file allowlist, and `career` bin before direct execution.
|
|
16
16
|
|
|
17
|
-
The reviewed external release is bound to Career Core commit/tag `
|
|
17
|
+
The reviewed external release is bound to Career Core commit/tag `536690632884c17336cc3c108f1bba0f254b862b`/`v0.2.0` and successful protected publication run [`31761238274`](https://github.com/revazi/career-core/actions/runs/31761238274). The launcher registry integrity is `sha512-5aksKh9S2fqPKBwlUY94XgCHjggr2Gep45zEWOMBNEfRtXvC/pYnlkI9CYrVHBFR8/gfGQog4pwV854FMzDxww==`; registry metadata reports SLSA v1 provenance for the user-facing launcher and all six lockstep launcher-owned native packages.
|
|
18
18
|
|
|
19
19
|
The sole permitted automated publication path is the tag-triggered `.github/workflows/release.yml` workflow using npm Trusted Publishing through GitHub OIDC and the protected `npm` environment. It must use no `NPM_TOKEN`, `NODE_AUTH_TOKEN`, OTP, or other long-lived publication credential. Preparation, CI success, a version bump, workflow availability, or this document does **not** authorize tag creation/push, npm publication, or a GitHub Release; release execution remains a separate explicit maintainer action. Do not publish to crates.io, attach an npm tarball/native binary as a custom GitHub Release asset, add signing/notarization claims, or add lifecycle/publication scripts.
|
|
20
20
|
|
|
@@ -31,9 +31,30 @@ Release execution completed on 2026-08-06:
|
|
|
31
31
|
- npm shasum: `4212cea50c08c98771df267361cee28070a15765`
|
|
32
32
|
- custom GitHub Release assets: none
|
|
33
33
|
|
|
34
|
-
That release bundled native Career Core artifacts. Its dependency/license/provenance evidence remains historical in [`native-dependency-inventory.md`](native-dependency-inventory.md) and [`licenses/`](licenses/). None of those native files may re-enter
|
|
34
|
+
That release bundled native Career Core artifacts. Its dependency/license/provenance evidence remains historical in [`native-dependency-inventory.md`](native-dependency-inventory.md) and [`licenses/`](licenses/). None of those native files may re-enter a future package.
|
|
35
35
|
|
|
36
|
-
## `v0.2.0`
|
|
36
|
+
## Historical `v0.2.0` outcome
|
|
37
|
+
|
|
38
|
+
Release execution completed on 2026-08-10:
|
|
39
|
+
|
|
40
|
+
- npm: [`pi-career@0.2.0`](https://www.npmjs.com/package/pi-career/v/0.2.0)
|
|
41
|
+
- published commit: `6db58644a6140202de2f2d661a740acd298c79b5`
|
|
42
|
+
- annotated unsigned tag and GitHub Release: [`v0.2.0`](https://github.com/revazi/pi-career/releases/tag/v0.2.0)
|
|
43
|
+
- npm integrity: `sha512-2V0z42oxsDHdE9a/UTskCzLY3inU0/DX30h2QhXse/Y3rAJpsaaNweqVhvZwZlMUovtyBu7pnGSpSo8CLhVOBg==`
|
|
44
|
+
- npm shasum: `c182b09945eee8cd85d817b7ce4965784731fd49`
|
|
45
|
+
- same-SHA six-target compatibility run: [`31352965430`](https://github.com/revazi/pi-career/actions/runs/31352965430)
|
|
46
|
+
- OIDC publication run: [`31353182855`](https://github.com/revazi/pi-career/actions/runs/31353182855)
|
|
47
|
+
- npm publisher identity: GitHub Actions trusted publisher for `revazi/pi-career`, workflow `release.yml`, environment `npm`
|
|
48
|
+
- SLSA provenance subject and resolved Git dependency: exact `pi-career@0.2.0` tarball and commit above
|
|
49
|
+
- custom GitHub Release assets: none
|
|
50
|
+
|
|
51
|
+
The first tag-triggered attempt, run [`31352716654`](https://github.com/revazi/pi-career/actions/runs/31352716654), failed before dependency installation or publication because `shell: node {0}` resolved a relative ESM import from GitHub's temporary script directory. Registry absence was reconfirmed; no publish retry occurred. PR [#23](https://github.com/revazi/pi-career/pull/23) moved the hosted-gate query into a checked-in script. After explicit incident authorization, the unpublished tag was replaced once on the corrected candidate.
|
|
52
|
+
|
|
53
|
+
In run `31353182855`, every gate and the OIDC `npm publish` step succeeded. The run then failed closed before GitHub Release creation because npm's attestation endpoint propagated after the original one-minute bound and the resulting SLSA bundle used the current Sigstore v0.3 media type while npm's publish attestation remained v0.2. The version already existed authoritatively, so it was never rerun or republished. PR [#24](https://github.com/revazi/pi-career/pull/24) extended bounded propagation polling and validates both exact bundle formats. The corrected verifier subsequently proved registry metadata, tarball bytes, trusted-publisher identity, provenance workflow/tag/SHA, and latest dist-tag; exact published Pi install/load/runtime/offline/remove acceptance passed before the GitHub Release and deployment status were finalized.
|
|
54
|
+
|
|
55
|
+
**Never rerun or republish after an ambiguous publish response.** Query authoritative registry state first. A post-publication recovery may finish verification and release-channel bookkeeping only; it must not create an alternate publication path, overwrite an immutable npm version, or move the published tag.
|
|
56
|
+
|
|
57
|
+
## Release gates
|
|
37
58
|
|
|
38
59
|
A skipped, unknown, stale, or merely planned result is not a pass.
|
|
39
60
|
|
|
@@ -41,21 +62,22 @@ A skipped, unknown, stale, or merely planned result is not a pass.
|
|
|
41
62
|
|
|
42
63
|
- Start from synchronized public `main` and identify one full candidate SHA.
|
|
43
64
|
- Require a clean Git tree and no divergence from `origin/main`.
|
|
44
|
-
- Confirm `package.json`, the root package-lock entries, the Skill metadata, package assertions, changelog, README, and release documentation all identify
|
|
45
|
-
- Keep Career Core and `@revazi/career` compatibility coordinates at exact `0.
|
|
46
|
-
- Confirm `package.json` is explicitly public only at `https://registry.npmjs.org/`, has exactly four wildcard Pi peers, declares no production/optional/bundled dependency tree, and has no lifecycle/publication script.
|
|
65
|
+
- Confirm `package.json`, the root package-lock entries, the Skill metadata, package assertions, changelog, README, and release documentation all identify the candidate version where appropriate.
|
|
66
|
+
- Keep Career Core and `@revazi/career` compatibility coordinates at exact `0.2.0` unless a separate compatibility/provenance review explicitly updates them; do not confuse the adapter release version with the external runtime version.
|
|
67
|
+
- Confirm `package.json` is explicitly public only at `https://registry.npmjs.org/`, has `os` exactly `['darwin', 'linux']`, has exactly four wildcard Pi peers, declares no production/optional/bundled dependency tree, and has no lifecycle/publication script.
|
|
47
68
|
- Ensure the candidate contains no real resume, vacancy, credentials, Pi session, provider output, generated local path, npm token, or unreviewed executable.
|
|
48
|
-
- Review the complete diff from
|
|
69
|
+
- Review the complete diff from the prior release tag, including authoritative `src/`, generated `dist/index.js`/`dist/pdf-worker.js`, `career_run`, all three exact raw tools, slash commands, external resolver, Skill, release automation, and package documentation.
|
|
49
70
|
- Do not move the candidate after local/hosted evidence is recorded. Any content change creates a new candidate and requires the gates again.
|
|
50
71
|
|
|
51
72
|
### 2. Review the external runtime boundary
|
|
52
73
|
|
|
53
|
-
- Confirm
|
|
74
|
+
- Confirm unsupported local/Git extension initialization registers no command/tool and fails with stable payload-free `unsupported_platform` before explicit/PATH lookup, package validation, acquisition, compatibility probing, or private stdin; retain invocation/resolver guards as defense in depth.
|
|
75
|
+
- Confirm the only acquisition coordinate remains exact `@revazi/career@0.2.0` from the canonical npm registry.
|
|
54
76
|
- Confirm runtime order remains: absolute `CAREER_CLI_PATH`, PATH `career`, package-local exact launcher, then bounded exact-package acquisition unless `PI_OFFLINE=1`.
|
|
55
|
-
- Confirm every caller-controlled route must pass the exact managed Core 0.
|
|
56
|
-
- Confirm package-local/acquired routes delegate native target/libc/provenance/mode
|
|
57
|
-
- Confirm
|
|
58
|
-
- Run the exact-package integration test on the six hosted macOS/GNU Linux/musl Linux release targets. Updating the external package coordinate, native target list, launcher schema, or managed Core contract requires separate compatibility, provenance, audit, and package review before this gate can pass.
|
|
77
|
+
- Confirm every caller-controlled route must pass the exact managed Core 0.2.0 operation catalog and required self-contained schema bundles before private stdin opens.
|
|
78
|
+
- Confirm package-local/acquired routes validate the exact ordered six-package v2 launcher manifest and delegate native target/libc/provenance/mode/size/format/architecture/SHA-256 verification to the reviewed launcher on the six supported targets.
|
|
79
|
+
- Confirm the external release's launcher plus six native packages remain version-lockstep, have canonical registry integrity and SLSA v1 provenance, and are bound to reviewed Core commit `536690632884c17336cc3c108f1bba0f254b862b`.
|
|
80
|
+
- Run the exact-package integration test on the six hosted macOS/GNU Linux/musl Linux release targets. Updating the external package coordinate, supported native target list, launcher schema, or managed Core contract requires separate compatibility, provenance, audit, and package review before this gate can pass.
|
|
59
81
|
|
|
60
82
|
### 3. Require clean audits and strict package proof
|
|
61
83
|
|
|
@@ -67,7 +89,7 @@ A skipped, unknown, stale, or merely planned result is not a pass.
|
|
|
67
89
|
- trusted npm is derived from the real Node installation and conflicting `npm_execpath` is rejected;
|
|
68
90
|
- npm environment overrides and duplicate decoded JSON keys cannot weaken checks;
|
|
69
91
|
- package listing/extraction uses verified absolute `/usr/bin/tar`;
|
|
70
|
-
- the tarball matches the exact allowlist and size bounds
|
|
92
|
+
- the tarball matches the exact allowlist and size bounds and declares `os: ['darwin', 'linux']`;
|
|
71
93
|
- no native runtime, `node_modules`, Pi peer contents, production dependency tree, or lifecycle/publication script is present;
|
|
72
94
|
- extracted package loading, stable offline failure, and isolated Pi install/list/remove behavior pass.
|
|
73
95
|
|
|
@@ -82,6 +104,7 @@ npm ci
|
|
|
82
104
|
npm run build
|
|
83
105
|
git diff --exit-code -- dist/index.js dist/pdf-worker.js
|
|
84
106
|
npm run bench:tokens
|
|
107
|
+
npm run bench:tokens:compare
|
|
85
108
|
npm run check
|
|
86
109
|
npm run test:runtime-resolution
|
|
87
110
|
npm run test:career-package
|
|
@@ -98,11 +121,11 @@ git diff --check
|
|
|
98
121
|
Requirements:
|
|
99
122
|
|
|
100
123
|
- The immediate dist diff after `npm run build` must pass; a later reproducibility test alone does not prove the candidate committed the generated output.
|
|
101
|
-
- Token measurements must
|
|
124
|
+
- Token measurements must satisfy the active before/optimizing/after manifest: immutable Git-history snapshot/manifest bytes and source/Skill tree anchors, exact frozen before/after comparability and deltas, unchanged current shape/invariants/budgets, and no current workflow regression relative to the frozen after snapshot. Later current source need not equal the historical after tree.
|
|
102
125
|
- Exact-package acquisition must execute managed discovery plus representative synthetic resume/job operations.
|
|
103
126
|
- Compatibility must run against an explicitly reviewed fixture checkout. A skip is not release evidence.
|
|
104
127
|
- The production npm tree must remain empty apart from unmet external peers expected in the Pi host.
|
|
105
|
-
- No command may create a repository tarball, native runtime, payload/result file, acceptance baseline, or publication side effect.
|
|
128
|
+
- No command may create a repository tarball, native runtime, payload/result file, audit-acceptance baseline, or publication side effect. Reviewed synthetic token snapshots are benchmark evidence, not vulnerability acceptance.
|
|
106
129
|
|
|
107
130
|
### 5. Require hosted checks on the same SHA
|
|
108
131
|
|
|
@@ -127,13 +150,13 @@ Record the dispatched run's `headSha` and reject it unless it equals the frozen
|
|
|
127
150
|
|
|
128
151
|
Before release authorization:
|
|
129
152
|
|
|
130
|
-
- convert `CHANGELOG.md` candidate notes to
|
|
131
|
-
- ensure README installation uses exact `npm:pi-career
|
|
132
|
-
- state that pi-career packages no native runtime
|
|
153
|
+
- convert `CHANGELOG.md` candidate notes to a dated candidate-version entry;
|
|
154
|
+
- ensure README installation uses the exact candidate `npm:pi-career@<version>` coordinate and clearly distinguishes historical releases;
|
|
155
|
+
- state that pi-career packages no native runtime, supports only the six reviewed macOS/Linux targets, uses exact external `@revazi/career@0.2.0`, and validates its exact ordered six-package v2 manifest;
|
|
133
156
|
- state that both production and complete development/host-Pi audits are clean at the explicit low threshold;
|
|
134
157
|
- keep all full commit SHA and npm integrity placeholders out of tracked files until those values exist; record them in the GitHub Release after publication.
|
|
135
158
|
|
|
136
|
-
The finalization commit cannot contain its own SHA. Only the separately authorized final clean commit may be published and receive
|
|
159
|
+
The finalization commit cannot contain its own SHA. Only the separately authorized final clean commit may be published and receive `<tag>`.
|
|
137
160
|
|
|
138
161
|
## Manual pre-publication checks
|
|
139
162
|
|
|
@@ -141,7 +164,7 @@ Run these only on the frozen clean candidate:
|
|
|
141
164
|
|
|
142
165
|
1. Confirm npm package `pi-career` has exactly the GitHub Actions trusted publisher `revazi/pi-career`, workflow `release.yml`, environment `npm`.
|
|
143
166
|
2. Confirm the GitHub `npm` environment exists and applies the reviewed deployment protections. No npm token or OTP may be stored in GitHub, npm configuration, repository files, Pi messages, logs, or release notes.
|
|
144
|
-
3. Confirm `npm view pi-career
|
|
167
|
+
3. Confirm `npm view pi-career@<version> version --json` reports no existing version. npm versions are immutable.
|
|
145
168
|
4. Run trusted `npm pack --dry-run --json --ignore-scripts` or rely on the stricter recorded `check:publish` artifact proof.
|
|
146
169
|
5. Record the candidate full SHA, package filename/size, clean audit results, hosted run URLs, and reviewed fixture SHA outside private content.
|
|
147
170
|
6. Obtain explicit release authorization. Do not infer authorization from readiness work.
|
|
@@ -150,20 +173,20 @@ Run these only on the frozen clean candidate:
|
|
|
150
173
|
|
|
151
174
|
Only after every gate passes and the maintainer explicitly authorizes release execution:
|
|
152
175
|
|
|
153
|
-
1. Reconfirm the clean SHA, branch protection checks, trusted-publisher/environment configuration, canonical registry, and absence of `pi-career
|
|
154
|
-
2. Create one annotated unsigned
|
|
176
|
+
1. Reconfirm the clean SHA, branch protection checks, trusted-publisher/environment configuration, canonical registry, and absence of `pi-career@<version>`.
|
|
177
|
+
2. Create one annotated unsigned `<tag>` on the exact candidate and push only that tag. The tag is the immutable input that triggers `.github/workflows/release.yml`; the workflow must never create or move it.
|
|
155
178
|
3. The workflow must verify the tag/version/changelog/SHA, install exact trusted-publishing-compatible npm tooling, run the complete package publication gate, and publish with lifecycle scripts disabled, public/latest coordinates, and npm provenance through OIDC.
|
|
156
179
|
4. If publication returns an ambiguous response, query the registry before any rerun. Never move the tag, attempt to overwrite the version, or blindly republish.
|
|
157
180
|
5. Before creating the GitHub Release, the workflow must verify registry metadata: version, repository, four wildcard peers, no dependency tree/lifecycle scripts, tarball integrity, shasum, provenance, and `gitHead` equal to the tagged candidate SHA.
|
|
158
|
-
6. The workflow must create the GitHub Release from the existing
|
|
181
|
+
6. The workflow must create the GitHub Release from the existing `<tag>` with:
|
|
159
182
|
- full commit SHA;
|
|
160
183
|
- npm integrity and shasum;
|
|
161
|
-
- exact external `@revazi/career@0.
|
|
162
|
-
- all
|
|
184
|
+
- exact external `@revazi/career@0.2.0` coordinate;
|
|
185
|
+
- all six supported macOS, GNU Linux, and musl Linux targets, plus a clear note that only the launcher is a pi-career installation surface;
|
|
163
186
|
- native-free pi-career package statement;
|
|
164
187
|
- clean production/full audit statement;
|
|
165
188
|
- no crate publication, signing/notarization claim, or custom release asset.
|
|
166
|
-
7. In an isolated Pi agent directory, install exact `npm:pi-career
|
|
189
|
+
7. In an isolated Pi agent directory, install exact `npm:pi-career@<version>`, list/load it, exercise exact-package runtime acquisition with synthetic operations on a supported target, test offline failure, and remove it.
|
|
167
190
|
8. Recheck the npm dist-tag, Git tag target, GitHub Release target, provenance, and main CI after all channels settle.
|
|
168
191
|
|
|
169
|
-
Do not sign, attach assets, change repository visibility, add an alternate publication workflow or token-based path, publish another registry tag/version, or retry an ambiguous operation without first querying authoritative state. A failed post-publication check is an incident, not permission to replace
|
|
192
|
+
Do not sign, attach assets, change repository visibility, add an alternate publication workflow or token-based path, publish another registry tag/version, or retry an ambiguous operation without first querying authoritative state. A failed post-publication check is an incident, not permission to replace the immutable published version.
|
|
@@ -0,0 +1,303 @@
|
|
|
1
|
+
# Materialized variant save design and threat review
|
|
2
|
+
|
|
3
|
+
## Status and authorization boundary
|
|
4
|
+
|
|
5
|
+
This document defines the implemented package-owned local save workflow for one successfully materialized, non-PDF assisted resume variant. The design was reviewed before implementation; implementation does not authorize publication, release, full-result export, or application-workspace persistence.
|
|
6
|
+
|
|
7
|
+
The design is intentionally narrower than the future application workspace in [`application-workspaces.md`](application-workspaces.md). It saves only one materialized Markdown or text resume plus integrity metadata under the selected original's configured library root. It does not create `application.json`, persist a vacancy, save review input or Core JSON, generate a cover letter, or establish an application workspace root.
|
|
8
|
+
|
|
9
|
+
## Goals
|
|
10
|
+
|
|
11
|
+
The implementation must:
|
|
12
|
+
|
|
13
|
+
1. accept only a current in-memory `variant:` handle returned by successful deterministic Career Core materialization;
|
|
14
|
+
2. show the exact destination, exact artifact bytes, exact sidecar bytes, hashes, and any directory marker before any filesystem mutation;
|
|
15
|
+
3. require a separate explicit confirmation after the unchanged preview;
|
|
16
|
+
4. publish new files without overwriting any existing path;
|
|
17
|
+
5. use `0600` regular files inside an owner-controlled `0700` managed directory;
|
|
18
|
+
6. preserve the original byte-for-byte and never use the original path as a write target;
|
|
19
|
+
7. label the artifact assisted/non-authoritative and bind it to the original and artifact hashes;
|
|
20
|
+
8. rescan immediately and prove that the new artifact cannot enter authoritative analysis or matching; and
|
|
21
|
+
9. retain payload-free failures, no logging, no provider/model call, no telemetry, and no network behavior.
|
|
22
|
+
|
|
23
|
+
## Non-goals
|
|
24
|
+
|
|
25
|
+
The save implementation does not add:
|
|
26
|
+
|
|
27
|
+
- a model-callable save tool or a `career_run save` command;
|
|
28
|
+
- arbitrary-path export, full Career Core result export, or raw provider-response persistence;
|
|
29
|
+
- PDF, DOCX, Pages, HTML, image, OCR, or layout-preserving output;
|
|
30
|
+
- mutation, replacement, rename, deletion, permission change, or reformatting of an original;
|
|
31
|
+
- automatic materialization, automatic save after materialization, automatic retry, or overwrite-on-confirmation;
|
|
32
|
+
- application workspace manifests, vacancy files, cover letters, notes, or application-root configuration;
|
|
33
|
+
- session entries containing artifact text, destination paths, save previews, or save receipts;
|
|
34
|
+
- lifecycle scripts, native code, external commands, shell execution, package acquisition, or other network behavior; or
|
|
35
|
+
- execution outside pi-career's supported macOS/Linux platforms; Windows is unsupported package-wide, not a deferred save-only feature.
|
|
36
|
+
|
|
37
|
+
Saving does not make assisted text authoritative, factually certified, safe to submit, or eligible for Career Core analysis or matching.
|
|
38
|
+
|
|
39
|
+
## User entry point and mode behavior
|
|
40
|
+
|
|
41
|
+
The only entry point is a user-invoked slash command:
|
|
42
|
+
|
|
43
|
+
```text
|
|
44
|
+
/career-save <variant-handle>
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
The command is deliberately absent from the active and raw model tool surfaces. An agent may tell the user that the command exists after materialization, but cannot invoke it as a tool or supply a destination. The command accepts exactly one bounded `variant:` handle and no path, filename, content, overwrite, or confirmation argument.
|
|
48
|
+
|
|
49
|
+
The command requires Pi to be idle and the handle to belong to the current session-scoped managed registry. It supports:
|
|
50
|
+
|
|
51
|
+
- **TUI:** ordinary Pi `editor` and `confirm` dialogs;
|
|
52
|
+
- **RPC:** the same dialogs through Pi's `extension_ui_request`/`extension_ui_response` protocol;
|
|
53
|
+
- **print/JSON:** stable fail-closed `interactive_mode_required` behavior with no write.
|
|
54
|
+
|
|
55
|
+
`ctx.ui.custom()` is not required and must not be the sole approval path because it returns `undefined` in RPC mode. Application-file approval remains independent from Pi session persistence and provider disclosure. A transient `pi --no-session` workflow may save only after the same file approval; a persisted session does not imply file approval.
|
|
56
|
+
|
|
57
|
+
The command performs no Core or provider call. It appends no custom or model-visible session entry. TUI dialogs are not a secure-erasure mechanism, and an RPC client may independently retain extension UI payloads.
|
|
58
|
+
|
|
59
|
+
## Eligible in-memory source
|
|
60
|
+
|
|
61
|
+
A save plan may be prepared only when all of these conditions hold:
|
|
62
|
+
|
|
63
|
+
- the handle resolves to a current registry entry of kind `variant` and operation `resume.variant.materialize`;
|
|
64
|
+
- the complete cached value has exact schema `career.resume_variant.v1` and authority `assisted_non_authoritative`;
|
|
65
|
+
- the entry retains an implementation-owned binding to the original resume ID, original root ID, canonical original path fingerprint, original format, and original text SHA-256 inherited unchanged through review and materialization;
|
|
66
|
+
- the original format is Markdown or text, never PDF;
|
|
67
|
+
- `assisted_resume_text` is a string with no carriage return or unpaired UTF-16 surrogate, and its exact LF-canonical UTF-8 encoding is non-empty and at most 262,144 bytes;
|
|
68
|
+
- at least one canonical reviewed change was explicitly selected; and
|
|
69
|
+
- a fresh pre-preview scan finds the same original as an eligible original with the same canonical identity, format, and text digest and finds neither the selected root nor total library scan capped.
|
|
70
|
+
|
|
71
|
+
The implementation must never reconstruct assisted text from conversation messages, tool-result projections, sidecars, a prior save, or model prose. Only the complete unchanged in-memory Core materialization value is eligible. Session switch, branch replacement, reload, shutdown, registry eviction, stale original content, or a PDF source invalidates saving.
|
|
72
|
+
|
|
73
|
+
## Destination derivation and managed directory
|
|
74
|
+
|
|
75
|
+
The command derives the destination; it never accepts one from the model or command arguments.
|
|
76
|
+
|
|
77
|
+
1. Start from the originating configured library root.
|
|
78
|
+
2. Use `generated_variants_root` only when it is a direct child of that exact canonical root.
|
|
79
|
+
3. Otherwise derive `<originating-library-root>/variants`.
|
|
80
|
+
4. Reject root paths, nested paths, paths outside that root, control characters, overlong paths, symlinks, aliases, and a destination equal to any configured library root.
|
|
81
|
+
|
|
82
|
+
The v1 save root is therefore a narrow managed variants directory inside the originating scan root. An existing `generated_variants_root` outside or deeper than that root remains suggestion-only and is not eligible for package-owned saving. The future separate application workspace is unaffected.
|
|
83
|
+
|
|
84
|
+
The directory marker path is exactly `<save-root>/.pi-career-variants.json` and uses this schema:
|
|
85
|
+
|
|
86
|
+
```json
|
|
87
|
+
{
|
|
88
|
+
"schema_version": "pi.career.variants_directory.v1",
|
|
89
|
+
"kind": "managed_variants_directory",
|
|
90
|
+
"library_root_id": "<64 lowercase hexadecimal characters>",
|
|
91
|
+
"created_at": "<canonical UTC timestamp with milliseconds>"
|
|
92
|
+
}
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
The encoded marker has the field order above, a single trailing LF, a 16,384-byte ceiling, mode `0600`, and no absolute path or private content. Parsing rejects duplicate decoded keys, unknown fields, invalid UTF-8, and noncanonical IDs or timestamps.
|
|
96
|
+
|
|
97
|
+
Before preview, the save root must be one of:
|
|
98
|
+
|
|
99
|
+
- absent, with its canonical configured library root as the existing parent; or
|
|
100
|
+
- an owner-controlled, non-symlink, canonical `0700` directory containing a valid matching marker; or
|
|
101
|
+
- an owner-controlled, non-symlink, canonical, empty `0700` directory that the preview explicitly proposes to initialize with the marker.
|
|
102
|
+
|
|
103
|
+
A non-empty unmarked directory is never adopted. Existing permissions are never changed silently. On supported macOS/Linux systems, the directory owner must equal the current effective user and exact permission bits must be `0700`. The implementation does not rely on `umask`; pi-career's package-level platform boundary excludes Windows before this workflow can run.
|
|
104
|
+
|
|
105
|
+
## Artifact naming and content
|
|
106
|
+
|
|
107
|
+
The package generates a fixed plan name before preview:
|
|
108
|
+
|
|
109
|
+
```text
|
|
110
|
+
resume-assisted-<UTC-basic-timestamp>-<first-8-lowercase-UUID-hex>.<md|txt>
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
The timestamp is the plan's canonical `Date.toISOString()` value transformed without punctuation, for example `20260811T030405123Z`. The extension comes only from the original format. Labels, company names, role names, original basenames, provider names, and model output never enter the filename. The random suffix is collision resistance, not overwrite permission. Both final paths must be absent and remain no-clobber publication targets.
|
|
114
|
+
|
|
115
|
+
The artifact bytes are exactly `Buffer.from(assisted_resume_text, "utf8")`. The package adds no BOM, trailing newline, newline normalization, header, label, or formatting change. The package never edits a successfully published artifact. A later user edit causes the sidecar hash check to fail closed until a separately designed adoption/review flow exists.
|
|
116
|
+
|
|
117
|
+
The paired sidecar is `<artifact-stem>.pi-career.json` and uses this exact package-owned schema:
|
|
118
|
+
|
|
119
|
+
```json
|
|
120
|
+
{
|
|
121
|
+
"schema_version": "pi.career.assisted_variant_meta.v2",
|
|
122
|
+
"kind": "assisted_variant",
|
|
123
|
+
"authority": "assisted_non_authoritative",
|
|
124
|
+
"base_document_id": "<original resume ID>",
|
|
125
|
+
"base_text_sha256": "<SHA-256 of the scanned original text>",
|
|
126
|
+
"artifact_sha256": "<SHA-256 of the exact artifact bytes>",
|
|
127
|
+
"created_at": "<canonical UTC timestamp with milliseconds>"
|
|
128
|
+
}
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
The encoded sidecar has the field order above, a single trailing LF, a 16,384-byte ceiling, and mode `0600`. Hashes provide local integrity binding only; they do not establish authorship, factuality, or provenance outside this workflow. No review handle, result handle, source path, vacancy, selected text, provider response, prompt, Core result, or credential is persisted.
|
|
132
|
+
|
|
133
|
+
Existing valid `pi.career.assisted_variant_meta.v1` sidecars remain supported and are not rewritten in place. Version 2 is used only for newly package-saved artifacts.
|
|
134
|
+
|
|
135
|
+
## Exact preview and confirmation protocol
|
|
136
|
+
|
|
137
|
+
Preparation is read-only. The command builds this exact preview envelope:
|
|
138
|
+
|
|
139
|
+
```json
|
|
140
|
+
{
|
|
141
|
+
"schema_version": "pi.career.variant_save_preview.v1",
|
|
142
|
+
"save_id": "<lowercase UUID>",
|
|
143
|
+
"initialize_directory": true,
|
|
144
|
+
"directory_path": "<exact absolute managed directory>",
|
|
145
|
+
"marker": {
|
|
146
|
+
"path": "<exact absolute marker path>",
|
|
147
|
+
"utf8_bytes": 0,
|
|
148
|
+
"sha256": "<SHA-256 of exact marker bytes>",
|
|
149
|
+
"text": "<complete exact marker text>"
|
|
150
|
+
},
|
|
151
|
+
"artifact": {
|
|
152
|
+
"path": "<exact absolute artifact path>",
|
|
153
|
+
"format": "markdown",
|
|
154
|
+
"utf8_bytes": 0,
|
|
155
|
+
"sha256": "<SHA-256 of exact artifact bytes>",
|
|
156
|
+
"text": "<complete exact materialized text>"
|
|
157
|
+
},
|
|
158
|
+
"sidecar": {
|
|
159
|
+
"path": "<exact absolute sidecar path>",
|
|
160
|
+
"utf8_bytes": 0,
|
|
161
|
+
"sha256": "<SHA-256 of exact sidecar bytes>",
|
|
162
|
+
"text": "<complete exact sidecar text>"
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
`initialize_directory` is `false` and `marker` is `null` when a valid marker already exists. `artifact.format` is exactly `markdown` or `text`. The field order shown is canonical; encoding is `JSON.stringify(preview, null, 2)` plus one LF. The preview itself is bounded to 524,288 UTF-8 bytes. No filesystem object is created before the preview is accepted.
|
|
168
|
+
|
|
169
|
+
The command opens the preview with `ctx.ui.editor()`. The returned text must be byte-for-byte identical to the generated preview. Cancellation or any edit—including whitespace—ends the command with no write. The editor is used for portable complete inspection, not for editing materialized content.
|
|
170
|
+
|
|
171
|
+
Only after unchanged preview acceptance does the command call `ctx.ui.confirm()` with the fixed save ID, exact directory, artifact and sidecar filenames, byte counts, hashes, assisted/non-authoritative warning, overwrite prohibition, and marker creation when applicable. A false, cancelled, missing, malformed, mismatched, or timed-out response produces no write. Confirmation cannot be supplied in command arguments, tool payloads, session entries, or prior conversation.
|
|
172
|
+
|
|
173
|
+
After confirmation and before the first mutation, the implementation revalidates:
|
|
174
|
+
|
|
175
|
+
- current session and registry ownership;
|
|
176
|
+
- complete variant schema, authority, bytes, and hashes;
|
|
177
|
+
- unchanged original identity and digest through a fresh uncapped scan;
|
|
178
|
+
- unchanged config and destination derivation;
|
|
179
|
+
- directory identity, ownership, mode, marker, and containment; and
|
|
180
|
+
- absence of both final paths.
|
|
181
|
+
|
|
182
|
+
Any drift invalidates the fixed plan. The command does not silently rebuild, rename, or reconfirm a replacement plan.
|
|
183
|
+
|
|
184
|
+
## No-clobber publication protocol
|
|
185
|
+
|
|
186
|
+
Implementation must use Node filesystem APIs directly with no shell or external executable. It must participate in Pi's `withFileMutationQueue()` for both real final paths, acquire a package-local save-root mutex in deterministic path order, and keep the whole validate/write/publish/verify window inside those guards. These queues prevent in-process lost updates; they do not claim protection from a malicious process running as the same operating-system user.
|
|
187
|
+
|
|
188
|
+
On supported POSIX systems, publication uses same-directory temporary regular files and no-clobber hard-link publication:
|
|
189
|
+
|
|
190
|
+
1. If approved initialization is needed, create only the direct-child directory with non-recursive `mkdir(..., 0o700)`, then revalidate canonical identity, owner, and exact mode. Publish the approved marker through the same temporary-file protocol before artifact publication.
|
|
191
|
+
2. Create unpredictable hidden temporary files in that directory with `O_CREAT | O_EXCL | O_WRONLY | O_NOFOLLOW` and mode `0600`.
|
|
192
|
+
3. Write the complete artifact and sidecar buffers, sync each file, close it, set mode `0600`, and verify regular-file type, owner, mode, size, and SHA-256.
|
|
193
|
+
4. Publish the sidecar first by hard-linking its temporary inode to the absent final sidecar path. `EEXIST` is a collision and never authorizes replacement.
|
|
194
|
+
5. Publish the artifact second by hard-linking its temporary inode to the absent final artifact path. This order ensures a package-published artifact is never intentionally visible without its assisted marker.
|
|
195
|
+
6. Remove temporary names and sync the containing directory.
|
|
196
|
+
7. Reopen and verify both final files as non-symlink regular files with the approved inode identity, owner, modes, sizes, hashes, and exact sidecar-to-artifact binding.
|
|
197
|
+
|
|
198
|
+
`rename()` must not be used where its platform behavior can replace an existing final path. No preflight `exists` check is treated as a write guarantee. Temporary names, marker names, and final names are fixed package-generated basenames and cannot contain separators.
|
|
199
|
+
|
|
200
|
+
Cancellation is honored through preview and final confirmation and once more immediately before publication. After publication starts, the bounded commit/verification sequence runs to settlement rather than aborting between files. No network or child process is involved.
|
|
201
|
+
|
|
202
|
+
On a known failure before final publication, temporary files are removed best-effort. If the sidecar was published but artifact publication failed, the implementation removes that sidecar only after proving it is the inode created by the current plan; otherwise it leaves the harmless orphan and reports a stable failure. A crash may leave an orphan sidecar or hidden temporary file, but scanner rules below prevent either from becoming an original resume.
|
|
203
|
+
|
|
204
|
+
If an error occurs after both links may have succeeded, the implementation first verifies the approved pair. An exact pair is treated as published and proceeds to rescan. An indeterminate state returns a stable `save_status_unknown` error and never retries, chooses a new name, or claims rollback. The user must inspect the already-previewed destination before another attempt.
|
|
205
|
+
|
|
206
|
+
## Scanner migration and fail-closed classification
|
|
207
|
+
|
|
208
|
+
The scanner must be changed before save publication is enabled. Classification becomes:
|
|
209
|
+
|
|
210
|
+
| Context | Sidecar state | Classification |
|
|
211
|
+
|---|---|---|
|
|
212
|
+
| Outside the exact managed variants directory | absent | original |
|
|
213
|
+
| Anywhere | valid v1 sidecar | assisted variant |
|
|
214
|
+
| Anywhere | valid v2 sidecar with matching artifact hash | assisted variant |
|
|
215
|
+
| Anywhere | present but invalid, unreadable, duplicated-key, symlinked, oversized, or hash-mismatched sidecar | quarantined; never original |
|
|
216
|
+
| Exact managed variants directory | missing sidecar | quarantined; never original |
|
|
217
|
+
| Exact managed variants directory | invalid or missing directory marker | quarantined; never original |
|
|
218
|
+
|
|
219
|
+
Quarantined candidates produce a bounded path-relative warning and are omitted from `eligibleOriginals()`, analysis, and matching. They must not fall back to `kind: original`. Sidecar parsing rejects unknown fields, duplicate decoded keys, invalid UTF-8, noncanonical hashes/timestamps, and content beyond 16,384 bytes. A valid v2 sidecar is checked against the exact bytes already read by the bounded scanner.
|
|
220
|
+
|
|
221
|
+
The managed-directory rule is exact and config/marker-bound; it is not a broad name exclusion for every directory called `variants`. Orphan sidecars and hidden temporary files are not supported resume candidates. Removing a valid sidecar or corrupting a package-saved file under the managed directory cannot promote it to an original.
|
|
222
|
+
|
|
223
|
+
After publication, the command immediately calls the normal bounded library scan and requires:
|
|
224
|
+
|
|
225
|
+
- the originating scan remains uncapped;
|
|
226
|
+
- exactly one record resolves to the approved canonical artifact path;
|
|
227
|
+
- its format and text equal the approved materialization;
|
|
228
|
+
- its kind is `assisted_variant`;
|
|
229
|
+
- its variant group/base document ID equals the original resume ID;
|
|
230
|
+
- no invalid-sidecar warning names it; and
|
|
231
|
+
- `eligibleOriginals()` excludes it.
|
|
232
|
+
|
|
233
|
+
Only then may the UI report success. If final files exist but rescan cannot prove these conditions, the command reports stable saved-but-unverified guidance without deleting or rewriting the approved pair. Subsequent analysis and matching remain protected by fail-closed scanner classification.
|
|
234
|
+
|
|
235
|
+
## Idempotency, retention, and removal
|
|
236
|
+
|
|
237
|
+
Within the current process, a verified save receipt is held only in memory and keyed by the variant handle. Repeating `/career-save` for that handle first verifies the exact existing pair and reports it without creating a duplicate. The receipt is cleared with the managed registry and is never appended to Pi session state.
|
|
238
|
+
|
|
239
|
+
After restart the variant handle no longer exists, so a save cannot be reconstructed from disk or conversation. Existing artifacts are discovered only as assisted variants by scanning.
|
|
240
|
+
|
|
241
|
+
Pi-career never automatically edits, overwrites, relocates, cleans, or deletes a saved artifact, sidecar, marker, orphan, or managed directory. Removing a library root from config, removing pi-career, deleting a Pi session, or enabling `PI_OFFLINE=1` does not remove saved files. User deletion is outside the package and does not provide secure erasure from backups, snapshots, sync services, RPC clients, or storage media.
|
|
242
|
+
|
|
243
|
+
## Stable failures and privacy
|
|
244
|
+
|
|
245
|
+
The implementation uses bounded workflow error codes including:
|
|
246
|
+
|
|
247
|
+
- `variant_save_unavailable`
|
|
248
|
+
- `variant_save_destination_invalid`
|
|
249
|
+
- `variant_save_preview_changed`
|
|
250
|
+
- `variant_save_collision`
|
|
251
|
+
- `variant_save_verification_failed`
|
|
252
|
+
- `variant_save_status_unknown`
|
|
253
|
+
|
|
254
|
+
Errors expose no resume/vacancy/result text, sidecar content, absolute path, environment, temporary name, inode, hash, raw filesystem error, or stack. The exact approved path and hashes are shown only in the user-facing preview/confirmation/success UI. Nothing is logged at the adapter boundary.
|
|
255
|
+
|
|
256
|
+
The package must not claim secure erasure, filesystem immutability, malicious same-user isolation, factual certification, or durability beyond successful file and directory sync on the supported local filesystem.
|
|
257
|
+
|
|
258
|
+
## Threat model
|
|
259
|
+
|
|
260
|
+
| Threat | Required mitigation |
|
|
261
|
+
|---|---|
|
|
262
|
+
| Agent or model initiates persistence | Save is a user-only slash command with no model tool or path/content argument. |
|
|
263
|
+
| Session persistence is mistaken for file consent | File preview and confirmation are separate in every session mode, including `pi --no-session`. |
|
|
264
|
+
| Preview is edited to bypass Core review | Returned preview must be byte-identical; edited content is never accepted as an artifact. |
|
|
265
|
+
| Original overwrite or alias | Destination is package-derived under a direct-child managed directory; the original is freshly revalidated and never opened for writing. |
|
|
266
|
+
| Traversal or filename injection | Command accepts only a bounded handle; all basenames are package-generated and separator-free. |
|
|
267
|
+
| Symlink or stale-root escape | Canonical root/directory checks, owner/mode checks, `O_NOFOLLOW`, same-directory temporary files, post-create revalidation, and strict containment. |
|
|
268
|
+
| Concurrent save or built-in file mutation | Root-local mutex plus `withFileMutationQueue()` around the complete mutation window. |
|
|
269
|
+
| Existing-file replacement | Final publication is no-clobber hard linking; `EEXIST` fails and `rename` replacement is forbidden. |
|
|
270
|
+
| Crash between sidecar and artifact | Sidecar publishes first; orphan sidecars are harmless; managed-root missing/invalid sidecars quarantine candidates. |
|
|
271
|
+
| Corrupt sidecar launders assisted text as original | Any present invalid sidecar and any missing sidecar in the managed directory fail closed, never to original. |
|
|
272
|
+
| Stale/foreign/evicted variant handle | Session registry ownership, operation/schema/authority checks, and inherited original binding are revalidated twice. |
|
|
273
|
+
| PDF styling loss | PDF-origin variant handles remain ineligible; only exact Markdown/text materializations can save. |
|
|
274
|
+
| Oversized memory/UI/file use | Fixed artifact, sidecar, marker, and preview byte ceilings; bounded normal scanner verification. |
|
|
275
|
+
| Private data leaks through errors or logs | Stable payload-free errors and no source/result/path/hash/raw-error logging. |
|
|
276
|
+
| Unexpected provider, Core, or network activity | Saving uses only current in-memory materialization and local Node filesystem APIs. |
|
|
277
|
+
| Unsupported operating system reaches save code | The package `os` allowlist and adapter-level `unsupported_platform` guard exclude it before runtime or save workflow use. |
|
|
278
|
+
| User edits a saved assisted file | V2 artifact hash mismatch quarantines it; pi-career never silently updates its sidecar. |
|
|
279
|
+
| Cleanup is mistaken for erasure | No automatic deletion or secure-erasure claim; retention surfaces are documented. |
|
|
280
|
+
|
|
281
|
+
## Implementation acceptance tests
|
|
282
|
+
|
|
283
|
+
Tests use synthetic Markdown/text only and must cover:
|
|
284
|
+
|
|
285
|
+
1. exact variant schema, assisted authority, selected-change, session, source binding, and byte eligibility;
|
|
286
|
+
2. PDF, stale original, changed original, foreign session, evicted handle, malformed Unicode, empty text, and oversized text rejection;
|
|
287
|
+
3. exact canonical preview-envelope bytes and TUI/RPC unchanged-preview plus separate-confirm success paths;
|
|
288
|
+
4. cancellation, changed preview, false confirmation, missing UI, print mode, and JSON mode with zero filesystem mutation;
|
|
289
|
+
5. exact package-derived direct-child root behavior and rejection of outside, nested, root-equal, stale, symlinked, wrong-owner, wrong-mode, and non-empty unmarked destinations;
|
|
290
|
+
6. first-use directory/marker preview and initialization with exact `0700`/`0600` modes;
|
|
291
|
+
7. exact artifact bytes with no BOM/newline/format mutation and exact canonical v2 sidecar bytes;
|
|
292
|
+
8. no-clobber behavior for artifact, sidecar, marker, temporary, symlink, hard-link, and concurrent collision cases;
|
|
293
|
+
9. injected failures before and after every create, write, sync, link, unlink, verification, and rescan boundary;
|
|
294
|
+
10. crash-state fixtures for orphan sidecar, hidden temporary file, missing sidecar, malformed sidecar, duplicate keys, hash mismatch, and invalid marker, all excluded from originals;
|
|
295
|
+
11. valid legacy v1 and new v2 sidecars remaining assisted and never rewritten during scan;
|
|
296
|
+
12. immediate uncapped rescan proving exact text, variant grouping, warnings, and `eligibleOriginals()` exclusion;
|
|
297
|
+
13. repeated same-process save returning the verified existing receipt without another file;
|
|
298
|
+
14. no Core invocation, provider call, network call, child process, session entry, full-result file, raw error, or log;
|
|
299
|
+
15. removal/config changes leaving user files untouched with documented no-erasure semantics;
|
|
300
|
+
16. deterministic package checks proving no synthetic saved artifacts or new runtime dependencies enter the npm tarball; and
|
|
301
|
+
17. Linux and macOS local filesystem acceptance under the package-wide supported-platform boundary.
|
|
302
|
+
|
|
303
|
+
The normal repository verification ladder and changed-file security/architecture review remain mandatory before merge.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-career",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Pi tools, slash commands, and Agent Skill for deterministic Career Core workflows",
|
|
6
6
|
"license": "MIT OR Apache-2.0",
|
|
@@ -23,6 +23,10 @@
|
|
|
23
23
|
"engines": {
|
|
24
24
|
"node": ">=22.19.0"
|
|
25
25
|
},
|
|
26
|
+
"os": [
|
|
27
|
+
"darwin",
|
|
28
|
+
"linux"
|
|
29
|
+
],
|
|
26
30
|
"files": [
|
|
27
31
|
"dist",
|
|
28
32
|
"docs",
|
|
@@ -56,6 +60,7 @@
|
|
|
56
60
|
"audit:production": "node scripts/audit-production.mjs",
|
|
57
61
|
"audit:full": "node scripts/audit-full.mjs",
|
|
58
62
|
"bench:tokens": "node --import tsx scripts/token-benchmark.mjs",
|
|
63
|
+
"bench:tokens:compare": "node --import tsx scripts/token-benchmark-compare.mjs",
|
|
59
64
|
"check:syntax": "node --check scripts/*.mjs scripts/lib/*.mjs tests/audit/*.mjs tests/process/*.mjs tests/runtime/*.mjs tests/workflow/*.mjs",
|
|
60
65
|
"check": "npm run typecheck && npm run check:dist && npm test && npm run check:runtime && npm run check:links && npm run check:secrets && npm run check:syntax"
|
|
61
66
|
},
|