cadet-agent 0.4.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/README.md ADDED
@@ -0,0 +1,71 @@
1
+ # Cadet-Agent
2
+
3
+ Cadet-Agent is a cross-IDE agent framework for game-development workflows, with a shared framework core and authored root integrations for GitHub Copilot, Cursor, Continue, and Claude Code.
4
+
5
+ ## Repository Layout
6
+ - `.cadet/agent/core/` contains the shared Cadet-Agent framework documents.
7
+ - `.cadet/agent/docs/` contains setup guides for each supported IDE.
8
+ - `AGENTS.md` contains shared top-level agent instructions.
9
+ - `.github/` contains GitHub Copilot-specific authored files.
10
+ - `.cursor/` contains Cursor-specific authored files.
11
+ - `.continue/` contains Continue-specific authored files.
12
+ - `.claude/` contains Claude Code-specific authored files.
13
+ - `package-agent.ps1` builds the distributable `cadet-agent.zip` package.
14
+
15
+ ## Getting Started
16
+ - For repository setup and package contents, see [.cadet/agent/README.md](.cadet/agent/README.md).
17
+ - For framework navigation, see [.cadet/agent/core/README.md](.cadet/agent/core/README.md).
18
+ - For GitHub Copilot setup, see [.cadet/agent/docs/github-copilot.md](.cadet/agent/docs/github-copilot.md).
19
+ - For Cursor setup, see [.cadet/agent/docs/cursor.md](.cadet/agent/docs/cursor.md).
20
+ - For Continue setup, see [.cadet/agent/docs/continue.md](.cadet/agent/docs/continue.md).
21
+ - For Claude Code setup, see [.cadet/agent/docs/claude-code.md](.cadet/agent/docs/claude-code.md).
22
+
23
+ ## Examples
24
+
25
+ ### GitHub Copilot kickoff
26
+ After extracting `cadet-agent.zip` into a game repository, open the repo in VS Code and start a kickoff chat using the Cadet prompt.
27
+
28
+ ```text
29
+ /cadet Help me bootstrap a beginner-friendly 2D racing prototype in Unity with AI opponents and a career progression loop.
30
+ ```
31
+
32
+ Cadet-Agent will use `.github/prompts/cadet.prompt.md` plus the shared framework in `.cadet/agent/core` to route the conversation through learner calibration, bootstrap checks, and planning.
33
+
34
+ ### Cursor feature request
35
+ After opening the repository in Cursor, the always-apply rule in `.cursor/rules/cadet-agent.md` should load automatically. A typical request looks like this:
36
+
37
+ ```text
38
+ Design a small vertical slice for a kart handling prototype in Unity. Start with requirements, then a technical design, then the first TDD task.
39
+ ```
40
+
41
+ Cursor will use the Cadet rule to pull workflow, standards, and guidance from `.cadet/agent/core` before responding.
42
+
43
+ ### Continue planning request
44
+ With Continue installed in VS Code, open the repository and ask for a scoped planning artifact:
45
+
46
+ ```text
47
+ Create a requirements outline for a single-player time-trial mode with ghost replay support and Given/When/Then acceptance criteria.
48
+ ```
49
+
50
+ The Continue rule in `.continue/rules/cadet-agent.md` should steer the response back through the shared Cadet framework.
51
+
52
+ ### Repository policy example
53
+ If a specific game repository needs local conventions, add a policy file under `.cadet/agent/policies` using `.cadet/agent/core/Templates/PolicyTemplate.md`. For example, a repository policy could define:
54
+ - where project plans should live
55
+ - where shared gameplay code should be extracted
56
+ - which Unity packages or UI stack are the project default
57
+
58
+ ## Package Output
59
+ Running `./package-agent.ps1` produces `cadet-agent.zip` with this layout:
60
+ - `.cadet/agent/core/`
61
+ - `AGENTS.md`
62
+ - `.github/cadet-copilot-instructions.md`
63
+ - `.github/prompts/cadet.prompt.md`
64
+ - `.cursor/rules/cadet-agent.md`
65
+ - `.continue/rules/cadet-agent.md`
66
+ - `.claude/skills/cadet-agent.md`
67
+
68
+ ## Notes
69
+ - `.cadet/agent/core/FrameworkManifest.json` defines the managed and preserved paths for packaged installs.
70
+ - Repository-specific policy overlays belong in `.cadet/agent/policies`.
71
+ - Planning artifacts belong in `.cadet/agent/project-plans` unless an active policy says otherwise.
package/bin/cli.mjs ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { run } from '../src/cli.mjs';
4
+
5
+ run(process.argv).catch((err) => {
6
+ console.error('\n❌ Unexpected error:', err.message);
7
+ process.exit(1);
8
+ });
package/package.json ADDED
@@ -0,0 +1,32 @@
1
+ {
2
+ "name": "cadet-agent",
3
+ "version": "0.4.0",
4
+ "description": "Cross-IDE agent framework for Unity/C# game-development — one-command install",
5
+ "type": "module",
6
+ "bin": {
7
+ "cadet-agent": "bin/cli.mjs"
8
+ },
9
+ "files": [
10
+ "bin/",
11
+ "src/"
12
+ ],
13
+ "keywords": [
14
+ "cadet",
15
+ "cadet-agent",
16
+ "unity",
17
+ "game-development",
18
+ "ai-agent",
19
+ "copilot",
20
+ "cursor",
21
+ "claude-code"
22
+ ],
23
+ "license": "CC-BY-4.0",
24
+ "repository": {
25
+ "type": "git",
26
+ "url": "git+https://github.com/naishtech/cadet-agent.git"
27
+ },
28
+ "homepage": "https://github.com/naishtech/cadet-agent#readme",
29
+ "engines": {
30
+ "node": ">=18.0.0"
31
+ }
32
+ }
package/src/cli.mjs ADDED
@@ -0,0 +1,67 @@
1
+ import { readFileSync } from 'node:fs';
2
+ import { fileURLToPath } from 'node:url';
3
+ import { dirname, join } from 'node:path';
4
+ import { install } from './install.mjs';
5
+
6
+ const __filename = fileURLToPath(import.meta.url);
7
+ const __dirname = dirname(__filename);
8
+
9
+ function getVersion() {
10
+ const pkg = JSON.parse(readFileSync(join(__dirname, '..', 'package.json'), 'utf-8'));
11
+ return pkg.version;
12
+ }
13
+
14
+ function showHelp() {
15
+ console.log(`
16
+ ██████╗ █████╗ ██████╗ ███████╗████████╗
17
+ ██╔════╝██╔══██╗██╔══██╗██╔════╝╚══██╔══╝
18
+ ██║ ███████║██║ ██║█████╗ ██║
19
+ ██║ ██╔══██║██║ ██║██╔══╝ ██║
20
+ ╚██████╗██║ ██║██████╔╝███████╗ ██║
21
+ ╚═════╝╚═╝ ╚═╝╚═════╝ ╚══════╝ ╚═╝
22
+
23
+ Cross-IDE agent framework for Unity/C# game-development
24
+
25
+ Usage:
26
+ npx cadet-agent@latest init Install Cadet-Agent into the current directory
27
+ npx cadet-agent@latest init --target <dir> Install into a specific directory
28
+
29
+ Options:
30
+ --target, -t Target directory (default: current working directory)
31
+ --help, -h Show this help
32
+ --version, -v Show version number
33
+ `);
34
+ }
35
+
36
+ export async function run(argv) {
37
+ const command = argv[2];
38
+
39
+ // Parse --target <dir> or -t <dir>
40
+ let targetDir = process.cwd();
41
+ const targetIdx = argv.indexOf('--target');
42
+ const tIdx = argv.indexOf('-t');
43
+ if (targetIdx !== -1 && argv[targetIdx + 1]) {
44
+ targetDir = argv[targetIdx + 1];
45
+ } else if (tIdx !== -1 && argv[tIdx + 1]) {
46
+ targetDir = argv[tIdx + 1];
47
+ }
48
+
49
+ switch (command) {
50
+ case 'init':
51
+ await install(targetDir);
52
+ break;
53
+ case '--version':
54
+ case '-v':
55
+ console.log(`cadet-agent v${getVersion()}`);
56
+ break;
57
+ case '--help':
58
+ case '-h':
59
+ case undefined:
60
+ showHelp();
61
+ break;
62
+ default:
63
+ console.error(`Unknown command: ${command}`);
64
+ console.error('Run cadet-agent --help for usage.');
65
+ process.exit(1);
66
+ }
67
+ }
@@ -0,0 +1,205 @@
1
+ import { createWriteStream, mkdirSync, existsSync } from 'node:fs';
2
+ import { join, dirname } from 'node:path';
3
+ import { pipeline } from 'node:stream/promises';
4
+ import { createGunzip } from 'node:zlib';
5
+ import { inflateRawSync } from 'node:zlib';
6
+ import { tmpdir } from 'node:os';
7
+ import { Readable } from 'node:stream';
8
+
9
+ // ── Constants ────────────────────────────────────────────────────────────────
10
+
11
+ const GITHUB_API = 'https://api.github.com/repos/naishtech/cadet-agent/releases/latest';
12
+ const USER_AGENT = 'cadet-agent-cli';
13
+
14
+ // ── ZIP parser (zero-dependency, handles store + deflate) ───────────────────
15
+
16
+ const SIG_EOCD = 0x06054b50;
17
+ const SIG_CD = 0x02014b50;
18
+ const SIG_LFH = 0x04034b50;
19
+
20
+ function read32(buf, off) { return buf.readUInt32LE(off); }
21
+ function read16(buf, off) { return buf.readUInt16LE(off); }
22
+
23
+ function findEocd(buf) {
24
+ // Search backwards from end for EOCD signature (comment is max 65535 bytes)
25
+ const maxStart = Math.max(0, buf.length - 65535 - 22);
26
+ for (let i = buf.length - 22; i >= maxStart; i--) {
27
+ if (read32(buf, i) === SIG_EOCD) return i;
28
+ }
29
+ throw new Error('Not a valid ZIP file: EOCD signature not found');
30
+ }
31
+
32
+ function* centralDirectoryEntries(buf, cdOffset, cdSize) {
33
+ let off = cdOffset;
34
+ const end = cdOffset + cdSize;
35
+ while (off < end) {
36
+ if (read32(buf, off) !== SIG_CD) break;
37
+ const method = read16(buf, off + 10);
38
+ const compressedSize = read32(buf, off + 20);
39
+ const uncompressedSize = read32(buf, off + 24);
40
+ const filenameLen = read16(buf, off + 28);
41
+ const extraLen = read16(buf, off + 30);
42
+ const commentLen = read16(buf, off + 32);
43
+ const localHeaderOff = read32(buf, off + 42);
44
+ const filename = buf.toString('utf-8', off + 46, off + 46 + filenameLen);
45
+
46
+ // Skip directory entries (trailing / in filename, or uncompressedSize == 0 with no method)
47
+ if (!filename.endsWith('/')) {
48
+ yield { filename, method, compressedSize, uncompressedSize, localHeaderOff };
49
+ }
50
+
51
+ off += 46 + filenameLen + extraLen + commentLen;
52
+ }
53
+ }
54
+
55
+ function extractFile(buf, entry, targetDir) {
56
+ const { filename, method, compressedSize, localHeaderOff } = entry;
57
+
58
+ // Read local file header to get filename + extra lengths (they may differ from CD)
59
+ const lfhFilenameLen = read16(buf, localHeaderOff + 26);
60
+ const lfhExtraLen = read16(buf, localHeaderOff + 28);
61
+
62
+ const dataStart = localHeaderOff + 30 + lfhFilenameLen + lfhExtraLen;
63
+ const compressed = buf.subarray(dataStart, dataStart + compressedSize);
64
+
65
+ let data;
66
+ if (method === 0) {
67
+ // Stored — no compression
68
+ data = compressed;
69
+ } else if (method === 8) {
70
+ // Deflate
71
+ data = inflateRawSync(compressed);
72
+ } else {
73
+ throw new Error(`Unsupported compression method ${method} for ${filename}`);
74
+ }
75
+
76
+ const outPath = join(targetDir, filename);
77
+ mkdirSync(dirname(outPath), { recursive: true });
78
+ const ws = createWriteStream(outPath);
79
+ Readable.from(data).pipe(ws);
80
+
81
+ return outPath;
82
+ }
83
+
84
+ function extractZip(buf, targetDir) {
85
+ const eocdOff = findEocd(buf);
86
+ const cdSize = read32(buf, eocdOff + 12);
87
+ const cdOff = read32(buf, eocdOff + 16);
88
+
89
+ const paths = [];
90
+ for (const entry of centralDirectoryEntries(buf, cdOff, cdSize)) {
91
+ const outPath = extractFile(buf, entry, targetDir);
92
+ paths.push(outPath);
93
+ }
94
+ return paths;
95
+ }
96
+
97
+ // ── GitHub release download ─────────────────────────────────────────────────
98
+
99
+ async function fetchLatestRelease() {
100
+ console.log('🔍 Fetching latest Cadet-Agent release...');
101
+
102
+ const res = await fetch(GITHUB_API, {
103
+ headers: {
104
+ 'User-Agent': USER_AGENT,
105
+ 'Accept': 'application/vnd.github+json',
106
+ },
107
+ });
108
+
109
+ if (!res.ok) {
110
+ if (res.status === 403 || res.status === 429) {
111
+ throw new Error(
112
+ `GitHub API rate-limited (${res.status}). ` +
113
+ 'Set GITHUB_TOKEN env var for higher limits, or try again later.'
114
+ );
115
+ }
116
+ throw new Error(`GitHub API returned ${res.status}: ${res.statusText}`);
117
+ }
118
+
119
+ return res.json();
120
+ }
121
+
122
+ function findZipAsset(release) {
123
+ const asset = release.assets?.find(a => a.name === 'cadet-agent.zip');
124
+ if (!asset) {
125
+ throw new Error(
126
+ `Release ${release.tag_name} does not contain cadet-agent.zip.\n` +
127
+ `Available assets: ${(release.assets || []).map(a => a.name).join(', ') || 'none'}`
128
+ );
129
+ }
130
+ return asset;
131
+ }
132
+
133
+ async function downloadZip(url) {
134
+ console.log('⬇️ Downloading cadet-agent.zip...');
135
+
136
+ const res = await fetch(url, {
137
+ headers: {
138
+ 'User-Agent': USER_AGENT,
139
+ 'Accept': 'application/octet-stream',
140
+ },
141
+ });
142
+
143
+ if (!res.ok) {
144
+ throw new Error(`Download failed: ${res.status} ${res.statusText}`);
145
+ }
146
+
147
+ const contentLength = res.headers.get('content-length');
148
+ const total = contentLength ? parseInt(contentLength, 10) : 0;
149
+
150
+ // Stream to buffer with progress
151
+ const chunks = [];
152
+ let downloaded = 0;
153
+ const reader = res.body.getReader();
154
+
155
+ while (true) {
156
+ const { done, value } = await reader.read();
157
+ if (done) break;
158
+ chunks.push(value);
159
+ downloaded += value.length;
160
+ if (total > 0) {
161
+ const pct = Math.round((downloaded / total) * 100);
162
+ process.stdout.write(`\r ${pct}% (${(downloaded / 1024).toFixed(0)} KB / ${(total / 1024).toFixed(0)} KB)`);
163
+ }
164
+ }
165
+ if (total > 0) process.stdout.write('\n');
166
+
167
+ return Buffer.concat(chunks);
168
+ }
169
+
170
+ // ── Public install entry ────────────────────────────────────────────────────
171
+
172
+ export async function install(targetDir) {
173
+ console.log(`📦 Cadet-Agent — installing to ${targetDir}\n`);
174
+
175
+ // 1. Fetch release metadata
176
+ const release = await fetchLatestRelease();
177
+ console.log(` Latest: ${release.tag_name} (published ${release.published_at})\n`);
178
+
179
+ // 2. Find zip asset
180
+ const asset = findZipAsset(release);
181
+
182
+ // 3. Download
183
+ const zipBuf = await downloadZip(asset.browser_download_url);
184
+ console.log(` Downloaded ${(zipBuf.length / 1024).toFixed(0)} KB\n`);
185
+
186
+ // 4. Extract
187
+ console.log('📂 Extracting...');
188
+ const extracted = extractZip(zipBuf, targetDir);
189
+
190
+ // 5. Report
191
+ console.log(`\n✅ Cadet-Agent ${release.tag_name} installed! Extracted ${extracted.length} files.\n`);
192
+
193
+ // Print per-IDE next steps
194
+ console.log('── Next steps ──');
195
+ console.log(' GitHub Copilot:');
196
+ console.log(' Rename .github\\cadet-copilot-instructions.md → .github\\copilot-instructions.md');
197
+ console.log(' Then start a chat: /cadet');
198
+ console.log(' Cursor:');
199
+ console.log(' Already active — .cursor\\rules\\cadet-agent.md loads automatically');
200
+ console.log(' Continue:');
201
+ console.log(' Already active — .continue\\rules\\cadet-agent.md loads automatically');
202
+ console.log(' Claude Code:');
203
+ console.log(' Already active — .claude\\skills\\cadet-agent.md loads as a project skill');
204
+ console.log('');
205
+ }