ctxr-cli 0.20.0 → 0.21.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 +55 -16
- package/dist/adapters/builtin/index.d.ts.map +1 -1
- package/dist/adapters/builtin/index.js +8 -1
- package/dist/adapters/builtin/index.js.map +1 -1
- package/dist/adapters/harness/antigravity.d.ts +18 -0
- package/dist/adapters/harness/antigravity.d.ts.map +1 -0
- package/dist/adapters/harness/antigravity.js +24 -0
- package/dist/adapters/harness/antigravity.js.map +1 -0
- package/dist/adapters/harness/codex.d.ts +22 -0
- package/dist/adapters/harness/codex.d.ts.map +1 -0
- package/dist/adapters/harness/codex.js +28 -0
- package/dist/adapters/harness/codex.js.map +1 -0
- package/dist/adapters/types.d.ts +9 -0
- package/dist/adapters/types.d.ts.map +1 -1
- package/dist/commands/adapters-generate.d.ts +2 -14
- package/dist/commands/adapters-generate.d.ts.map +1 -1
- package/dist/commands/adapters-generate.js +2 -50
- package/dist/commands/adapters-generate.js.map +1 -1
- package/dist/commands/ingest.d.ts.map +1 -1
- package/dist/commands/ingest.js +13 -1
- package/dist/commands/ingest.js.map +1 -1
- package/dist/commands/init.d.ts +2 -0
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +32 -3
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/publish-urls.d.ts +32 -0
- package/dist/commands/publish-urls.d.ts.map +1 -0
- package/dist/commands/publish-urls.js +125 -0
- package/dist/commands/publish-urls.js.map +1 -0
- package/dist/commands/update.d.ts.map +1 -1
- package/dist/commands/update.js +0 -3
- package/dist/commands/update.js.map +1 -1
- package/dist/config/defaults.d.ts +26 -0
- package/dist/config/defaults.d.ts.map +1 -1
- package/dist/config/defaults.js +25 -1
- package/dist/config/defaults.js.map +1 -1
- package/dist/config/schema.d.ts +19 -0
- package/dist/config/schema.d.ts.map +1 -1
- package/dist/config/schema.js +31 -0
- package/dist/config/schema.js.map +1 -1
- package/dist/core/adapter-outputs.d.ts +19 -0
- package/dist/core/adapter-outputs.d.ts.map +1 -0
- package/dist/core/adapter-outputs.js +54 -0
- package/dist/core/adapter-outputs.js.map +1 -0
- package/dist/core/agents-doc.d.ts +26 -0
- package/dist/core/agents-doc.d.ts.map +1 -1
- package/dist/core/agents-doc.js +95 -39
- package/dist/core/agents-doc.js.map +1 -1
- package/dist/core/checks/harness-portability-checks.d.ts +32 -0
- package/dist/core/checks/harness-portability-checks.d.ts.map +1 -1
- package/dist/core/checks/harness-portability-checks.js +177 -2
- package/dist/core/checks/harness-portability-checks.js.map +1 -1
- package/dist/core/checks/integrity-checks.d.ts.map +1 -1
- package/dist/core/checks/integrity-checks.js +34 -14
- package/dist/core/checks/integrity-checks.js.map +1 -1
- package/dist/core/checks/organize-checks.d.ts +5 -0
- package/dist/core/checks/organize-checks.d.ts.map +1 -1
- package/dist/core/checks/organize-checks.js +57 -4
- package/dist/core/checks/organize-checks.js.map +1 -1
- package/dist/core/convention-doc.d.ts.map +1 -1
- package/dist/core/convention-doc.js +5 -2
- package/dist/core/convention-doc.js.map +1 -1
- package/dist/core/conventions.d.ts +7 -0
- package/dist/core/conventions.d.ts.map +1 -1
- package/dist/core/conventions.js +3 -0
- package/dist/core/conventions.js.map +1 -1
- package/dist/core/errors.d.ts +16 -0
- package/dist/core/errors.d.ts.map +1 -1
- package/dist/core/errors.js +32 -0
- package/dist/core/errors.js.map +1 -1
- package/dist/core/ingest/required-sections.d.ts +3 -3
- package/dist/core/ingest/required-sections.d.ts.map +1 -1
- package/dist/core/ingest/required-sections.js +79 -16
- package/dist/core/ingest/required-sections.js.map +1 -1
- package/dist/core/notes/list.d.ts.map +1 -1
- package/dist/core/notes/list.js +3 -0
- package/dist/core/notes/list.js.map +1 -1
- package/dist/core/reconcile.d.ts +2 -1
- package/dist/core/reconcile.d.ts.map +1 -1
- package/dist/core/reconcile.js +10 -2
- package/dist/core/reconcile.js.map +1 -1
- package/dist/core/skills.d.ts.map +1 -1
- package/dist/core/skills.js +16 -5
- package/dist/core/skills.js.map +1 -1
- package/dist/run.d.ts.map +1 -1
- package/dist/run.js +14 -1
- package/dist/run.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +3 -3
- package/templates/agents/canonical.md +3 -6
- package/templates/agents/capture-and-ingest.md +1 -36
- package/templates/agents/conventions.md +3 -1
- package/templates/agents/guidance-index.md +5 -0
- package/templates/agents/mission.md +2 -0
- package/templates/agents/retrieval-leg-routing.md +7 -36
- package/templates/conventions/baseline-conventions.md +20 -9
- package/templates/conventions/house-conventions-seed.md +10 -0
- package/templates/notes/Concept.md +2 -1
- package/templates/skills/ctxr-capture.md +30 -4
- package/templates/skills/ctxr-derived-artifacts.md +6 -0
- package/templates/skills/ctxr-ingest-orchestration.md +5 -1
- package/templates/skills/ctxr-mission.md +40 -31
- package/templates/skills/ctxr-organize-audit.md +6 -0
- package/templates/skills/ctxr-placement.md +5 -0
- package/templates/skills/ctxr-publish.md +18 -4
- package/templates/skills/ctxr-second-opinion/lenses.md +3 -1
- package/templates/skills/ctxr-second-opinion/run.mjs +39 -12
- package/templates/skills/ctxr-second-opinion.md +19 -6
- package/templates/skills/ctxr-submit.md +28 -4
|
@@ -31,6 +31,11 @@ clutter — worse than a slightly crowded existing one. Starting small and promo
|
|
|
31
31
|
starting big and hollow is not. Make the promotion trigger a rule, not a vibe, and write it INTO the
|
|
32
32
|
note: "Promote to its own top-level location the moment this holds 3+ distinct notes or topics."
|
|
33
33
|
|
|
34
|
+
A unit that will carry supporting notes (a project with its research, an exploration with its evidence)
|
|
35
|
+
gets a folder of its own. The graph clusters notes by their first __CLUSTER_DEPTH__ path segments, so
|
|
36
|
+
grouping such units under one common parent at that depth merges their clusters, and the graph then asserts
|
|
37
|
+
a relationship between them that does not exist.
|
|
38
|
+
|
|
34
39
|
## 4. What must never enter the store?
|
|
35
40
|
|
|
36
41
|
Credentials, full account numbers, and secrets never enter the store — last-4 only. This is a placement
|
|
@@ -51,7 +51,8 @@ says something.
|
|
|
51
51
|
When `gather` reports that an existing page belongs at the reported path too, it is because this
|
|
52
52
|
subject is acquiring a second page, and a subject's pages collect under one folder naming it. Move
|
|
53
53
|
that page there before you scaffold the new one, and tell the operator its URL changed — somebody
|
|
54
|
-
may already be holding that link. `
|
|
54
|
+
may already be holding that link. `ctxr publish urls` reports the old address beside the new one, and
|
|
55
|
+
`ctxr-submit` carries both into the pull request. `gather` moves nothing itself, and it names which signal counted
|
|
55
56
|
the page as this subject's; read that before you move anything, because the signal is a reading of
|
|
56
57
|
the page's README and can be wrong. Lead a page's source notes with the note it is a representation
|
|
57
58
|
of — that lead link is what says whose page this is, and everything after it is a citation.
|
|
@@ -99,9 +100,17 @@ before reporting the page as ready. It answers only what's derivable from the fi
|
|
|
99
100
|
in step 1, the form and reader choices in step 5, and factual accuracy stay judgment calls, not checker output.
|
|
100
101
|
|
|
101
102
|
`ctxr publish new` and `ctxr publish check` each end by naming the address `ctxr serve` answers for
|
|
102
|
-
this page.
|
|
103
|
-
|
|
104
|
-
|
|
103
|
+
this page. Look at the page before you hand it on. Whether the form works, whether the prose reads,
|
|
104
|
+
whether it renders at all is exactly what the checks above cannot answer, and it is cheapest to fix
|
|
105
|
+
while the page is still yours.
|
|
106
|
+
|
|
107
|
+
That address may be served from another host, or behind an access proxy, where you cannot reach it.
|
|
108
|
+
You do not need it: from this machine, start `ctxr serve` in the background, open the address it
|
|
109
|
+
prints followed by the page's route in your browser tool, and stop the server when you are done. A
|
|
110
|
+
page still in a session worktree is served there under its previewable route, the same as anywhere
|
|
111
|
+
else. If you have no way to see a rendered page, say in your hand-off that it has not been checked
|
|
112
|
+
visually, so whoever reviews it knows they are the first to look. Never report a page as ready on the
|
|
113
|
+
strength of `ctxr publish check` alone.
|
|
105
114
|
|
|
106
115
|
A page written in a session worktree is previewable rather than published, because the
|
|
107
116
|
published-pages address reads the store's own checkout and the page has not reached it yet. That
|
|
@@ -110,6 +119,11 @@ previewable address stops answering the moment the worktree is reclaimed — the
|
|
|
110
119
|
Report the address you actually opened, and say which of the two it is, so nobody is handed a link
|
|
111
120
|
that is about to change.
|
|
112
121
|
|
|
122
|
+
Both addresses are full URLs when the store declares `serve.base_url` in `contexture.yaml`, and bare
|
|
123
|
+
routes such as `/preview/…` when it does not. A bare route is not a link anyone else can open. Do not
|
|
124
|
+
guess a host to put in front of it: hand on the route as it is, and tell the operator that declaring
|
|
125
|
+
`serve.base_url` would make every address a command reports a link.
|
|
126
|
+
|
|
113
127
|
## 7. It's a page, not a note
|
|
114
128
|
|
|
115
129
|
The published-pages location is excluded from retrieval by default — a page never becomes a source for
|
|
@@ -12,4 +12,6 @@ drop one: a collapsed pair adds cost and no breadth.
|
|
|
12
12
|
- **brand-strategist** — long-term positioning, category ownership, how it ages.
|
|
13
13
|
|
|
14
14
|
A store may add its own lens inline as `Name:description`, for example
|
|
15
|
-
`"Plainspoken:blunt, substance first, distrusts slogans"`.
|
|
15
|
+
`"Plainspoken:blunt, substance first, distrusts slogans"`. The description may contain commas. A comma starts
|
|
16
|
+
the next lens only when the text after it is exactly a lens name above or begins `Name:`, so keep colons out
|
|
17
|
+
of a description.
|
|
@@ -33,19 +33,30 @@ const MAX_ARGV_BYTES = 120_000;
|
|
|
33
33
|
|
|
34
34
|
const env = (name, fallback) => process.env[`CTXR_SECOND_OPINION_${name}`] || fallback;
|
|
35
35
|
|
|
36
|
-
/**
|
|
36
|
+
/**
|
|
37
|
+
* Model choice lives here, in one table. Override by environment, never by editing a store.
|
|
38
|
+
*
|
|
39
|
+
* Effort is each provider's own recommended default, not one this runner picked:
|
|
40
|
+
* - claude: no --effort at all, so Claude Code applies its own default for the model.
|
|
41
|
+
* - codex: `medium`, the default its model catalog declares (`default_reasoning_level`). It is passed
|
|
42
|
+
* explicitly because the flag cannot simply be left off: with no pin in config.toml, codex resolves to
|
|
43
|
+
* `reasoning effort: none` on a ChatGPT login (seen 2026-10-05), which is no review at all. `low` at the
|
|
44
|
+
* `fast` tier. A machine that pins its own effort in config.toml is overridden by this; set
|
|
45
|
+
* CTXR_SECOND_OPINION_CODEX_EFFORT to use another.
|
|
46
|
+
* - agy: the effort is part of the model name; `(High)` is Gemini's default thinking level.
|
|
47
|
+
* For scale: on one short plan Claude took 35 s at `high` and 514 s at `max`, so a deeper pass is a choice
|
|
48
|
+
* (CTXR_SECOND_OPINION_CLAUDE_EFFORT=max), not something to leave on by default.
|
|
49
|
+
*/
|
|
37
50
|
function tiers() {
|
|
38
51
|
return {
|
|
39
52
|
strong: {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
claude: { model: env('CLAUDE_MODEL', 'opus'), effort: env('CLAUDE_EFFORT', 'high') },
|
|
43
|
-
codex: { effort: env('CODEX_EFFORT', 'xhigh') },
|
|
53
|
+
claude: { model: env('CLAUDE_MODEL', 'opus'), effort: env('CLAUDE_EFFORT', null) },
|
|
54
|
+
codex: { effort: env('CODEX_EFFORT', 'medium') },
|
|
44
55
|
agy: { model: env('AGY_MODEL', 'Gemini 3.1 Pro (High)') },
|
|
45
56
|
},
|
|
46
57
|
fast: {
|
|
47
|
-
claude: { model: env('CLAUDE_MODEL', 'haiku'), effort: null },
|
|
48
|
-
codex: { effort: env('CODEX_EFFORT', '
|
|
58
|
+
claude: { model: env('CLAUDE_MODEL', 'haiku'), effort: env('CLAUDE_EFFORT', null) },
|
|
59
|
+
codex: { effort: env('CODEX_EFFORT', 'low') },
|
|
49
60
|
agy: { model: env('AGY_MODEL', 'Gemini 3.8 Flash (High)') },
|
|
50
61
|
},
|
|
51
62
|
};
|
|
@@ -54,10 +65,11 @@ function tiers() {
|
|
|
54
65
|
/**
|
|
55
66
|
* The flags this runner passes, so preflight can confirm each CLI's --help still lists them. Only flags
|
|
56
67
|
* the help text documents belong here: `claude` still accepts a hidden --max-turns, but with `--tools ""`
|
|
57
|
-
* there is no tool turn to bound, so it is not passed at all.
|
|
68
|
+
* there is no tool turn to bound, so it is not passed at all. --effort is not listed because it is only
|
|
69
|
+
* passed when the environment asks for one.
|
|
58
70
|
*/
|
|
59
71
|
const FLAGS_USED = {
|
|
60
|
-
claude: { helpArgs: ['--help'], flags: ['--tools', '--model', '--
|
|
72
|
+
claude: { helpArgs: ['--help'], flags: ['--tools', '--model', '--no-session-persistence', '--disable-slash-commands', '--output-format'] },
|
|
61
73
|
codex: { helpArgs: ['exec', '--help'], flags: ['--skip-git-repo-check', '--sandbox', '--ephemeral', '--color', '--config'] },
|
|
62
74
|
agy: { helpArgs: ['--help'], flags: ['--print', '--sandbox', '--disable-slash-commands', '--model'] },
|
|
63
75
|
};
|
|
@@ -267,13 +279,28 @@ function loadLensRoster() {
|
|
|
267
279
|
return roster;
|
|
268
280
|
}
|
|
269
281
|
|
|
282
|
+
/**
|
|
283
|
+
* Splits `--lens` into one string per lens. Lenses are comma-separated, but an inline description may itself
|
|
284
|
+
* contain commas: a fragment starts a NEW lens only when it is exactly a roster name or begins `Name:`;
|
|
285
|
+
* any other fragment continues the lens before it. So `minimalist,House taste:blunt, anti-slogan` is two
|
|
286
|
+
* lenses, and a description must not contain a colon (that would read as the start of another lens).
|
|
287
|
+
*/
|
|
288
|
+
export function splitLenses(spec, roster) {
|
|
289
|
+
const lenses = [];
|
|
290
|
+
for (const fragment of spec.split(',').map((f) => f.trim()).filter(Boolean)) {
|
|
291
|
+
const startsLens = roster.has(fragment.toLowerCase()) || /^[^:,]{1,40}:/.test(fragment);
|
|
292
|
+
if (startsLens || lenses.length === 0) lenses.push(fragment);
|
|
293
|
+
else lenses[lenses.length - 1] += `, ${fragment}`;
|
|
294
|
+
}
|
|
295
|
+
return lenses;
|
|
296
|
+
}
|
|
297
|
+
|
|
270
298
|
function lensBlock(spec) {
|
|
271
299
|
const roster = loadLensRoster();
|
|
272
|
-
const specs = spec.split(',').map((s) => s.trim()).filter(Boolean);
|
|
273
300
|
const described = [];
|
|
274
|
-
for (const s of
|
|
301
|
+
for (const s of splitLenses(spec, roster)) {
|
|
275
302
|
if (roster.has(s.toLowerCase())) described.push(`- ${s.toLowerCase()} — ${roster.get(s.toLowerCase())}`);
|
|
276
|
-
else if (s
|
|
303
|
+
else if (/^[^:,]{1,40}:/.test(s)) {
|
|
277
304
|
const [name, ...rest] = s.split(':');
|
|
278
305
|
described.push(`- ${name.trim()} — ${rest.join(':').trim()}`);
|
|
279
306
|
} else throw new UsageError(`unknown lens "${s}" (known: ${[...roster.keys()].join(', ')}; or pass "Name:description")`);
|
|
@@ -13,6 +13,11 @@ what it reviews. Weighing the answers is your job, and steps 4 and 5 are how.
|
|
|
13
13
|
- **Poll** when the question is *which of these is better?* and being wrong costs mild regret: a name, a
|
|
14
14
|
framing, a piece of copy, which of several tools fits. If all three agreeing would settle it, it is a poll.
|
|
15
15
|
If you would still want each reviewer's top objections and a suggested edit, it is a critique.
|
|
16
|
+
A critique is required, not optional, before implementing a change that is architectural, irreversible, or touches
|
|
17
|
+
what may be disclosed and to whom — run it on the written plan before the work, never as a justification after it.
|
|
18
|
+
Its verdict, and the reasoning behind the option chosen, land in the pull request's body: for a structural change
|
|
19
|
+
the pull request and its commit are the decision record, and there is no separate governance step.
|
|
20
|
+
|
|
16
21
|
- **Answer directly** when there is one right answer, when the operator has already decided and wants
|
|
17
22
|
confirmation, or when the work is read-only investigation.
|
|
18
23
|
|
|
@@ -82,11 +87,17 @@ nothing in the plan, so it was written without reading it; it does not count. **
|
|
|
82
87
|
two valid critiques: say so at the top of your answer and do not call anything a consensus.
|
|
83
88
|
|
|
84
89
|
Add `--tier fast` to drop each family to a cheaper model, for a plan that is small and easy to redo. The
|
|
85
|
-
default tier is right for anything the operator will act on.
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
+
default tier is right for anything the operator will act on.
|
|
91
|
+
|
|
92
|
+
Each reviewer runs at its provider's own recommended default effort, not one this skill chose. Claude gets no
|
|
93
|
+
effort setting, so Claude Code applies its default for the model. Codex gets `medium`, the default its model
|
|
94
|
+
catalog declares; the runner passes it explicitly because Codex left to itself, with no setting pinned, can
|
|
95
|
+
resolve to no reasoning at all. Gemini's effort is part of its model name, and `High` is its default. Measured on a
|
|
96
|
+
short plan, a default critique took about 40 seconds in all, 30 to 37 seconds per reviewer, and costs a few tens
|
|
97
|
+
of cents. A deeper pass is a choice: set `CTXR_SECOND_OPINION_CLAUDE_EFFORT=max` and Claude alone took over
|
|
98
|
+
eight minutes on the same plan, close enough to the runner's ten-minute limit that you should start such a run
|
|
99
|
+
in the background and tell the operator it is under way. A machine that pins its own Codex effort in its
|
|
100
|
+
configuration is overridden by `medium`; set `CTXR_SECOND_OPINION_CODEX_EFFORT` to use another.
|
|
90
101
|
|
|
91
102
|
## 4. Synthesize on the letters first
|
|
92
103
|
|
|
@@ -150,7 +161,9 @@ This mode names its files by model, because what you are reading is whether the
|
|
|
150
161
|
To get breadth as well as model diversity, add `--lens` with two or three taste lenses. Each model then
|
|
151
162
|
answers as every lens in one response, giving a lens-by-model grid. The built-in lenses are minimalist,
|
|
152
163
|
marketer, contrarian, end-user and brand-strategist. A store's own lens goes in as `Name:description`, for
|
|
153
|
-
example `--lens "minimalist,Plainspoken:blunt
|
|
164
|
+
example `--lens "minimalist,Plainspoken:blunt, substance first, distrusts slogans"`. A description may contain
|
|
165
|
+
commas: a comma starts the next lens only when what follows is a built-in lens name or begins `Name:`. So a
|
|
166
|
+
description must not contain a colon. Choose lenses that pull in different
|
|
154
167
|
directions; if two would obviously agree, drop one.
|
|
155
168
|
|
|
156
169
|
Read a lens grid on both axes. Down a column (one lens across the three models) agreement means that
|
|
@@ -23,13 +23,25 @@ pull request?" — needing to ask is itself the answer: leave, and let the work
|
|
|
23
23
|
Ending a turn without that signal is normal and is not this skill. Say in one line what is uncommitted
|
|
24
24
|
and which worktree holds it, then stop. The work is safe on the branch and the next message picks it up.
|
|
25
25
|
|
|
26
|
+
## Routes
|
|
27
|
+
|
|
28
|
+
Every pull request takes one of three routes. Say which, and why, in its body:
|
|
29
|
+
|
|
30
|
+
- **Session** (the default): the session's work plus the capture it approved.
|
|
31
|
+
- **Own**: a new skill, a structural change (folders, the entry document, conventions), or a refactor touching five
|
|
32
|
+
or more files — reviewed on its own so it is not buried in content.
|
|
33
|
+
- **Housekeeping**: small appends nothing else depends on (a log line, a stray link fix), batched rather than folded
|
|
34
|
+
into unrelated work.
|
|
35
|
+
|
|
26
36
|
## Steps
|
|
27
37
|
|
|
28
38
|
1. Re-scan (mandatory — never replay a plan from an earlier snapshot): `git fetch origin`,
|
|
29
39
|
`git status --short`, `git diff --stat`, `git diff --cached --stat`,
|
|
30
40
|
`git ls-files --others --exclude-standard`, `git log --oneline origin/__DEFAULT_BRANCH__..HEAD`. State moves
|
|
31
41
|
under you while you work; name the delta from the previous scan rather than silently folding new work
|
|
32
|
-
into old buckets.
|
|
42
|
+
into old buckets. If the session touched or linked to an entity note, run `ctxr rollup stale --for <entity>`
|
|
43
|
+
(or a plain `ctxr rollup stale` when unsure which), and offer `ctxr-rollup` on anything flagged — never run a
|
|
44
|
+
rollup unasked; the operator decides.
|
|
33
45
|
2. Capture pass: run `ctxr-session-capture` exactly once here — closing a session is itself a capture
|
|
34
46
|
trigger; do not fire it again after submitting.
|
|
35
47
|
3. Stage surgically: `git add <paths>`, never `git add -A`; confirm with `git status --short` that the
|
|
@@ -39,11 +51,23 @@ and which worktree holds it, then stop. The work is safe on the branch and the n
|
|
|
39
51
|
5. Validate: run `ctxr doctor` (store scope, not `--staged` — a session's job is to leave the whole store
|
|
40
52
|
healthy, not merely pass one commit's gate). Fix a failure; never bypass it, and never proceed past it.
|
|
41
53
|
6. Commit: `git commit -m "<message>"`, describing the unit staged in step 3.
|
|
42
|
-
7. Name the branch:
|
|
54
|
+
7. Name the branch: `<prefix>/<short-slug>`, with a prefix from `skill/` `feat/` `project/` `notes/` `chore/`
|
|
55
|
+
`refactor/` `fix/` unless this store's conventions say otherwise. If it still carries a generated name,
|
|
56
|
+
`git branch -m "<name>"` before pushing — never
|
|
43
57
|
let a generated name reach the forge. A name given at `ctxr session start` does not settle this: it
|
|
44
58
|
named a worktree when the work began, and what ships is decided here.
|
|
45
|
-
8.
|
|
46
|
-
|
|
59
|
+
8. Before opening the pull request, run `ctxr publish urls --since origin/__DEFAULT_BRANCH__ --json`. When it
|
|
60
|
+
lists any page, the body gets a **Pages** section: a table with one row per page giving its status, its
|
|
61
|
+
preview address, and its published address — copied from the report, never rebuilt by hand. Mark a moved
|
|
62
|
+
page's old address as one that stops working, and a removed page's the same. Under the table state the
|
|
63
|
+
condition once: a preview resolves only while this pull request is open and the server can see this
|
|
64
|
+
session's worktree, and the published address resolves once the served checkout takes the landed commit.
|
|
65
|
+
When the report carries no preview, leave that column out; when it says no base URL is declared, say the
|
|
66
|
+
addresses are bare routes. When it lists no page, add no section.
|
|
67
|
+
Then run: `git push -u origin "<branch>"`, then `gh pr create --base __DEFAULT_BRANCH__ --title "<title>" --body
|
|
68
|
+
"<why / what changed / route / verification / follow-ups>"`. `gh` authenticates from its own credential
|
|
69
|
+
file: never export or interpolate a token, and never rewrite the origin's URL — it is a credential. The body answers those five questions; write the
|
|
70
|
+
why so a reviewer need not re-derive it. Do not stop to confirm first — the request to
|
|
47
71
|
submit is the consent for both, and `ctxr doctor` in step 5 is the gate on this path. If `gh` has no
|
|
48
72
|
reachable GitHub remote for this repository, `git push` still succeeds on its own — report the pushed
|
|
49
73
|
branch and give the operator the manual pull-request instructions instead of retrying `gh`.
|