@erclx/aitk 1.1.0 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/claude/.claude-plugin/plugin.json +1 -1
- package/claude/skills/claude-address-review/SKILL.md +5 -6
- package/claude/skills/claude-autoship/SKILL.md +2 -2
- package/claude/skills/claude-design-extract/SKILL.md +3 -5
- package/claude/skills/claude-diagram/SKILL.md +2 -2
- package/claude/skills/claude-docs/SKILL.md +11 -11
- package/claude/skills/claude-feature/SKILL.md +3 -3
- package/claude/skills/claude-groundwork/SKILL.md +2 -2
- package/claude/skills/claude-intake/SKILL.md +1 -1
- package/claude/skills/claude-intake-answer/SKILL.md +1 -1
- package/claude/skills/claude-memory-capture/SKILL.md +7 -9
- package/claude/skills/claude-memory-review/SKILL.md +6 -8
- package/claude/skills/claude-memory-review/references/receipt-format.md +1 -1
- package/claude/skills/claude-orchestrate/SKILL.md +3 -3
- package/claude/skills/claude-orchestrate/references/orchestrator-handoff.md +1 -1
- package/claude/skills/claude-orchestrate/references/orchestrator-resume.md +1 -1
- package/claude/skills/claude-pr-review/SKILL.md +2 -2
- package/claude/skills/claude-review/SKILL.md +1 -1
- package/claude/skills/claude-seed-sync/SKILL.md +1 -1
- package/claude/skills/claude-standards-audit/SKILL.md +4 -4
- package/claude/skills/claude-tasks/SKILL.md +34 -9
- package/claude/skills/claude-teach/SKILL.md +2 -2
- package/claude/skills/claude-ui-test/SKILL.md +1 -1
- package/claude/skills/claude-ux-audit/SKILL.md +2 -4
- package/claude/skills/claude-ux-measure/SKILL.md +1 -1
- package/claude/skills/claude-worktree/SKILL.md +3 -3
- package/claude/skills/create-rule/SKILL.md +2 -2
- package/claude/skills/create-skill/SKILL.md +4 -6
- package/claude/skills/create-snippet/SKILL.md +1 -3
- package/claude/skills/create-standard/SKILL.md +2 -4
- package/claude/skills/decision-escalate/SKILL.md +1 -1
- package/claude/skills/docs-sync/SKILL.md +3 -5
- package/claude/skills/git-commit/SKILL.md +1 -3
- package/claude/skills/git-followup/SKILL.md +1 -1
- package/claude/skills/git-issue/SKILL.md +2 -4
- package/claude/skills/git-pr/SKILL.md +4 -6
- package/claude/skills/git-split/SKILL.md +1 -1
- package/claude/skills/git-stage/SKILL.md +1 -3
- package/claude/skills/migration-claude-md/SKILL.md +2 -2
- package/claude/skills/session-resume/SKILL.md +1 -1
- package/claude/skills/setup-gov/SKILL.md +1 -1
- package/claude/skills/setup-indexes/SKILL.md +1 -1
- package/claude/skills/write-human/SKILL.md +2 -2
- package/docs/agents/commands.md +2 -1
- package/docs/agents/index.md +1 -1
- package/docs/agents/markdown-audit.md +3 -1
- package/docs/agents/records.md +32 -4
- package/docs/ai-workflow.md +3 -1
- package/docs/target-projects.md +3 -3
- package/governance/rules/claude/501-markdown.md +1 -1
- package/governance/rules/claude/510-context.md +1 -1
- package/governance/rules/claude/520-wireframes.md +1 -1
- package/governance/rules/claude/530-requirements.md +1 -1
- package/governance/rules/claude/540-architecture.md +1 -1
- package/governance/rules/claude/550-design.md +1 -1
- package/governance/rules/claude/555-tasks.md +1 -1
- package/governance/rules/claude/556-groundwork.md +1 -1
- package/governance/rules/claude/557-intake.md +1 -1
- package/governance/rules/claude/558-plan.md +1 -1
- package/governance/rules/claude/559-memory.md +1 -1
- package/governance/rules/claude/560-diagrams.md +1 -1
- package/governance/rules/claude/561-teach.md +1 -1
- package/governance/rules/claude/562-session.md +1 -1
- package/governance/rules/claude/570-skill.md +1 -1
- package/governance/rules/claude/580-readme.md +1 -1
- package/governance/rules/claude/590-rule-authoring.md +1 -1
- package/governance/rules/claude/591-standard-authoring.md +1 -1
- package/package.json +1 -1
- package/src/cli.ts +2 -1
- package/src/commands/records.ts +145 -7
- package/src/markdown/structure.ts +39 -4
- package/src/records/size.ts +260 -0
- package/standards/tasks.md +3 -1
package/docs/ai-workflow.md
CHANGED
|
@@ -93,10 +93,12 @@ An execution that picks other than the suggestion rewrites the `- Suggested:` li
|
|
|
93
93
|
|
|
94
94
|
`aitk records validate plans` reports where a plan and that standard disagree: a filename that is not `feature-<slug>.md`, a missing required section, a files-to-touch entry naming no file, and a question carrying a suggestion with no answer slot. The same verb takes `groundwork`, `intake`, `memory`, and `teach`, which are governed the same way and were unreachable for the same reason. Nothing fires it automatically, because all five folders are gitignored and every check the repository runs reads changed files from git. It reports and never writes, since the folders are per-machine scratch with no history to recover a wrong repair from.
|
|
95
95
|
|
|
96
|
-
`aitk records push` carries these folders off the disk they live on, and `aitk records pull` brings them back.
|
|
96
|
+
`aitk records push` carries these folders off the disk they live on, and `aitk records pull` brings them back. Nine of them are backed: `groundwork`, `intake`, `memory`, `plans`, `plans-archive`, `review`, `task-archive`, `tasks`, and `teach`. The history lives in a second git directory at `.claude/.records.git` with `.claude/` as its work tree, so every path a task file cites stays where it is.
|
|
97
97
|
|
|
98
98
|
A person points it at a private repository once and both verbs refuse until they have, and `push` refuses when that origin is also a remote of the project, since the payload is the memory pen and the groundwork trails. `.husky/post-merge` runs the push after its archive loop, on every merge rather than only on one that closed a task. See [records](agents/records.md) for the refusal table.
|
|
99
99
|
|
|
100
|
+
`aitk records size` reports what each of these folders holds, heaviest first, along with `.claude/.tmp`. Each row carries the file count, the bytes, how many files were written in the last 7 and 30 days, and the dates of the least and most recently written one. Nothing fails on a number, because a record folder has no correct size. What the verb replaces is a reading somebody had to remember to take: the memory pen went from 44 entries to 236 between two counts made by hand a fortnight apart, and nothing reported the rate in between.
|
|
101
|
+
|
|
100
102
|
A plan that ships is archived, never deleted. `aitk:claude-docs` moves it to `.claude/plans-archive/` and retargets the task file's `Plan:` line at the new location, so a completed task still leads to the reasoning behind it. Both folders are gitignored, which is why a deleted plan had no recovery path. A plan cited by more than one task stays put until the last of them closes, since moving it early would strand every other pointer.
|
|
101
103
|
|
|
102
104
|
The sweep reads the whole board rather than the tasks the session touched. It is the one place the skill reaches past its own rule against editing a task file the session did not change, because a task that closed while an earlier run missed its archive is exactly what the sweep exists to clear. Reaching it is safe: the archive moves the plan and retargets the pointer in the same pass, so an untouched task ends up with a working link rather than a broken one.
|
package/docs/target-projects.md
CHANGED
|
@@ -88,11 +88,11 @@ Run `aitk tooling list --json` and `aitk gov list --json` to see the current cat
|
|
|
88
88
|
|
|
89
89
|
`governance`, `standards`, and `wiki` are skippable:
|
|
90
90
|
|
|
91
|
-
- `--skip governance`: leave `.claude/rules/` empty. Standards still install,
|
|
92
|
-
- `--skip standards`: leave standards out. The governance rules
|
|
91
|
+
- `--skip governance`: leave `.claude/rules/` empty, so no coding standard loads on a file match. Standards still install, and the installed copy is the first root `aitk standards <name>` resolves, so it stays the editable seed a project owns. The preview names any `--add` rules the skip drops, and the run prints the `aitk gov install <stack> <path>` command to add rules afterward, carrying those extras so one paste restores what the skip declined.
|
|
92
|
+
- `--skip standards`: leave standards out. The governance rules are unaffected, since each authority line names `aitk standards <name>` and that command answers from the corpus inside the CLI's own package. Toolkit skills are unaffected too, each naming the copy in its own plugin root. `aitk standards <name>` searches the corpus inside the CLI's own package behind both project roots, so it prints a standard in a project that skipped the install, and `aitk markdown audit` needs no standard at all, its ban sets and checkpoints shipping with the package as data. What the skip costs is the editable copy rather than the enforcement.
|
|
93
93
|
- `--skip wiki`: skip the `.claude/wiki/` scaffold. A target that already carries a root `wiki/` keeps it, since the verb reports that folder rather than migrating it.
|
|
94
94
|
|
|
95
|
-
|
|
95
|
+
The plugin corpus carries runtime behavior rather than reference prose alone, because the pre-publish scan and the branch-slug transform each have a standard of their own, `publish.md` and `slug.md`, cited by the skills that run them.
|
|
96
96
|
|
|
97
97
|
## Add a domain later
|
|
98
98
|
|
|
@@ -8,7 +8,7 @@ paths:
|
|
|
8
8
|
|
|
9
9
|
## Authority
|
|
10
10
|
|
|
11
|
-
- Follow
|
|
11
|
+
- Follow the markdown standard for headings, paragraph and list structure, code spans, punctuation, emphasis, file references, the banned words and spellings, and the wording of a `title` or `description`. It is the single source. Read it with `aitk standards markdown`.
|
|
12
12
|
- Read it before a substantial markdown edit. Do not work the banned words or characters from memory.
|
|
13
13
|
- Run `aitk markdown audit <path>` after the edit, and rewrite the sentence carrying a hit rather than swapping the token for a near-synonym.
|
|
14
14
|
- Voice, rhythm, and sentence construction are a separate topic. `500-prose` routes them.
|
|
@@ -26,4 +26,4 @@ Do not put a sibling bullet's design in the past with one of these.
|
|
|
26
26
|
|
|
27
27
|
## Authority
|
|
28
28
|
|
|
29
|
-
- Follow
|
|
29
|
+
- Follow the context standard for entry shape: frontmatter, sections, length, and what goes in. It is the single source. Read it with `aitk standards context`.
|
|
@@ -16,5 +16,5 @@ paths:
|
|
|
16
16
|
|
|
17
17
|
## Authority
|
|
18
18
|
|
|
19
|
-
- Follow
|
|
19
|
+
- Follow the wireframes standard for layout and interaction intent: ASCII layout, region labels, variants, copy, and what moves to `.claude/context/`. It is the single source. Read it with `aitk standards wireframes`.
|
|
20
20
|
- Read it before adding or revising a surface.
|
|
@@ -16,4 +16,4 @@ paths:
|
|
|
16
16
|
|
|
17
17
|
## Authority
|
|
18
18
|
|
|
19
|
-
- Follow
|
|
19
|
+
- Follow the requirements standard for what belongs in the problem, goals, non-goals, MVP features, tech stack, and constraints. It is the single source. Read it with `aitk standards requirements`.
|
|
@@ -18,4 +18,4 @@ paths:
|
|
|
18
18
|
|
|
19
19
|
## Authority
|
|
20
20
|
|
|
21
|
-
- Follow
|
|
21
|
+
- Follow the architecture standard for the overview, named decision entries, and risks. It is the single source. Read it with `aitk standards architecture`.
|
|
@@ -16,4 +16,4 @@ paths:
|
|
|
16
16
|
|
|
17
17
|
## Authority
|
|
18
18
|
|
|
19
|
-
- Follow
|
|
19
|
+
- Follow the design standard for visual intent, the token tables, and the render contract. It is the single source. Read it with `aitk standards design`.
|
|
@@ -16,5 +16,5 @@ paths:
|
|
|
16
16
|
|
|
17
17
|
## Authority
|
|
18
18
|
|
|
19
|
-
- Follow
|
|
19
|
+
- Follow the tasks standard for filenames, frontmatter, what belongs, and the task file format. It is the single source. Read it with `aitk standards tasks`.
|
|
20
20
|
- Never hand-edit `.claude/tasks/index.md`. A hook regenerates it from sibling frontmatter.
|
|
@@ -13,4 +13,4 @@ paths:
|
|
|
13
13
|
|
|
14
14
|
## Authority
|
|
15
15
|
|
|
16
|
-
- Follow
|
|
16
|
+
- Follow the groundwork standard for reserved numbering, frontmatter and dating, what each required file holds, and the conventions a track keeps. It is the single source. Read it with `aitk standards groundwork`.
|
|
@@ -13,4 +13,4 @@ paths:
|
|
|
13
13
|
|
|
14
14
|
## Authority
|
|
15
15
|
|
|
16
|
-
- Follow
|
|
16
|
+
- Follow the intake standard for the folder layout, frontmatter and dating, the item format, and retrieval. It is the single source. Read it with `aitk standards intake`.
|
|
@@ -20,4 +20,4 @@ paths:
|
|
|
20
20
|
|
|
21
21
|
## Authority
|
|
22
22
|
|
|
23
|
-
- Follow
|
|
23
|
+
- Follow the plan standard for the filename and slug, the required sections, the suggested-and-answer contract, and the lifecycle. It is the single source. Read it with `aitk standards plan`.
|
|
@@ -17,4 +17,4 @@ paths:
|
|
|
17
17
|
|
|
18
18
|
## Authority
|
|
19
19
|
|
|
20
|
-
- Follow
|
|
20
|
+
- Follow the memory standard for the filename and type prefix, the frontmatter, the body shape per type, links between entries, and the lifecycle. It is the single source. Read it with `aitk standards memory`.
|
|
@@ -9,7 +9,7 @@ paths:
|
|
|
9
9
|
|
|
10
10
|
## Authority
|
|
11
11
|
|
|
12
|
-
- Follow
|
|
12
|
+
- Follow the diagrams standard for Mermaid diagram layout, budgets, accessibility, verification, and explanation prose. It is the single source. Read it with `aitk standards diagrams`.
|
|
13
13
|
- A diagram entry carries structure and flow, not implementation. Read the standard before adding or revising a kind.
|
|
14
14
|
|
|
15
15
|
## Scope
|
|
@@ -16,6 +16,6 @@ paths:
|
|
|
16
16
|
|
|
17
17
|
## Authority
|
|
18
18
|
|
|
19
|
-
- Follow
|
|
19
|
+
- Follow the teach standard for the folder layout, ordinal naming, frontmatter, and the mission and learning-record formats. It is the single source. Read it with `aitk standards teach`.
|
|
20
20
|
- Read `references/glossary.md` inside the `claude-teach` skill for the glossary every workspace carries at its root. It is the single source for the entry shape, the ordering, and which terms the file carries. Read it rather than invoking the skill, which resumes a workspace and runs lessons.
|
|
21
21
|
- Report it rather than proceeding silently when that file does not resolve. It ships with the plugin and this rule ships with the CLI, so a project that installed governance alone does not have it.
|
|
@@ -16,4 +16,4 @@ paths:
|
|
|
16
16
|
|
|
17
17
|
## Authority
|
|
18
18
|
|
|
19
|
-
- Follow
|
|
19
|
+
- Follow the session standard for the filename and location, frontmatter, the core sections, and the write and read procedures. It is the single source. Read it with `aitk standards session`.
|
|
@@ -20,4 +20,4 @@ paths:
|
|
|
20
20
|
|
|
21
21
|
## Authority
|
|
22
22
|
|
|
23
|
-
- Follow
|
|
23
|
+
- Follow the skill standard for skill structure, frontmatter fields, invocation rules, and the shape a `REQUIREMENT.md` states. It is the single source. Read it with `aitk standards skill`.
|
|
@@ -16,4 +16,4 @@ paths:
|
|
|
16
16
|
|
|
17
17
|
## Authority
|
|
18
18
|
|
|
19
|
-
- Follow
|
|
19
|
+
- Follow the readme standard for voice, structure, required and optional sections, heading hierarchy, badge classes, per-project-type content, and what to link out rather than inline. It is the single source. Read it with `aitk standards readme`.
|
|
@@ -19,5 +19,5 @@ paths:
|
|
|
19
19
|
|
|
20
20
|
## Authority
|
|
21
21
|
|
|
22
|
-
- Follow
|
|
22
|
+
- Follow the rule-authoring standard for rule frontmatter, body shape, and voice. It is the single source. Read it with `aitk standards rule`.
|
|
23
23
|
- Read it before writing or editing a rule. Do not work the shape from memory.
|
|
@@ -17,5 +17,5 @@ paths:
|
|
|
17
17
|
|
|
18
18
|
## Authority
|
|
19
19
|
|
|
20
|
-
- Follow
|
|
20
|
+
- Follow the standard-authoring standard for a standard's frontmatter, shape, scope, and success criterion. It is the single source. Read it with `aitk standards standard`.
|
|
21
21
|
- Read it before writing or editing a standard. Do not work the shape from memory.
|
package/package.json
CHANGED
package/src/cli.ts
CHANGED
|
@@ -61,7 +61,7 @@ function showHelp(): void {
|
|
|
61
61
|
`${GREY}│${NC} comments [cmd] ${GREY}# Measure comment density and trend (scan)${NC}`,
|
|
62
62
|
`${GREY}│${NC} context [cmd] ${GREY}# Report context folder health (audit)${NC}`,
|
|
63
63
|
`${GREY}│${NC} markdown [cmd] ${GREY}# Report markdown against the attribute standards (audit)${NC}`,
|
|
64
|
-
`${GREY}│${NC} records [cmd] ${GREY}# Session records under .claude/ (validate, push, pull)${NC}`,
|
|
64
|
+
`${GREY}│${NC} records [cmd] ${GREY}# Session records under .claude/ (validate, size, push, pull)${NC}`,
|
|
65
65
|
`${GREY}│${NC} sessions [cmd] ${GREY}# Resolve live sessions to worktree and branch (list)${NC}`,
|
|
66
66
|
`${GREY}│${NC} audits [cmd] ${GREY}# Run every health check as one set (run, list)${NC}`,
|
|
67
67
|
`${GREY}│${NC} upgrade ${GREY}# Reinstall the CLI globally with the manager that installed it${NC}`,
|
|
@@ -101,6 +101,7 @@ function showHelp(): void {
|
|
|
101
101
|
`${GREY}│${NC} aitk context audit --json`,
|
|
102
102
|
`${GREY}│${NC} aitk markdown audit .claude/rules --json`,
|
|
103
103
|
`${GREY}│${NC} aitk records validate plans`,
|
|
104
|
+
`${GREY}│${NC} aitk records size --json`,
|
|
104
105
|
`${GREY}│${NC} aitk records push --json`,
|
|
105
106
|
`${GREY}│${NC} aitk sessions list --json`,
|
|
106
107
|
`${GREY}│${NC} aitk audits run --json`,
|
package/src/commands/records.ts
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import type { Command } from 'commander'
|
|
2
|
+
import { BACKED_FOLDERS, pullRecords, pushRecords } from '@/records/backup'
|
|
2
3
|
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
4
|
+
type FolderSize,
|
|
5
|
+
formatBytes,
|
|
6
|
+
GROWTH_WINDOWS,
|
|
7
|
+
SIZED_FOLDERS,
|
|
8
|
+
type SizeOutcome,
|
|
9
|
+
sizeRecords,
|
|
10
|
+
} from '@/records/size'
|
|
9
11
|
import {
|
|
10
12
|
type Finding,
|
|
11
13
|
isRecordKind,
|
|
@@ -23,6 +25,7 @@ import {
|
|
|
23
25
|
logWarn,
|
|
24
26
|
outro,
|
|
25
27
|
pipeOutput,
|
|
28
|
+
plural,
|
|
26
29
|
} from '@/ui'
|
|
27
30
|
import { currentWorktreeRoot, mainWorktreeRoot } from '@/worktree'
|
|
28
31
|
|
|
@@ -87,6 +90,41 @@ export function register(program: Command): void {
|
|
|
87
90
|
process.exitCode = await runValidate(kind, opts)
|
|
88
91
|
})
|
|
89
92
|
|
|
93
|
+
records
|
|
94
|
+
.command('size')
|
|
95
|
+
.description('Report what each record folder holds and how much is recent')
|
|
96
|
+
.helpOption('-h, --help', 'Show this help message')
|
|
97
|
+
.option('--json', 'Add a machine-readable record on stdout')
|
|
98
|
+
.option('--root <path>', 'Project root, defaulting to the main worktree')
|
|
99
|
+
.addHelpText(
|
|
100
|
+
'after',
|
|
101
|
+
[
|
|
102
|
+
'',
|
|
103
|
+
'Folders read under .claude/:',
|
|
104
|
+
` ${SIZED_FOLDERS.join(', ')}`,
|
|
105
|
+
'',
|
|
106
|
+
'Exit codes:',
|
|
107
|
+
' 0 the reading completed',
|
|
108
|
+
' 1 refused, with the reason on stderr or in the JSON record',
|
|
109
|
+
'',
|
|
110
|
+
'It gates nothing. A record folder has no correct size, so the reading is',
|
|
111
|
+
'a number to notice rather than a threshold to fail, and a session takes it',
|
|
112
|
+
`by running this rather than by counting the folder. The ${GROWTH_WINDOWS.join(
|
|
113
|
+
' and ',
|
|
114
|
+
)} day`,
|
|
115
|
+
'counts read mtime, so a file rewritten long after it landed reads as recent,',
|
|
116
|
+
'and a machine restored by records pull reads its whole tree as one week old.',
|
|
117
|
+
'',
|
|
118
|
+
'Examples:',
|
|
119
|
+
' aitk records size',
|
|
120
|
+
' aitk records size --json',
|
|
121
|
+
'',
|
|
122
|
+
].join('\n'),
|
|
123
|
+
)
|
|
124
|
+
.action(async (opts: BackupCommandOptions) => {
|
|
125
|
+
process.exitCode = await runSize(opts)
|
|
126
|
+
})
|
|
127
|
+
|
|
90
128
|
records
|
|
91
129
|
.command('push')
|
|
92
130
|
.description(
|
|
@@ -149,6 +187,99 @@ function backupHelp(verb: 'push' | 'pull'): string {
|
|
|
149
187
|
].join('\n')
|
|
150
188
|
}
|
|
151
189
|
|
|
190
|
+
async function runSize(opts: BackupCommandOptions): Promise<number> {
|
|
191
|
+
const root = opts.root ?? (await mainWorktreeRoot())
|
|
192
|
+
const outcome = await sizeRecords(root)
|
|
193
|
+
|
|
194
|
+
if (!outcome.ok)
|
|
195
|
+
return reportRefusal('aitk records size', outcome, opts.json ?? false)
|
|
196
|
+
|
|
197
|
+
if (opts.json ?? false) {
|
|
198
|
+
process.stdout.write(`${JSON.stringify(outcome)}\n`)
|
|
199
|
+
return 0
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
reportSize(outcome)
|
|
203
|
+
return 0
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/** Widest cell in the column, so a row lines up against the header as well. */
|
|
207
|
+
function columnWidth(header: string, cells: readonly string[]): number {
|
|
208
|
+
return Math.max(header.length, ...cells.map((cell) => cell.length))
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
function sizeRow(entry: FolderSize): string[] {
|
|
212
|
+
return [
|
|
213
|
+
entry.folder,
|
|
214
|
+
String(entry.files),
|
|
215
|
+
formatBytes(entry.bytes),
|
|
216
|
+
...entry.touched.map((window) => String(window.files)),
|
|
217
|
+
entry.oldest ?? '',
|
|
218
|
+
entry.newest ?? '',
|
|
219
|
+
]
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* Renders the present folders as a table, heaviest first.
|
|
224
|
+
*
|
|
225
|
+
* The order is what makes the reading worth taking. A folder listed
|
|
226
|
+
* alphabetically hides behind its neighbors, and the one that grew is the row
|
|
227
|
+
* a reader came for, so it leads.
|
|
228
|
+
*/
|
|
229
|
+
function reportSize(outcome: Extract<SizeOutcome, { ok: true }>): void {
|
|
230
|
+
const present = outcome.folders
|
|
231
|
+
.filter((entry) => entry.present)
|
|
232
|
+
.toSorted((left, right) => right.files - left.files)
|
|
233
|
+
const absent = outcome.folders
|
|
234
|
+
.filter((entry) => !entry.present)
|
|
235
|
+
.map((entry) => entry.folder)
|
|
236
|
+
|
|
237
|
+
intro('aitk records size')
|
|
238
|
+
logStep('Folders')
|
|
239
|
+
|
|
240
|
+
if (present.length === 0) {
|
|
241
|
+
logInfo('none of the record folders exist yet')
|
|
242
|
+
} else {
|
|
243
|
+
const headers = [
|
|
244
|
+
'folder',
|
|
245
|
+
'files',
|
|
246
|
+
'size',
|
|
247
|
+
...GROWTH_WINDOWS.map((days) => `${days}d`),
|
|
248
|
+
'oldest',
|
|
249
|
+
'newest',
|
|
250
|
+
]
|
|
251
|
+
const rows = present.map(sizeRow)
|
|
252
|
+
const widths = headers.map((header, column) =>
|
|
253
|
+
columnWidth(
|
|
254
|
+
header,
|
|
255
|
+
rows.map((row) => row[column]),
|
|
256
|
+
),
|
|
257
|
+
)
|
|
258
|
+
|
|
259
|
+
// The name column reads as a list and the rest as numbers, so one is
|
|
260
|
+
// left-aligned and the others are not.
|
|
261
|
+
const render = (cells: readonly string[]): string =>
|
|
262
|
+
cells
|
|
263
|
+
.map((cell, column) =>
|
|
264
|
+
column === 0
|
|
265
|
+
? cell.padEnd(widths[column])
|
|
266
|
+
: cell.padStart(widths[column]),
|
|
267
|
+
)
|
|
268
|
+
.join(' ')
|
|
269
|
+
.trimEnd()
|
|
270
|
+
|
|
271
|
+
pipeOutput([render(headers), ...rows.map(render)].join('\n'))
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
if (absent.length > 0) logInfo(`absent: ${absent.join(', ')}`)
|
|
275
|
+
|
|
276
|
+
logStep('Total')
|
|
277
|
+
logInfo(
|
|
278
|
+
`${plural(outcome.files, 'file')}, ${formatBytes(outcome.bytes)} across ${plural(present.length, 'folder')}`,
|
|
279
|
+
)
|
|
280
|
+
outro()
|
|
281
|
+
}
|
|
282
|
+
|
|
152
283
|
async function runPush(opts: BackupCommandOptions): Promise<number> {
|
|
153
284
|
const root = opts.root ?? (await mainWorktreeRoot())
|
|
154
285
|
const outcome = await pushRecords(root)
|
|
@@ -197,9 +328,16 @@ async function runPull(opts: BackupCommandOptions): Promise<number> {
|
|
|
197
328
|
return 0
|
|
198
329
|
}
|
|
199
330
|
|
|
331
|
+
/**
|
|
332
|
+
* Reports a refusal from any of the three verbs that carry one.
|
|
333
|
+
*
|
|
334
|
+
* The parameter is structural rather than the union of their outcome types,
|
|
335
|
+
* because the three refusal vocabularies are separate lists and naming them all
|
|
336
|
+
* here would grow with every verb added.
|
|
337
|
+
*/
|
|
200
338
|
function reportRefusal(
|
|
201
339
|
banner: string,
|
|
202
|
-
outcome:
|
|
340
|
+
outcome: { readonly reason: string; readonly message: string },
|
|
203
341
|
emitJson: boolean,
|
|
204
342
|
): number {
|
|
205
343
|
if (emitJson) {
|
|
@@ -536,10 +536,45 @@ function measureParagraph(block: readonly BodyLine[]): CadenceFinding {
|
|
|
536
536
|
* absence of something, so no addition to that set catches a paragraph whose
|
|
537
537
|
* sentences are all one length. The measure stops at what is countable. A
|
|
538
538
|
* sentence's grammatical shape and whether it carries a finite verb are the two
|
|
539
|
-
* rules `write-human` states that this does not implement
|
|
540
|
-
*
|
|
541
|
-
*
|
|
542
|
-
*
|
|
539
|
+
* rules `write-human` states that this does not implement. Reporting them wrong
|
|
540
|
+
* is worse than not reporting them, since they name the exact failure this
|
|
541
|
+
* exists to measure.
|
|
542
|
+
*
|
|
543
|
+
* That was a prediction and it has now been measured, against two parsers
|
|
544
|
+
* rather than against the idea of one. Both ran over 11,389 paragraph sentences
|
|
545
|
+
* across 503 markdown files at `c7e92612` on 2026-08-20, and they disagree by
|
|
546
|
+
* a factor of four on a number one of them has to be wrong about.
|
|
547
|
+
*
|
|
548
|
+
* `compromise` reported 2 percent. It tags a fronted past participle as a
|
|
549
|
+
* finite past-tense verb, so all twelve of those sentences in
|
|
550
|
+
* `.claude/ARCHITECTURE.md` read as carrying one, eleven opening `Measured at`
|
|
551
|
+
* and one `Overturned by`, which is the exact shape the measure exists to
|
|
552
|
+
* catch. It is not even consistent with itself there: `Measured at` tags a verb
|
|
553
|
+
* and `Measured against` tags an adjective.
|
|
554
|
+
*
|
|
555
|
+
* `wink-pos-tagger` reported 9 percent and fixes that class, tagging the
|
|
556
|
+
* participle `VBN`. Roughly three quarters of what it flags is still wrong:
|
|
557
|
+
* hand-classifying every 21st of the 1,071 flagged sentences put 12 of 51
|
|
558
|
+
* genuinely verbless. Two classes split the other 39 almost evenly and neither
|
|
559
|
+
* is a tuning problem. Nineteen are imperatives, which this instructional
|
|
560
|
+
* corpus is full of and whose verb tags as a proper noun as often as a verb.
|
|
561
|
+
* Twenty are ordinary declaratives whose predicate is noun-ambiguous and tags
|
|
562
|
+
* as a noun outright, so `Each maps to a skill.` and `Nothing checks either
|
|
563
|
+
* one.` both report verbless. This corpus is built from exactly those words:
|
|
564
|
+
* reports, answers, checks, maps, holds, names, carries, records, measures.
|
|
565
|
+
*
|
|
566
|
+
* Separating them needs to know which token is the predicate, which is syntax
|
|
567
|
+
* rather than a tag. Neither tagger carries one and nothing was found worth
|
|
568
|
+
* taking for a number nothing gates on, so the rule the deferral set is met and
|
|
569
|
+
* still returns no: a parse was tried, twice, and neither produced a number
|
|
570
|
+
* worth printing beside two that hold.
|
|
571
|
+
*
|
|
572
|
+
* Where a shape sits is a different question and is already answered. A heading
|
|
573
|
+
* fragment, a list item, and a table cell are all legitimately verbless and
|
|
574
|
+
* none of them reaches this measure, because `paragraphBlocks` ends a paragraph
|
|
575
|
+
* on each. That exclusion is structural and needs no grammar. The imperative is
|
|
576
|
+
* the one that sits in paragraph prose, and it is what neither parser could
|
|
577
|
+
* separate out.
|
|
543
578
|
*
|
|
544
579
|
* A paragraph under the floor is skipped rather than scored. A two-sentence
|
|
545
580
|
* configuration note has no spread worth reading, and the opener rule is
|