@acrasie/dev-flow 0.0.0-stage → 1.0.1
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/.codex-plugin/plugin.json +20 -0
- package/LICENSE +21 -0
- package/README.md +181 -2
- package/dist/codex-dev-flow.mjs +3 -0
- package/dist/dev-flow.mjs +241 -0
- package/docs/adr/0001-hybrid-portable-workflow.md +23 -0
- package/docs/adr/0002-share-an-invalidable-context-capsule.md +55 -0
- package/docs/adr/0004-scale-assurance-lanes-by-applicable-risk.md +36 -0
- package/docs/adr/0006-make-intake-adaptive-user-authoritative-and-token-efficient.md +76 -0
- package/docs/adr/0007-collect-opt-in-local-benchmark-feedback.md +82 -0
- package/docs/adr/0008-automate-maintainer-releases-with-an-interactive-bun-workflow.md +121 -0
- package/docs/adr/0009-separate-intake-decisions-from-shape-discovery.md +200 -0
- package/docs/adr/0010-choose-quick-or-plan-after-discovery.md +161 -0
- package/docs/adr/0011-separate-fast-local-and-authoritative-ci-quality-gates.md +49 -0
- package/docs/adr/0012-use-bun-test-and-require-node-24.md +41 -0
- package/docs/adr/0013-layer-source-distribution-and-runtime-tests.md +42 -0
- package/docs/adr/0014-ratchet-source-coverage-with-bun.md +51 -0
- package/docs/adr/0015-split-fast-and-type-aware-linting.md +41 -0
- package/docs/adr/0016-use-husky-with-a-tested-bun-staged-file-adapter.md +45 -0
- package/docs/adr/0017-format-conservatively-with-oxfmt.md +45 -0
- package/docs/adr/0018-use-a-high-signal-oxlint-policy.md +53 -0
- package/docs/adr/0019-gate-deterministic-size-and-observe-timing.md +44 -0
- package/docs/adr/0020-support-linux-and-macos-with-targeted-ci.md +41 -0
- package/docs/adr/0021-randomize-tests-without-retries.md +35 -0
- package/docs/adr/0022-use-one-root-bun-workspace.md +41 -0
- package/docs/adr/0024-make-gate-a-minimal-plan-approval.md +74 -0
- package/docs/adr/0025-end-the-lifecycle-after-assure.md +55 -0
- package/docs/adr/0026-keep-intake-product-stable-and-interview-shape-by-dependency.md +151 -0
- package/docs/adr/0027-add-agentic-project-init-and-versioned-engineering-profiles.md +147 -0
- package/docs/adr/0028-make-public-documentation-user-first-and-current.md +65 -0
- package/docs/adr/0029-make-build-a-native-execution-boundary.md +51 -0
- package/docs/adr/0030-unify-product-domain-and-technical-design-interviews.md +240 -0
- package/docs/adr/0031-make-assure-the-success-boundary.md +205 -0
- package/docs/artifacts.md +47 -0
- package/docs/baselines/2026-07-18-p0-lifecycle.json +142 -0
- package/docs/design.md +101 -0
- package/docs/getting-started.md +204 -0
- package/docs/glossary/dev-flow.md +527 -0
- package/docs/lifecycle-contract.md +189 -0
- package/docs/lifecycle-contract.projection.json +931 -0
- package/docs/metrics-protocol.md +113 -0
- package/docs/project-profile-contract.md +157 -0
- package/docs/runbooks/maintainer-release.md +291 -0
- package/docs/target-intake-shape-contract.md +416 -0
- package/package.json +68 -4
- package/schemas/config.schema.json +104 -0
- package/schemas/policy.schema.json +17 -0
- package/schemas/project-init-state.schema.json +159 -0
- package/schemas/project-profile-local.schema.json +53 -0
- package/schemas/project-profile.schema.json +285 -0
- package/schemas/state.schema.json +826 -0
- package/skills/debug-root-cause/SKILL.md +16 -0
- package/skills/design-decisions/SKILL.md +24 -0
- package/skills/dev-flow/SKILL.md +306 -0
- package/skills/dev-flow/agents/openai.yaml +6 -0
- package/skills/discover-change/SKILL.md +31 -0
- package/skills/plan-change/SKILL.md +29 -0
- package/skills/review-change/SKILL.md +21 -0
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
# Lifecycle measurement protocol
|
|
2
|
+
|
|
3
|
+
## Status and purpose
|
|
4
|
+
|
|
5
|
+
This protocol is normative from `P8.1`. It measures quota/token cost and lifecycle
|
|
6
|
+
reliability without changing transition eligibility. Reliability and truthful status
|
|
7
|
+
remain hard gates; measurements can never authorize success.
|
|
8
|
+
|
|
9
|
+
## Privacy boundary
|
|
10
|
+
|
|
11
|
+
Metric events use an allowlist. They may contain only:
|
|
12
|
+
|
|
13
|
+
- schema version and monotonically increasing sequence/timestamp numbers;
|
|
14
|
+
- opaque per-run UUID generated independently from task/objective identity;
|
|
15
|
+
- preparation profile (`quick|plan|unselected`), macro-phase, metric, numeric value,
|
|
16
|
+
measurement label, and source enum.
|
|
17
|
+
|
|
18
|
+
Never accept or store raw task ID, prompt, objective prose, source code, diff, file content, secret, credential,
|
|
19
|
+
raw command output, model response, exception message, user identity, remote URL, or
|
|
20
|
+
artifact prose. Unknown event fields fail closed rather than being copied or redacted
|
|
21
|
+
afterward.
|
|
22
|
+
|
|
23
|
+
## Measurement truthfulness
|
|
24
|
+
|
|
25
|
+
Every numeric observation is one of:
|
|
26
|
+
|
|
27
|
+
- `measured`: native counter or deterministic local observation;
|
|
28
|
+
- `estimated`: explicit estimate/proxy, never displayed as native usage;
|
|
29
|
+
- `unavailable`: field absent from events and explicit in reports.
|
|
30
|
+
|
|
31
|
+
Allowed source bindings:
|
|
32
|
+
|
|
33
|
+
| Metric | Measurement | Source |
|
|
34
|
+
| ------------------------------------------------------------------------------------ | ----------- | ------------------------- |
|
|
35
|
+
| `input_tokens`, `output_tokens` | `measured` | `native_token_api` |
|
|
36
|
+
| `input_tokens`, `output_tokens` | `estimated` | `explicit_token_estimate` |
|
|
37
|
+
| `token_proxy_context_bytes` | `estimated` | `context_bytes_proxy` |
|
|
38
|
+
| `latency_ms` | `measured` | `monotonic_clock` |
|
|
39
|
+
| `false_success_detections` | `measured` | `operator_audit` |
|
|
40
|
+
| structural lifecycle counters | `measured` | `state_history` |
|
|
41
|
+
| model/delegation/context/capsule counters | `measured` | `orchestrator_counter` |
|
|
42
|
+
| INTAKE questions/avoided/recommendation/zero-path/reopen counters | `measured` | `orchestrator_counter` |
|
|
43
|
+
| SHAPE Discovery/Planning session, targeted invalidation, and evidence reuse counters | `measured` | `orchestrator_counter` |
|
|
44
|
+
| GATE preflight and approval-reuse counters | `measured` | `orchestrator_counter` |
|
|
45
|
+
| GATE decision and targeted-return counters | `measured` | `state_history` |
|
|
46
|
+
|
|
47
|
+
Missing token or latency telemetry is `unavailable`, never numeric zero. Estimated data
|
|
48
|
+
cannot be combined with measured data without retaining both labels and sources.
|
|
49
|
+
Contract fixtures may source false-success detection only from `contract_tests`; runtime
|
|
50
|
+
traces require `operator_audit`.
|
|
51
|
+
|
|
52
|
+
## Event and aggregation contract
|
|
53
|
+
|
|
54
|
+
`createLifecycleMetricEvent()` enforces event fields, enums, non-negative values,
|
|
55
|
+
measurement/source compatibility, and allowlisted model/effort/quota-pressure dimensions
|
|
56
|
+
for model calls. `summarizeLifecycleTrace()` validates every edge
|
|
57
|
+
against canonical `STATE_MACHINE` before counting transitions, gates, blocks, resumes,
|
|
58
|
+
ASSURE checks, evidence reuse, review calls/escalations, and correction cycles.
|
|
59
|
+
|
|
60
|
+
Runtime collection must call non-throwing `tryCreateLifecycleMetricEvent()`. Rejected
|
|
61
|
+
telemetry returns only `metric_rejected`; it never changes workflow state or exit status.
|
|
62
|
+
Strict constructors remain for tests/offline validation. Latency summaries accept only an
|
|
63
|
+
explicit `{measurement: measured, source: monotonic_clock}` observation; other data stays
|
|
64
|
+
`unavailable`.
|
|
65
|
+
|
|
66
|
+
Aggregation groups by contract version, preparation profile, macro-phase, metric, measurement, and
|
|
67
|
+
source. Median/p90 require runtime samples; contract fixtures report structural counts
|
|
68
|
+
only. False-success target remains absolute zero. A detected false success invalidates
|
|
69
|
+
optimization acceptance regardless of token or latency improvement.
|
|
70
|
+
|
|
71
|
+
Instrumentation is observational and removable: disabling event collection must not
|
|
72
|
+
change state, guards, approvals, assurance, or exit status.
|
|
73
|
+
|
|
74
|
+
## P0 baseline
|
|
75
|
+
|
|
76
|
+
[`baselines/2026-07-18-p0-lifecycle.json`](baselines/2026-07-18-p0-lifecycle.json) is a
|
|
77
|
+
reproducible contract-fixture baseline generated by `npm run baseline:p0`. It covers one
|
|
78
|
+
canonical Quick and Plan trace under TaskState V6. Both cross all five phases.
|
|
79
|
+
|
|
80
|
+
Limitations are explicit:
|
|
81
|
+
|
|
82
|
+
- `contract_fixture_not_runtime`;
|
|
83
|
+
- `token_telemetry_unavailable`;
|
|
84
|
+
- `latency_telemetry_unavailable`.
|
|
85
|
+
|
|
86
|
+
This is structural baseline, not dogfooding performance claim. Runtime median/p90 remain
|
|
87
|
+
pending until P1+ supplies durable orchestration events.
|
|
88
|
+
|
|
89
|
+
## Mandatory before/after record for P1–P7
|
|
90
|
+
|
|
91
|
+
Every approved change artifact in P1, P2, P3, P4, P5, P6, and P7 must contain compact
|
|
92
|
+
measurement projection:
|
|
93
|
+
|
|
94
|
+
```yaml
|
|
95
|
+
measurement:
|
|
96
|
+
schemaVersion: 1
|
|
97
|
+
baselineRef: plugins/codex-dev-flow/docs/baselines/2026-07-18-p0-lifecycle.json
|
|
98
|
+
budget:
|
|
99
|
+
falseSuccessMax: 0
|
|
100
|
+
requiredEvidenceRegressionMax: 0
|
|
101
|
+
targetMetrics: []
|
|
102
|
+
after:
|
|
103
|
+
sampleRefs: []
|
|
104
|
+
unavailableMetrics: []
|
|
105
|
+
delta:
|
|
106
|
+
measured: []
|
|
107
|
+
estimated: []
|
|
108
|
+
reliabilityGate: pending
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
`after` and `delta` stay pending before implementation evidence exists. A missing metric
|
|
112
|
+
is recorded under `unavailableMetrics`; it is never inferred as improvement. Comparison
|
|
113
|
+
must use matching preparation-profile/source/measurement and preserve raw evidence outside metric data.
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
# Project Engineering Profile Contract
|
|
2
|
+
|
|
3
|
+
This document is normative for agentic `$dev-flow init`, shared project profiles, local
|
|
4
|
+
overlays, validation, reconciliation, and publication. It is outside TaskState lifecycle
|
|
5
|
+
and does not yet make project profiles part of ordinary SHAPE completion.
|
|
6
|
+
|
|
7
|
+
## Interfaces
|
|
8
|
+
|
|
9
|
+
- `$dev-flow init`: agentic Discovery, adaptive interview, validation, and explicit
|
|
10
|
+
Profile Approval.
|
|
11
|
+
- `npx @acrasie/dev-flow init`: separate deterministic plugin-configuration wizard.
|
|
12
|
+
- `dev-flow project-profile inspect`: read existing shared/local profiles and
|
|
13
|
+
ignore status.
|
|
14
|
+
- `dev-flow project-profile validate [--local]`: validate stdin without writing.
|
|
15
|
+
- `dev-flow project-profile publish [--local]`: publish validated stdin after
|
|
16
|
+
agent confirms explicit Profile Approval.
|
|
17
|
+
- `dev-flow project-profile view [--local]`: render exact published canonical
|
|
18
|
+
YAML.
|
|
19
|
+
- `dev-flow project-profile session-view|session-save|session-clear`: resume,
|
|
20
|
+
persist, or remove compact local INIT interview state.
|
|
21
|
+
|
|
22
|
+
`project-profile` commands are deterministic backend primitives. They perform no model
|
|
23
|
+
call, repository discovery, interview, or approval inference.
|
|
24
|
+
|
|
25
|
+
## Agentic INIT
|
|
26
|
+
|
|
27
|
+
INIT discovers repository facts before asking. Core scope is stack, source structure,
|
|
28
|
+
architecture boundaries, dependency direction, naming, error handling, testing, and
|
|
29
|
+
quality. Frontend, API, data, security, concurrency, performance, compatibility,
|
|
30
|
+
migration, observability, deployment, rollback, and operations activate only when
|
|
31
|
+
applicable.
|
|
32
|
+
|
|
33
|
+
Questions are limited to missing, contradictory, stale, or material decisions and
|
|
34
|
+
appear exactly one at a time. Each carries evidence, recommendation and confidence,
|
|
35
|
+
2–3 viable options, direct consequences, and free-form path. There is no hard question
|
|
36
|
+
cap, periodic progress checkpoint, or cost-estimation prompt. Greenfield INIT produces
|
|
37
|
+
profile and optional generated diagram only, never product scaffold.
|
|
38
|
+
|
|
39
|
+
Compact local `.codex/project-init/state.yaml` persists normalized decisions, stale
|
|
40
|
+
keys, status, candidate digest, and at most one exact active question. Schema:
|
|
41
|
+
[project-init-state.schema.json](../schemas/project-init-state.schema.json). It contains
|
|
42
|
+
no transcript or hidden reasoning and is gitignored. Every save preserves session/profile
|
|
43
|
+
identity and increments revision exactly once. Resume reuses active question unless
|
|
44
|
+
dependency evidence changed. Successful publication clears session explicitly.
|
|
45
|
+
|
|
46
|
+
Multi-service Discovery is progressive. Each repository owns its profile. Root profile
|
|
47
|
+
contains logical topology, responsibilities, dependencies, contracts, and external
|
|
48
|
+
profile refs. Absolute service paths stay local. An inaccessible service claim is
|
|
49
|
+
`user_asserted`, never verified evidence. External repository update requires own
|
|
50
|
+
validation and approval transaction.
|
|
51
|
+
|
|
52
|
+
## Shared profile
|
|
53
|
+
|
|
54
|
+
Canonical shared file is versioned:
|
|
55
|
+
|
|
56
|
+
```text
|
|
57
|
+
.codex/dev-flow.project.yaml
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Schema: [project-profile.schema.json](../schemas/project-profile.schema.json).
|
|
61
|
+
|
|
62
|
+
Required content:
|
|
63
|
+
|
|
64
|
+
- stable project identity and stack;
|
|
65
|
+
- logical service topology and contracts;
|
|
66
|
+
- all eight core convention categories plus applicable optional categories;
|
|
67
|
+
- decision rationale, provenance, durable fingerprints, and dependency edges;
|
|
68
|
+
- optional `domainDocumentation` conventions: single/multiple context mode, portable
|
|
69
|
+
glossary/rules/ADR/context-map paths, language, stable identity/link conventions, and
|
|
70
|
+
source fingerprints;
|
|
71
|
+
- optional relative Markdown diagram refs below `.codex/dev-flow/diagrams/`; and
|
|
72
|
+
- monotonic revision, canonical content digest, and Profile Approval Receipt.
|
|
73
|
+
|
|
74
|
+
Decision dependency graph is acyclic. `user_asserted` decisions cannot carry verified
|
|
75
|
+
fingerprints. Shared profile rejects secret-like values, local absolute filesystem
|
|
76
|
+
paths, duplicate identities, unknown service/dependency refs, and missing core domains.
|
|
77
|
+
Volatile task observations never belong here.
|
|
78
|
+
|
|
79
|
+
Canonical content digest is SHA-256 of recursively key-sorted JSON representation of
|
|
80
|
+
`content`. Receipt remains outside content digest to avoid cycle. Receipt binds actor
|
|
81
|
+
`user`, approval time, profile identity, revision, and exact content digest; receipt
|
|
82
|
+
digest binds those fields. Any mismatch makes profile invalid.
|
|
83
|
+
|
|
84
|
+
## Local overlay
|
|
85
|
+
|
|
86
|
+
Local file is gitignored:
|
|
87
|
+
|
|
88
|
+
```text
|
|
89
|
+
.codex/dev-flow.project.local.yaml
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
Schema: [project-profile-local.schema.json](../schemas/project-profile-local.schema.json).
|
|
93
|
+
Before publication repository `.gitignore` must contain exact path entry. Overlay may
|
|
94
|
+
contain only absolute local service paths and non-contractual preferences. Service IDs
|
|
95
|
+
must exist in shared topology when shared profile exists. A preference cannot override
|
|
96
|
+
shared decision key. Local profile identity and optional shared digest binding must
|
|
97
|
+
match shared profile.
|
|
98
|
+
|
|
99
|
+
## Authority
|
|
100
|
+
|
|
101
|
+
```text
|
|
102
|
+
system instructions and repository policy
|
|
103
|
+
-> INTAKE product decisions when task-scoped
|
|
104
|
+
-> explicitly approved task exception
|
|
105
|
+
-> shared engineering profile
|
|
106
|
+
-> non-contractual local preferences
|
|
107
|
+
-> agent defaults
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
Lower authority cannot weaken higher authority. Domain destination resolution uses
|
|
111
|
+
repository policy, approved profile, unambiguous detected convention, then portable
|
|
112
|
+
defaults. Task exceptions remain task-local and cannot silently rewrite shared profile.
|
|
113
|
+
|
|
114
|
+
## Reconciliation
|
|
115
|
+
|
|
116
|
+
Every decision and domain-documentation fingerprint source is rediscovered when accessible. Missing observations remain
|
|
117
|
+
unknown, never current proof. Changed fingerprint marks owning decision stale and
|
|
118
|
+
invalidates only transitive dependent closure. Repository facts are rediscovered;
|
|
119
|
+
user-owned conventions are re-interviewed. Proposed update accumulates outside shared
|
|
120
|
+
file. Rejection leaves shared profile byte-for-byte unchanged and creates no shared
|
|
121
|
+
stale marker.
|
|
122
|
+
|
|
123
|
+
Revision 1 creates profile. Update preserves `profileId`, increments revision exactly by
|
|
124
|
+
one, and must change content digest. Same-content and stale-revision publication fail.
|
|
125
|
+
|
|
126
|
+
## Validation and publication
|
|
127
|
+
|
|
128
|
+
Candidate stdin may be raw profile YAML/JSON or transaction object:
|
|
129
|
+
|
|
130
|
+
````yaml
|
|
131
|
+
profile: # profile proposal without approval
|
|
132
|
+
projections:
|
|
133
|
+
- path: .codex/dev-flow/diagrams/example-r1.mermaid.md
|
|
134
|
+
content: |-
|
|
135
|
+
```mermaid
|
|
136
|
+
flowchart LR
|
|
137
|
+
A --> B
|
|
138
|
+
```
|
|
139
|
+
````
|
|
140
|
+
|
|
141
|
+
Validation is read-only and returns exact canonical proposal YAML, digest, revision,
|
|
142
|
+
decision/topology/stack diff, and projection paths. Agent shows adaptive summary and
|
|
143
|
+
exact YAML on request, then asks one explicit Profile Approval. Candidate or projection
|
|
144
|
+
change requires validation and approval again.
|
|
145
|
+
|
|
146
|
+
Before shared publication, existing INIT session—when present—must be
|
|
147
|
+
`awaiting_approval` and bound to same candidate content digest. This prevents resume or
|
|
148
|
+
candidate drift from inheriting prior validation.
|
|
149
|
+
|
|
150
|
+
After approval, backend publishes new immutable projection paths first and shared
|
|
151
|
+
profile through one final atomic rename. Shared profile rename is authority boundary;
|
|
152
|
+
failed rename leaves prior profile current, while any orphan new projection remains
|
|
153
|
+
non-authoritative. Existing projection path can be reused only with byte-identical
|
|
154
|
+
content. Symlinked profile or projection path is rejected. Local overlay uses separate
|
|
155
|
+
atomic write after ignore and authority validation.
|
|
156
|
+
|
|
157
|
+
Direct file write bypass is forbidden.
|
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
# Maintainer Release Runbook
|
|
2
|
+
|
|
3
|
+
## Purpose and ownership
|
|
4
|
+
|
|
5
|
+
This runbook is the canonical production-release procedure for Dev Flow. A
|
|
6
|
+
maintainer runs it from a trusted local workstation. CI validates releases but does not
|
|
7
|
+
publish the canonical npm package or the Codex plugin. After an npm-bearing GitHub
|
|
8
|
+
Release is published, a separate GitHub Actions workflow mirrors its canonical npmjs
|
|
9
|
+
tarball to GitHub Packages as `@acrazie/dev-flow`.
|
|
10
|
+
|
|
11
|
+
Use the repository release program rather than invoking `npm publish`, creating tags,
|
|
12
|
+
or editing release versions manually:
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
bun run release
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
The release design and safety rationale are recorded in
|
|
19
|
+
[ADR 0008](../adr/0008-automate-maintainer-releases-with-an-interactive-bun-workflow.md).
|
|
20
|
+
|
|
21
|
+
## Supported release targets
|
|
22
|
+
|
|
23
|
+
| Target | Version change | Tag | Publication |
|
|
24
|
+
| ------------ | ---------------------------------------------------------------- | --------------------------------------- | ------------------------------------------------------------ |
|
|
25
|
+
| Plugin + npm | Increment npm SemVer; give plugin same base plus UTC cachebuster | `v<version>` | Git push, npm, GitHub Release, optional local plugin refresh |
|
|
26
|
+
| Codex plugin | Keep semantic base; replace plugin UTC cachebuster | `plugin-v<version>-codex.<cachebuster>` | Git push, GitHub Release, optional local plugin refresh |
|
|
27
|
+
| npm package | Increment npm SemVer; leave plugin manifest unchanged | `npm-v<version>` | Git push, npm, GitHub Release |
|
|
28
|
+
|
|
29
|
+
Only stable npm versions are supported. The program recommends patch, minor, or major
|
|
30
|
+
from Conventional Commits; maintainer retains final version authority.
|
|
31
|
+
|
|
32
|
+
## Preconditions
|
|
33
|
+
|
|
34
|
+
- Run on Linux or macOS. Windows is rejected.
|
|
35
|
+
- Install Node.js 24 or newer.
|
|
36
|
+
- Install repository-pinned Bun version from root `package.json`.
|
|
37
|
+
- Install `git` and GitHub CLI `gh`.
|
|
38
|
+
- Have push permission for `origin/main` and release creation permission on GitHub.
|
|
39
|
+
- For npm or combined release, have publish permission for `@acrasie/dev-flow`.
|
|
40
|
+
- Keep `main` clean, with no staged, unstaged, or untracked files.
|
|
41
|
+
- Ensure local `main` can fast-forward to `origin/main`; release program never rebases,
|
|
42
|
+
resets, or creates a merge commit.
|
|
43
|
+
|
|
44
|
+
Authenticate without placing credentials in repository files:
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
gh auth status
|
|
48
|
+
cd plugins/codex-dev-flow
|
|
49
|
+
bun pm whoami
|
|
50
|
+
cd ../..
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
`bun pm whoami` is unnecessary for a plugin-only release. OTP, when required, remains
|
|
54
|
+
inside interactive `bun publish`.
|
|
55
|
+
|
|
56
|
+
## Recommended procedure
|
|
57
|
+
|
|
58
|
+
### 1. Prepare local `main`
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
git switch main
|
|
62
|
+
git pull --ff-only
|
|
63
|
+
git status --short
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
`git status --short` must produce no output. Do not stash unrelated work inside the
|
|
67
|
+
release procedure; finish or move it before starting.
|
|
68
|
+
|
|
69
|
+
### 2. Run read-only preview
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
bun run release
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Choose intended target, then **Preview only**. Preview still requires GitHub and, when
|
|
76
|
+
applicable, npm authentication plus network access. It checks version availability and
|
|
77
|
+
runs validation, but restores generated bundle bytes and changes no remote state.
|
|
78
|
+
|
|
79
|
+
Confirm preview shows expected:
|
|
80
|
+
|
|
81
|
+
- target;
|
|
82
|
+
- npm and plugin versions;
|
|
83
|
+
- tag and release identity;
|
|
84
|
+
- changed-file allowlist;
|
|
85
|
+
- publication order.
|
|
86
|
+
|
|
87
|
+
Preview requires local `main` to equal `origin/main`. If it refuses, reconcile with
|
|
88
|
+
`git pull --ff-only`, inspect result, then rerun preview.
|
|
89
|
+
|
|
90
|
+
### 3. Publish
|
|
91
|
+
|
|
92
|
+
Run same command again, choose same target, then **Prepare and publish**:
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
bun run release
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Before any publication, program performs:
|
|
99
|
+
|
|
100
|
+
1. Git branch, cleanliness, synchronization, authentication, and version-availability
|
|
101
|
+
checks;
|
|
102
|
+
2. frozen dependency installation;
|
|
103
|
+
3. typecheck and deterministic build;
|
|
104
|
+
4. main and release test suites;
|
|
105
|
+
5. plugin-manifest validation;
|
|
106
|
+
6. npm package inspection and publish dry-run when applicable;
|
|
107
|
+
7. generated-file allowlist validation;
|
|
108
|
+
8. release commit, annotated tag, and generated GitHub release-note preview.
|
|
109
|
+
|
|
110
|
+
Review final summary. Final publication confirmation defaults to **No**. Approval starts
|
|
111
|
+
publication in this order:
|
|
112
|
+
|
|
113
|
+
1. atomically push release commit and tag;
|
|
114
|
+
2. run `bun publish --access public` when target includes npm;
|
|
115
|
+
3. create GitHub Release from generated notes;
|
|
116
|
+
4. optionally refresh locally installed Codex plugin.
|
|
117
|
+
|
|
118
|
+
Publishing the GitHub Release asynchronously starts `Publish GitHub package mirror`
|
|
119
|
+
for combined `v<version>` and npm-only `npm-v<version>` tags. Plugin-only tags have no
|
|
120
|
+
npm artifact and do not start the mirror. The release program does not wait for or
|
|
121
|
+
include this asynchronous mirror in its partial-release state.
|
|
122
|
+
|
|
123
|
+
Start a new Codex thread after local plugin refresh so new plugin version loads.
|
|
124
|
+
|
|
125
|
+
## Verification
|
|
126
|
+
|
|
127
|
+
Use tag printed by release program:
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
git show --no-patch <tag>
|
|
131
|
+
gh release view <tag>
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
For npm or combined target, use npm version printed by release program:
|
|
135
|
+
|
|
136
|
+
```bash
|
|
137
|
+
npm view @acrasie/dev-flow@<version> version
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
After the mirror workflow succeeds, an authenticated GitHub Packages client can verify
|
|
141
|
+
the scoped alias:
|
|
142
|
+
|
|
143
|
+
```bash
|
|
144
|
+
npm view @acrazie/dev-flow@<version> version \
|
|
145
|
+
--registry=https://npm.pkg.github.com
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
Expected final state:
|
|
149
|
+
|
|
150
|
+
- local and remote `main` point to release commit;
|
|
151
|
+
- annotated tag points to same commit;
|
|
152
|
+
- GitHub Release exists for tag;
|
|
153
|
+
- selected npm version exists when applicable;
|
|
154
|
+
- matching `@acrazie/dev-flow` version exists after the asynchronous mirror;
|
|
155
|
+
- worktree is clean.
|
|
156
|
+
|
|
157
|
+
The release commit, tag, npm registry entry, and GitHub Release are durable audit
|
|
158
|
+
records. No separate local release-state file exists.
|
|
159
|
+
|
|
160
|
+
## Package rename
|
|
161
|
+
|
|
162
|
+
New releases target `@acrasie/dev-flow` on npmjs and `@acrazie/dev-flow` on GitHub Packages.
|
|
163
|
+
Historical `codex-dev-flow` releases remain separate; this workflow does not republish
|
|
164
|
+
or migrate them. Its `all` selector backfills only versions published as `@acrasie/dev-flow`.
|
|
165
|
+
The unscoped `dev-flow` publication was rejected by npm due to similarity to `devflow`.
|
|
166
|
+
The npm scope is `acrasie`, while the GitHub owner and mirror scope remain `acrazie`.
|
|
167
|
+
The CLI and Codex plugin identity remain `dev-flow`.
|
|
168
|
+
Before the first scoped release, verify npm name availability and publication rights
|
|
169
|
+
and set the new GitHub package visibility after its first publication. The retained
|
|
170
|
+
`codex-dev-flow` binary alias is included in the new package. No package is published
|
|
171
|
+
by the rename itself.
|
|
172
|
+
|
|
173
|
+
## Initial GitHub Packages publication and historical backfill
|
|
174
|
+
|
|
175
|
+
The canonical package is now the public, scoped `@acrasie/dev-flow` package on npmjs.
|
|
176
|
+
GitHub Packages contains a scoped mirror because its npm registry accepts only scoped
|
|
177
|
+
names. Mirror input always comes from the already-published npmjs tarball; the workflow
|
|
178
|
+
validates source name, version, and repository, then changes only the package name.
|
|
179
|
+
|
|
180
|
+
Because this repository is private, the first linked GitHub package initially inherits
|
|
181
|
+
private visibility. To create the approved public mirror without racing the complete
|
|
182
|
+
backfill:
|
|
183
|
+
|
|
184
|
+
1. Merge the mirror workflow to the default branch.
|
|
185
|
+
2. Obtain separate authorization for package publication, then publish only the oldest
|
|
186
|
+
version:
|
|
187
|
+
|
|
188
|
+
```bash
|
|
189
|
+
gh workflow run publish-github-package.yml -f versions=0.1.0
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
3. Wait for success. Open the new `@acrazie/dev-flow` package settings and change
|
|
193
|
+
visibility to **Public**. This UI operation is deliberately manual.
|
|
194
|
+
4. Obtain confirmation immediately before the visibility change: making a GitHub
|
|
195
|
+
package public cannot be reversed.
|
|
196
|
+
5. Backfill every stable npmjs version:
|
|
197
|
+
|
|
198
|
+
```bash
|
|
199
|
+
gh workflow run publish-github-package.yml -f versions=all
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
The `all` selector discovers stable npmjs versions, skips exact versions already present
|
|
203
|
+
in GitHub Packages, and publishes missing versions oldest first. A precise stable
|
|
204
|
+
version, `v<version>`, or `npm-v<version>` may also be dispatched for targeted recovery.
|
|
205
|
+
Publishing the public package exposes only content already present in the public npmjs
|
|
206
|
+
tarball; it does not make the private source repository readable.
|
|
207
|
+
|
|
208
|
+
## Cancellation and failure recovery
|
|
209
|
+
|
|
210
|
+
### Complete npm publication for an existing Release Please release
|
|
211
|
+
|
|
212
|
+
When Release Please has already merged a release PR and published its GitHub release,
|
|
213
|
+
but the corresponding npm version is missing, use:
|
|
214
|
+
|
|
215
|
+
```bash
|
|
216
|
+
bun run release --publish-existing dev-flow-v1.0.1
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
This mode verifies the published stable GitHub release, the local and remote tag commit,
|
|
220
|
+
and ancestry on `origin/main`. It exports that exact commit into a temporary directory,
|
|
221
|
+
requires its pinned Bun version, installs frozen workspace dependencies, runs release
|
|
222
|
+
validations and the full quality gate, and previews npm publication before confirmation.
|
|
223
|
+
The invoking checkout is not published, so it may contain the recovery-tool correction
|
|
224
|
+
on a dedicated branch. No version, plugin manifest, tag, or GitHub release is changed.
|
|
225
|
+
An already-published npm version is skipped. Only the missing npm publication is performed.
|
|
226
|
+
|
|
227
|
+
The existing GitHub release event is not emitted again. If a GitHub Packages mirror is
|
|
228
|
+
required, dispatch the repository mirror workflow for the exact npm version after npm
|
|
229
|
+
publication is verified; do not create another release.
|
|
230
|
+
|
|
231
|
+
### Before first successful push
|
|
232
|
+
|
|
233
|
+
Cancellation, `Ctrl+C`, or validation failure restores original release files and
|
|
234
|
+
removes only commit or tag objects created by program. Inspect:
|
|
235
|
+
|
|
236
|
+
```bash
|
|
237
|
+
git status --short
|
|
238
|
+
git log -1 --oneline
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
Fix cause, ensure clean `main`, then restart with `bun run release`.
|
|
242
|
+
|
|
243
|
+
### After push, npm publication, or GitHub publication begins
|
|
244
|
+
|
|
245
|
+
Do not delete remote tag, rewrite `main`, unpublish package, or create replacement
|
|
246
|
+
release manually. Published systems are not one atomic transaction and program never
|
|
247
|
+
attempts remote rollback.
|
|
248
|
+
|
|
249
|
+
Keep checkout on clean release commit and rerun:
|
|
250
|
+
|
|
251
|
+
```bash
|
|
252
|
+
bun run release
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
Program recognizes release commit, reconciles Git, npm, and GitHub state, displays
|
|
256
|
+
missing steps, then asks whether to resume. Already completed publication steps are
|
|
257
|
+
skipped. This also handles case where npm accepted package but local command lost its
|
|
258
|
+
response.
|
|
259
|
+
|
|
260
|
+
If all remote publication steps succeeded and only optional local plugin refresh
|
|
261
|
+
failed, do **not** rerun release solely for that refresh. Run it directly:
|
|
262
|
+
|
|
263
|
+
```bash
|
|
264
|
+
codex plugin marketplace upgrade acrazie
|
|
265
|
+
codex plugin add dev-flow@acrazie
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
Then start a new Codex thread.
|
|
269
|
+
|
|
270
|
+
If the asynchronous GitHub Packages mirror fails, do not create another npm or GitHub
|
|
271
|
+
Release. Rerun the failed Actions job or dispatch its exact stable version. Existing
|
|
272
|
+
destination versions are verified and skipped, so recovery is idempotent. Authentication,
|
|
273
|
+
network, malformed metadata, and unexpected registry responses block instead of being
|
|
274
|
+
treated as a missing version.
|
|
275
|
+
|
|
276
|
+
### Bad release discovered after completion
|
|
277
|
+
|
|
278
|
+
Prefer forward correction: fix defect and publish a new patch or plugin-cachebuster
|
|
279
|
+
release. Published npm versions are immutable release identities and must never be
|
|
280
|
+
reused.
|
|
281
|
+
|
|
282
|
+
## Forbidden shortcuts
|
|
283
|
+
|
|
284
|
+
- No validation bypass or force-publish path.
|
|
285
|
+
- No manual version edits followed by direct publish.
|
|
286
|
+
- No direct `npm publish` or `bun publish` of the canonical npmjs package outside the
|
|
287
|
+
release program. The repository-owned GitHub Packages mirror workflow is the only
|
|
288
|
+
scoped-alias exception.
|
|
289
|
+
- No manual tag or GitHub Release for a new release.
|
|
290
|
+
- No automatic or manual merge/rebase/reset inside release procedure.
|
|
291
|
+
- Never commit npm tokens, GitHub tokens, OTP values, or generated credential files.
|