axstack 0.43.0 → 0.44.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "axstack",
3
- "version": "0.43.0",
3
+ "version": "0.44.0",
4
4
  "description": "Axstack installer and setup CLI: installs owned chat skills and role data, configures supported harness settings, and checks T3 Code capabilities.",
5
5
  "keywords": [
6
6
  "claude-code",
@@ -0,0 +1,61 @@
1
+ #!/usr/bin/env bun
2
+ // Read only the index. No hooks, configuration writes or working-tree reads.
3
+ import { readFileSync } from 'node:fs';
4
+
5
+ const ignoredPath = /(^|\/)(?:[^/]*\.lockb?|package-lock\.json|pnpm-lock\.yaml|yarn\.lock|go\.sum)$|(^|\/)(?:dist|build|__mocks__|__fixtures__|fixtures|captures)\/|\.(?:min|generated|gen)\.|\.(?:map|snap)$/i;
6
+ const asset = /\.(?:svg|png|jpe?g|gif|webp|avif|ico|bmp|tiff?|pdf|woff2?|ttf|otf|eot|mp[34]|wav|ogg|flac|webm|mov|avi|zip|gz|bz2|xz|7z|rar|tar|exe|dll|so|dylib|wasm|bin|class|jar|pyc|sqlite3?|db)$/i;
7
+ let root = process.cwd();
8
+ function git(...args) {
9
+ const result = Bun.spawnSync(['git', '--literal-pathspecs', ...args], { cwd: root });
10
+ if (result.exitCode !== 0) throw Error(result.stderr.toString().trim());
11
+ return result.stdout.toString();
12
+ }
13
+
14
+ try {
15
+ root = git('rev-parse', '--show-toplevel').trim();
16
+ const ignoreFile = git('rev-parse', '--path-format=absolute', '--git-path', 'info/token-limit-ignore').trim();
17
+ let ignores = [];
18
+ try {
19
+ ignores = readFileSync(ignoreFile, 'utf8').split(/\r?\n/)
20
+ .map((line) => line.trim()).filter((line) => line && !line.startsWith('#'))
21
+ .map((pattern) => new Bun.Glob(pattern));
22
+ } catch (error) {
23
+ if (error.code !== 'ENOENT') throw error;
24
+ }
25
+ const paths = git('diff', '--cached', '--name-only', '--diff-filter=ACMR', '-z').split('\0').filter(Boolean);
26
+ const offenders = [];
27
+ for (const path of paths) {
28
+ if (ignoredPath.test(path) || asset.test(path) || ignores.some((glob) => glob.match(path))) continue;
29
+ if (git('ls-files', '--stage', '-z', '--', path).startsWith('160000 ')) continue;
30
+ const bytes = Number(git('cat-file', '-s', `:${path}`));
31
+ if (bytes <= 20000) continue;
32
+ if (git('diff', '--cached', '--numstat', '--no-renames', '-z', '--', path).startsWith('-\t')) continue;
33
+ // Consume the blob fully: closing a pipeline at line five can cause SIGPIPE.
34
+ const firstLines = git('cat-file', 'blob', `:${path}`).split('\n', 5).join('\n');
35
+ if (/@generated|auto[- ]?generated|do not edit|code generated by/i.test(firstLines)) continue;
36
+ offenders.push(`${JSON.stringify(path)}: ${Math.floor(bytes / 4)} tokens`);
37
+ }
38
+ if (offenders.length) {
39
+ console.error(`Staged files exceed 5000 tokens (20000 bytes; tokens = floor(bytes / 4)):
40
+ ${offenders.join('\n')}
41
+
42
+ Split each file before committing:
43
+ 1. Find seams: group top-level units by responsibility.
44
+ 2. Create a folder named after the original file, with one module per responsibility.
45
+ TS: foo.ts -> foo/types.ts, foo/parse.ts, foo/index.ts.
46
+ Rust: foo.rs -> foo/mod.rs + submodules with re-exports.
47
+ Svelte: child components + a .ts module for pure logic.
48
+ Specs: one spec per describe block or behaviour.
49
+ HTML docs: one doc per topic, linked from an index.
50
+ 3. Keep the public surface stable via re-exports, or update all imports in the same commit.
51
+ 4. Move code verbatim first, then refactor in a separate commit.
52
+ 5. Aim for ~3000 tokens per file.
53
+ 6. Stage the new files and re-commit.
54
+ If truly generated or recorded data, add a glob to ${JSON.stringify(ignoreFile)}
55
+ or give the file a generated banner in its first 5 lines.`);
56
+ process.exit(1);
57
+ }
58
+ } catch (error) {
59
+ console.error(`Staged-file token check failed: ${error.message}`);
60
+ process.exit(1);
61
+ }
@@ -162,6 +162,13 @@ applied or found not applicable in the `Simplification:` line of the
162
162
  [section 5 implementation receipt](#5-verify-and-return-the-candidate),
163
163
  including evidence and retained complexity.
164
164
 
165
+ Before every commit, the author runs the
166
+ [staged-file token gate](../axstack/scripts/check-staged-file-tokens.js)
167
+ with `bun` from the target repository.
168
+ If the gate fails, split files per its instructions before retrying.
169
+ Never bypass the staged-file token gate.
170
+ Record the staged-file token gate result in the implementation receipt.
171
+
165
172
  ## 5. Verify and return the candidate
166
173
 
167
174
  Run the acceptance checks and affected integration boundaries. Record commands,
@@ -189,6 +196,7 @@ Owner: <profile + session ID + worktree>
189
196
  Scope: <approved spec + capability | small-change intent | maintenance snapshot>
190
197
  Shape: <total> lines vs base <sha>; bulk: <buckets>; theme: <one line>
191
198
  TDD: <normal red/green | structure-preserving old-green/same-check-new-green evidence | F-repair base-green/removal-inversion-red/rewording-green evidence>
199
+ Token limit: <staged-file gate command + observed result before each commit>
192
200
  Simplification: <applied | not-applicable> — evidence: <diff locations and checks>; retained complexity: <necessary complexity and why>
193
201
  Acceptance: <checks + observed results>
194
202
  Dependencies: <parent revisions or none>