ai-runtime-kit 0.5.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.
Files changed (44) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +307 -0
  3. package/bin/cli.js +52 -0
  4. package/package.json +40 -0
  5. package/runtime/BOOTSTRAP.md +230 -0
  6. package/runtime/CAPABILITIES.md +166 -0
  7. package/runtime/INDEX.md +397 -0
  8. package/runtime/PRIORITIES.md +84 -0
  9. package/runtime/RUNTIME_HEALTH.md +87 -0
  10. package/runtime/RUNTIME_MODE.md +109 -0
  11. package/runtime/RUNTIME_TRANSITIONS.md +141 -0
  12. package/runtime/RUNTIME_VERSION.md +17 -0
  13. package/runtime/SAFETY.md +156 -0
  14. package/runtime/adr/0000-template.md +55 -0
  15. package/runtime/agents/executor.md +19 -0
  16. package/runtime/agents/verifier.md +83 -0
  17. package/runtime/hooks/README.md +163 -0
  18. package/runtime/hooks/_template/HOOK.md +87 -0
  19. package/runtime/hooks/pre-executor/runtime-scoped-preflight/HOOK.md +189 -0
  20. package/runtime/memory/architecture/principles.md +107 -0
  21. package/runtime/memory/engineering/principles.md +102 -0
  22. package/runtime/memory/runtime/context-loading.md +107 -0
  23. package/runtime/plans/_template.md +81 -0
  24. package/runtime/prds/_template.md +73 -0
  25. package/runtime/reviews/_template.md +37 -0
  26. package/runtime/rules/README.md +101 -0
  27. package/runtime/rules/_template/RULE.md +75 -0
  28. package/runtime/skills/README.md +96 -0
  29. package/runtime/skills/_template/SKILL.md +61 -0
  30. package/runtime/specs/_template/spec.md +50 -0
  31. package/runtime/specs/_template-bug-fix/spec.md +120 -0
  32. package/runtime/tasks/TASK_STATUS.md +58 -0
  33. package/runtime/tasks/_template.md +73 -0
  34. package/runtime/workflows/branching.md +128 -0
  35. package/runtime/workflows/bug-fix.md +169 -0
  36. package/runtime/workflows/feature-development.md +238 -0
  37. package/src/diff.js +81 -0
  38. package/src/git.js +38 -0
  39. package/src/init.js +166 -0
  40. package/src/prompt.js +17 -0
  41. package/src/snapshot.js +84 -0
  42. package/src/templates.js +96 -0
  43. package/src/upgrade.js +179 -0
  44. package/src/version.js +42 -0
@@ -0,0 +1,96 @@
1
+ 'use strict';
2
+
3
+ // Project-side templates instantiated by `init` into .ai/project/.
4
+
5
+ function projectStateMd() {
6
+ return `# Project Runtime State
7
+
8
+ This file holds the current instance values for runtime metadata
9
+ whose definitions live in \`.ai/runtime/\`. Reading this file plus
10
+ the corresponding runtime file is equivalent to reading the
11
+ single-file version.
12
+
13
+ ## Mode
14
+
15
+ FEATURE_DEVELOPMENT
16
+
17
+ ### Runtime Intent
18
+
19
+ Current focus:
20
+
21
+ - (fill me in: what this project is currently optimizing for)
22
+
23
+ ## Health
24
+
25
+ GREEN
26
+
27
+ ### Health Drivers
28
+
29
+ Reasons:
30
+
31
+ - (fill me in: what is currently true that justifies GREEN)
32
+
33
+ ### Recovery Goals
34
+
35
+ (fill me in: what would degrade health, and how to recover)
36
+
37
+ ## Priorities
38
+
39
+ Current runtime health:
40
+
41
+ - GREEN
42
+
43
+ Current priority focus:
44
+
45
+ - (fill me in)
46
+ `;
47
+ }
48
+
49
+ function projectTaskStatusMd() {
50
+ return `# Task Status — Active Sets
51
+
52
+ Active task lifecycle state for this project. Lifecycle schema is
53
+ defined in \`.ai/runtime/tasks/TASK_STATUS.md\`.
54
+
55
+ ---
56
+
57
+ ## Active Task Sets
58
+
59
+ (empty — populate as task sets are opened)
60
+ `;
61
+ }
62
+
63
+ function agentEntryClaudeMd() {
64
+ return `# CLAUDE.md
65
+
66
+ This repository uses an \`.ai/\` runtime managed by
67
+ [ai-runtime-kit](https://github.com/kaelen2026/ai-runtime-kit).
68
+
69
+ ## Agent entry point
70
+
71
+ Before doing engineering work in this repo, read the runtime bootstrap:
72
+
73
+ \`\`\`
74
+ .ai/runtime/BOOTSTRAP.md
75
+ \`\`\`
76
+
77
+ That file defines the read sequence (INDEX → CAPABILITIES → RUNTIME_MODE
78
+ → SAFETY → PRIORITIES → workflows). Project-instance state — current
79
+ mode, health, priorities — lives at \`.ai/project/STATE.md\`.
80
+
81
+ ## Loading order
82
+
83
+ 1. This file (\`CLAUDE.md\`), auto-loaded by Claude Code from cwd.
84
+ 2. \`.ai/runtime/BOOTSTRAP.md\` — explicitly read on task start.
85
+ 3. \`.ai/project/STATE.md\` — current instance state.
86
+ 4. Task-relevant runtime and project files per BOOTSTRAP's read sequence.
87
+
88
+ ## Editing this file
89
+
90
+ This file is **project-owned**. \`ai-runtime-kit upgrade\` never
91
+ touches it. Add repo-specific notes (stack, conventions, gotchas)
92
+ below — they will be preserved across kit upgrades.
93
+ `;
94
+ }
95
+
96
+ module.exports = { projectStateMd, projectTaskStatusMd, agentEntryClaudeMd };
package/src/upgrade.js ADDED
@@ -0,0 +1,179 @@
1
+ 'use strict';
2
+
3
+ const fs = require('node:fs');
4
+ const path = require('node:path');
5
+ const { parseArgs } = require('node:util');
6
+
7
+ const { copyKitRuntimeTo, removeDir } = require('./snapshot');
8
+ const {
9
+ KIT_VERSION,
10
+ readProjectKitVersion,
11
+ writeProjectKitVersion,
12
+ compareSemver,
13
+ } = require('./version');
14
+ const { computeRuntimeDiff, printDiffSummary, printPerFileDiff } = require('./diff');
15
+ const { gitStatusPorcelain, isGitRepo } = require('./git');
16
+ const { confirm } = require('./prompt');
17
+
18
+ async function run(argv) {
19
+ let parsed;
20
+ try {
21
+ parsed = parseArgs({
22
+ args: argv,
23
+ options: {
24
+ cwd: { type: 'string' },
25
+ yes: { type: 'boolean', short: 'y', default: false },
26
+ 'no-diff': { type: 'boolean', default: false },
27
+ pager: { type: 'string' },
28
+ 'allow-dirty': { type: 'boolean', default: false },
29
+ 'allow-downgrade': { type: 'boolean', default: false },
30
+ help: { type: 'boolean', short: 'h', default: false },
31
+ },
32
+ strict: true,
33
+ allowPositionals: false,
34
+ });
35
+ } catch (e) {
36
+ console.error(`upgrade: ${e.message}`);
37
+ console.error('Try: ai-runtime-kit upgrade --help');
38
+ process.exit(1);
39
+ }
40
+
41
+ if (parsed.values.help) {
42
+ printHelp();
43
+ return;
44
+ }
45
+
46
+ const cwd = path.resolve(parsed.values.cwd ?? process.cwd());
47
+ const runtimeDir = path.join(cwd, '.ai', 'runtime');
48
+
49
+ if (!fs.existsSync(runtimeDir)) {
50
+ console.error(`upgrade: ${runtimeDir} does not exist.`);
51
+ console.error('Run `ai-runtime-kit init` first.');
52
+ process.exit(1);
53
+ }
54
+
55
+ const installedVersion = readProjectKitVersion(cwd);
56
+ if (!installedVersion) {
57
+ console.error('upgrade: .ai/runtime/KIT_VERSION not found.');
58
+ console.error('Either re-run init in --migrate mode or write KIT_VERSION manually.');
59
+ process.exit(1);
60
+ }
61
+
62
+ const cmp = compareSemver(KIT_VERSION, installedVersion);
63
+ if (cmp === 0) {
64
+ console.log(`Already on kit ${KIT_VERSION}. No upgrade needed.`);
65
+ return;
66
+ }
67
+ if (cmp < 0) {
68
+ if (!parsed.values['allow-downgrade']) {
69
+ console.error(`upgrade: refusing downgrade — installed ${installedVersion} > kit ${KIT_VERSION}.`);
70
+ console.error('Pass --allow-downgrade to override.');
71
+ process.exit(1);
72
+ }
73
+ console.warn(`Warning: downgrading from ${installedVersion} to ${KIT_VERSION}.`);
74
+ }
75
+
76
+ // Git dirty check
77
+ if (!parsed.values['allow-dirty']) {
78
+ if (isGitRepo(cwd)) {
79
+ const status = gitStatusPorcelain('.ai/runtime', cwd);
80
+ if (!status.ok) {
81
+ console.error(`upgrade: git status check failed: ${status.error}`);
82
+ console.error('Pass --allow-dirty to skip the git check.');
83
+ process.exit(1);
84
+ }
85
+ if (status.lines.length) {
86
+ console.error('upgrade: .ai/runtime/ has uncommitted changes:');
87
+ for (const line of status.lines) console.error(` ${line}`);
88
+ console.error('Commit or stash them, or pass --allow-dirty.');
89
+ process.exit(1);
90
+ }
91
+ } else {
92
+ console.warn(`upgrade: ${cwd} is not a git repository — skipping dirty check.`);
93
+ }
94
+ }
95
+
96
+ // Compute and print diff
97
+ const diff = computeRuntimeDiff(runtimeDir);
98
+ console.log(`Upgrading kit ${installedVersion} → ${KIT_VERSION}`);
99
+ console.log('');
100
+ printDiffSummary(diff);
101
+
102
+ if (
103
+ diff.added.length === 0 &&
104
+ diff.removed.length === 0 &&
105
+ diff.replaced.length === 0
106
+ ) {
107
+ console.log('No file-level changes. Updating KIT_VERSION only.');
108
+ writeProjectKitVersion(cwd, KIT_VERSION);
109
+ return;
110
+ }
111
+
112
+ if (!parsed.values['no-diff']) {
113
+ const pagerCmd = parsed.values.pager ?? process.env.AI_RUNTIME_KIT_PAGER;
114
+ if (pagerCmd && process.stdout.isTTY) {
115
+ const { spawn } = require('node:child_process');
116
+ const [bin, ...pagerArgs] = pagerCmd.split(/\s+/);
117
+ const child = spawn(bin, pagerArgs, {
118
+ stdio: ['pipe', 'inherit', 'inherit'],
119
+ });
120
+ printPerFileDiff(diff, runtimeDir, child.stdin);
121
+ child.stdin.end();
122
+ await new Promise((resolve, reject) => {
123
+ child.on('close', resolve);
124
+ child.on('error', reject);
125
+ });
126
+ } else {
127
+ printPerFileDiff(diff, runtimeDir);
128
+ }
129
+ }
130
+
131
+ // Confirm
132
+ let ok;
133
+ if (parsed.values.yes) {
134
+ ok = true;
135
+ console.log('--yes passed; proceeding without prompt.');
136
+ } else {
137
+ ok = await confirm('Apply this upgrade?', { defaultYes: false });
138
+ }
139
+
140
+ if (!ok) {
141
+ console.log('Aborted. No changes made.');
142
+ process.exit(2);
143
+ }
144
+
145
+ removeDir(runtimeDir);
146
+ copyKitRuntimeTo(runtimeDir);
147
+ writeProjectKitVersion(cwd, KIT_VERSION);
148
+ console.log(`Done. Kit upgraded to ${KIT_VERSION}.`);
149
+ console.log('Changes are unstaged; review with `git diff .ai/runtime/` and commit when ready.');
150
+ }
151
+
152
+ function printHelp() {
153
+ console.log(`ai-runtime-kit upgrade [options]
154
+
155
+ Replace .ai/runtime/ with the kit's current canonical snapshot.
156
+
157
+ Process:
158
+ 1. Verify .ai/runtime/KIT_VERSION exists.
159
+ 2. Verify .ai/runtime/ has no uncommitted git changes.
160
+ 3. Show file-level ADD / REPLACE / DELETE summary + per-file diff.
161
+ 4. Prompt: Apply this upgrade? (y/N).
162
+ 5. On y: rm -rf .ai/runtime/, lay down new snapshot, update KIT_VERSION.
163
+
164
+ Never touches .ai/project/.
165
+
166
+ Options:
167
+ --cwd <dir> Target directory (default: process.cwd())
168
+ --yes, -y Skip the y/N prompt (apply immediately)
169
+ --no-diff Skip the per-file diff preview (still shows summary)
170
+ --pager <cmd> Pipe per-file diff through this pager (e.g.
171
+ \`--pager 'less -R'\`). Also honored via env
172
+ AI_RUNTIME_KIT_PAGER. Only applied when stdout
173
+ is a TTY.
174
+ --allow-dirty Skip the git dirty check
175
+ --allow-downgrade Permit installing an older kit version
176
+ -h, --help Show this help.`);
177
+ }
178
+
179
+ module.exports = { run, printHelp };
package/src/version.js ADDED
@@ -0,0 +1,42 @@
1
+ 'use strict';
2
+
3
+ const fs = require('node:fs');
4
+ const path = require('node:path');
5
+
6
+ const KIT_PKG = require('../package.json');
7
+
8
+ const KIT_VERSION = KIT_PKG.version;
9
+
10
+ function kitVersionFilePath(projectRoot) {
11
+ return path.join(projectRoot, '.ai', 'runtime', 'KIT_VERSION');
12
+ }
13
+
14
+ function readProjectKitVersion(projectRoot) {
15
+ const f = kitVersionFilePath(projectRoot);
16
+ if (!fs.existsSync(f)) return null;
17
+ return fs.readFileSync(f, 'utf8').trim();
18
+ }
19
+
20
+ function writeProjectKitVersion(projectRoot, version) {
21
+ fs.writeFileSync(kitVersionFilePath(projectRoot), `${version}\n`);
22
+ }
23
+
24
+ // Returns 1 / 0 / -1 if a is newer / equal / older than b. Pre-release tags
25
+ // ignored (we don't need full semver here — v0.x and v1.x suffice).
26
+ function compareSemver(a, b) {
27
+ const norm = (s) => s.replace(/^v/, '').split('-')[0].split('.').map(Number);
28
+ const [aMaj, aMin, aPat] = norm(a);
29
+ const [bMaj, bMin, bPat] = norm(b);
30
+ if (aMaj !== bMaj) return aMaj > bMaj ? 1 : -1;
31
+ if (aMin !== bMin) return aMin > bMin ? 1 : -1;
32
+ if (aPat !== bPat) return aPat > bPat ? 1 : -1;
33
+ return 0;
34
+ }
35
+
36
+ module.exports = {
37
+ KIT_VERSION,
38
+ kitVersionFilePath,
39
+ readProjectKitVersion,
40
+ writeProjectKitVersion,
41
+ compareSemver,
42
+ };