@lab43/q 0.5.0 → 0.6.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/README.md +66 -41
- package/package.json +7 -4
- package/{.claude-plugin → q-extension/.claude-plugin}/plugin.json +1 -1
- package/q-extension/agents/adversarial-reviewer.md +98 -0
- package/q-extension/conventions/conventions.md +49 -0
- package/q-extension/conventions/documentation.md +79 -0
- package/q-extension/conventions/extensions.md +70 -0
- package/q-extension/conventions/issue-tracking.md +56 -0
- package/{conventions → q-extension/conventions}/plans.md +7 -3
- package/{conventions → q-extension/conventions}/principles.md +2 -0
- package/{conventions → q-extension/conventions}/pull-requests.md +1 -1
- package/q-extension/conventions/specs.md +31 -0
- package/q-extension/hooks/locked-version.mjs +169 -0
- package/q-extension/hooks/session-start.mjs +155 -0
- package/{hooks → q-extension/hooks}/session-start.sh +9 -8
- package/{references → q-extension/references}/agent-briefing.md +20 -9
- package/q-extension/references/enforce-declarations.md +16 -0
- package/q-extension/references/q-state.md +31 -0
- package/{references → q-extension/references}/run-contract.md +8 -5
- package/{skills → q-extension/skills}/address-feedback/SKILL.md +15 -11
- package/q-extension/skills/clean-worktrees/SKILL.md +66 -0
- package/{skills → q-extension/skills}/create-plan/SKILL.md +3 -3
- package/q-extension/skills/groom-docs/SKILL.md +65 -0
- package/{skills → q-extension/skills}/implement/SKILL.md +3 -3
- package/{skills → q-extension/skills}/implement-plan/SKILL.md +5 -5
- package/q-extension/skills/install/SKILL.md +136 -0
- package/q-extension/skills/reconcile/SKILL.md +110 -0
- package/{skills → q-extension/skills}/review/SKILL.md +2 -1
- package/{skills → q-extension/skills}/update-docs/SKILL.md +15 -10
- package/{skills → q-extension/skills}/upstream/SKILL.md +4 -2
- package/.claude-plugin/marketplace.json +0 -6
- package/agents/adversarial-reviewer.md +0 -62
- package/conventions/documentation.md +0 -102
- package/conventions/extensions.md +0 -52
- package/conventions/issue-tracking.md +0 -28
- package/hooks/session-start.mjs +0 -128
- package/references/enforce-pins.md +0 -16
- package/references/q-state.md +0 -31
- package/skills/groom-docs/SKILL.md +0 -62
- package/skills/install/SKILL.md +0 -150
- package/skills/sync/SKILL.md +0 -45
- package/skills/uninstall-extension/SKILL.md +0 -52
- package/skills/update/SKILL.md +0 -76
- /package/{conventions → q-extension/conventions}/writing.md +0 -0
- /package/{hooks → q-extension/hooks}/hooks.json +0 -0
- /package/{skills → q-extension/skills}/drive/SKILL.md +0 -0
- /package/{skills → q-extension/skills}/parallelize/SKILL.md +0 -0
- /package/{skills → q-extension/skills}/triage/SKILL.md +0 -0
package/hooks/session-start.mjs
DELETED
|
@@ -1,128 +0,0 @@
|
|
|
1
|
-
// Validate the project's q setup and, when it doesn't validate, tell the
|
|
2
|
-
// session to run /q:sync. Claude Code loads whatever plugin version is on
|
|
3
|
-
// disk, so drift surfaces only if something checks at session start — no
|
|
4
|
-
// other channel runs every session. The checks: the q copy this session
|
|
5
|
-
// loaded vs the project's pin, each watermarked package's pin vs its
|
|
6
|
-
// watermark vs its installed version, and the reverse direction — a
|
|
7
|
-
// q-extension devDependency with no watermark entry (installed by hand,
|
|
8
|
-
// never indexed).
|
|
9
|
-
//
|
|
10
|
-
// The remedy is uniform — /q:sync re-derives the specifics and routes each
|
|
11
|
-
// finding to its remedy — so every failure emits the same message and
|
|
12
|
-
// the script stops at the first one. Two silences are designed. A project
|
|
13
|
-
// that declares no @lab43/q devDependency is not a q project. A devDependency
|
|
14
|
-
// with no watermark entry and no readable manifest cannot be identified as an
|
|
15
|
-
// extension. Fail every other missing or unreadable input like any other
|
|
16
|
-
// invalid state.
|
|
17
|
-
|
|
18
|
-
import fs from "node:fs";
|
|
19
|
-
import path from "node:path";
|
|
20
|
-
import { fileURLToPath } from "node:url";
|
|
21
|
-
|
|
22
|
-
const proj = process.env.CLAUDE_PROJECT_DIR || ".";
|
|
23
|
-
const root =
|
|
24
|
-
process.env.CLAUDE_PLUGIN_ROOT ||
|
|
25
|
-
path.join(path.dirname(fileURLToPath(import.meta.url)), "..");
|
|
26
|
-
|
|
27
|
-
// Keep in sync with the message in session-start.sh (bash can't import it).
|
|
28
|
-
const MESSAGE =
|
|
29
|
-
"The q plugin could not validate this project's q setup, so its conventions and tooling may be stale or broken. Run /q:sync to repair it.";
|
|
30
|
-
|
|
31
|
-
const fail = () => {
|
|
32
|
-
console.log(
|
|
33
|
-
JSON.stringify({
|
|
34
|
-
hookSpecificOutput: {
|
|
35
|
-
hookEventName: "SessionStart",
|
|
36
|
-
additionalContext: MESSAGE,
|
|
37
|
-
},
|
|
38
|
-
}),
|
|
39
|
-
);
|
|
40
|
-
process.exit(0);
|
|
41
|
-
};
|
|
42
|
-
const read = (file) => {
|
|
43
|
-
try {
|
|
44
|
-
return fs.readFileSync(file, "utf8");
|
|
45
|
-
} catch {
|
|
46
|
-
return null;
|
|
47
|
-
}
|
|
48
|
-
};
|
|
49
|
-
const parse = (text) => {
|
|
50
|
-
try {
|
|
51
|
-
return JSON.parse(text);
|
|
52
|
-
} catch {
|
|
53
|
-
return undefined;
|
|
54
|
-
}
|
|
55
|
-
};
|
|
56
|
-
const installedVersion = (dir) => parse(read(path.join(dir, "package.json")) ?? "")?.version;
|
|
57
|
-
|
|
58
|
-
// Pins: one exact devDependency for q and one per extension, in the project's
|
|
59
|
-
// package.json. A missing manifest means not a q project. One that exists but
|
|
60
|
-
// can't be read or parsed fails like any other invalid state.
|
|
61
|
-
let pkgText;
|
|
62
|
-
try {
|
|
63
|
-
pkgText = fs.readFileSync(path.join(proj, "package.json"), "utf8");
|
|
64
|
-
} catch (e) {
|
|
65
|
-
if (e.code === "ENOENT" || e.code === "ENOTDIR") process.exit(0);
|
|
66
|
-
fail();
|
|
67
|
-
}
|
|
68
|
-
const pkg = parse(pkgText);
|
|
69
|
-
if (pkg === undefined) fail();
|
|
70
|
-
|
|
71
|
-
const devDeps =
|
|
72
|
-
pkg && typeof pkg.devDependencies === "object" && pkg.devDependencies !== null
|
|
73
|
-
? pkg.devDependencies
|
|
74
|
-
: {};
|
|
75
|
-
|
|
76
|
-
// Declaring no @lab43/q devDependency is a designed silence. A pin that
|
|
77
|
-
// is declared but is not a version string is an invalid state like any other,
|
|
78
|
-
// and fails the way a malformed pin fails for every extension below.
|
|
79
|
-
if (!Object.hasOwn(devDeps, "@lab43/q")) process.exit(0);
|
|
80
|
-
const pinned = devDeps["@lab43/q"];
|
|
81
|
-
if (typeof pinned !== "string") fail();
|
|
82
|
-
|
|
83
|
-
// The q this session actually loaded. CLAUDE_PLUGIN_ROOT is the directory it
|
|
84
|
-
// was resolved from, and npm wrote that copy's version, so comparing it
|
|
85
|
-
// against the pin also catches a session running some other checkout's q.
|
|
86
|
-
const loaded = installedVersion(root);
|
|
87
|
-
if (typeof loaded !== "string") fail();
|
|
88
|
-
if (loaded !== pinned) fail();
|
|
89
|
-
|
|
90
|
-
// Watermarks. A pinned project with no state file is unrecorded drift.
|
|
91
|
-
const stateText = read(path.join(proj, ".claude/q-state.json"));
|
|
92
|
-
if (stateText === null) fail();
|
|
93
|
-
|
|
94
|
-
const state = parse(stateText);
|
|
95
|
-
if (state === undefined || typeof state !== "object" || state === null) fail();
|
|
96
|
-
|
|
97
|
-
const recon = state.reconciledAgainst ?? {};
|
|
98
|
-
if (typeof recon !== "object" || recon === null || Array.isArray(recon)) fail();
|
|
99
|
-
// q is the framework rather than an extension, so it is checked by name: a
|
|
100
|
-
// pinned project with no entry for it is caught here. The reverse-direction
|
|
101
|
-
// loop below cannot stand in. It identifies extensions by a keyword read from
|
|
102
|
-
// node_modules, which q does not carry and which an uninstalled or stale copy
|
|
103
|
-
// doesn't supply either.
|
|
104
|
-
if (!Object.hasOwn(recon, "@lab43/q")) fail();
|
|
105
|
-
|
|
106
|
-
for (const [ext, mark] of Object.entries(recon)) {
|
|
107
|
-
if (typeof mark !== "string") fail();
|
|
108
|
-
const pin = Object.hasOwn(devDeps, ext) ? devDeps[ext] : undefined;
|
|
109
|
-
if (typeof pin !== "string") fail(); // removed out of band, never reconciled
|
|
110
|
-
if (pin !== mark) fail();
|
|
111
|
-
|
|
112
|
-
const inst = installedVersion(path.join(proj, "node_modules", ext));
|
|
113
|
-
if (typeof inst !== "string") fail();
|
|
114
|
-
if (inst !== pin) fail();
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
// Reverse direction: a devDependency whose installed manifest carries the
|
|
118
|
-
// q-extension keyword but that has no watermark entry was installed by hand
|
|
119
|
-
// and never indexed. The keyword is readable only from the package's own
|
|
120
|
-
// manifest under node_modules. A devDependency whose manifest is absent or
|
|
121
|
-
// unparseable is therefore skipped here rather than reported.
|
|
122
|
-
for (const dep of Object.keys(devDeps)) {
|
|
123
|
-
if (Object.hasOwn(recon, dep)) continue;
|
|
124
|
-
const keywords = parse(
|
|
125
|
-
read(path.join(proj, "node_modules", dep, "package.json")) ?? "",
|
|
126
|
-
)?.keywords;
|
|
127
|
-
if (Array.isArray(keywords) && keywords.includes("q-extension")) fail();
|
|
128
|
-
}
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
# Enforce Pins
|
|
2
|
-
|
|
3
|
-
The machine-local enforcement procedure: make this machine match the project's declared pins. Enforce without asking — pins are the project's recorded decisions, and this merely applies them.
|
|
4
|
-
|
|
5
|
-
1. Check that `node` and `npm` resolve. When either is missing, Node.js is not installed — report that fix. Nothing below runs without it.
|
|
6
|
-
2. When `node_modules/` is missing a pinned package, or holds a version other than its pin, run the project's package-manager install — `npm install`, or the pnpm or yarn equivalent its lockfile indicates. That install is the whole update mechanism: a session reads q from `node_modules/@lab43/q` as it stands, so nothing else has to reach it.
|
|
7
|
-
3. Register the project's marketplace: `claude plugin marketplace add --scope local ./`. The manifest at the project root supplies the name, so nothing has to read or pass one. Skip this step when the project has no `.claude-plugin/marketplace.json`. The add fails outright against a directory holding no manifest. A project without one has not been scaffolded yet. Otherwise run it unconditionally, since the add changes nothing when the registry already points here. Local scope records the registration in the project's own `.claude/settings.local.json`, which does not keep it private.
|
|
8
|
-
|
|
9
|
-
Three situations need it:
|
|
10
|
-
|
|
11
|
-
- A fresh clone has never registered the marketplace.
|
|
12
|
-
- A declined trust prompt left it unregistered.
|
|
13
|
-
- Another checkout of this repo has repointed the project's name at itself. The machine-global registry holds one entry per marketplace name. The add repoints it back, because an entry whose name matches but whose path differs is updated to the new path.
|
|
14
|
-
4. After any change above, run `/reload-plugins`.
|
|
15
|
-
|
|
16
|
-
Name any tracked file the enforcement rewrote (a lockfile). That change stays in the tree as the user's.
|
package/references/q-state.md
DELETED
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
# The q State File
|
|
2
|
-
|
|
3
|
-
Format and writer rules for `.claude/q-state.json`, the consumer-side record of the versions a project was last reconciled against. The skills that read or write the file follow this doc; nothing else edits it.
|
|
4
|
-
|
|
5
|
-
## What the file is
|
|
6
|
-
|
|
7
|
-
The file holds machine-written version watermarks — never rules, never doc enumerations. Pins stay authoritative where they are: the project's `package.json`, one exact devDependency for q and one per installed extension. Reconciliation is the work of folding a version change into the project — holding its docs against an extension release's changed rules, or its scaffolded surfaces against a new q version; `/q:update` performs it. A watermark records the version its pin was last reconciled against, so an out-of-band pin move — a hand-run npm install, a teammate's merge, a Dependabot bump — is detectable as pin ≠ watermark. The skills and the session-start hook compare its versions against the pins; nothing consults it for how to behave.
|
|
8
|
-
|
|
9
|
-
## Format
|
|
10
|
-
|
|
11
|
-
The file lives at `.claude/q-state.json`, committed. JSON, one key per line, so a watermark move reads as a one-line diff:
|
|
12
|
-
|
|
13
|
-
```json
|
|
14
|
-
{
|
|
15
|
-
"note": "Machine state written by q's skills. Never edit by hand; /q:sync reports drift.",
|
|
16
|
-
"reconciledAgainst": {
|
|
17
|
-
"@lab43/q": "0.3.0"
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
```
|
|
21
|
-
|
|
22
|
-
`reconciledAgainst` holds one entry for `@lab43/q` and one per installed extension: the version the project was last reconciled against. q's entry has the same shape as the rest, carrying no privilege and no separate field.
|
|
23
|
-
|
|
24
|
-
## Writer rules
|
|
25
|
-
|
|
26
|
-
- `/q:install` fills in missing watermarks and never touches present ones — a stale entry is reconciliation's to move. Bootstrapping q, it writes the `@lab43/q` entry; installing an extension, it writes that extension's. Each value is the version just installed, which has no reconciliation debt.
|
|
27
|
-
- `/q:update` writes the affected watermark after each reconciliation, whether the run moved a pin or caught up an out-of-band move.
|
|
28
|
-
- `/q:uninstall-extension` drops the extension's entry as part of reconciling its removal.
|
|
29
|
-
- `/q:sync` reads and compares; it never writes. Watermarks certify reconciliation, and sync never reconciles.
|
|
30
|
-
|
|
31
|
-
An absent file means no record — create it on the first watermark write. The file never ships in an extension: it lives in `.claude/`, outside the `files` whitelist a tarball is built from (source: @lab43/q conventions/extensions.md).
|
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: groom-docs
|
|
3
|
-
description: Audit the project's whole documentation surface against the documentation policy and consolidate what has drifted. Approved edits ship as a PR. Use when docs feel inflated or stale, after a stretch of merged changes, or on a docs-cleanup request.
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Groom Docs
|
|
7
|
-
|
|
8
|
-
**Read the rubric first, and follow it over any instinct:**
|
|
9
|
-
|
|
10
|
-
1. q's documentation policy (see: @lab43/q conventions/documentation.md) and its writing rules (see: @lab43/q conventions/writing.md), plus any installed extension's doc whose topic governs documentation. An extension's rule beats q's where the two disagree (source: @lab43/q conventions/documentation.md, Three tiers of conventions).
|
|
11
|
-
2. The project's recorded rulings and deviations: `docs/conventions/documentation.md` plus any "(overrides: …)" markers across `docs/conventions/` — grep for them. These win over both.
|
|
12
|
-
|
|
13
|
-
If the project has no `docs/conventions/` directory, or `node_modules/@lab43/q/` is absent (a fresh clone may just need `npm install`), stop and suggest the fix — without both there is no surface or rubric to groom against.
|
|
14
|
-
|
|
15
|
-
Follow the run contract — `${CLAUDE_PLUGIN_ROOT}/references/run-contract.md`.
|
|
16
|
-
|
|
17
|
-
## Step 1: Inventory
|
|
18
|
-
|
|
19
|
-
Build the grooming surface, taking each item only if it exists in this project:
|
|
20
|
-
|
|
21
|
-
- `docs/conventions/*.md`, `README.md`, `CLAUDE.md` (the agent briefing) — full checks.
|
|
22
|
-
- The `conventions/` of any extension this repo authors — a working-tree `package.json` carrying the `q-extension` keyword — full checks, like the project's own conventions (source: @lab43/q conventions/extensions.md). That manifest's `description` joins the surface with them (source: @lab43/q conventions/extensions.md, Description). Anything else the project's own `documentation.md` puts on the surface joins it, under rubric item 2.
|
|
23
|
-
- `docs/guides/*.md` — **guide mode**, per the policy's Taxonomy rules.
|
|
24
|
-
- `docs/plans/*.md` — **status check only**, per the policy's `docs/plans/` taxonomy rule.
|
|
25
|
-
|
|
26
|
-
Project-local `.claude/` skills and agents are outside the surface — q doesn't govern them. Everything installed under `node_modules/` is read-only, q's conventions and every extension's alike — never groomed.
|
|
27
|
-
|
|
28
|
-
## Step 2: Fan out verification (read-only subagents)
|
|
29
|
-
|
|
30
|
-
Launch read-only subagents in parallel — one per check below, except accuracy, which fans out per doc cluster; the duplication and consistency sweeps each hold the whole surface, since cross-file checks can't be sharded. Each reads the rubric first and returns findings with `file:line` citations:
|
|
31
|
-
|
|
32
|
-
1. **Accuracy, per doc cluster** (conventions docs grouped by area; guides clustered separately, in guide mode): every checkable claim — file paths, symbol names, behavior descriptions, commands — verified against current source. Exemplar references get a deeper check: the file exists and still exhibits the rules its doc attaches to it. An authored extension's `description` is checked with its docs: it must still name the territory they govern.
|
|
33
|
-
2. **Duplication sweep**, cross-surface: facts stated in more than one place. For each, name the home — implied by the taxonomy, or assigned by a recorded ruling; where the call is genuinely contestable, flag it for the user, whose decision becomes a new ruling. The sweep also runs **cross-tier**, comparing project docs against q's conventions and every installed extension's: a project statement matching one of their rules in substance is duplication to prune; one differing from such a rule without an overrides marker naming it is drift or an unrecorded deviation — escalate to the user; a marked override whose target updated to agree or disappeared is spent — propose deleting it (source: @lab43/q conventions/documentation.md, Three tiers of conventions). Those docs are read-only: an extension's stale override of a q rule, or two extensions in conflict, can't be edited here — escalate; the remedy is a project ruling or the extension author's.
|
|
34
|
-
3. **Dead references**: every file, symbol, helper, script, and skill named anywhere on the surface exists. Greps must exclude build artifacts (`dist/`, `node_modules/`, and the like) — stale generated files resurrect deleted symbols.
|
|
35
|
-
4. **Consistency**: the agent briefing matches the briefing template (see: `${CLAUDE_PLUGIN_ROOT}/references/agent-briefing.md`); any README skills/conventions table matches its home (skill tables drift-check against `SKILL.md` frontmatter descriptions); cross-references between docs resolve. One concept goes by one name across the surface. Report a synonym against the name its home doc establishes (source: @lab43/q conventions/writing.md, One name per concept).
|
|
36
|
-
5. **Organization**: each doc's structure — topic scope, intro, section placement, and splits or merges across docs — conforms to the policy. Findings here become reorganization proposals.
|
|
37
|
-
6. **Plan statuses** (if `docs/plans/` exists): every plan has valid `status` frontmatter (source: @lab43/q conventions/plans.md, Frontmatter); list every `pending` plan with its age (last git commit date).
|
|
38
|
-
|
|
39
|
-
## Step 3: Consolidate with the user
|
|
40
|
-
|
|
41
|
-
Merge the findings into proposed edits, each stating its remedy and citing its finding — in conversational mode (see: ${CLAUDE_PLUGIN_ROOT}/references/run-contract.md, Collaboration modes).
|
|
42
|
-
|
|
43
|
-
- Apply autonomously: wording-level fixes, replacing a single restated sentence or bullet with a cross-reference to its home, and dead-reference corrections.
|
|
44
|
-
- **Everything else goes to the user** (AskUserQuestion) — including larger deletions and rewrites, any reorganization, any `pending` plan proposed as `abandoned` (only the user flips a status), and any fact that couldn't be verified either way.
|
|
45
|
-
- When a user ruling sets a precedent, record it in the same run: project-specific rulings go in the project's `docs/conventions/documentation.md`; a ruling that would apply to every q project is recorded as a project deviation and flagged in the report as a candidate to upstream (via `/q:upstream`).
|
|
46
|
-
- In the same batch, ask which review mode — local or ship — the delivery runs under (see: ${CLAUDE_PLUGIN_ROOT}/references/run-contract.md, Review modes).
|
|
47
|
-
|
|
48
|
-
## Step 4: Apply
|
|
49
|
-
|
|
50
|
-
1. Pick the delivery branch (see: ${CLAUDE_PLUGIN_ROOT}/references/run-contract.md, The delivery branch).
|
|
51
|
-
2. Step 3's rulings are the agreement — apply the approved edits autonomously. In ship mode, commit them.
|
|
52
|
-
3. Re-run the dead-reference and consistency checks over the result — approved edits can break each other's targets.
|
|
53
|
-
|
|
54
|
-
## Step 5: Adversarial review
|
|
55
|
-
|
|
56
|
-
Validate the applied edits (see: ${CLAUDE_PLUGIN_ROOT}/references/run-contract.md, Validation) with the **correctness** and **conventions** lenses.
|
|
57
|
-
|
|
58
|
-
## Step 6: Open the PR
|
|
59
|
-
|
|
60
|
-
1. **The local gate**: run it over the uncommitted edits (see: ${CLAUDE_PLUGIN_ROOT}/references/run-contract.md, The local gate).
|
|
61
|
-
2. **Open the PR**: push the branch and open the PR per the PR-authoring rules (see: @lab43/q conventions/pull-requests.md).
|
|
62
|
-
3. Close the session by reporting: what changed per doc, what was deduped and into where, every autonomous fix, every user decision and its outcome, any upstream-to-q candidates, and anything that couldn't be verified — named explicitly, never silently dropped.
|
package/skills/install/SKILL.md
DELETED
|
@@ -1,150 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: install
|
|
3
|
-
description: Install q into a project, or add an extension to one. Invoke bare to set q up; name an extension to install it. Idempotent, safe to re-run on a partially set-up project. The changes ship as a PR.
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Install
|
|
7
|
-
|
|
8
|
-
The scaffold is deliberately near-empty — this skill creates the structure the other skills expect, not content.
|
|
9
|
-
|
|
10
|
-
Follow the run contract — `${CLAUDE_PLUGIN_ROOT}/references/run-contract.md`. The invocation picks the path: a bare run bootstraps q (Steps 3–4); an extension run adds the extension install (Step 5) after them. A run naming `q` or `@lab43/q` is a bare run, because q is the framework rather than an extension (source: @lab43/q conventions/extensions.md, Identity). Scaffolding brings q's surfaces to the forms in Step 3: create what is absent, correct what has drifted. Any run therefore completes a partially set-up project. Never rewrite what the user owns — each item below marks its own boundary.
|
|
11
|
-
|
|
12
|
-
## Step 1: Survey current state
|
|
13
|
-
|
|
14
|
-
Hold the project against each of Step 3's scaffold items, noting what is absent and what has drifted from its form. Alongside, check:
|
|
15
|
-
|
|
16
|
-
- Convention-like docs living elsewhere (a `docs/` scan for rule-carrying files, a briefing bloated with per-task rules) — candidates for migration
|
|
17
|
-
- Whether an earlier run's scaffold sits uncommitted in the working tree
|
|
18
|
-
- On an extension run: whether the named extension is already pinned, installed, indexed, and watermarked
|
|
19
|
-
- The GitHub CLI: `gh auth status`, and that the repo's `origin` is GitHub-hosted (`gh repo view` succeeds). q's workflow skills require both. If either fails, tell the user the fix (install via <https://cli.github.com> and authenticate with `gh auth login`; `gh repo view` failing with an authenticated CLI means `origin` is not GitHub-hosted) and continue — the scaffold still lands.
|
|
20
|
-
|
|
21
|
-
## Step 2: Settle delivery
|
|
22
|
-
|
|
23
|
-
Skip this step in any of these cases:
|
|
24
|
-
|
|
25
|
-
- A bare run where Step 1 found nothing missing or drifted beyond an unpopulated `node_modules/`, no migration candidates, and no scaffold sitting uncommitted from an earlier run — there is nothing to change or deliver. Enforce the pins per `${CLAUDE_PLUGIN_ROOT}/references/enforce-pins.md` (machine state, not a repo change), then stop with the closing report (Step 8).
|
|
26
|
-
- An extension run where the named extension is already pinned, installed, indexed, and watermarked, Step 1 found nothing missing from the q scaffold, and no install sits uncommitted from an earlier run — report that and stop.
|
|
27
|
-
- Step 1's GitHub CLI check failed — there is no delivery to settle.
|
|
28
|
-
- Another skill's run invoked this one — the changes join that run's change.
|
|
29
|
-
|
|
30
|
-
Otherwise, ask which review mode — local or ship — the run delivers under (see: ${CLAUDE_PLUGIN_ROOT}/references/run-contract.md, Review modes). Then pick the delivery branch (see: ${CLAUDE_PLUGIN_ROOT}/references/run-contract.md, The delivery branch); on an extension run the connected-work case is the extension arriving with the dependency that ships it.
|
|
31
|
-
|
|
32
|
-
## Step 3: Scaffold
|
|
33
|
-
|
|
34
|
-
The invocation is the agreement — scaffold autonomously; on a fully set-up, undrifted project the whole step is a no-op:
|
|
35
|
-
|
|
36
|
-
1. **The two mirror docs** — create each if missing, with exactly this content; if present, leave it untouched. A seeded doc is the user's from creation, intro and entries alike — never corrected on a re-run. `docs/conventions/principles.md`:
|
|
37
|
-
|
|
38
|
-
```markdown
|
|
39
|
-
# Principles
|
|
40
|
-
|
|
41
|
-
This project's cross-cutting rules, including any deviations from q's (see: @lab43/q conventions/principles.md).
|
|
42
|
-
```
|
|
43
|
-
|
|
44
|
-
`docs/conventions/documentation.md`:
|
|
45
|
-
|
|
46
|
-
```markdown
|
|
47
|
-
# Documentation
|
|
48
|
-
|
|
49
|
-
This project's documentation rulings and deviations (see: @lab43/q conventions/documentation.md, Three tiers of conventions).
|
|
50
|
-
```
|
|
51
|
-
|
|
52
|
-
No other conventions doc is scaffolded — `/q:update-docs` creates each topical doc when its first entry is recorded.
|
|
53
|
-
2. **The q dependency** — q installs as one pinned npm package, carrying its conventions and its plugin together:
|
|
54
|
-
- Ensure a root `package.json` — create `{"private": true}` if the project has none.
|
|
55
|
-
- If `@lab43/q` is not yet in `devDependencies`: `npm install --save-dev --save-exact --ignore-scripts @lab43/q` (via the project's package manager when it isn't npm). If it is, leave the recorded pin alone.
|
|
56
|
-
|
|
57
|
-
That pin is the only place a q version appears. Moving it and installing is the whole of an update.
|
|
58
|
-
3. **Agent briefing** — ensure the project's briefing carries the section the briefing template defines, adding what is missing and correcting drift, per that file's rules (see: `${CLAUDE_PLUGIN_ROOT}/references/agent-briefing.md`).
|
|
59
|
-
4. **Plugin declaration** — the project publishes its own marketplace, sourcing the q it already has in `node_modules`. Two files hold it, created if missing.
|
|
60
|
-
|
|
61
|
-
`.claude-plugin/marketplace.json` at the project root is the conventional path for a project publishing a marketplace, so the file is shared territory rather than q's. Merge the `q` entry into an existing manifest: leave every other `plugins` entry and the recorded name untouched. Write the whole file only when creating it.
|
|
62
|
-
|
|
63
|
-
The marketplace needs a name no other project on the machine will use. The registry the CLI resolves against holds one entry per marketplace name, machine-wide (source: ${CLAUDE_PLUGIN_ROOT}/references/enforce-pins.md). Two projects sharing a name means the second one loads a q version it never pinned.
|
|
64
|
-
|
|
65
|
-
Name it `q-pin-<owner>-<repo>-<suffix>` — for example, `q-pin-acme-storefront-4f2ab9`. Owner and repo keep the name legible in that registry. The suffix is six random hex characters. It is what keeps the name unique. Read owner and repo from the repo's GitHub origin with `gh repo view --json nameWithOwner`. Use the project directory's name in their place when that command yields nothing. Lowercase the whole name and replace every character outside `a-z0-9-` with a hyphen.
|
|
66
|
-
|
|
67
|
-
Generate that name only when creating the file. A project that already records one keeps it, whatever it is. Other clones have already registered that name locally. Regenerating it strands them. Keeping a name the project chose gives up guaranteed uniqueness, which is the better trade against renaming a marketplace the project owns.
|
|
68
|
-
|
|
69
|
-
```json
|
|
70
|
-
{
|
|
71
|
-
"name": "<marketplace>",
|
|
72
|
-
"owner": { "name": "this project" },
|
|
73
|
-
"metadata": { "description": "Pins this project's q version. The name must stay unique to this project. Sharing another project's name makes this one resolve to that project's pinned q." },
|
|
74
|
-
"plugins": [
|
|
75
|
-
{
|
|
76
|
-
"name": "q",
|
|
77
|
-
"source": "./node_modules/@lab43/q",
|
|
78
|
-
"description": "The q workflow plugin, pinned for this project."
|
|
79
|
-
}
|
|
80
|
-
]
|
|
81
|
-
}
|
|
82
|
-
```
|
|
83
|
-
|
|
84
|
-
Then merge into `.claude/settings.json`, leaving other keys untouched. Key both entries to whatever name the manifest records, and correct either if it has drifted from it:
|
|
85
|
-
|
|
86
|
-
```json
|
|
87
|
-
{
|
|
88
|
-
"extraKnownMarketplaces": {
|
|
89
|
-
"<marketplace>": { "source": { "source": "directory", "path": "./" } }
|
|
90
|
-
},
|
|
91
|
-
"enabledPlugins": { "q@<marketplace>": true, "q@q": false }
|
|
92
|
-
}
|
|
93
|
-
```
|
|
94
|
-
|
|
95
|
-
Write the path by hand, relative to the project root — `claude plugin marketplace add` records an absolute path, which breaks every other checkout of the repo.
|
|
96
|
-
|
|
97
|
-
`"q@q": false` retires the bootstrap marketplace the package ships. Its name is the same in every copy of q, so leaving it enabled means loading whichever copy registered that name last. Disabling it is what makes the project's own pin authoritative.
|
|
98
|
-
5. **Enforce the declarations** — make this machine match the pins just declared, per `${CLAUDE_PLUGIN_ROOT}/references/enforce-pins.md`.
|
|
99
|
-
6. **State file** — write `.claude/q-state.json` per `${CLAUDE_PLUGIN_ROOT}/references/q-state.md`: a `reconciledAgainst` entry for `@lab43/q`, from the version in `node_modules/@lab43/q/package.json`. Write only absent watermarks — a present entry, stale or not, is reconciliation's to move (source: ${CLAUDE_PLUGIN_ROOT}/references/q-state.md).
|
|
100
|
-
7. **Ignore rules** — ensure `.gitignore` covers `node_modules/`, `.claude/settings.local.json`, and `.claude/worktrees/`, and that the committed scaffold files are not ignored: run `git check-ignore` on `.claude/settings.json`, `.claude-plugin/`, and `.claude/q-state.json`, fixing the rules until it reports nothing. A bare negation under an ignored `.claude/` does nothing — the directory rule itself must become `.claude/*` plus the negations. Leave every unrelated ignore rule alone.
|
|
101
|
-
8. **README setup instructions** — ensure the README tells a collaborator using Claude Code how to bring up a fresh clone: install the project's dependencies, which is what delivers q. Fold that into the project's existing setup instructions or setup script — a dependency install the project already documents (`npm install`, a pnpm or yarn equivalent, a bootstrap script) covers it, and a README already carrying the information needs nothing. Present the q steps as applying to collaborators who use Claude Code, never as requirements for working in the repo. Create a minimal README with just these instructions when the project has none.
|
|
102
|
-
9. Scaffold nothing else. An empty taxonomy directory arrives when its first document does.
|
|
103
|
-
|
|
104
|
-
## Step 4: Migration proposals (existing projects only)
|
|
105
|
-
|
|
106
|
-
On an extension run, skip this step unless Step 3 just bootstrapped a previously q-less project. If Step 1 found convention-like content outside `docs/conventions/` — rules in the briefing that apply only to particular kinds of work, rule-carrying docs elsewhere in `docs/` — read `node_modules/@lab43/q/conventions/documentation.md` and propose moving the content per its taxonomy, via AskUserQuestion — in conversational mode (see: ${CLAUDE_PLUGIN_ROOT}/references/run-contract.md, Collaboration modes). Apply approved moves, leaving a one-line pointer behind where the policy calls for one.
|
|
107
|
-
|
|
108
|
-
## Step 5: Install the extension (extension runs only)
|
|
109
|
-
|
|
110
|
-
The named extension is the agreement — install it autonomously. If it is not yet in `devDependencies` (via the project's package manager when it isn't npm):
|
|
111
|
-
|
|
112
|
-
```sh
|
|
113
|
-
npm install --save-dev --save-exact --ignore-scripts <extension>
|
|
114
|
-
```
|
|
115
|
-
|
|
116
|
-
If it is, leave the recorded pin alone and make this machine match through `${CLAUDE_PLUGIN_ROOT}/references/enforce-pins.md`.
|
|
117
|
-
|
|
118
|
-
Verify what arrived is an extension: `node_modules/<extension>/package.json` carries the `q-extension` keyword, and the package root holds a `conventions/` directory, a `.claude-plugin/` directory, or both (source: @lab43/q conventions/extensions.md). If not, `npm uninstall` it and report — never index it. When the run changed nothing else, switch back to the prior branch and delete any branch this run created; when Step 3 bootstrapped the project, keep that scaffold, carry on to Step 6, and report the extension failure in the close.
|
|
119
|
-
|
|
120
|
-
An extension shipping `conventions/` gets its own group in the briefing's docs index, headed by the package name and the extension's description (see: `${CLAUDE_PLUGIN_ROOT}/references/agent-briefing.md`). Under that heading goes one line per doc the index doesn't already carry: package name plus path from the package root (see: @lab43/q conventions/documentation.md, Package doc paths), blurb restating the doc's intro (source: @lab43/q conventions/documentation.md, Taxonomy). One shipping no `conventions/` is watermarked without being indexed, having no docs to index (source: @lab43/q conventions/extensions.md, Layout).
|
|
121
|
-
|
|
122
|
-
When the extension has no `reconciledAgainst` entry, write one from the version in `node_modules/<extension>/package.json` (see: ${CLAUDE_PLUGIN_ROOT}/references/q-state.md) — an extension Step 1 found pinned and installed by hand included. Never overwrite a present entry, stale or not — it is reconciliation's to move (source: ${CLAUDE_PLUGIN_ROOT}/references/q-state.md).
|
|
123
|
-
|
|
124
|
-
Installing an extension's plugin is not yet part of this step: q scaffolds only its own marketplace entry.
|
|
125
|
-
|
|
126
|
-
## Step 6: Adversarial review
|
|
127
|
-
|
|
128
|
-
Invoked from another skill's run, stop here — the changes are that run's to validate and deliver. When the run changed nothing tracked — every proposal declined on an otherwise complete project — and no earlier run's scaffold awaits delivery: switch back to the prior branch, delete any branch this run created, and report that and stop. When Step 1's GitHub CLI check failed, stop here with the closing report (Step 8), adding:
|
|
129
|
-
|
|
130
|
-
- That the changes stay uncommitted — restate the `gh` fix.
|
|
131
|
-
- That a re-run delivers them once `gh` is in place.
|
|
132
|
-
|
|
133
|
-
Otherwise: in ship mode, commit first. In both modes, validate the changes (see: ${CLAUDE_PLUGIN_ROOT}/references/run-contract.md, Validation) with the **correctness** and **conventions** lenses.
|
|
134
|
-
|
|
135
|
-
## Step 7: Open the PR
|
|
136
|
-
|
|
137
|
-
1. **The local gate**: run it over the uncommitted changes (see: ${CLAUDE_PLUGIN_ROOT}/references/run-contract.md, The local gate).
|
|
138
|
-
2. **Open the PR**: push the branch and open the PR per the PR-authoring rules (see: @lab43/q conventions/pull-requests.md).
|
|
139
|
-
|
|
140
|
-
## Step 8: Report
|
|
141
|
-
|
|
142
|
-
Close the session by reporting:
|
|
143
|
-
|
|
144
|
-
- What was created.
|
|
145
|
-
- What already existed and was left untouched.
|
|
146
|
-
- What was proposed, and the user's decisions.
|
|
147
|
-
- On an extension run:
|
|
148
|
-
- The extension and version installed, and the index lines added.
|
|
149
|
-
- Any overrides markers its docs carry against q's rules. These are deviations the project now lives under. The project's own rulings still win on conflict.
|
|
150
|
-
- Its q declaration — its `@lab43/q` devDependency (source: @lab43/q conventions/extensions.md) — held against the project's own pin. An extension written against a newer q than the project runs is the signal to suggest `/q:update`. One written against an older q, or carrying no declaration, is noted as-is — no update closes it.
|
package/skills/sync/SKILL.md
DELETED
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: sync
|
|
3
|
-
description: Set up or repair this machine for a q-using project, handing off to /q:install, /q:update, or /q:uninstall-extension when the project's records don't match its pins. Use on a fresh clone or a new machine, or whenever the session-start check says the project's q setup did not validate. Never moves pins and never reconciles docs; the only tracked file it may touch is a lockfile a dependency install rewrites.
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Sync
|
|
7
|
-
|
|
8
|
-
Follow the run contract — `${CLAUDE_PLUGIN_ROOT}/references/run-contract.md`. The invocation is the agreement — proceed autonomously throughout. Sync delivers no repo change, so there is no branch, review mode, or PR.
|
|
9
|
-
|
|
10
|
-
## Step 1: Enforce the pins
|
|
11
|
-
|
|
12
|
-
Two states have nothing to sync yet. Propose `/q:install` and stop for either:
|
|
13
|
-
|
|
14
|
-
- The project declares no `@lab43/q` devDependency. It has no pins to enforce.
|
|
15
|
-
- It declares one but has no `.claude/q-state.json`. q's bytes arrived. The scaffold that records them has not run. This is the window between the bootstrap install and the first `/q:install`. It is the state the session-start check reports.
|
|
16
|
-
|
|
17
|
-
Otherwise enforce the pins per `${CLAUDE_PLUGIN_ROOT}/references/enforce-pins.md`.
|
|
18
|
-
|
|
19
|
-
## Step 2: Check the GitHub CLI
|
|
20
|
-
|
|
21
|
-
Run `gh auth status`, and `gh repo view` to confirm the repo's `origin` is GitHub-hosted — q's workflow skills require both. When either fails, report the fix: install via <https://cli.github.com> and authenticate with `gh auth login` for a missing or unauthenticated CLI; a failing `gh repo view` with an authenticated CLI means `origin` is not GitHub-hosted.
|
|
22
|
-
|
|
23
|
-
## Step 3: Compare pins against watermarks
|
|
24
|
-
|
|
25
|
-
Read `.claude/q-state.json` (see: ${CLAUDE_PLUGIN_ROOT}/references/q-state.md) and compare:
|
|
26
|
-
|
|
27
|
-
- the pin of `@lab43/q` and of each extension in `package.json` against its `reconciledAgainst` entry, in both directions — the extensions are the direct `devDependencies` whose own `package.json` carries the `q-extension` keyword (source: @lab43/q conventions/extensions.md)
|
|
28
|
-
|
|
29
|
-
Each finding routes to its remedy:
|
|
30
|
-
|
|
31
|
-
- A pin differing from its watermark (moved out of band, unreconciled) → `/q:update`, invoked bare once — a bare run covers every such finding.
|
|
32
|
-
- An entry for an extension no longer in `package.json` (removed out of band, the removal never reconciled) → `/q:uninstall-extension`, with the extension name, one run per extension.
|
|
33
|
-
- No record where one belongs → `/q:install` — bare for a missing state file or a missing `@lab43/q` entry; with the extension name for any other pinned extension that has no entry, one run per extension. These were installed or scaffolded by hand, never recorded.
|
|
34
|
-
|
|
35
|
-
Never write the state file — watermarks certify reconciliation, and sync never reconciles (source: ${CLAUDE_PLUGIN_ROOT}/references/q-state.md).
|
|
36
|
-
|
|
37
|
-
## Step 4: Report, then hand off
|
|
38
|
-
|
|
39
|
-
Report:
|
|
40
|
-
|
|
41
|
-
- What Step 1 enforced, and any tracked file it rewrote (a lockfile) left in the tree as the user's.
|
|
42
|
-
- The GitHub CLI result, with the fix when it failed.
|
|
43
|
-
- Each finding from Step 3 and the remedy it routes to.
|
|
44
|
-
|
|
45
|
-
Then make Step 3's hand-offs — each invocation a full run of its own that asks and delivers for itself. Make the `/q:install` and `/q:uninstall-extension` runs before any `/q:update` run, so update starts from repaired records.
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: uninstall-extension
|
|
3
|
-
description: Remove a q extension from a project, or reconcile a removal already made out of band — a hand-run npm uninstall, a teammate's merge. Invoke with the extension name. Uninstalls the package, removes its group from the briefing's docs index, drops its watermark, and surfaces the project docs that reference it for the user's ruling. Refuses @lab43/q. The changes ship as a PR.
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Uninstall Extension
|
|
7
|
-
|
|
8
|
-
Follow the run contract — `${CLAUDE_PLUGIN_ROOT}/references/run-contract.md`. Given no extension, ask which one.
|
|
9
|
-
|
|
10
|
-
## Step 1: Take stock
|
|
11
|
-
|
|
12
|
-
Refuse `q` and `@lab43/q`. q is the framework rather than an extension (source: @lab43/q conventions/extensions.md, Identity), and no q project can remove it (source: @lab43/q conventions/documentation.md, Three tiers of conventions).
|
|
13
|
-
|
|
14
|
-
Confirm the named target is an extension — any of the following identifies it:
|
|
15
|
-
|
|
16
|
-
- the `q-extension` keyword in `node_modules/<extension>/package.json` (source: @lab43/q conventions/extensions.md)
|
|
17
|
-
- the same keyword read from the registry (`npm view <extension> keywords`), for one pinned but not installed
|
|
18
|
-
- a `reconciledAgainst` entry (see: ${CLAUDE_PLUGIN_ROOT}/references/q-state.md)
|
|
19
|
-
|
|
20
|
-
A target none of these identify has nothing here to remove — report that and stop.
|
|
21
|
-
|
|
22
|
-
## Step 2: Settle delivery
|
|
23
|
-
|
|
24
|
-
Ask which review mode — local or ship — the run delivers under (see: ${CLAUDE_PLUGIN_ROOT}/references/run-contract.md, Review modes). Then pick the delivery branch (see: ${CLAUDE_PLUGIN_ROOT}/references/run-contract.md, The delivery branch).
|
|
25
|
-
|
|
26
|
-
## Step 3: Remove the extension's records
|
|
27
|
-
|
|
28
|
-
Remove without asking — each item a no-op when already absent:
|
|
29
|
-
|
|
30
|
-
1. When the extension is pinned: `npm uninstall --ignore-scripts <extension>` (via the project's package manager when it isn't npm).
|
|
31
|
-
2. When the pin is already gone: run the package manager's dependency install, catching up any lockfile and `node_modules` remnants the removal left.
|
|
32
|
-
3. Remove the extension's group from the agent briefing's docs index — its heading and every line under it. An extension that shipped no `conventions/` has no group to remove.
|
|
33
|
-
4. Drop the extension's `reconciledAgainst` entry, per `${CLAUDE_PLUGIN_ROOT}/references/q-state.md`.
|
|
34
|
-
|
|
35
|
-
## Step 4: Rule on references
|
|
36
|
-
|
|
37
|
-
Grep the docs the documentation policy owns (see: @lab43/q conventions/documentation.md, Taxonomy) for the extension's name. Every hit lost its backing with the extension: an overrides marker's target, a restatement's home, a cross-reference's destination. On a clean grep, skip the step.
|
|
38
|
-
|
|
39
|
-
Recommend a resolution for each hit, grounded in the documentation policy, in conversational mode (see: ${CLAUDE_PLUGIN_ROOT}/references/run-contract.md, Collaboration modes) — one AskUserQuestion batch. The user rules. Apply the rulings.
|
|
40
|
-
|
|
41
|
-
## Step 5: Adversarial review
|
|
42
|
-
|
|
43
|
-
In ship mode, commit first. In both modes, validate the changes (see: ${CLAUDE_PLUGIN_ROOT}/references/run-contract.md, Validation) with the **correctness** and **conventions** lenses.
|
|
44
|
-
|
|
45
|
-
## Step 6: Open the PR
|
|
46
|
-
|
|
47
|
-
1. **The local gate**: run it over the uncommitted changes (see: ${CLAUDE_PLUGIN_ROOT}/references/run-contract.md, The local gate).
|
|
48
|
-
2. **Open the PR**: push the branch and open the PR per the PR-authoring rules (see: @lab43/q conventions/pull-requests.md).
|
|
49
|
-
3. Close the session by reporting:
|
|
50
|
-
- The extension removed, or the out-of-band removal reconciled.
|
|
51
|
-
- The index lines and watermark entry dropped, and any lockfile catch-up applied.
|
|
52
|
-
- Each reference surfaced and the user's ruling on it.
|
package/skills/update/SKILL.md
DELETED
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: update
|
|
3
|
-
description: Update q and the project's installed extensions — move pins to the latest releases with the user's go-ahead, reconcile the project's docs with what each release changed, and catch up any pin that moved out of band. Invoked bare it covers q and every installed extension; a named target — q, or an extension — scopes the run. Use after a release ships, or whenever pins may be behind. To audit docs without updating, use groom-docs; to repair this machine without touching docs, use sync. A pin move or catch-up ships as a PR.
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Update
|
|
7
|
-
|
|
8
|
-
Follow the run contract — `${CLAUDE_PLUGIN_ROOT}/references/run-contract.md`.
|
|
9
|
-
|
|
10
|
-
## Step 1: Take stock
|
|
11
|
-
|
|
12
|
-
Bare invocation covers `@lab43/q` and every installed extension — the direct `devDependencies` whose own `package.json` carries the `q-extension` keyword (source: @lab43/q conventions/extensions.md). A named target scopes the run: `q` means `@lab43/q`; any other name means that extension. Confirm any target you can't identify as an extension before treating it as one. Below, *package* covers both q and an extension.
|
|
13
|
-
|
|
14
|
-
Read four versions for each package in scope — the watermarks per `${CLAUDE_PLUGIN_ROOT}/references/q-state.md`:
|
|
15
|
-
|
|
16
|
-
| Pinned | Installed | Latest | Watermark |
|
|
17
|
-
| --- | --- | --- | --- |
|
|
18
|
-
| its pin in the project's `package.json`; in a repo authoring an extension, the q pin lives in that extension's own manifest (source: @lab43/q conventions/extensions.md) | `version` in `node_modules/<package>/package.json` | `npm view <package> version` | its `reconciledAgainst` entry |
|
|
19
|
-
|
|
20
|
-
Alongside the versions, hold each third-party extension's q declaration — its `@lab43/q` devDependency (source: @lab43/q conventions/extensions.md) — against the project's own q pin, and flag a mismatch either way. A declaration ahead of the pin closes by updating q here; one behind closes only by that extension's release.
|
|
21
|
-
|
|
22
|
-
A package with no pin and no watermark entry has nothing to update — propose `/q:install` for it and stop.
|
|
23
|
-
|
|
24
|
-
Validate the records before sorting. Check that every pinned package in scope carries its watermark. Check that no watermark outlives its pin: every watermark on a bare run, the target's on a named run. On any failure, propose `/q:sync` and stop.
|
|
25
|
-
|
|
26
|
-
Report the versions, then sort each package by its state:
|
|
27
|
-
|
|
28
|
-
- **Pinned behind latest** → a pin move to offer. Diff the two published versions: `npm pack <package>@<version>` for each into a scratch directory, extract both, and diff the trees. Diff the whole tarball rather than `conventions/` alone, because a release can change skills, hooks, agents and references too. Step 4's reconciliation and the closing report both read from this diff. Summarize what changed and what reconciliation it demands. Pins are recorded decisions — only the user moves them.
|
|
29
|
-
- **Pinned ≠ watermark** → a catch-up: the pin moved out of band. Reconciled in Step 4, without moving any pin.
|
|
30
|
-
- **Installed ≠ pinned** → machine drift: enforce without asking, per `${CLAUDE_PLUGIN_ROOT}/references/enforce-pins.md`. When a pin move is on offer, enforce only after the ask below, so enforcement lands on the pins the run keeps; otherwise enforce now.
|
|
31
|
-
- **Everything agreeing, nothing newer** → in force and reconciled; report and stop.
|
|
32
|
-
|
|
33
|
-
Then ask once, one batch: each offered pin move (take it or stay), and the review mode — local or ship — the delivery runs under (see: ${CLAUDE_PLUGIN_ROOT}/references/run-contract.md, Review modes). A run with only catch-ups asks the review mode alone. A run finding only machine drift asks nothing — enforce, report, stop. The go-ahead makes the rest of the run autonomous: declined moves drop out, catch-ups stay in. When the answers leave nothing due, report and stop.
|
|
34
|
-
|
|
35
|
-
## Step 2: Branch
|
|
36
|
-
|
|
37
|
-
Pick the delivery branch (see: ${CLAUDE_PLUGIN_ROOT}/references/run-contract.md, The delivery branch).
|
|
38
|
-
|
|
39
|
-
## Step 3: Move the pins
|
|
40
|
-
|
|
41
|
-
For each pin the user agreed to move:
|
|
42
|
-
|
|
43
|
-
Run `npm install --save-dev --save-exact --ignore-scripts <package>@<latest>`, via the project's package manager when it isn't npm. Moving any pin is the same act, q's included.
|
|
44
|
-
|
|
45
|
-
## Step 4: Reconcile what the diff touched
|
|
46
|
-
|
|
47
|
-
Work only from the diffs. Each package's diff runs from its watermark to its pin as Step 3 left it. What the diff touched decides which of these applies. A diff may touch more than one:
|
|
48
|
-
|
|
49
|
-
- **Changed `conventions/`** — hold the project's docs against each changed rule:
|
|
50
|
-
- remove an override whose target updated to agree or disappeared — it is spent (source: @lab43/q conventions/documentation.md, Three tiers of conventions)
|
|
51
|
-
- re-check each "(source: …)" restatement against its changed home
|
|
52
|
-
- prune a project rule the new text now owns — it is duplication now
|
|
53
|
-
- ask about a project rule the new text contradicts, the one call the go-ahead didn't settle: keep it as a recorded deviation (add the overrides marker) or adopt the incoming rule. Adopting can leave code non-conforming — suggest `/q:review` on the affected area; code fixes are out of scope here
|
|
54
|
-
|
|
55
|
-
An extension authored in this repo is part of that surface: re-check its docs and its own `description` the same way. The q pin this run moved is also that extension's shipped written-against declaration, and the re-check is what makes the moved declaration true (source: @lab43/q conventions/extensions.md).
|
|
56
|
-
|
|
57
|
-
Then sync the briefing's index lines for the package — a doc added or removed changes the list, a changed intro re-draws its blurb (see: @lab43/q conventions/documentation.md, Taxonomy).
|
|
58
|
-
- **A changed extension `description`** — re-draw that extension's group heading in the briefing's docs index (see: `${CLAUDE_PLUGIN_ROOT}/references/agent-briefing.md`). A release can change the description alone.
|
|
59
|
-
- **A changed plugin** — re-run `/q:install`, scoped to join this run's change: it is idempotent, creating what the new version's scaffold expects and correcting what has drifted from it.
|
|
60
|
-
|
|
61
|
-
After each package's reconciliation, write its watermark per `${CLAUDE_PLUGIN_ROOT}/references/q-state.md`: its `reconciledAgainst` entry to its pinned version.
|
|
62
|
-
|
|
63
|
-
The go-ahead in Step 1 covered this reconciliation — apply it without re-asking.
|
|
64
|
-
|
|
65
|
-
## Step 5: Adversarial review
|
|
66
|
-
|
|
67
|
-
In ship mode, commit first. In both modes, validate the changes (see: ${CLAUDE_PLUGIN_ROOT}/references/run-contract.md, Validation) with the **correctness** and **conventions** lenses.
|
|
68
|
-
|
|
69
|
-
## Step 6: Open the PR
|
|
70
|
-
|
|
71
|
-
1. **The local gate**: run it over the uncommitted changes (see: ${CLAUDE_PLUGIN_ROOT}/references/run-contract.md, The local gate).
|
|
72
|
-
2. **Open the PR**: push the branch and open the PR per the PR-authoring rules (see: @lab43/q conventions/pull-requests.md).
|
|
73
|
-
3. Close the session by reporting:
|
|
74
|
-
- Old and new pins, and each catch-up applied without a pin move.
|
|
75
|
-
- What each release changed.
|
|
76
|
-
- Each reconciliation applied and any follow-up suggested — a third-party extension the moved q pin leaves behind included; a newer release of that extension is what closes the gap.
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|