@opensassi/opencode 0.1.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/AGENTS.md +35 -0
- package/README.md +81 -0
- package/bin/opencode.js +3 -0
- package/lib/cli.js +38 -0
- package/lib/commands/init.js +117 -0
- package/lib/commands/print-agents.js +6 -0
- package/lib/commands/print-skill.js +8 -0
- package/lib/commands/run.js +57 -0
- package/lib/index.js +4 -0
- package/lib/util/paths.js +21 -0
- package/package.json +40 -0
- package/scripts/asm-optimizer/run-baseline.sh +158 -0
- package/scripts/check-artifacts.js +131 -0
- package/scripts/extract-artifacts.js +204 -0
- package/scripts/install/linux/ubuntu-noble-24.04/install.sh +94 -0
- package/scripts/install/osx/macos-sequoia-15.0/install.sh +115 -0
- package/scripts/install/windows/wsl2/install.ps1 +98 -0
- package/scripts/install.ps1 +32 -0
- package/scripts/install.sh +83 -0
- package/scripts/puppeteer-config.json +3 -0
- package/scripts/test-artifacts.js +346 -0
- package/scripts/validate-all.js +18 -0
- package/scripts/verify-artifact.js +157 -0
- package/skills/asm-optimizer/SKILL.md +295 -0
- package/skills/daily-evaluation/SKILL.md +86 -0
- package/skills/git/SKILL.md +100 -0
- package/skills/issue/SKILL.md +104 -0
- package/skills/npm-optimizer/SKILL.md +218 -0
- package/skills/opensassi/SKILL.md +77 -0
- package/skills/opensassi/scripts/ensure-gitignore.sh +89 -0
- package/skills/opensassi/scripts/env-check.ps1 +139 -0
- package/skills/opensassi/scripts/env-check.sh +200 -0
- package/skills/opensassi/scripts/install-flamegraph.sh +32 -0
- package/skills/opensassi/scripts/install-npm-deps.sh +25 -0
- package/skills/profiler/SKILL.md +213 -0
- package/skills/profiler/scripts/benchmark.sh +63 -0
- package/skills/profiler/scripts/common.sh +55 -0
- package/skills/profiler/scripts/compare.sh +63 -0
- package/skills/profiler/scripts/profile.sh +63 -0
- package/skills/profiler/scripts/setup.sh +32 -0
- package/skills/session-evaluation/SKILL.md +128 -0
- package/skills/skill-manager/SKILL.md +251 -0
- package/skills/system-design/SKILL.md +558 -0
- package/skills/system-design-review/SKILL.md +396 -0
- package/skills/todo/SKILL.md +165 -0
- package/skills-index.json +137 -0
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { fileURLToPath } from 'url';
|
|
3
|
+
import fs from 'fs';
|
|
4
|
+
import path from 'path';
|
|
5
|
+
|
|
6
|
+
const __dirname = fileURLToPath(new URL('.', import.meta.url));
|
|
7
|
+
const ROOT = path.resolve(__dirname, '..');
|
|
8
|
+
|
|
9
|
+
function getReviewPath(specPath) {
|
|
10
|
+
const rel = path.relative(ROOT, specPath);
|
|
11
|
+
const dir = path.dirname(rel);
|
|
12
|
+
const basename = path.basename(rel);
|
|
13
|
+
|
|
14
|
+
if (rel === 'technical-specification.md') {
|
|
15
|
+
return path.join(ROOT, '.artifacts', 'review.md');
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
return path.join(ROOT, dir, '.artifacts', basename, 'review.md');
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function getReviewStatus(specPath) {
|
|
22
|
+
const reviewPath = getReviewPath(specPath);
|
|
23
|
+
|
|
24
|
+
if (!fs.existsSync(reviewPath)) return { reviewFile: null, reviewMtime: null, reviewStatus: "MISSING" };
|
|
25
|
+
|
|
26
|
+
const reviewMtime = fs.statSync(reviewPath).mtimeMs;
|
|
27
|
+
const specMtime = fs.statSync(specPath).mtimeMs;
|
|
28
|
+
const status = reviewMtime < specMtime ? "STALE" : "OK";
|
|
29
|
+
|
|
30
|
+
return {
|
|
31
|
+
reviewFile: path.relative(ROOT, reviewPath),
|
|
32
|
+
reviewMtime: Math.floor(reviewMtime),
|
|
33
|
+
reviewStatus: status,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function getAllSpecFiles() {
|
|
38
|
+
const files = [];
|
|
39
|
+
|
|
40
|
+
const rootSpec = path.join(ROOT, 'technical-specification.md');
|
|
41
|
+
if (fs.existsSync(rootSpec)) files.push(rootSpec);
|
|
42
|
+
|
|
43
|
+
const srcDir = path.join(ROOT, 'src');
|
|
44
|
+
if (!fs.existsSync(srcDir)) return files;
|
|
45
|
+
|
|
46
|
+
for (const entry of fs.readdirSync(srcDir)) {
|
|
47
|
+
const moduleDir = path.join(srcDir, entry);
|
|
48
|
+
if (!fs.statSync(moduleDir).isDirectory()) continue;
|
|
49
|
+
|
|
50
|
+
for (const file of fs.readdirSync(moduleDir)) {
|
|
51
|
+
if (file.endsWith('.spec.md')) {
|
|
52
|
+
files.push(path.join(moduleDir, file));
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return files;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function getModuleSpecFiles(name) {
|
|
61
|
+
const moduleDir = path.join(ROOT, 'src', name);
|
|
62
|
+
if (!fs.existsSync(moduleDir) || !fs.statSync(moduleDir).isDirectory()) {
|
|
63
|
+
console.error(`ERROR: No such module: "${name}" (not found at src/${name}/)`);
|
|
64
|
+
process.exit(1);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const files = [];
|
|
68
|
+
for (const file of fs.readdirSync(moduleDir)) {
|
|
69
|
+
if (file.endsWith('.spec.md')) {
|
|
70
|
+
files.push(path.join(moduleDir, file));
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
return files;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function main() {
|
|
78
|
+
const args = process.argv.slice(2);
|
|
79
|
+
const issuesOnly = args.includes('--errors');
|
|
80
|
+
const subModuleIdx = args.indexOf('--sub-module');
|
|
81
|
+
const fileIdx = args.indexOf('--file');
|
|
82
|
+
|
|
83
|
+
let specFiles;
|
|
84
|
+
|
|
85
|
+
if (subModuleIdx !== -1) {
|
|
86
|
+
const moduleName = args[subModuleIdx + 1];
|
|
87
|
+
if (!moduleName) {
|
|
88
|
+
console.error('Usage: node scripts/check-artifacts.js --sub-module <name>');
|
|
89
|
+
process.exit(1);
|
|
90
|
+
}
|
|
91
|
+
specFiles = getModuleSpecFiles(moduleName);
|
|
92
|
+
} else if (fileIdx !== -1) {
|
|
93
|
+
const filePath = args[fileIdx + 1];
|
|
94
|
+
if (!filePath) {
|
|
95
|
+
console.error('Usage: node scripts/check-artifacts.js --file <path>');
|
|
96
|
+
process.exit(1);
|
|
97
|
+
}
|
|
98
|
+
const resolvedPath = path.resolve(process.cwd(), filePath);
|
|
99
|
+
if (!fs.existsSync(resolvedPath)) {
|
|
100
|
+
console.error(`ERROR: File not found: ${filePath}`);
|
|
101
|
+
process.exit(1);
|
|
102
|
+
}
|
|
103
|
+
if (!resolvedPath.endsWith('.spec.md')) {
|
|
104
|
+
console.error(`ERROR: Not a .spec.md file: ${filePath}`);
|
|
105
|
+
process.exit(1);
|
|
106
|
+
}
|
|
107
|
+
specFiles = [resolvedPath];
|
|
108
|
+
} else {
|
|
109
|
+
specFiles = getAllSpecFiles();
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const results = specFiles.map(specPath => {
|
|
113
|
+
const relSpecPath = path.relative(ROOT, specPath);
|
|
114
|
+
const specMtime = fs.statSync(specPath).mtimeMs;
|
|
115
|
+
const review = getReviewStatus(specPath);
|
|
116
|
+
|
|
117
|
+
return {
|
|
118
|
+
specFile: relSpecPath,
|
|
119
|
+
specMtime: Math.floor(specMtime),
|
|
120
|
+
reviewFile: review.reviewFile,
|
|
121
|
+
reviewMtime: review.reviewMtime,
|
|
122
|
+
reviewStatus: review.reviewStatus,
|
|
123
|
+
};
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
const output = issuesOnly ? results.filter(r => r.reviewStatus !== "OK") : results;
|
|
127
|
+
|
|
128
|
+
console.log(JSON.stringify(output, null, 2));
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
main();
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { fileURLToPath } from 'url';
|
|
3
|
+
import fs from 'fs';
|
|
4
|
+
import path from 'path';
|
|
5
|
+
|
|
6
|
+
const __dirname = fileURLToPath(new URL('.', import.meta.url));
|
|
7
|
+
const ROOT = path.resolve(__dirname, '..');
|
|
8
|
+
const SPEC_FILE = 'technical-specification.md';
|
|
9
|
+
|
|
10
|
+
function parseModuleReference() {
|
|
11
|
+
const content = fs.readFileSync(path.join(ROOT, SPEC_FILE), 'utf-8');
|
|
12
|
+
const lines = content.split('\n');
|
|
13
|
+
|
|
14
|
+
let inTable = false;
|
|
15
|
+
const rows = [];
|
|
16
|
+
|
|
17
|
+
for (const line of lines) {
|
|
18
|
+
const trimmed = line.trim();
|
|
19
|
+
if (!trimmed.startsWith('|') || !trimmed.endsWith('|')) {
|
|
20
|
+
if (inTable) break;
|
|
21
|
+
continue;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const cells = trimmed.split('|').map(c => c.trim()).filter(c => c.length > 0);
|
|
25
|
+
|
|
26
|
+
if (!inTable) {
|
|
27
|
+
inTable = true;
|
|
28
|
+
continue;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (cells.every(c => /^[-:` ]+$/.test(c))) continue;
|
|
32
|
+
|
|
33
|
+
rows.push(cells);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const modules = {};
|
|
37
|
+
for (const row of rows) {
|
|
38
|
+
if (row.length < 4) continue;
|
|
39
|
+
const name = row[0];
|
|
40
|
+
const dir = row[1].replace(/`/g, '').trim();
|
|
41
|
+
const specRaw = row[3];
|
|
42
|
+
|
|
43
|
+
if (dir === '—' || dir === '-') continue;
|
|
44
|
+
|
|
45
|
+
const specFiles = specRaw
|
|
46
|
+
.split(',')
|
|
47
|
+
.map(s => {
|
|
48
|
+
const cleaned = s.replace(/`/g, '').trim();
|
|
49
|
+
const parenIdx = cleaned.indexOf('(');
|
|
50
|
+
return parenIdx !== -1 ? cleaned.substring(0, parenIdx).trim() : cleaned;
|
|
51
|
+
})
|
|
52
|
+
.filter(s => s.endsWith('.spec.md') && s.length > 0);
|
|
53
|
+
|
|
54
|
+
modules[name.toLowerCase()] = { name, dir, specFiles };
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return modules;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function extractCodeBlocks(content) {
|
|
61
|
+
const blocks = [];
|
|
62
|
+
const regex = /```(mermaid|html)\s*\n([\s\S]*?)```/g;
|
|
63
|
+
let match;
|
|
64
|
+
while ((match = regex.exec(content)) !== null) {
|
|
65
|
+
const code = match[2].trim();
|
|
66
|
+
if (code.length > 0) {
|
|
67
|
+
blocks.push({ lang: match[1], code });
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return blocks;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function getDiagramName(code, lang, index) {
|
|
74
|
+
if (lang === 'html') return 'd3-animation.html';
|
|
75
|
+
const firstLine = code.trim().split('\n')[0].trim();
|
|
76
|
+
if (/^graph\s+(TB|LR|RL|BT|TD)/.test(firstLine)) return 'architecture.mmd';
|
|
77
|
+
if (/^sequenceDiagram/.test(firstLine)) return 'sequence.mmd';
|
|
78
|
+
return `diagram-${index + 1}.mmd`;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function processSpecFile(specPath, outputDir, extraFiles) {
|
|
82
|
+
const content = fs.readFileSync(specPath, 'utf-8');
|
|
83
|
+
const blocks = extractCodeBlocks(content);
|
|
84
|
+
|
|
85
|
+
const specName = path.basename(specPath);
|
|
86
|
+
const specOutputDir = path.join(outputDir, specName);
|
|
87
|
+
fs.mkdirSync(specOutputDir, { recursive: true });
|
|
88
|
+
|
|
89
|
+
const usedNames = new Set();
|
|
90
|
+
for (let i = 0; i < blocks.length; i++) {
|
|
91
|
+
const { lang, code } = blocks[i];
|
|
92
|
+
let filename = getDiagramName(code, lang, i);
|
|
93
|
+
if (usedNames.has(filename)) {
|
|
94
|
+
const base = filename.replace(/\.(mmd|html)$/, '');
|
|
95
|
+
const ext = filename.match(/\.(mmd|html)$/)[0];
|
|
96
|
+
let counter = 2;
|
|
97
|
+
while (usedNames.has(`${base}-${counter}${ext}`)) counter++;
|
|
98
|
+
filename = `${base}-${counter}${ext}`;
|
|
99
|
+
}
|
|
100
|
+
usedNames.add(filename);
|
|
101
|
+
fs.writeFileSync(path.join(specOutputDir, filename), code + '\n');
|
|
102
|
+
console.log(` extracted ${specName}/${filename}`);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
if (extraFiles) {
|
|
106
|
+
for (const { src, dest } of extraFiles) {
|
|
107
|
+
if (fs.existsSync(src)) {
|
|
108
|
+
fs.copyFileSync(src, path.join(specOutputDir, dest));
|
|
109
|
+
console.log(` copied ${dest} from project root`);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const hasMermaid = blocks.some(b => b.lang === 'mermaid');
|
|
115
|
+
if (blocks.length === 0 && !extraFiles?.some(e => fs.existsSync(e.src))) {
|
|
116
|
+
console.error(`ERROR: No artifacts found in ${specPath}`);
|
|
117
|
+
console.error(`HINT: Run system-design skill to regenerate spec with diagrams.`);
|
|
118
|
+
process.exit(1);
|
|
119
|
+
}
|
|
120
|
+
if (!hasMermaid && blocks.length > 0) {
|
|
121
|
+
console.log(` (no mermaid diagrams in this spec file — HTML only)`);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function processSubModule(mod) {
|
|
126
|
+
const outputDir = path.join(ROOT, mod.dir, '.artifacts');
|
|
127
|
+
fs.mkdirSync(outputDir, { recursive: true });
|
|
128
|
+
console.log(`\nProcessing ${mod.name} module → ${path.join(mod.dir, '.artifacts/')}`);
|
|
129
|
+
for (const specFile of mod.specFiles) {
|
|
130
|
+
const specPath = path.join(ROOT, mod.dir, specFile);
|
|
131
|
+
if (fs.existsSync(specPath)) {
|
|
132
|
+
processSpecFile(specPath, outputDir);
|
|
133
|
+
} else {
|
|
134
|
+
console.error(` WARNING: ${path.join(mod.dir, specFile)} not found, skipping`);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function main() {
|
|
140
|
+
const args = process.argv.slice(2);
|
|
141
|
+
const subModuleIdx = args.indexOf('--sub-module');
|
|
142
|
+
const allFlag = args.includes('--all');
|
|
143
|
+
const fileIdx = args.indexOf('--file');
|
|
144
|
+
|
|
145
|
+
if (fileIdx !== -1) {
|
|
146
|
+
const filePath = args[fileIdx + 1];
|
|
147
|
+
if (!filePath) {
|
|
148
|
+
console.error('Usage: node scripts/extract-artifacts.js --file <relative-path>');
|
|
149
|
+
process.exit(1);
|
|
150
|
+
}
|
|
151
|
+
const absPath = path.resolve(ROOT, filePath);
|
|
152
|
+
if (!fs.existsSync(absPath)) {
|
|
153
|
+
console.error(`ERROR: File not found: ${absPath}`);
|
|
154
|
+
process.exit(1);
|
|
155
|
+
}
|
|
156
|
+
const outputDir = path.join(path.dirname(absPath), '.artifacts');
|
|
157
|
+
fs.mkdirSync(outputDir, { recursive: true });
|
|
158
|
+
console.log(`Processing ${filePath} → ${path.join(path.dirname(filePath), '.artifacts/')}`);
|
|
159
|
+
processSpecFile(absPath, outputDir);
|
|
160
|
+
console.log('\nDone. Run `npm run test-artifacts` to validate.');
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
const modules = parseModuleReference();
|
|
165
|
+
|
|
166
|
+
if (subModuleIdx !== -1) {
|
|
167
|
+
const moduleName = args[subModuleIdx + 1];
|
|
168
|
+
if (!moduleName) {
|
|
169
|
+
console.error('Usage: node scripts/extract-artifacts.js --sub-module <name>');
|
|
170
|
+
console.error(`Available modules: ${Object.keys(modules).join(', ')}`);
|
|
171
|
+
process.exit(1);
|
|
172
|
+
}
|
|
173
|
+
const mod = modules[moduleName.toLowerCase()];
|
|
174
|
+
if (!mod) {
|
|
175
|
+
console.error(`Unknown sub-module: "${moduleName}". Available: ${Object.keys(modules).join(', ')}`);
|
|
176
|
+
process.exit(1);
|
|
177
|
+
}
|
|
178
|
+
processSubModule(mod);
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
if (allFlag) {
|
|
183
|
+
console.log(`Processing ${SPEC_FILE} → .artifacts/`);
|
|
184
|
+
const rootD3 = path.join(ROOT, 'd3-animation.html');
|
|
185
|
+
const rootExtra = fs.existsSync(rootD3) ? [{ src: rootD3, dest: 'd3-animation.html' }] : [];
|
|
186
|
+
processSpecFile(path.join(ROOT, SPEC_FILE), path.join(ROOT, '.artifacts'), rootExtra);
|
|
187
|
+
console.log('Extracting artifacts from all modules...');
|
|
188
|
+
for (const mod of Object.values(modules)) {
|
|
189
|
+
processSubModule(mod);
|
|
190
|
+
}
|
|
191
|
+
console.log('\nDone. Run `npm run test-artifacts` to validate.');
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
const outputDir = path.join(ROOT, '.artifacts');
|
|
196
|
+
fs.mkdirSync(outputDir, { recursive: true });
|
|
197
|
+
console.log(`Processing ${SPEC_FILE} → .artifacts/`);
|
|
198
|
+
const rootD3 = path.join(ROOT, 'd3-animation.html');
|
|
199
|
+
const extraFiles = fs.existsSync(rootD3) ? [{ src: rootD3, dest: 'd3-animation.html' }] : [];
|
|
200
|
+
processSpecFile(path.join(ROOT, SPEC_FILE), outputDir, extraFiles);
|
|
201
|
+
console.log('\nDone. Run `npm run test-artifacts` to validate.');
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
main();
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
# Ubuntu 24.04.2 LTS (noble) — full development environment for opencode projects
|
|
5
|
+
# Usage: bash scripts/install/linux/ubuntu-noble-24.04/install.sh
|
|
6
|
+
UBUNTU_CODENAME="$(lsb_release -c -s 2>/dev/null || echo 'noble')"
|
|
7
|
+
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
8
|
+
REPO_ROOT="$(cd "$SCRIPT_DIR/../../.." && pwd)"
|
|
9
|
+
|
|
10
|
+
PACKAGES=(
|
|
11
|
+
# ---- Build toolchain ----
|
|
12
|
+
build-essential
|
|
13
|
+
cmake
|
|
14
|
+
nasm
|
|
15
|
+
git
|
|
16
|
+
|
|
17
|
+
# ---- Artifact pipeline ----
|
|
18
|
+
nodejs
|
|
19
|
+
npm
|
|
20
|
+
|
|
21
|
+
# ---- Code search & navigation ----
|
|
22
|
+
ripgrep
|
|
23
|
+
fd-find
|
|
24
|
+
bat
|
|
25
|
+
fzf
|
|
26
|
+
|
|
27
|
+
# ---- System monitoring ----
|
|
28
|
+
htop
|
|
29
|
+
duf
|
|
30
|
+
|
|
31
|
+
# ---- Performance & benchmarking ----
|
|
32
|
+
hyperfine
|
|
33
|
+
linux-tools-common
|
|
34
|
+
linux-tools-generic
|
|
35
|
+
|
|
36
|
+
# ---- Network tools ----
|
|
37
|
+
httpie
|
|
38
|
+
whois
|
|
39
|
+
net-tools
|
|
40
|
+
dnsutils
|
|
41
|
+
traceroute
|
|
42
|
+
nmap
|
|
43
|
+
mtr
|
|
44
|
+
|
|
45
|
+
# ---- Development utilities ----
|
|
46
|
+
tmux
|
|
47
|
+
parallel
|
|
48
|
+
pv
|
|
49
|
+
entr
|
|
50
|
+
tree
|
|
51
|
+
strace
|
|
52
|
+
ltrace
|
|
53
|
+
jq
|
|
54
|
+
zip
|
|
55
|
+
unzip
|
|
56
|
+
pigz
|
|
57
|
+
rsync
|
|
58
|
+
curl
|
|
59
|
+
wget
|
|
60
|
+
ssh
|
|
61
|
+
|
|
62
|
+
# ---- Debugging ----
|
|
63
|
+
gdb
|
|
64
|
+
python3-pip
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
echo "==> opencode: installing ${#PACKAGES[@]} packages for Ubuntu $UBUNTU_CODENAME..."
|
|
68
|
+
|
|
69
|
+
sudo apt update
|
|
70
|
+
sudo apt install -y "${PACKAGES[@]}"
|
|
71
|
+
|
|
72
|
+
echo "==> Installing gdb-mcp-server (structured GDB interface for agents)..."
|
|
73
|
+
pip3 install gdb-mcp-server
|
|
74
|
+
|
|
75
|
+
if [ -f "$REPO_ROOT/package.json" ]; then
|
|
76
|
+
echo "==> Installing npm dependencies..."
|
|
77
|
+
cd "$REPO_ROOT" && npm install
|
|
78
|
+
fi
|
|
79
|
+
|
|
80
|
+
echo ""
|
|
81
|
+
echo "=============================="
|
|
82
|
+
echo " Toolchain Verification"
|
|
83
|
+
echo "=============================="
|
|
84
|
+
printf "%-20s %s\n" "g++" "$(g++ --version | head -1)"
|
|
85
|
+
printf "%-20s %s\n" "cmake" "$(cmake --version | head -1)"
|
|
86
|
+
printf "%-20s %s\n" "nasm" "$(nasm --version | head -1)"
|
|
87
|
+
printf "%-20s %s\n" "node" "$(node --version)"
|
|
88
|
+
printf "%-20s %s\n" "perf" "$(perf --version | head -1)"
|
|
89
|
+
printf "%-20s %s\n" "gdb" "$(gdb --version | head -1)"
|
|
90
|
+
printf "%-20s %s\n" "rg" "$(rg --version | head -1)"
|
|
91
|
+
printf "%-20s %s\n" "gdb-mcp" "$(pip3 show gdb-mcp-server 2>/dev/null | grep Version || echo 'not found')"
|
|
92
|
+
echo ""
|
|
93
|
+
echo "Installation complete."
|
|
94
|
+
echo "Run 'gh auth login' for GitHub CLI (issue management)."
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
# macOS — full development environment for opencode projects
|
|
5
|
+
# Usage: bash scripts/install/osx/macos-sequoia-15.0/install.sh
|
|
6
|
+
|
|
7
|
+
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
8
|
+
REPO_ROOT="$(cd "$SCRIPT_DIR/../../.." && pwd)"
|
|
9
|
+
|
|
10
|
+
# ---- Version detection ----
|
|
11
|
+
OS_NAME="macos"
|
|
12
|
+
OS_VERSION=$(sw_vers -productVersion 2>/dev/null || echo "0.0")
|
|
13
|
+
|
|
14
|
+
# Codename lookup (newest → oldest)
|
|
15
|
+
if [[ $OS_VERSION == 15.* ]]; then OS_CODENAME="sequoia"
|
|
16
|
+
elif [[ $OS_VERSION == 14.* ]]; then OS_CODENAME="sonoma"
|
|
17
|
+
elif [[ $OS_VERSION == 13.* ]]; then OS_CODENAME="ventura"
|
|
18
|
+
elif [[ $OS_VERSION == 12.* ]]; then OS_CODENAME="monterey"
|
|
19
|
+
elif [[ $OS_VERSION == 11.* ]]; then OS_CODENAME="big-sur"
|
|
20
|
+
else OS_CODENAME="unknown"
|
|
21
|
+
fi
|
|
22
|
+
|
|
23
|
+
echo "==> opencode: installing for macOS ${OS_VERSION} (${OS_CODENAME})..."
|
|
24
|
+
|
|
25
|
+
# ---- 1. Xcode Command Line Tools ----
|
|
26
|
+
if ! xcode-select -p &>/dev/null; then
|
|
27
|
+
echo "==> Installing Xcode Command Line Tools..."
|
|
28
|
+
xcode-select --install
|
|
29
|
+
echo " Please complete the installation dialog, then re-run this script."
|
|
30
|
+
exit 0
|
|
31
|
+
fi
|
|
32
|
+
echo " ✓ Xcode Command Line Tools found"
|
|
33
|
+
|
|
34
|
+
# ---- 2. Homebrew ----
|
|
35
|
+
if ! command -v brew &>/dev/null; then
|
|
36
|
+
echo "==> Installing Homebrew..."
|
|
37
|
+
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
|
|
38
|
+
fi
|
|
39
|
+
echo " ✓ Homebrew found"
|
|
40
|
+
|
|
41
|
+
# ---- 3. Install packages ----
|
|
42
|
+
BREW_PACKAGES=(
|
|
43
|
+
# Build toolchain
|
|
44
|
+
cmake
|
|
45
|
+
nasm
|
|
46
|
+
git
|
|
47
|
+
node
|
|
48
|
+
|
|
49
|
+
# Code search & navigation
|
|
50
|
+
ripgrep
|
|
51
|
+
fd
|
|
52
|
+
bat
|
|
53
|
+
fzf
|
|
54
|
+
|
|
55
|
+
# System monitoring
|
|
56
|
+
htop
|
|
57
|
+
duf
|
|
58
|
+
|
|
59
|
+
# Performance & benchmarking
|
|
60
|
+
hyperfine
|
|
61
|
+
|
|
62
|
+
# Network tools
|
|
63
|
+
httpie
|
|
64
|
+
whois
|
|
65
|
+
nmap
|
|
66
|
+
mtr
|
|
67
|
+
|
|
68
|
+
# Development utilities
|
|
69
|
+
tmux
|
|
70
|
+
parallel
|
|
71
|
+
pv
|
|
72
|
+
entr
|
|
73
|
+
tree
|
|
74
|
+
jq
|
|
75
|
+
pigz
|
|
76
|
+
wget
|
|
77
|
+
|
|
78
|
+
# Debugging
|
|
79
|
+
python
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
echo "==> Installing ${#BREW_PACKAGES[@]} Homebrew packages..."
|
|
83
|
+
brew install "${BREW_PACKAGES[@]}"
|
|
84
|
+
|
|
85
|
+
# ---- 4. Python + GDB MCP ----
|
|
86
|
+
echo "==> Installing gdb-mcp-server..."
|
|
87
|
+
pip3 install gdb-mcp-server
|
|
88
|
+
|
|
89
|
+
# ---- 5. npm ----
|
|
90
|
+
if [ -f "$REPO_ROOT/package.json" ]; then
|
|
91
|
+
echo "==> Installing npm dependencies..."
|
|
92
|
+
cd "$REPO_ROOT" && npm install
|
|
93
|
+
fi
|
|
94
|
+
|
|
95
|
+
# ---- 6. Verification ----
|
|
96
|
+
echo ""
|
|
97
|
+
echo "=============================="
|
|
98
|
+
echo " Toolchain Verification"
|
|
99
|
+
echo "=============================="
|
|
100
|
+
printf "%-20s %s\n" "clang++" "$(clang++ --version | head -1)"
|
|
101
|
+
printf "%-20s %s\n" "cmake" "$(cmake --version | head -1)"
|
|
102
|
+
printf "%-20s %s\n" "nasm" "$(nasm --version | head -1)"
|
|
103
|
+
printf "%-20s %s\n" "node" "$(node --version)"
|
|
104
|
+
printf "%-20s %s\n" "lldb" "$(lldb --version | head -1)"
|
|
105
|
+
printf "%-20s %s\n" "rg" "$(rg --version | head -1)"
|
|
106
|
+
printf "%-20s %s\n" "gdb-mcp" "$(pip3 show gdb-mcp-server 2>/dev/null | grep Version || echo 'not found')"
|
|
107
|
+
echo ""
|
|
108
|
+
echo "Installation complete."
|
|
109
|
+
echo ""
|
|
110
|
+
echo "Notes:"
|
|
111
|
+
echo " - perf/strace/ltrace are Linux-specific and not available on macOS."
|
|
112
|
+
echo " - Use Xcode Instruments.app for profiling."
|
|
113
|
+
echo " - Use lldb for debugging (Xcode CLT provides it)."
|
|
114
|
+
echo " - Run 'gh auth login' for GitHub CLI (issue management)."
|
|
115
|
+
echo ""
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
#Requires -RunAsAdministrator
|
|
2
|
+
|
|
3
|
+
# WSL2 — full development environment for opencode projects
|
|
4
|
+
# Usage (as Administrator):
|
|
5
|
+
# powershell -ExecutionPolicy Bypass -File scripts\install\windows\wsl2\install.ps1
|
|
6
|
+
|
|
7
|
+
$ErrorActionPreference = "Stop"
|
|
8
|
+
$SCRIPT_DIR = Split-Path -Parent $MyInvocation.MyCommand.Path
|
|
9
|
+
$REPO_ROOT = Resolve-Path "$SCRIPT_DIR\..\..\..\.."
|
|
10
|
+
|
|
11
|
+
Write-Host "==> opencode: installing for Windows (WSL2)..."
|
|
12
|
+
|
|
13
|
+
# ---- 1. Check if WSL feature is enabled ----
|
|
14
|
+
$wslFeature = Get-WindowsOptionalFeature -Online -FeatureName "Microsoft-Windows-Subsystem-Linux"
|
|
15
|
+
$vmpFeature = Get-WindowsOptionalFeature -Online -FeatureName "VirtualMachinePlatform"
|
|
16
|
+
|
|
17
|
+
if ($wslFeature.State -ne "Enabled" -or $vmpFeature.State -ne "Enabled") {
|
|
18
|
+
Write-Host "==> Enabling WSL and Virtual Machine Platform..."
|
|
19
|
+
Enable-WindowsOptionalFeature -Online -FeatureName "Microsoft-Windows-Subsystem-Linux" -NoRestart
|
|
20
|
+
Enable-WindowsOptionalFeature -Online -FeatureName "VirtualMachinePlatform" -NoRestart
|
|
21
|
+
Write-Host ""
|
|
22
|
+
Write-Host "WARNING: A system reboot is required before continuing."
|
|
23
|
+
Write-Host "After rebooting, run this script again to complete setup."
|
|
24
|
+
Write-Host ""
|
|
25
|
+
pause
|
|
26
|
+
exit
|
|
27
|
+
}
|
|
28
|
+
Write-Host " ✓ WSL feature is enabled"
|
|
29
|
+
|
|
30
|
+
# ---- 2. Install/update WSL2 kernel ----
|
|
31
|
+
Write-Host "==> Updating WSL2 kernel..."
|
|
32
|
+
wsl --update
|
|
33
|
+
|
|
34
|
+
# ---- 3. Set WSL2 as default ----
|
|
35
|
+
Write-Host "==> Setting WSL2 as default..."
|
|
36
|
+
wsl --set-default-version 2
|
|
37
|
+
|
|
38
|
+
# ---- 4. Install Ubuntu distro if not present ----
|
|
39
|
+
$distros = wsl --list --quiet
|
|
40
|
+
if ($distros -notcontains "Ubuntu") {
|
|
41
|
+
Write-Host "==> Installing Ubuntu distribution..."
|
|
42
|
+
wsl --install -d Ubuntu
|
|
43
|
+
Write-Host ""
|
|
44
|
+
Write-Host "Ubuntu installed. It will start automatically to complete setup."
|
|
45
|
+
Write-Host "Create a Linux username/password when prompted, then re-run this script."
|
|
46
|
+
Write-Host ""
|
|
47
|
+
pause
|
|
48
|
+
exit
|
|
49
|
+
}
|
|
50
|
+
Write-Host " ✓ Ubuntu distribution found"
|
|
51
|
+
|
|
52
|
+
# ---- 5. Set up the repo inside WSL ----
|
|
53
|
+
$WSL_HOME = "~"
|
|
54
|
+
$WSL_REPO_DIR = Split-Path -Leaf $REPO_ROOT
|
|
55
|
+
|
|
56
|
+
# Check if the repo already exists in WSL
|
|
57
|
+
$repoExists = wsl -d Ubuntu -e bash -c "test -d $WSL_HOME/$WSL_REPO_DIR && echo 'exists' || echo ''"
|
|
58
|
+
if (-not $repoExists) {
|
|
59
|
+
# Check if we're inside a git repo (clone scenario)
|
|
60
|
+
if (Test-Path "$REPO_ROOT\.git") {
|
|
61
|
+
$repoUrl = (git -C $REPO_ROOT remote get-url origin 2>$null)
|
|
62
|
+
if ($repoUrl) {
|
|
63
|
+
Write-Host "==> Cloning existing repository inside WSL..."
|
|
64
|
+
wsl -d Ubuntu -e bash -c "cd $WSL_HOME && git clone $repoUrl $WSL_REPO_DIR"
|
|
65
|
+
} else {
|
|
66
|
+
Write-Host "==> Copying files to WSL (no remote origin)..."
|
|
67
|
+
wsl -d Ubuntu -e bash -c "mkdir -p $WSL_HOME/$WSL_REPO_DIR"
|
|
68
|
+
# Copy files from current directory into WSL (excluding node_modules, .git, etc.)
|
|
69
|
+
wsl -d Ubuntu -e bash -c "rsync -a --exclude='node_modules' --exclude='.git' '$REPO_ROOT/' '$WSL_HOME/$WSL_REPO_DIR/'"
|
|
70
|
+
}
|
|
71
|
+
} else {
|
|
72
|
+
# Starter scenario — create directory structure
|
|
73
|
+
Write-Host "==> Creating project structure inside WSL..."
|
|
74
|
+
wsl -d Ubuntu -e bash -c "mkdir -p $WSL_HOME/$WSL_REPO_DIR"
|
|
75
|
+
if (Test-Path $REPO_ROOT) {
|
|
76
|
+
wsl -d Ubuntu -e bash -c "rsync -a '$REPO_ROOT/' '$WSL_HOME/$WSL_REPO_DIR/'"
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
Write-Host " ✓ Repository set up at ~/$WSL_REPO_DIR inside WSL"
|
|
81
|
+
|
|
82
|
+
# ---- 6. Run the Ubuntu install script inside WSL ----
|
|
83
|
+
Write-Host "==> Running Ubuntu install script inside WSL..."
|
|
84
|
+
wsl -d Ubuntu -e bash -c "
|
|
85
|
+
cd ~/$WSL_REPO_DIR
|
|
86
|
+
bash scripts/install/linux/ubuntu-noble-24.04/install.sh
|
|
87
|
+
"
|
|
88
|
+
|
|
89
|
+
# ---- 7. Done ----
|
|
90
|
+
Write-Host ""
|
|
91
|
+
Write-Host "=============================="
|
|
92
|
+
Write-Host " WSL2 Setup Complete"
|
|
93
|
+
Write-Host "=============================="
|
|
94
|
+
Write-Host " Enter WSL: wsl -d Ubuntu"
|
|
95
|
+
Write-Host " Project path: ~/$WSL_REPO_DIR"
|
|
96
|
+
Write-Host ""
|
|
97
|
+
Write-Host " Run 'gh auth login' inside WSL for GitHub CLI access."
|
|
98
|
+
Write-Host ""
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
#Requires -RunAsAdministrator
|
|
2
|
+
|
|
3
|
+
# deepenc environment installer — Windows detection and dispatch
|
|
4
|
+
# Usage (as Administrator):
|
|
5
|
+
# powershell -ExecutionPolicy Bypass -File scripts\install.ps1
|
|
6
|
+
|
|
7
|
+
$ErrorActionPreference = "Stop"
|
|
8
|
+
$SCRIPT_DIR = Split-Path -Parent $MyInvocation.MyCommand.Path
|
|
9
|
+
|
|
10
|
+
Write-Host "==> deepenc: detected Windows"
|
|
11
|
+
|
|
12
|
+
# Check if WSL is available
|
|
13
|
+
$wslFeature = Get-WindowsOptionalFeature -Online -FeatureName "Microsoft-Windows-Subsystem-Linux" -ErrorAction SilentlyContinue
|
|
14
|
+
$hasWsl = ($wslFeature -and $wslFeature.State -eq "Enabled")
|
|
15
|
+
|
|
16
|
+
if (-not $hasWsl) {
|
|
17
|
+
Write-Host "==> WSL is not installed. Running WSL2 installer..."
|
|
18
|
+
& "$SCRIPT_DIR\install\windows\wsl2\install.ps1"
|
|
19
|
+
} else {
|
|
20
|
+
# WSL is already enabled — check if Ubuntu distro exists
|
|
21
|
+
$distros = wsl --list --quiet 2>$null
|
|
22
|
+
if ($distros -contains "Ubuntu") {
|
|
23
|
+
Write-Host "==> WSL2 + Ubuntu detected. Running Ubuntu installer inside WSL..."
|
|
24
|
+
wsl -d Ubuntu -e bash -c "
|
|
25
|
+
cd ~/deepenc 2>/dev/null || mkdir -p ~/deepenc
|
|
26
|
+
bash scripts/install/linux/ubuntu-noble-24.04/install.sh
|
|
27
|
+
"
|
|
28
|
+
} else {
|
|
29
|
+
Write-Host "==> WSL enabled but Ubuntu not installed. Running WSL2 installer..."
|
|
30
|
+
& "$SCRIPT_DIR\install\windows\wsl2\install.ps1"
|
|
31
|
+
}
|
|
32
|
+
}
|