@erclx/canon 5.25.0 → 5.27.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 +4 -3
- package/claude/.claude-plugin/plugin.json +1 -1
- package/claude/skills/api-design/SKILL.md +2 -0
- package/claude/skills/auto-ship/SKILL.md +3 -11
- package/claude/skills/auto-ship/references/review-findings.md +20 -0
- package/claude/skills/backlog-triage/SKILL.md +2 -0
- package/claude/skills/bash-cli-script/SKILL.md +2 -0
- package/claude/skills/build-in-slices/SKILL.md +2 -0
- package/claude/skills/canon-cli/SKILL.md +2 -0
- package/claude/skills/canon-feedback/SKILL.md +2 -0
- package/claude/skills/canon-feedback-triage/SKILL.md +2 -0
- package/claude/skills/canon-operator/SKILL.md +2 -0
- package/claude/skills/canon-rollout/SKILL.md +3 -11
- package/claude/skills/canon-rollout/references/failure-recovery.md +20 -0
- package/claude/skills/canvas/SKILL.md +14 -1
- package/claude/skills/ci-workflow/SKILL.md +2 -0
- package/claude/skills/code-craft/SKILL.md +2 -0
- package/claude/skills/codebase-layout/SKILL.md +2 -0
- package/claude/skills/context-fold/REQUIREMENT.md +6 -2
- package/claude/skills/context-fold/SKILL.md +9 -21
- package/claude/skills/context-fold/references/anchor-sweep.md +2 -2
- package/claude/skills/context-fold/references/completion-report.md +26 -0
- package/claude/skills/create-rule/SKILL.md +2 -0
- package/claude/skills/create-skill/SKILL.md +2 -0
- package/claude/skills/create-standard/SKILL.md +2 -0
- package/claude/skills/decision-escalate/SKILL.md +2 -0
- package/claude/skills/deploy-app/SKILL.md +2 -0
- package/claude/skills/deprecation-migration/SKILL.md +2 -0
- package/claude/skills/design-extract/SKILL.md +2 -0
- package/claude/skills/design-taste/REQUIREMENT.md +1 -1
- package/claude/skills/design-taste/SKILL.md +6 -2
- package/claude/skills/design-taste/references/adopted.md +40 -0
- package/claude/skills/design-taste/references/kinds.md +1 -1
- package/claude/skills/design-taste/references/systems.md +1 -7
- package/claude/skills/design-taste/references/tells.md +2 -24
- package/claude/skills/docs-sync/REQUIREMENT.md +2 -1
- package/claude/skills/docs-sync/SKILL.md +2 -0
- package/claude/skills/document-health/REQUIREMENT.md +2 -0
- package/claude/skills/document-health/SKILL.md +23 -0
- package/claude/skills/document-health/references/axes.md +12 -0
- package/claude/skills/draft-and-pick/SKILL.md +3 -1
- package/claude/skills/draft-doc/SKILL.md +2 -0
- package/claude/skills/draft-doc/references/wiki.md +1 -1
- package/claude/skills/draft-figure/SKILL.md +2 -0
- package/claude/skills/draft-identity/SKILL.md +3 -1
- package/claude/skills/draft-ready/SKILL.md +2 -0
- package/claude/skills/draft-screencast/SKILL.md +11 -7
- package/claude/skills/draft-slides/REQUIREMENT.md +17 -12
- package/claude/skills/draft-slides/SKILL.md +33 -20
- package/claude/skills/git-branch/SKILL.md +2 -0
- package/claude/skills/git-commit/SKILL.md +2 -0
- package/claude/skills/git-followup/SKILL.md +2 -0
- package/claude/skills/git-issue/SKILL.md +2 -0
- package/claude/skills/git-issue/references/issue.md +10 -0
- package/claude/skills/git-pr/SKILL.md +2 -0
- package/claude/skills/git-pr/references/evidence.md +14 -6
- package/claude/skills/git-pr/references/labels.md +12 -0
- package/claude/skills/git-ship/SKILL.md +2 -0
- package/claude/skills/git-split/SKILL.md +21 -8
- package/claude/skills/git-stage/SKILL.md +2 -0
- package/claude/skills/git-worktree/SKILL.md +2 -0
- package/claude/skills/index-lookup/SKILL.md +2 -0
- package/claude/skills/markdown-propose/SKILL.md +2 -0
- package/claude/skills/markdown-propose/references/format.md +9 -0
- package/claude/skills/memory-capture/SKILL.md +2 -0
- package/claude/skills/memory-review/SKILL.md +2 -0
- package/claude/skills/memory-review/references/later-phases.md +7 -0
- package/claude/skills/plan-feature/SKILL.md +2 -0
- package/claude/skills/plan-groundwork/SKILL.md +2 -0
- package/claude/skills/plan-intake/SKILL.md +2 -0
- package/claude/skills/plan-intake-answer/SKILL.md +2 -0
- package/claude/skills/project-commands/SKILL.md +2 -0
- package/claude/skills/read-frames/SKILL.md +2 -0
- package/claude/skills/record-screencast/SKILL.md +2 -0
- package/claude/skills/repo-metadata/SKILL.md +2 -0
- package/claude/skills/restate-plainly/SKILL.md +2 -0
- package/claude/skills/review-address/SKILL.md +3 -7
- package/claude/skills/review-address/references/post-review-findings.md +16 -0
- package/claude/skills/review-branch/SKILL.md +2 -0
- package/claude/skills/review-craft/SKILL.md +2 -0
- package/claude/skills/review-craft/references/ui.md +2 -2
- package/claude/skills/review-pr/SKILL.md +4 -8
- package/claude/skills/review-pr/references/body-variants.md +52 -0
- package/claude/skills/review-pr/references/key-changes.md +16 -0
- package/claude/skills/review-pr/references/post.md +15 -43
- package/claude/skills/review-ui/SKILL.md +3 -1
- package/claude/skills/review-ui/references/post.md +4 -2
- package/claude/skills/role-orchestrator/SKILL.md +5 -14
- package/claude/skills/role-orchestrator/references/orchestrator-cloud-launch.md +8 -0
- package/claude/skills/role-orchestrator/references/orchestrator-dispatch.md +13 -0
- package/claude/skills/role-orchestrator/references/orchestrator-handback.md +1 -1
- package/claude/skills/role-orchestrator/references/orchestrator-inbound.md +23 -0
- package/claude/skills/role-orchestrator/references/orchestrator-launch.md +5 -33
- package/claude/skills/role-orchestrator/references/orchestrator-poll.md +1 -21
- package/claude/skills/role-orchestrator/references/orchestrator-review-dispatch.md +1 -1
- package/claude/skills/role-orchestrator/references/orchestrator-reviewer-launch.md +38 -0
- package/claude/skills/role-orchestrator/references/orchestrator-watch.md +26 -0
- package/claude/skills/role-planner/SKILL.md +2 -0
- package/claude/skills/role-reviewer/REQUIREMENT.md +1 -1
- package/claude/skills/role-reviewer/SKILL.md +2 -0
- package/claude/skills/role-worker/SKILL.md +2 -0
- package/claude/skills/search-craft/REQUIREMENT.md +1 -1
- package/claude/skills/search-craft/SKILL.md +5 -1
- package/claude/skills/search-craft/references/adopted.md +30 -0
- package/claude/skills/seed-sync/SKILL.md +2 -0
- package/claude/skills/session-compact/SKILL.md +2 -0
- package/claude/skills/session-map/SKILL.md +2 -0
- package/claude/skills/session-relay/SKILL.md +2 -0
- package/claude/skills/session-resume/SKILL.md +2 -0
- package/claude/skills/session-worktree/SKILL.md +3 -11
- package/claude/skills/session-worktree/references/install-command.md +20 -0
- package/claude/skills/sketch-design/SKILL.md +2 -0
- package/claude/skills/systematic-debugging/SKILL.md +2 -0
- package/claude/skills/target-check/SKILL.md +2 -0
- package/claude/skills/target-setup/SKILL.md +2 -0
- package/claude/skills/target-setup/references/detect.md +8 -0
- package/claude/skills/target-setup/references/indexes.md +13 -0
- package/claude/skills/target-setup/references/verify.md +8 -0
- package/claude/skills/task-board/SKILL.md +2 -0
- package/claude/skills/teach-workspace/SKILL.md +5 -15
- package/claude/skills/teach-workspace/references/lesson-build.md +75 -0
- package/claude/skills/teach-workspace/references/lesson-craft.md +13 -69
- package/claude/skills/teach-workspace/references/revisit.md +22 -0
- package/claude/skills/test-craft/SKILL.md +2 -0
- package/claude/skills/test-first/SKILL.md +4 -0
- package/claude/skills/test-first/references/adopted.md +36 -0
- package/claude/skills/ui-checklist/SKILL.md +2 -0
- package/claude/skills/ux-audit/SKILL.md +2 -0
- package/claude/skills/ux-measure/SKILL.md +2 -0
- package/claude/skills/ux-walkthrough/SKILL.md +2 -0
- package/claude/skills/video-craft/SKILL.md +2 -0
- package/claude/skills/write-human/SKILL.md +3 -1
- package/claude/skills/write-human/references/machine-tells.md +13 -0
- package/claude/skills/youtube-transcripts/SKILL.md +2 -0
- package/docs/agents/canvas.md +24 -6
- package/docs/agents/capture.md +6 -6
- package/docs/agents/commands.md +5 -5
- package/docs/agents/index.md +5 -5
- package/docs/agents/install-and-sync.md +7 -0
- package/docs/agents/key-changes.md +1 -1
- package/docs/agents/pr-evidence.md +38 -15
- package/docs/agents/pr-local.md +19 -13
- package/docs/agents/pr-preview.md +44 -21
- package/docs/agents/records-stale.md +22 -9
- package/docs/agents/records.md +1 -1
- package/docs/agents/sandbox.md +29 -5
- package/docs/agents/scripting.md +8 -1
- package/docs/agents/skills-audit.md +11 -3
- package/docs/agents/slides.md +15 -3
- package/docs/workflow/ai-workflow.md +1 -1
- package/docs/workflow/index.md +1 -0
- package/docs/workflow/operating-model.md +5 -6
- package/docs/workflow/parallel-features.md +23 -2
- package/docs/workflow/skill-map-on-request.md +42 -0
- package/docs/workflow/skill-map.md +3 -34
- package/docs/workflow/zshrc-aliases.md +1 -1
- package/package.json +1 -1
- package/scripts/core/regen-hero.ts +1 -1
- package/scripts/lib/sandbox-git.sh +1 -9
- package/scripts/lib/sandbox-path.sh +6 -162
- package/scripts/sandbox-hook.sh +99 -0
- package/src/audits/run.ts +1 -1
- package/src/canvas/address.ts +12 -3
- package/src/canvas/capture.ts +1 -9
- package/src/canvas/client/inspector/align-grid.tsx +162 -0
- package/src/canvas/client/inspector/color-field.tsx +398 -0
- package/src/canvas/client/inspector/color-inputs.tsx +139 -0
- package/src/canvas/client/inspector/color-picker.tsx +668 -0
- package/src/canvas/client/inspector/color-space.ts +240 -0
- package/src/canvas/client/inspector/field.tsx +5 -1
- package/src/canvas/client/inspector/fields.css +547 -17
- package/src/canvas/client/inspector/size-field.tsx +69 -0
- package/src/canvas/client/inspector/values.ts +166 -1
- package/src/canvas/client/inspector.tsx +236 -73
- package/src/canvas/client/selection.tsx +197 -0
- package/src/canvas/client/shell.css +104 -12
- package/src/canvas/client/state.ts +69 -9
- package/src/canvas/client/surface.tsx +147 -22
- package/src/canvas/content.ts +50 -1
- package/src/canvas/edit.ts +37 -4
- package/src/canvas/editing.ts +203 -0
- package/src/canvas/global.d.ts +15 -0
- package/src/canvas/server.ts +149 -12
- package/src/canvas/tokens.ts +59 -17
- package/src/capture/render.ts +45 -7
- package/src/capture/sources.ts +43 -0
- package/src/census/count.ts +2 -2
- package/src/claude/cases/workflow.ts +5 -0
- package/src/claude/seeds.ts +2 -2
- package/src/claude/skills-audit.ts +96 -14
- package/src/claude/skills-drift.ts +1 -1
- package/src/claude/skills-families.ts +36 -0
- package/src/claude/skills-list.ts +76 -15
- package/src/commands/audits.ts +2 -2
- package/src/commands/canvas.ts +179 -2
- package/src/commands/claude.ts +94 -11
- package/src/commands/design.ts +142 -2
- package/src/commands/feedback.ts +3 -3
- package/src/commands/gov.ts +1 -1
- package/src/commands/hooks.ts +1 -1
- package/src/commands/indexes.ts +1 -1
- package/src/commands/init.ts +1 -1
- package/src/commands/intake.ts +1 -1
- package/src/commands/migrate.ts +1 -1
- package/src/commands/pr.ts +105 -58
- package/src/commands/records.ts +89 -7
- package/src/commands/repo.ts +1 -1
- package/src/commands/sandbox.ts +103 -11
- package/src/commands/sessions.ts +1 -1
- package/src/commands/slides.ts +31 -77
- package/src/commands/sync.ts +1 -1
- package/src/commands/tasks.ts +2 -2
- package/src/commands/teach.ts +1 -1
- package/src/commands/transcripts.ts +1 -1
- package/src/commands/worktrees.ts +1 -1
- package/src/comments/scan.ts +1 -1
- package/src/comments/trend.ts +1 -1
- package/src/context/audit.ts +1 -1
- package/src/context/citations.ts +1 -1
- package/src/context/classify/extract.ts +2 -2
- package/src/design/project-fonts.ts +392 -0
- package/src/design/tokens.ts +2 -18
- package/src/docs/read.ts +1 -1
- package/src/{github.ts → feedback/github.ts} +2 -2
- package/src/{client-commands.ts → gate/client-commands.ts} +1 -1
- package/src/gate/measures.ts +53 -13
- package/src/gate/sequencer.ts +1 -1
- package/src/gate/stages.ts +9 -0
- package/src/{git-files.ts → git/files.ts} +2 -2
- package/src/{git-ignore.ts → git/ignore.ts} +1 -1
- package/src/{worktree.ts → git/worktree.ts} +1 -1
- package/src/gov/citations.ts +2 -2
- package/src/gov/install.ts +1 -1
- package/src/gov/payload.ts +1 -1
- package/src/gov/superseded.ts +3 -3
- package/src/gov/test-order.ts +2 -2
- package/src/help.ts +1 -1
- package/src/hooks/post-merge.ts +1 -1
- package/src/indexes/walk.ts +1 -1
- package/src/labels/audit.ts +1 -1
- package/src/markdown/ceiling.ts +1 -1
- package/src/markdown/files.ts +1 -1
- package/src/migrate/apply.ts +1 -1
- package/src/pr/bijection.ts +1 -1
- package/src/pr/evidence.ts +96 -43
- package/src/pr/local.ts +16 -10
- package/src/pr/preview.ts +78 -2
- package/src/record-root.ts +1 -0
- package/src/records/backup.ts +2 -1
- package/src/records/push-guard.ts +1 -1
- package/src/records/stale-canonical.ts +146 -0
- package/src/records/stale.ts +1 -1
- package/src/sandbox/headless/dispatch.ts +264 -0
- package/src/sandbox/headless/run.ts +653 -0
- package/src/sandbox/headless/watch.ts +145 -0
- package/src/sandbox/hooks.ts +128 -0
- package/src/sandbox/provision.ts +607 -0
- package/src/sandbox/tree.ts +99 -4
- package/src/secrets/marker.ts +2 -2
- package/src/secrets/scan.ts +2 -2
- package/src/sessions/claim.ts +1 -1
- package/src/sessions/resolve.ts +1 -1
- package/src/sessions/transfer/bundle.ts +1 -1
- package/src/shipped/references.ts +2 -2
- package/src/slides/convert/export.ts +2 -16
- package/src/slides/decks.ts +110 -0
- package/src/slides/package/fonts.ts +6 -2
- package/src/standards/audit.ts +2 -2
- package/src/standards/read.ts +1 -1
- package/src/sync/check.ts +2 -2
- package/src/sync/engine.ts +2 -2
- package/src/sync/git.ts +1 -1
- package/src/sync/history.ts +1 -1
- package/src/sync/reverse.ts +1 -1
- package/src/sync/seeds-report.ts +1 -1
- package/src/sync/target.ts +1 -1
- package/src/sync/workflow.ts +1 -1
- package/src/targets/pulls.ts +2 -2
- package/src/targets/sweep.ts +2 -2
- package/src/tasks/answers.ts +1 -1
- package/src/tasks/archive.ts +1 -1
- package/src/tasks/reach.ts +1 -1
- package/src/tasks/trunk.ts +1 -1
- package/src/teach/nav.ts +1 -1
- package/src/tooling/inject.ts +2 -2
- package/src/tooling/subfolder.ts +1 -1
- package/src/web/readme-citations.ts +2 -2
- package/src/worktrees/bare-flag.ts +1 -1
- package/src/worktrees/reclaim.ts +2 -2
- package/src/worktrees/remove.ts +1 -1
- package/standards/architecture.md +1 -0
- package/standards/canvas.md +3 -2
- package/standards/requirements.md +2 -0
- package/standards/skill-practice.md +2 -1
- package/standards/skill.md +2 -0
- package/standards/wiki.md +12 -3
- package/tooling/base/configs/.github/workflows/pr-local-preview.yml +2 -2
- package/scripts/lib/sandbox-dispatch.sh +0 -190
- package/scripts/manage-sandbox.sh +0 -472
- package/src/slides/layouts.ts +0 -478
- package/src/slides/parse.ts +0 -84
- package/src/slides/render.ts +0 -110
- package/src/slides/styles.ts +0 -96
- /package/claude/skills/write-human/references/{source-material.md → adopted.md} +0 -0
- /package/src/{commands/feedback-format.ts → feedback/body.ts} +0 -0
- /package/src/{github-format.ts → feedback/github-format.ts} +0 -0
- /package/src/{git-base.ts → git/base.ts} +0 -0
- /package/src/{git-env.ts → git/env.ts} +0 -0
- /package/src/{frontmatter.ts → markdown/frontmatter.ts} +0 -0
- /package/src/{binary.ts → sweep/binary.ts} +0 -0
- /package/src/{exempt-marker.ts → sweep/exempt-marker.ts} +0 -0
- /package/src/{copy.ts → sync/copy.ts} +0 -0
- /package/src/{target.ts → targets/validate.ts} +0 -0
- /package/src/{paths.ts → tasks/paths.ts} +0 -0
- /package/src/{seed-marker.ts → tooling/seed-marker.ts} +0 -0
package/src/commands/migrate.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { existsSync, readFileSync } from 'node:fs'
|
|
2
2
|
import { join } from 'node:path'
|
|
3
3
|
import type { Command } from 'commander'
|
|
4
|
-
import { listRepositoryFiles } from '@/git
|
|
4
|
+
import { listRepositoryFiles } from '@/git/files'
|
|
5
5
|
import { indexSourceRules } from '@/gov/adapter'
|
|
6
6
|
import { applyRecordsMove, applyRename, readSources } from '@/migrate/apply'
|
|
7
7
|
import { isToolkitOwned, planRename, type RenamePlan } from '@/migrate/plan'
|
package/src/commands/pr.ts
CHANGED
|
@@ -4,7 +4,7 @@ import { basename, join, resolve } from 'node:path'
|
|
|
4
4
|
import { $ } from 'bun'
|
|
5
5
|
import type { Command } from 'commander'
|
|
6
6
|
import { execa } from 'execa'
|
|
7
|
-
import { gitEnv } from '@/git
|
|
7
|
+
import { gitEnv } from '@/git/env'
|
|
8
8
|
import {
|
|
9
9
|
listChangedFiles,
|
|
10
10
|
listIgnoreAdditions,
|
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
parseIgnoreAdditions,
|
|
14
14
|
type RenamePair,
|
|
15
15
|
resolveBaseRef,
|
|
16
|
-
} from '@/git
|
|
16
|
+
} from '@/git/files'
|
|
17
17
|
import {
|
|
18
18
|
type Bijection,
|
|
19
19
|
type BijectionRefusal,
|
|
@@ -51,13 +51,13 @@ import {
|
|
|
51
51
|
} from '@/pr/frames'
|
|
52
52
|
import { type HeadRefusal, resolveHead, resolveTip } from '@/pr/head'
|
|
53
53
|
import {
|
|
54
|
+
dropAddressLine,
|
|
54
55
|
findLocalServer,
|
|
55
56
|
type Listener,
|
|
56
57
|
type LocalRefusal,
|
|
57
58
|
type LocalRunner,
|
|
58
59
|
parseLsofListeners,
|
|
59
60
|
parseProcNetTcp,
|
|
60
|
-
stripLocalLine,
|
|
61
61
|
} from '@/pr/local'
|
|
62
62
|
import { KEY_CHANGES } from '@/pr/paths'
|
|
63
63
|
import {
|
|
@@ -68,6 +68,7 @@ import {
|
|
|
68
68
|
type PreviewRefusal,
|
|
69
69
|
type PreviewRunner,
|
|
70
70
|
type RunRow,
|
|
71
|
+
servesChange,
|
|
71
72
|
type WorkflowFile,
|
|
72
73
|
} from '@/pr/preview'
|
|
73
74
|
import {
|
|
@@ -110,17 +111,12 @@ interface EvidenceOptions extends ReadOptions {
|
|
|
110
111
|
|
|
111
112
|
interface LocalOptions extends ReadOptions {
|
|
112
113
|
readonly remove?: boolean
|
|
113
|
-
readonly note?: string
|
|
114
114
|
}
|
|
115
115
|
|
|
116
116
|
/** Shared by every verb that resolves a pull request from the checkout's branch. */
|
|
117
117
|
const AMBIGUOUS_PULL =
|
|
118
118
|
'More than one pull request is open on this branch, each against another base. Name the pull request number.'
|
|
119
119
|
|
|
120
|
-
/** What replaces the local address line once the pull request closes. */
|
|
121
|
-
const LOCAL_REMOVED_NOTE =
|
|
122
|
-
'_Local preview removed when the pull request closed._'
|
|
123
|
-
|
|
124
120
|
/** How long the probe waits on a listener before reading it as not a server. */
|
|
125
121
|
const LOCAL_PROBE_TIMEOUT_MS = 2_000
|
|
126
122
|
|
|
@@ -194,7 +190,7 @@ const PREVIEW_TIMEOUT_MINUTES = 15
|
|
|
194
190
|
const PREVIEW_POLL_MS = 15_000
|
|
195
191
|
|
|
196
192
|
const PREVIEW_REFUSALS: Record<
|
|
197
|
-
PreviewRefusal | 'bad-timeout' | 'check-timeout',
|
|
193
|
+
PreviewRefusal | 'bad-timeout' | 'check-timeout' | 'unreadable-changes',
|
|
198
194
|
string
|
|
199
195
|
> = {
|
|
200
196
|
'bad-timeout': '--timeout takes a positive number of minutes.',
|
|
@@ -202,6 +198,8 @@ const PREVIEW_REFUSALS: Record<
|
|
|
202
198
|
'--check only reads the deploy runs and waits on nothing, so it takes no --timeout.',
|
|
203
199
|
'no-deploy':
|
|
204
200
|
'No workflow under .github/workflows/ runs pages deploy and carries a workflow_dispatch trigger, so there is nothing to dispatch.',
|
|
201
|
+
unserved:
|
|
202
|
+
"The deploy workflow's push path filter matches no path this pull request changed, so the site it publishes would not show the change. Nothing was dispatched.",
|
|
205
203
|
// biome-ignore lint/suspicious/noTemplateCurlyInString: a workflow expression, not a template
|
|
206
204
|
unfenced:
|
|
207
205
|
'The deploy workflow passes no --branch=${{ github.ref_name }}, so a dispatch from this branch would publish it to production. Add the flag before asking for a preview.',
|
|
@@ -209,6 +207,8 @@ const PREVIEW_REFUSALS: Record<
|
|
|
209
207
|
'The deploy never printed a canon-preview-alias line, so no address could be read. Add the alias step from the cloudflare stack reference to the workflow.',
|
|
210
208
|
'gh-failed':
|
|
211
209
|
'gh could not list or dispatch the deploy workflow for this branch.',
|
|
210
|
+
'unreadable-changes':
|
|
211
|
+
'GitHub could not list what this pull request changed, so whether the deploy serves it is unknown. Nothing was dispatched.',
|
|
212
212
|
'run-failed':
|
|
213
213
|
'The deploy run finished without succeeding, so no preview was published. Read the run log.',
|
|
214
214
|
timeout:
|
|
@@ -508,7 +508,7 @@ export function register(program: Command): void {
|
|
|
508
508
|
.option('--json', 'Add a machine-readable record on stdout')
|
|
509
509
|
.option(
|
|
510
510
|
'--preview <url>',
|
|
511
|
-
'
|
|
511
|
+
'Put this preview address on the line under the heading, from canon pr preview',
|
|
512
512
|
)
|
|
513
513
|
.option(
|
|
514
514
|
'--checklist <path>',
|
|
@@ -516,7 +516,7 @@ export function register(program: Command): void {
|
|
|
516
516
|
)
|
|
517
517
|
.option(
|
|
518
518
|
'--local <url>',
|
|
519
|
-
"Add this worktree's running server
|
|
519
|
+
"Add this worktree's running server to the address line, from canon pr local",
|
|
520
520
|
)
|
|
521
521
|
.option(
|
|
522
522
|
'--check',
|
|
@@ -544,11 +544,21 @@ export function register(program: Command): void {
|
|
|
544
544
|
' would-empty the render holds no cases and the marked comment holds',
|
|
545
545
|
' some, so no body is printed and a person edits the comment',
|
|
546
546
|
'',
|
|
547
|
-
|
|
548
|
-
'
|
|
549
|
-
'
|
|
550
|
-
'
|
|
551
|
-
'
|
|
547
|
+
'Every body opens with `## Evidence`, then one address line joining',
|
|
548
|
+
'the hosted and local previews with " · ", carrying whichever apply,',
|
|
549
|
+
'then the Base and Head line when there are screenshots.',
|
|
550
|
+
'',
|
|
551
|
+
'--preview puts the hosted address on that line. With no evidence in',
|
|
552
|
+
'the diff, the body is the heading, that line, and the marker alone,',
|
|
553
|
+
'reported as ok, so the preview still lands in one comment a later',
|
|
554
|
+
'call can edit. Without --preview, an address the marked comment',
|
|
555
|
+
'already carries is carried into the new body, so a re-render after a',
|
|
556
|
+
'push keeps it, unless a deploy workflow resolves and its push path',
|
|
557
|
+
'filter matches no path the pull request changed, in which case the',
|
|
558
|
+
'carried hosted address is dropped. An explicit --preview is always',
|
|
559
|
+
'kept. The address region above the comparison is read for each',
|
|
560
|
+
'prefix wherever it sits, so a comment that opens on the addresses',
|
|
561
|
+
'still carries them forward.',
|
|
552
562
|
'',
|
|
553
563
|
'--checklist closes the body with a visual checklist, below the',
|
|
554
564
|
'comparison it annotates. A checklist the marked comment already',
|
|
@@ -558,17 +568,17 @@ export function register(program: Command): void {
|
|
|
558
568
|
'image renders a marked body holding the checklist, so a later call',
|
|
559
569
|
'finds and edits that comment.',
|
|
560
570
|
'',
|
|
561
|
-
'--local adds a **Local preview:**
|
|
562
|
-
'or
|
|
563
|
-
'
|
|
571
|
+
'--local adds a **Local preview:** segment after any hosted one on the',
|
|
572
|
+
'address line, or carries the line alone, and is carried forward the',
|
|
573
|
+
'same way. It does not by itself turn no-evidence into ok, so a',
|
|
564
574
|
'branch with a server running and nothing to show posts no link-only',
|
|
565
575
|
'comment. Together with --checklist the link and the checklist land in',
|
|
566
576
|
'one comment.',
|
|
567
577
|
'',
|
|
568
578
|
'Both reasons carry what the marked comment already posted, each field',
|
|
569
579
|
'present only when that comment holds it:',
|
|
570
|
-
' preview the hosted **Preview:** address the comment
|
|
571
|
-
' local the **Local preview:** address
|
|
580
|
+
' preview the hosted **Preview:** address the comment carries',
|
|
581
|
+
' local the **Local preview:** address beside it',
|
|
572
582
|
' checklist the checklist between its delimiters, ticks included',
|
|
573
583
|
'These come from the comment already posted, never from the flags this',
|
|
574
584
|
'call passed. A checklist the caller posted raw after a refused render',
|
|
@@ -582,8 +592,9 @@ export function register(program: Command): void {
|
|
|
582
592
|
' owed `owed` lists evidence, preview, or both, in that order',
|
|
583
593
|
'evidence is owed when an evidence image changed and no comment carries',
|
|
584
594
|
'the marker. preview is owed when either holds, a deploy workflow in',
|
|
585
|
-
|
|
586
|
-
'
|
|
595
|
+
'this checkout resolves, its push path filter matches a path the pull',
|
|
596
|
+
'request changed, and the marked comment carries no **Preview:**',
|
|
597
|
+
'address. A failed deploy reads the same as a skipped one.',
|
|
587
598
|
'The record carries `owed` and the same marked fields. --check refuses',
|
|
588
599
|
'with --preview, --local, or --checklist as check-writes.',
|
|
589
600
|
'',
|
|
@@ -636,9 +647,16 @@ export function register(program: Command): void {
|
|
|
636
647
|
'A deploy without the --branch flag is refused before anything runs,',
|
|
637
648
|
'because Pages publishes an unfenced deploy to production.',
|
|
638
649
|
'',
|
|
650
|
+
"The pull request's changed paths are then matched against the",
|
|
651
|
+
"workflow's own on.push.paths or paths-ignore filter, since a dispatch",
|
|
652
|
+
'ignores that filter and would publish a site showing none of the',
|
|
653
|
+
'change. A workflow with neither filter serves every change.',
|
|
654
|
+
'',
|
|
639
655
|
'Read `reason` on the JSON record:',
|
|
640
656
|
' ok the preview was published, with its address in `url`',
|
|
641
657
|
' no-deploy no dispatchable workflow runs pages deploy',
|
|
658
|
+
' unserved the push filter matches no changed path, so nothing was',
|
|
659
|
+
' dispatched, and --check answers the same',
|
|
642
660
|
' unfenced the deploy passes no --branch, so nothing was dispatched',
|
|
643
661
|
' no-alias the workflow prints no canon-preview-alias line',
|
|
644
662
|
' run-failed the deploy run finished without succeeding',
|
|
@@ -675,15 +693,7 @@ export function register(program: Command): void {
|
|
|
675
693
|
.helpOption('-h, --help', 'Show this help message')
|
|
676
694
|
.option('--root <path>', 'Worktree to read, defaulting to the cwd')
|
|
677
695
|
.option('--json', 'Add a machine-readable record on stdout')
|
|
678
|
-
.option(
|
|
679
|
-
'--remove',
|
|
680
|
-
"Replace the evidence comment's local preview line with a note",
|
|
681
|
-
)
|
|
682
|
-
.option(
|
|
683
|
-
'--note <text>',
|
|
684
|
-
'What replaces the line on --remove',
|
|
685
|
-
LOCAL_REMOVED_NOTE,
|
|
686
|
-
)
|
|
696
|
+
.option('--remove', "Drop the evidence comment's preview address line")
|
|
687
697
|
.addHelpText(
|
|
688
698
|
'after',
|
|
689
699
|
[
|
|
@@ -700,16 +710,19 @@ export function register(program: Command): void {
|
|
|
700
710
|
'without it.',
|
|
701
711
|
'',
|
|
702
712
|
'--remove reads the pull request comment carrying the pr-evidence',
|
|
703
|
-
'marker and
|
|
704
|
-
'
|
|
713
|
+
'marker and drops its address line, the **Preview:** and **Local',
|
|
714
|
+
'preview:** segments together, leaving no note in its place. It edits',
|
|
715
|
+
'the comment itself so a close workflow with no session can call it,',
|
|
716
|
+
'and drops the hosted link too because the same close deletes the',
|
|
717
|
+
"branch's preview deployments.",
|
|
705
718
|
'',
|
|
706
719
|
'Read `reason` on the JSON record:',
|
|
707
720
|
' ok a page answered, with its address in `url`',
|
|
708
721
|
' no-server nothing inside this worktree served a page',
|
|
709
722
|
' no-listener-reader neither lsof nor /proc is available',
|
|
710
|
-
' removed --remove
|
|
723
|
+
' removed --remove dropped the line',
|
|
711
724
|
' no-comment --remove found no marked comment, a no-op',
|
|
712
|
-
' no-line --remove found no
|
|
725
|
+
' no-line --remove found no address line, a no-op',
|
|
713
726
|
'',
|
|
714
727
|
'Exit codes:',
|
|
715
728
|
' 0 a server was found, or --remove finished, including a no-op',
|
|
@@ -1597,18 +1610,24 @@ async function runReviewState(
|
|
|
1597
1610
|
return 0
|
|
1598
1611
|
}
|
|
1599
1612
|
|
|
1613
|
+
interface PullFiles {
|
|
1614
|
+
/** Each path that still exists at the head, tagged with whether the pull request added it. */
|
|
1615
|
+
readonly present: ReadonlyMap<string, boolean>
|
|
1616
|
+
/** Each path the pull request removed, which a deploy's push filter still counts. */
|
|
1617
|
+
readonly removed: readonly string[]
|
|
1618
|
+
}
|
|
1619
|
+
|
|
1600
1620
|
/**
|
|
1601
|
-
* The paths a pull request changed
|
|
1602
|
-
*
|
|
1603
|
-
*
|
|
1604
|
-
* first view. `renamed` and `copied` count as added, since the new path has no
|
|
1621
|
+
* The paths a pull request changed, read through the paginated files endpoint
|
|
1622
|
+
* so the set is the same from any checkout and never capped at the first
|
|
1623
|
+
* view. `renamed` and `copied` count as added, since the new path has no
|
|
1605
1624
|
* counterpart at the merge base. Returns undefined when the read fails, which
|
|
1606
1625
|
* refuses rather than rendering a short set.
|
|
1607
1626
|
*/
|
|
1608
1627
|
async function listPullFiles(
|
|
1609
1628
|
cwd: string,
|
|
1610
1629
|
number: number,
|
|
1611
|
-
): Promise<
|
|
1630
|
+
): Promise<PullFiles | undefined> {
|
|
1612
1631
|
const stdout = await gh(cwd, [
|
|
1613
1632
|
'api',
|
|
1614
1633
|
'--paginate',
|
|
@@ -1617,15 +1636,19 @@ async function listPullFiles(
|
|
|
1617
1636
|
'.[] | [.status, .filename] | @tsv',
|
|
1618
1637
|
])
|
|
1619
1638
|
if (stdout === null) return undefined
|
|
1620
|
-
const
|
|
1639
|
+
const present = new Map<string, boolean>()
|
|
1640
|
+
const removed: string[] = []
|
|
1621
1641
|
for (const line of stdout.split('\n').filter(Boolean)) {
|
|
1622
1642
|
const [status, path] = line.split('\t')
|
|
1623
|
-
if (status === undefined || path === undefined
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
files.set(path, status !== 'modified' && status !== 'changed')
|
|
1643
|
+
if (status === undefined || path === undefined) continue
|
|
1644
|
+
if (status === 'removed') removed.push(path)
|
|
1645
|
+
else present.set(path, status !== 'modified' && status !== 'changed')
|
|
1627
1646
|
}
|
|
1628
|
-
return
|
|
1647
|
+
return { present, removed }
|
|
1648
|
+
}
|
|
1649
|
+
|
|
1650
|
+
function everyChangedPath(files: PullFiles): string[] {
|
|
1651
|
+
return [...files.present.keys(), ...files.removed]
|
|
1629
1652
|
}
|
|
1630
1653
|
|
|
1631
1654
|
/**
|
|
@@ -1729,8 +1752,8 @@ async function runEvidence(
|
|
|
1729
1752
|
}
|
|
1730
1753
|
|
|
1731
1754
|
const grouped = await groupEvidence(
|
|
1732
|
-
[...pullFiles.keys()],
|
|
1733
|
-
async (path) => pullFiles.get(path) === false,
|
|
1755
|
+
[...pullFiles.present.keys()],
|
|
1756
|
+
async (path) => pullFiles.present.get(path) === false,
|
|
1734
1757
|
)
|
|
1735
1758
|
|
|
1736
1759
|
let existingCases = 0
|
|
@@ -1766,13 +1789,20 @@ async function runEvidence(
|
|
|
1766
1789
|
...(carriedChecklist !== undefined && { checklist: carriedChecklist }),
|
|
1767
1790
|
}
|
|
1768
1791
|
|
|
1792
|
+
// A deploy that resolves and does not build from any changed path makes a
|
|
1793
|
+
// carried hosted link point at a site that shows none of this change.
|
|
1794
|
+
const deploy = findDeployWorkflow(await readWorkflows(root))
|
|
1795
|
+
const deployServesChange =
|
|
1796
|
+
deploy.kind === 'found' &&
|
|
1797
|
+
servesChange(deploy.filter, everyChangedPath(pullFiles))
|
|
1798
|
+
const isUnserved = deploy.kind === 'found' && !deployServesChange
|
|
1799
|
+
|
|
1769
1800
|
if (isCheck) {
|
|
1770
1801
|
const owed = readOwed({
|
|
1771
1802
|
hasEvidenceChange: grouped.kind === 'read',
|
|
1772
1803
|
hasMarkedComment: hasMarkedEvidenceComment(comments),
|
|
1773
1804
|
carriedPreview: carriedPreview !== undefined,
|
|
1774
|
-
|
|
1775
|
-
findDeployWorkflow(await readWorkflows(root)).kind === 'found',
|
|
1805
|
+
deployServesChange,
|
|
1776
1806
|
})
|
|
1777
1807
|
logStep(owed.length === 0 ? 'Settled' : 'Owed')
|
|
1778
1808
|
logInfo(
|
|
@@ -1838,7 +1868,7 @@ async function runEvidence(
|
|
|
1838
1868
|
)
|
|
1839
1869
|
}
|
|
1840
1870
|
|
|
1841
|
-
const preview = opts.preview ?? carriedPreview
|
|
1871
|
+
const preview = opts.preview ?? (isUnserved ? undefined : carriedPreview)
|
|
1842
1872
|
const local = opts.local ?? carriedLocal
|
|
1843
1873
|
const checklist = suppliedChecklist ?? carriedChecklist
|
|
1844
1874
|
const states = grouped.kind === 'read' ? grouped.states : []
|
|
@@ -2037,6 +2067,24 @@ async function runPreview(
|
|
|
2037
2067
|
}
|
|
2038
2068
|
const { identity } = read
|
|
2039
2069
|
|
|
2070
|
+
// A dispatch ignores the workflow's own push filter, so the filter is read
|
|
2071
|
+
// here, ahead of both the mint and the check, rather than left to GitHub.
|
|
2072
|
+
const changed =
|
|
2073
|
+
identity.number === undefined
|
|
2074
|
+
? undefined
|
|
2075
|
+
: await listPullFiles(root, identity.number)
|
|
2076
|
+
if (changed === undefined) {
|
|
2077
|
+
return refuseWith(
|
|
2078
|
+
'unreadable-changes',
|
|
2079
|
+
PREVIEW_REFUSALS['unreadable-changes'],
|
|
2080
|
+
emitJson,
|
|
2081
|
+
root,
|
|
2082
|
+
)
|
|
2083
|
+
}
|
|
2084
|
+
if (!servesChange(pick.filter, everyChangedPath(changed))) {
|
|
2085
|
+
return refuseWith('unserved', PREVIEW_REFUSALS.unserved, emitJson, root)
|
|
2086
|
+
}
|
|
2087
|
+
|
|
2040
2088
|
if (opts.check === true) {
|
|
2041
2089
|
return runPreviewCheck(root, emitJson, pick.path, identity)
|
|
2042
2090
|
}
|
|
@@ -2280,7 +2328,7 @@ async function runLocal(opts: LocalOptions): Promise<number> {
|
|
|
2280
2328
|
}
|
|
2281
2329
|
|
|
2282
2330
|
/**
|
|
2283
|
-
*
|
|
2331
|
+
* Drops the address line on the marked comment. The verb writes here rather
|
|
2284
2332
|
* than handing a body back, because its caller is a close workflow with no
|
|
2285
2333
|
* session to post one.
|
|
2286
2334
|
*/
|
|
@@ -2290,7 +2338,6 @@ async function runLocalRemove(
|
|
|
2290
2338
|
): Promise<number> {
|
|
2291
2339
|
const root = resolve(opts.root ?? process.cwd())
|
|
2292
2340
|
const emitJson = opts.json ?? false
|
|
2293
|
-
const note = opts.note ?? LOCAL_REMOVED_NOTE
|
|
2294
2341
|
|
|
2295
2342
|
intro('canon pr local --remove')
|
|
2296
2343
|
|
|
@@ -2333,9 +2380,9 @@ async function runLocalRemove(
|
|
|
2333
2380
|
return finish('no-comment', 'No comment carries the evidence marker.')
|
|
2334
2381
|
}
|
|
2335
2382
|
|
|
2336
|
-
const
|
|
2337
|
-
if (
|
|
2338
|
-
return finish('no-line', 'The evidence comment carries no
|
|
2383
|
+
const dropped = dropAddressLine(marked.body)
|
|
2384
|
+
if (dropped === undefined) {
|
|
2385
|
+
return finish('no-line', 'The evidence comment carries no address line.')
|
|
2339
2386
|
}
|
|
2340
2387
|
|
|
2341
2388
|
const patched = await gh(root, [
|
|
@@ -2344,7 +2391,7 @@ async function runLocalRemove(
|
|
|
2344
2391
|
'PATCH',
|
|
2345
2392
|
`repos/{owner}/{repo}/issues/comments/${commentId}`,
|
|
2346
2393
|
'-f',
|
|
2347
|
-
`body=${
|
|
2394
|
+
`body=${dropped}`,
|
|
2348
2395
|
])
|
|
2349
2396
|
if (patched === null) {
|
|
2350
2397
|
return refuseWith('gh-failed', LOCAL_REFUSALS['gh-failed'], emitJson, root)
|
package/src/commands/records.ts
CHANGED
|
@@ -30,6 +30,11 @@ import {
|
|
|
30
30
|
type StaleReport,
|
|
31
31
|
staleMemory,
|
|
32
32
|
} from '@/records/stale'
|
|
33
|
+
import {
|
|
34
|
+
type CanonicalDoc,
|
|
35
|
+
type CanonicalReport,
|
|
36
|
+
staleCanonical,
|
|
37
|
+
} from '@/records/stale-canonical'
|
|
33
38
|
import {
|
|
34
39
|
type Finding,
|
|
35
40
|
type FindingRemedy,
|
|
@@ -51,7 +56,7 @@ import {
|
|
|
51
56
|
pipeOutput,
|
|
52
57
|
plural,
|
|
53
58
|
} from '@/ui'
|
|
54
|
-
import { currentWorktreeRoot, mainWorktreeRoot } from '@/worktree'
|
|
59
|
+
import { currentWorktreeRoot, mainWorktreeRoot } from '@/git/worktree'
|
|
55
60
|
|
|
56
61
|
/** Returned when a record carries a finding, which is the gating result. */
|
|
57
62
|
const EXIT_FINDINGS = 2
|
|
@@ -85,8 +90,11 @@ interface StaleCommandOptions extends ValidateCommandOptions {
|
|
|
85
90
|
readonly days?: string
|
|
86
91
|
}
|
|
87
92
|
|
|
88
|
-
/**
|
|
89
|
-
|
|
93
|
+
/**
|
|
94
|
+
* The kinds `stale` reads. A memory entry ages by days in the shared pen, and
|
|
95
|
+
* a canonical doc ages by the releases shipped since its review.
|
|
96
|
+
*/
|
|
97
|
+
const STALE_KINDS = ['memory', 'canonical'] as const
|
|
90
98
|
|
|
91
99
|
interface OrdinalCommandOptions extends ValidateCommandOptions {
|
|
92
100
|
readonly claim?: boolean
|
|
@@ -270,14 +278,17 @@ export function register(program: Command): void {
|
|
|
270
278
|
.option('--json', 'Add a machine-readable record on stdout')
|
|
271
279
|
.option(
|
|
272
280
|
'--days <n>',
|
|
273
|
-
`Days after a review before
|
|
281
|
+
`Days after a review before a memory entry is due again (default ${DEFAULT_REVIEW_DAYS})`,
|
|
282
|
+
)
|
|
283
|
+
.option(
|
|
284
|
+
'--root <path>',
|
|
285
|
+
'Project root, defaulting to the main worktree except on canonical',
|
|
274
286
|
)
|
|
275
|
-
.option('--root <path>', 'Project root, defaulting to the main worktree')
|
|
276
287
|
.addHelpText(
|
|
277
288
|
'after',
|
|
278
289
|
[
|
|
279
290
|
'',
|
|
280
|
-
'
|
|
291
|
+
'memory: reads the top-level entries of the memory folder, never review/, archive/,',
|
|
281
292
|
'or index.md. An entry is due when it carries no reviewed date, a reviewed',
|
|
282
293
|
'value that is not a date, or one older than --days. A path is a backticked',
|
|
283
294
|
'token holding a / and a file extension, resolved against the project root',
|
|
@@ -288,17 +299,24 @@ export function register(program: Command): void {
|
|
|
288
299
|
'Entries are ordered due first, then those citing a missing path, then the',
|
|
289
300
|
'longest unreviewed, then by name, so a review takes the first N as a batch.',
|
|
290
301
|
'',
|
|
302
|
+
'canonical: reads REQUIREMENTS.md and ARCHITECTURE.md at whichever surface',
|
|
303
|
+
'root carries each, in the current worktree since both are tracked. Each',
|
|
304
|
+
'reports its reviewed date and the release tags merged into HEAD after that',
|
|
305
|
+
'day, or never when it carries no date. --days does not apply.',
|
|
306
|
+
'',
|
|
291
307
|
'Exit codes:',
|
|
292
308
|
' 0 the reading completed, whatever it found',
|
|
293
309
|
' 1 refused, with the reason on stderr or in the JSON record',
|
|
294
310
|
'',
|
|
295
311
|
'It gates nothing and writes nothing. A due entry is a queue position rather',
|
|
296
|
-
'than a failure, and a missing path is a prompt for the
|
|
312
|
+
'than a failure, and a missing path or a release count is a prompt for the',
|
|
313
|
+
'review to judge.',
|
|
297
314
|
'',
|
|
298
315
|
'Examples:',
|
|
299
316
|
' canon records stale memory',
|
|
300
317
|
' canon records stale memory --json',
|
|
301
318
|
' canon records stale memory --days 60 --json',
|
|
319
|
+
' canon records stale canonical --json',
|
|
302
320
|
'',
|
|
303
321
|
].join('\n'),
|
|
304
322
|
)
|
|
@@ -560,6 +578,8 @@ async function runStale(
|
|
|
560
578
|
)
|
|
561
579
|
}
|
|
562
580
|
|
|
581
|
+
if (kind === 'canonical') return runStaleCanonical(opts, emitJson)
|
|
582
|
+
|
|
563
583
|
const days = Number(opts.days ?? DEFAULT_REVIEW_DAYS)
|
|
564
584
|
|
|
565
585
|
if (!Number.isInteger(days) || days <= 0) {
|
|
@@ -588,6 +608,68 @@ async function runStale(
|
|
|
588
608
|
return 0
|
|
589
609
|
}
|
|
590
610
|
|
|
611
|
+
/**
|
|
612
|
+
* Both docs are tracked, so the root is the checkout the caller stands in. The
|
|
613
|
+
* main worktree would answer from its own copy and miss a stamp this branch
|
|
614
|
+
* just wrote.
|
|
615
|
+
*/
|
|
616
|
+
async function runStaleCanonical(
|
|
617
|
+
opts: StaleCommandOptions,
|
|
618
|
+
emitJson: boolean,
|
|
619
|
+
): Promise<number> {
|
|
620
|
+
if (opts.days !== undefined) {
|
|
621
|
+
return reportRefusal(
|
|
622
|
+
'canon records stale',
|
|
623
|
+
{
|
|
624
|
+
reason: 'bad-days',
|
|
625
|
+
message:
|
|
626
|
+
'--days does not apply to canonical, which counts releases rather than days.',
|
|
627
|
+
},
|
|
628
|
+
emitJson,
|
|
629
|
+
)
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
const root = opts.root ?? (await currentWorktreeRoot())
|
|
633
|
+
const outcome = await staleCanonical(root)
|
|
634
|
+
|
|
635
|
+
if (!outcome.ok)
|
|
636
|
+
return reportRefusal('canon records stale', outcome, emitJson)
|
|
637
|
+
|
|
638
|
+
if (emitJson) {
|
|
639
|
+
process.stdout.write(`${JSON.stringify(outcome)}\n`)
|
|
640
|
+
return 0
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
intro('canon records stale')
|
|
644
|
+
logStep('Canonical')
|
|
645
|
+
|
|
646
|
+
if (outcome.docs.length === 0) {
|
|
647
|
+
logInfo('neither REQUIREMENTS.md nor ARCHITECTURE.md exists')
|
|
648
|
+
} else {
|
|
649
|
+
for (const doc of outcome.docs) logInfo(describeCanonical(doc, outcome))
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
if (!outcome.tagged) logInfo('no release tags merged into HEAD')
|
|
653
|
+
outro()
|
|
654
|
+
return 0
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
function describeCanonical(
|
|
658
|
+
doc: CanonicalDoc,
|
|
659
|
+
outcome: CanonicalReport,
|
|
660
|
+
): string {
|
|
661
|
+
if (doc.reviewed === null) {
|
|
662
|
+
return doc.invalidReviewed === undefined
|
|
663
|
+
? `${doc.path}: never reviewed`
|
|
664
|
+
: `${doc.path}: reviewed value is not a date: ${doc.invalidReviewed}`
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
const since = outcome.tagged
|
|
668
|
+
? `${plural(doc.releasesSince ?? 0, 'release')} since`
|
|
669
|
+
: 'no releases to count'
|
|
670
|
+
return `${doc.path}: reviewed ${doc.reviewed}, ${since}`
|
|
671
|
+
}
|
|
672
|
+
|
|
591
673
|
function staleRow(entry: StaleEntry): string[] {
|
|
592
674
|
return [
|
|
593
675
|
entry.name,
|
package/src/commands/repo.ts
CHANGED