@erclx/aitk 0.62.1 → 0.63.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
One source for your repos' AI conventions. Install once, sync everywhere.
|
|
8
8
|
|
|
9
|
-

|
|
10
10
|
|
|
11
11
|
If you work across more than one repository and your AI setup has started to drift between them, this is for you. The counts above are read from the catalogs when the image is built, so they're what the repo actually ships today.
|
|
12
12
|
|
package/docs/ai-workflow.md
CHANGED
|
@@ -77,7 +77,7 @@ Run one orchestrator at a time. The board is gitignored, so a second session rea
|
|
|
77
77
|
|
|
78
78
|
Before a handoff, the orchestrator checks the plan against the tree rather than reading it: grep each construct it names and count the sites, confirm every phase label it cites is still open, and open each file it describes. A plan goes stale from whatever merged after it was written, and reading cannot catch that.
|
|
79
79
|
|
|
80
|
-
`.claude/plans/`, `.claude/review/`, and `.claude/memory/` all resolve at the main worktree root, so artifacts created in any session are visible from any sibling worktree. See [Claude Code and git worktrees](../wiki/claude/claude-worktrees.md) for the full rule and the domain-level fan-out guidance.
|
|
80
|
+
`.claude/plans/`, `.claude/review/`, and `.claude/memory/` all resolve at the main worktree root, so artifacts created in any session are visible from any sibling worktree. A session inside a worktree reads them directly and writes them through the shell, since the file-editing tools refuse a main-root path. See [Claude Code and git worktrees](../wiki/claude/claude-worktrees.md) for the full rule and the domain-level fan-out guidance.
|
|
81
81
|
|
|
82
82
|
The plan's shape is fixed by `.claude/standards/plan.md`: the section list, the filename, the lifecycle, and the contract its questions keep. Every question carries a `- Suggested:` line and an empty `- Answer:` slot, and a blank answer accepts the suggestion at execution time. That default is what makes a plan decision-ready in one pass, and it is the opposite of the contract an intake folder keeps, where an empty slot means nobody reached the item.
|
|
83
83
|
|
package/package.json
CHANGED
|
@@ -19,6 +19,7 @@ PROJECT_ROOT="${PROJECT_ROOT:-$(cd "$SCRIPT_DIR/../.." && pwd)}"
|
|
|
19
19
|
|
|
20
20
|
TEMPLATE="$PROJECT_ROOT/assets/hero.html.tmpl"
|
|
21
21
|
OUTPUT="$PROJECT_ROOT/assets/hero.html"
|
|
22
|
+
CLI_ENTRY="$PROJECT_ROOT/src/cli.ts"
|
|
22
23
|
LISTED=10
|
|
23
24
|
|
|
24
25
|
# `bun src/cli.ts` rather than `aitk`, since a globally linked binary resolves to
|
|
@@ -32,6 +33,20 @@ if [ ! -f "$TEMPLATE" ]; then
|
|
|
32
33
|
exit 1
|
|
33
34
|
fi
|
|
34
35
|
|
|
36
|
+
# The commands have no `--json` catalog to read, so the count comes from the
|
|
37
|
+
# registration block in the CLI entry point, which is the one place a command is
|
|
38
|
+
# added. `--help` is hand-authored ASCII and would drift from what is registered.
|
|
39
|
+
if [ ! -f "$CLI_ENTRY" ]; then
|
|
40
|
+
echo "regen-hero: missing CLI entry point at $CLI_ENTRY" >&2
|
|
41
|
+
exit 1
|
|
42
|
+
fi
|
|
43
|
+
|
|
44
|
+
COMMAND_COUNT="$(grep -c '^import { register as ' "$CLI_ENTRY" || true)"
|
|
45
|
+
if [ "${COMMAND_COUNT:-0}" -eq 0 ]; then
|
|
46
|
+
echo "regen-hero: no command registrations found in $CLI_ENTRY, refusing to write a zeroed hero" >&2
|
|
47
|
+
exit 1
|
|
48
|
+
fi
|
|
49
|
+
|
|
35
50
|
SKILLS_JSON="$(catalog claude skills list)"
|
|
36
51
|
GOV_JSON="$(catalog gov list)"
|
|
37
52
|
STANDARDS_JSON="$(catalog standards list)"
|
|
@@ -59,12 +74,12 @@ printf '%s' "$SNIPPETS_JSON" >"$PAYLOAD_DIR/snippets.json"
|
|
|
59
74
|
printf '%s' "$TOOLING_JSON" >"$PAYLOAD_DIR/tooling.json"
|
|
60
75
|
|
|
61
76
|
export PAYLOAD_DIR
|
|
62
|
-
export TEMPLATE OUTPUT LISTED PROJECT_ROOT
|
|
77
|
+
export TEMPLATE OUTPUT LISTED PROJECT_ROOT COMMAND_COUNT
|
|
63
78
|
|
|
64
79
|
bun --eval '
|
|
65
80
|
const { readFileSync } = require("node:fs")
|
|
66
81
|
|
|
67
|
-
const { PAYLOAD_DIR, TEMPLATE, OUTPUT, LISTED, PROJECT_ROOT } = process.env
|
|
82
|
+
const { PAYLOAD_DIR, TEMPLATE, OUTPUT, LISTED, PROJECT_ROOT, COMMAND_COUNT } = process.env
|
|
68
83
|
|
|
69
84
|
const payload = (name) => readFileSync(PAYLOAD_DIR + "/" + name + ".json", "utf8")
|
|
70
85
|
|
|
@@ -79,7 +94,13 @@ const skills = JSON.parse(SKILLS_JSON).skills.map((entry) => entry.name)
|
|
|
79
94
|
const gov = JSON.parse(GOV_JSON)
|
|
80
95
|
// Rule names carry a numeric prefix that orders the load, not the identity a
|
|
81
96
|
// reader knows them by, so the frame shows the slug alone.
|
|
82
|
-
const
|
|
97
|
+
const slug = (entry) => entry.name.replace(/^\d+-/, "")
|
|
98
|
+
const rules = gov.rules.map(slug)
|
|
99
|
+
// A rule no stack names is opt-in behind `--add`, so featuring one advertises
|
|
100
|
+
// an entry no ordinary `aitk gov install` delivers. The column samples the
|
|
101
|
+
// stack-reached subset while its count and remainder describe the whole catalog.
|
|
102
|
+
const stacked = new Set(gov.stacks.flatMap((stack) => stack.rules))
|
|
103
|
+
const deliveredRules = gov.rules.filter((entry) => stacked.has(entry.name)).map(slug)
|
|
83
104
|
const standards = JSON.parse(STANDARDS_JSON).standards.map((entry) => entry.name)
|
|
84
105
|
const snippets = new Set(
|
|
85
106
|
JSON.parse(SNIPPETS_JSON).categories.flatMap((category) => category.entries),
|
|
@@ -89,20 +110,62 @@ const toolingStacks = JSON.parse(TOOLING_JSON).stacks
|
|
|
89
110
|
const escape = (value) =>
|
|
90
111
|
value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">")
|
|
91
112
|
|
|
92
|
-
// Even spacing across the sorted catalog rather than its first N
|
|
93
|
-
// names
|
|
94
|
-
//
|
|
113
|
+
// Even spacing across the sorted catalog rather than its first N, so a column
|
|
114
|
+
// whose names share a prefix does not read as a narrower catalog than the one
|
|
115
|
+
// that ships. Rules and standards sample. Skills do not, because the even step
|
|
116
|
+
// lands on the entries closest to commodity and on none of the workflow the
|
|
117
|
+
// toolkit exists to carry.
|
|
95
118
|
const sample = (names) => {
|
|
96
119
|
if (names.length <= listed) return names
|
|
97
120
|
const step = names.length / listed
|
|
98
121
|
return Array.from({ length: listed }, (_, i) => names[Math.floor(i * step)])
|
|
99
122
|
}
|
|
100
123
|
|
|
101
|
-
|
|
102
|
-
|
|
124
|
+
// The first seven are the method and exist nowhere else. The last three are
|
|
125
|
+
// recognizable on sight and are what keeps a column of chosen names from
|
|
126
|
+
// reading as an all-`claude-` catalog, which is the failure the sampler above
|
|
127
|
+
// was written against.
|
|
128
|
+
const FEATURED_SKILLS = [
|
|
129
|
+
"claude-feature",
|
|
130
|
+
"claude-groundwork",
|
|
131
|
+
"claude-intake",
|
|
132
|
+
"claude-orchestrate",
|
|
133
|
+
"claude-autoship",
|
|
134
|
+
"claude-pr-review",
|
|
135
|
+
"claude-tasks",
|
|
136
|
+
"git-ship",
|
|
137
|
+
"setup-init",
|
|
138
|
+
"systematic-debugging",
|
|
139
|
+
]
|
|
140
|
+
|
|
141
|
+
// A chosen name is maintained by hand where a sample never goes stale, so a
|
|
142
|
+
// rename has to fail the run rather than quietly shrink the column. This is
|
|
143
|
+
// what makes the trade acceptable.
|
|
144
|
+
//
|
|
145
|
+
// The length is asserted because the `+N more` figure below counts down from
|
|
146
|
+
// `listed` rather than from what this returns, so a list of any other length
|
|
147
|
+
// renders a remainder that is wrong by the difference.
|
|
148
|
+
const featured = (names, chosen) => {
|
|
149
|
+
if (chosen.length !== listed) {
|
|
150
|
+
console.error(`regen-hero: ${chosen.length} featured skills, expected ${listed}`)
|
|
151
|
+
process.exit(1)
|
|
152
|
+
}
|
|
153
|
+
const catalog = new Set(names)
|
|
154
|
+
const missing = chosen.filter((name) => !catalog.has(name))
|
|
155
|
+
if (missing.length > 0) {
|
|
156
|
+
console.error(`regen-hero: featured skills missing from the catalog: ${missing.join(", ")}`)
|
|
157
|
+
process.exit(1)
|
|
158
|
+
}
|
|
159
|
+
return chosen
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
const markup = (names) =>
|
|
163
|
+
names
|
|
103
164
|
.map((name) => ` <div class="entry">${escape(name)}</div>`)
|
|
104
165
|
.join("\n")
|
|
105
166
|
|
|
167
|
+
const entries = (names) => markup(sample(names))
|
|
168
|
+
|
|
106
169
|
const remaining = (names) => String(Math.max(0, names.length - listed))
|
|
107
170
|
|
|
108
171
|
// An empty array is well-formed JSON, so the shell guard on an empty payload
|
|
@@ -111,6 +174,7 @@ const remaining = (names) => String(Math.max(0, names.length - listed))
|
|
|
111
174
|
for (const [label, list] of [
|
|
112
175
|
["skills", skills], ["rules", rules], ["standards", standards],
|
|
113
176
|
["snippets", [...snippets]], ["tooling stacks", toolingStacks], ["gov stacks", gov.stacks],
|
|
177
|
+
["stack-delivered rules", deliveredRules],
|
|
114
178
|
]) {
|
|
115
179
|
if (list.length === 0) {
|
|
116
180
|
console.error(`regen-hero: the ${label} catalog is empty, refusing to write a zeroed hero`)
|
|
@@ -125,8 +189,9 @@ const values = {
|
|
|
125
189
|
SNIPPET_COUNT: String(snippets.size),
|
|
126
190
|
GOV_STACK_COUNT: String(gov.stacks.length),
|
|
127
191
|
TOOLING_STACK_COUNT: String(toolingStacks.length),
|
|
128
|
-
|
|
129
|
-
|
|
192
|
+
COMMAND_COUNT: String(Number(COMMAND_COUNT)),
|
|
193
|
+
SKILL_ENTRIES: markup(featured(skills, FEATURED_SKILLS)),
|
|
194
|
+
RULE_ENTRIES: entries(deliveredRules),
|
|
130
195
|
STANDARD_ENTRIES: entries(standards),
|
|
131
196
|
SKILL_MORE: remaining(skills),
|
|
132
197
|
RULE_MORE: remaining(rules),
|
|
@@ -84,4 +84,6 @@
|
|
|
84
84
|
|
|
85
85
|
- Implementation work runs in a linked worktree. From the main worktree, enter one with `/claude-worktree` before editing tracked files for a feature.
|
|
86
86
|
- Shared session scratch (`.claude/plans/`, `.claude/review/`, `.claude/memory/`, `.claude/tasks/`) lives at the main worktree root, not inside a linked worktree. From a linked worktree, resolve these paths against the main root via `git worktree list --porcelain | grep -m 1 '^worktree ' | cut -d' ' -f2-`. Fall back to `pwd` if not a git repo.
|
|
87
|
-
- From a linked worktree, every `Edit` or `Write` to a tracked file (source, docs) must use a path starting with `pwd`.
|
|
87
|
+
- From a linked worktree, every `Edit` or `Write` to a tracked file (source, docs) must use a path starting with `pwd`.
|
|
88
|
+
- From a linked worktree, `Edit` and `Write` are refused for every main-root path, session scratch included. The refusal names session isolation and points at the worktree copy, which is a second gitignored file no later session reads, so never take that redirect.
|
|
89
|
+
- `Read` resolves against the main root normally from a linked worktree. A main-root write reaches it only through `Bash`, as one plain command rather than a compound one, which is refused for complexity.
|