@erclx/aitk 0.22.0 → 0.22.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.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "aitk",
3
3
  "description": "Automated governance, versioning, and discovery tools for Claude Code.",
4
- "version": "0.22.0",
4
+ "version": "0.22.1",
5
5
  "author": {
6
6
  "name": "Eric Le",
7
7
  "url": "https://github.com/erclx"
package/docs/agents.md CHANGED
@@ -66,7 +66,7 @@ Full help: `aitk <command> --help`.
66
66
  | `aitk init [path]` | Bootstrap a project with selected toolkit domains |
67
67
  | `aitk sync [path]` | Sync all installed domains in a target project |
68
68
  | `aitk sync --check` | Report toolkit drift without writing (`--json`, `--exit-code`) |
69
- | `aitk sandbox [cat:cmd]` | Run sandbox scenarios (interactive or routed) |
69
+ | `aitk sandbox [cat:cmd]` | Run sandbox scenarios (interactive or routed), toolkit-only like the tree it reads |
70
70
  | `aitk sandbox reset` | Reset sandbox to baseline |
71
71
  | `aitk sandbox clean` | Wipe the sandbox |
72
72
  | `aitk sandbox check` | Score a provisioned sandbox against a scenario expectation (`--json` for the verdict) |
@@ -189,7 +189,7 @@ inside an already-open frame.
189
189
 
190
190
  ### Sandbox scenarios
191
191
 
192
- Scenarios live under `scripts/sandbox/`, one folder per category. `scripts/sandbox/fixtures/` is the exception, holding file content that scenarios stage rather than scenarios of its own, so both pickers filter it out. Route non-interactively with `SANDBOX_SCENARIO`:
192
+ Scenarios live under `scripts/sandbox/`, one folder per category. `scripts/sandbox/fixtures/` is the exception, holding file content that scenarios stage rather than scenarios of its own, so both pickers filter it out. `files` in `package.json` excludes that tree, so an installed `aitk` carries the command, reports it as toolkit-only on one line, and exits 1 rather than failing on the missing directory. Route non-interactively with `SANDBOX_SCENARIO`:
193
193
 
194
194
  ```bash
195
195
  SANDBOX_SCENARIO=sync aitk sandbox infra:tooling
@@ -222,7 +222,7 @@ Exit 0 means `pass` or `unchecked`. Exit 1 means `fail`, or a caller error: a ma
222
222
 
223
223
  ### Scenario coverage
224
224
 
225
- `aitk sandbox coverage` reports which scenarios declare expectations and which only provision a state. It reads the fixture tree, so it needs no provisioned sandbox and runs nothing.
225
+ `aitk sandbox coverage` reports which scenarios declare expectations and which only provision a state. It reads the fixture tree, so it needs no provisioned sandbox and runs nothing. Where that tree does not ship it exits 1 and prints no percentage, since a denominator nobody looked at is not a coverage result. A tree that is present and holds no scenarios is a real zero and still reports one.
226
226
 
227
227
  ```bash
228
228
  aitk sandbox coverage --json
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@erclx/aitk",
3
3
  "type": "module",
4
- "version": "0.22.0",
4
+ "version": "0.22.1",
5
5
  "description": "Infrastructure and quality tooling for developer workflows",
6
6
  "license": "MIT",
7
7
  "bin": {
@@ -17,6 +17,7 @@ import {
17
17
  type Verdict,
18
18
  } from '@/sandbox/expect'
19
19
  import {
20
+ frameError,
20
21
  intro,
21
22
  logError,
22
23
  logInfo,
@@ -29,6 +30,34 @@ import {
29
30
 
30
31
  const SANDBOX_DIR = join(PROJECT_ROOT, 'scripts', 'sandbox')
31
32
 
33
+ /**
34
+ * Reports that the scenario tree does not ship, and answers whether it reported,
35
+ * so a caller that sees `true` returns without touching the tree.
36
+ *
37
+ * `scripts/sandbox` is excluded from the published package, so an installed
38
+ * `aitk` resolves `SANDBOX_DIR` to a directory that is not there. Both entry
39
+ * points that walk the tree ask here rather than carrying a check each, because
40
+ * absence is a property of the install rather than of a verb, and a second copy
41
+ * of the question is a second message to keep true. `check` reads the tree as
42
+ * well, through `expectFilePath`, and needs no guard because its provisioned-tree
43
+ * check already stops an installed run before the read.
44
+ *
45
+ * The distinction it preserves is between an absent tree and an empty one. Only
46
+ * the second is a real zero, and a coverage percentage over a denominator nobody
47
+ * looked at reads as a suite that examined everything and found it clean.
48
+ *
49
+ * The frame opens and closes here, so this runs before `intro` rather than
50
+ * inside an open frame.
51
+ */
52
+ function reportAbsentScenarioTree(): boolean {
53
+ if (existsSync(SANDBOX_DIR)) return false
54
+
55
+ frameError('sandbox is toolkit-only and is absent from an installed aitk')
56
+ process.exitCode = 1
57
+
58
+ return true
59
+ }
60
+
32
61
  /**
33
62
  * The provisioned tree, as opposed to `SANDBOX_DIR` above, which holds the
34
63
  * scenario scripts. It sits outside the toolkit worktree so the toolkit's own
@@ -217,6 +246,8 @@ function reportCoverage(report: CoverageReport): void {
217
246
  }
218
247
 
219
248
  function runCoverage(options: CoverageOptions): void {
249
+ if (reportAbsentScenarioTree()) return
250
+
220
251
  intro('aitk sandbox coverage')
221
252
 
222
253
  const report = collectCoverage(PROJECT_ROOT)
@@ -284,6 +315,8 @@ export function register(program: Command): void {
284
315
  .allowExcessArguments(true)
285
316
  .passThroughOptions()
286
317
  .action(async (_opts: unknown, cmd: Command) => {
318
+ if (reportAbsentScenarioTree()) return
319
+
287
320
  const args = cmd.args
288
321
 
289
322
  if (args.length === 0) {
@@ -336,7 +369,8 @@ export function register(program: Command): void {
336
369
  ' aitk sandbox coverage',
337
370
  ' aitk sandbox coverage --json',
338
371
  '',
339
- 'Exit codes: 0 always, unless --strict and a scenario declares nothing.',
372
+ 'Exit codes: 0, unless --strict and a scenario declares nothing.',
373
+ 'Where the scenario tree does not ship, exits 1 without a report.',
340
374
  ].join('\n'),
341
375
  )
342
376
  .action((options: CoverageOptions) => {