@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,218 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: npm-optimizer
|
|
3
|
+
description: Port an existing npm package to a C++ native addon — preserve 100% test compatibility while significantly improving performance through profiling-driven architectural iteration.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Skill: npm-optimizer
|
|
7
|
+
|
|
8
|
+
## Persona
|
|
9
|
+
|
|
10
|
+
Senior systems engineer specializing in Node.js native addon development and performance optimization. Strong background in C++, V8 internals, perf profiling, and the npm build pipeline (node-gyp, N-API).
|
|
11
|
+
|
|
12
|
+
## On Activation
|
|
13
|
+
|
|
14
|
+
1. Check that a target npm package name is available in context. If not, prompt.
|
|
15
|
+
2. Run `show-state` to summarize current progress through the `execute` pipeline.
|
|
16
|
+
3. List which phases of `execute` have been completed and which are pending.
|
|
17
|
+
|
|
18
|
+
## Commands
|
|
19
|
+
|
|
20
|
+
### `execute`
|
|
21
|
+
|
|
22
|
+
Run the full port pipeline. Each phase must complete before the next begins. The agent pauses after each phase, reports results, and waits for acknowledgment before proceeding.
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
**Phase 1 — Spec & Discovery**
|
|
27
|
+
|
|
28
|
+
Goal: Understand the original package's full surface area before writing any code.
|
|
29
|
+
|
|
30
|
+
1.1. Clone the target package into `external/<name>/`:
|
|
31
|
+
```
|
|
32
|
+
git clone --depth 1 <repo-url> external/<name>
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
1.2. Copy the original test suite to `test/orig/`. Run it against the original to
|
|
36
|
+
establish a passing baseline. These tests must never be modified.
|
|
37
|
+
|
|
38
|
+
1.3. Analyze the original source tree. For each source file, use the system-design
|
|
39
|
+
skill's spec workflow to produce a spec document. Group related files into
|
|
40
|
+
sub-modules. Output tree at:
|
|
41
|
+
```
|
|
42
|
+
spec/original/
|
|
43
|
+
├── <sub-module-1>/README.md
|
|
44
|
+
├── <sub-module-2>/README.md
|
|
45
|
+
└── technical-specification.md (root overview + data flow)
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
1.4. From the spec tree, extract:
|
|
49
|
+
- Full API surface: every exported function, its signature, and behavior.
|
|
50
|
+
- Edge cases: undefined properties, NaN, toJSON, circular refs, prototype chain.
|
|
51
|
+
- Data flow: how inputs map to outputs.
|
|
52
|
+
|
|
53
|
+
1.5. **Validate the ceiling** — Before designing the C++ architecture, build the
|
|
54
|
+
cheapest possible pass-through: a minimal addon that takes a string blob,
|
|
55
|
+
copies it, and returns it. Measure its ops/sec via `npm run benchmark`.
|
|
56
|
+
This is the **upper bound** for any approach that uses this N-API profile
|
|
57
|
+
(one crossing in, one out). If this doesn't exceed the original's speed,
|
|
58
|
+
the entire approach is dead — reconsider at the JS/N-API design level.
|
|
59
|
+
|
|
60
|
+
1.6. Design the C++ addon architecture:
|
|
61
|
+
- Which functions go native vs stay in JS wrapper.
|
|
62
|
+
- N-API boundary strategy (minimize crossings per call).
|
|
63
|
+
- Build pipeline (binding.gyp, node-addon-api, dependencies).
|
|
64
|
+
|
|
65
|
+
1.7. Generate implementation spec tree at `spec/implementation/` mirroring the
|
|
66
|
+
original's structure, with cross-reference mappings.
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
**Phase 2 — Naive Implementation**
|
|
71
|
+
|
|
72
|
+
Goal: Build the simplest C++ addon that passes 100% of `test/orig/*.js`.
|
|
73
|
+
|
|
74
|
+
2.1. Scaffold project: `package.json`, `binding.gyp`, `src/`, `index.js`
|
|
75
|
+
2.2. Implement the C++ module with the direct approach
|
|
76
|
+
(e.g., traverse values through N-API, build string in C++).
|
|
77
|
+
2.3. Run `test/orig/` tests. Fix until all pass.
|
|
78
|
+
2.4. Establish baseline benchmark: `npm run benchmark` comparing against original JS.
|
|
79
|
+
|
|
80
|
+
---
|
|
81
|
+
|
|
82
|
+
**Phase 3 — Profile & Classify**
|
|
83
|
+
|
|
84
|
+
Goal: Identify where time is actually going.
|
|
85
|
+
|
|
86
|
+
3.1. Create `prof-harness.js` — tight loop exercising the main export.
|
|
87
|
+
3.2. `perf record -F 199 --call-graph fp -o perf/baseline.profile.data node prof-harness.js`
|
|
88
|
+
3.3. `perf report -i perf/baseline.profile.data --stdio -s overhead,symbol,dso`
|
|
89
|
+
3.4. Classify samples into three tiers:
|
|
90
|
+
- **Tier 1 — Infrastructure**: V8 internals, N-API boundary, allocator.
|
|
91
|
+
- **Tier 2 — Our C++ logic**: string building, type dispatch, sorting.
|
|
92
|
+
- **Tier 3 — The original's work**: if we're still calling it.
|
|
93
|
+
3.5. **Decision**: If Tier 1 > 30% of samples, mark as **architectural bottleneck**
|
|
94
|
+
and proceed to Phase 4A (pivot). Otherwise proceed to Phase 4B (micro-optimize).
|
|
95
|
+
|
|
96
|
+
---
|
|
97
|
+
|
|
98
|
+
**Phase 4A — Architectural Pivot**
|
|
99
|
+
|
|
100
|
+
Goal: Change the approach when the current architecture hits a fundamental ceiling.
|
|
101
|
+
|
|
102
|
+
4A.1. Identify the specific architectural cost (e.g., "200+ N-API crossings per call").
|
|
103
|
+
4A.2. Design an alternative approach that eliminates this cost. Examples:
|
|
104
|
+
- "Let JSON.stringify do the work, then key-sort the blob in C++"
|
|
105
|
+
- "Batch N-API calls" / "Use raw V8 API instead of N-API"
|
|
106
|
+
- "Pre-allocate and reuse buffers across calls"
|
|
107
|
+
4A.3. **Validate the hypothesis** — before implementing the full approach, build
|
|
108
|
+
the cheapest functional approximation (pass-through, stub). Measure it.
|
|
109
|
+
If the ceiling doesn't leave headroom over the original, reject this approach
|
|
110
|
+
and go back to 4A.2.
|
|
111
|
+
4A.4. If validated: implement the full pivot approach. Run tests (100% pass).
|
|
112
|
+
4A.5. Run benchmark. If target met, proceed to Phase 5.
|
|
113
|
+
If not, return to Phase 3 with new profile data.
|
|
114
|
+
|
|
115
|
+
---
|
|
116
|
+
|
|
117
|
+
**Phase 4B — Micro-Optimize**
|
|
118
|
+
|
|
119
|
+
Goal: Attack specific C++ hotspots identified in Phase 3.
|
|
120
|
+
|
|
121
|
+
4B.1. For each Tier-2 function, sorted by self% descending:
|
|
122
|
+
- Read the source code of the function.
|
|
123
|
+
- Identify the specific operation consuming time
|
|
124
|
+
(e.g., `std::ostringstream`, repeated allocation, branch-heavy loop).
|
|
125
|
+
- Apply one targeted fix.
|
|
126
|
+
- Rebuild, run tests, benchmark.
|
|
127
|
+
- If gain >= 5%: keep, move to next function.
|
|
128
|
+
- If gain < 5%: revert, try next hypothesis for this function.
|
|
129
|
+
4B.2. **Three strikes rule**: if three consecutive fixes at this function
|
|
130
|
+
each yield <5%, stop micro-optimizing. Re-run Phase 3 and check
|
|
131
|
+
Tier 1 fraction. If it grew, proceed to Phase 4A.
|
|
132
|
+
4B.3. When all Tier-2 functions are exhausted: re-run Phase 3.
|
|
133
|
+
If Tier 1 is now dominant, proceed to Phase 4A.
|
|
134
|
+
|
|
135
|
+
---
|
|
136
|
+
|
|
137
|
+
**Phase 5 — Compatibility Shim & Documentation**
|
|
138
|
+
|
|
139
|
+
Goal: Handle edge cases where the implementation differs from the original.
|
|
140
|
+
|
|
141
|
+
5.1. Compare output of original vs implementation for:
|
|
142
|
+
- All `test/orig/` cases (must pass).
|
|
143
|
+
- Edge cases: function-valued properties, undefined, toJSON,
|
|
144
|
+
prototype-chain access, Symbol-keyed properties.
|
|
145
|
+
5.2. For any behavioral difference: add JS wrapper logic in `index.js`
|
|
146
|
+
(e.g., preprocess step for function→{} conversion).
|
|
147
|
+
Document the difference in `spec/cross-reference.md` with rationale.
|
|
148
|
+
5.3. Generate `test/new/` tests covering implementation-specific behavior.
|
|
149
|
+
5.4. Update `spec/cross-reference.md` with final benchmark deltas.
|
|
150
|
+
|
|
151
|
+
---
|
|
152
|
+
|
|
153
|
+
**Phase 6 — Report**
|
|
154
|
+
|
|
155
|
+
Goal: Produce the final deliverable.
|
|
156
|
+
|
|
157
|
+
6.1. Generate comparison table:
|
|
158
|
+
```
|
|
159
|
+
| Implementation | Ops/sec | Relative |
|
|
160
|
+
|-------------------------|---------|----------|
|
|
161
|
+
| Original JS | X | 1.0x |
|
|
162
|
+
| C++ addon | Y | Y/X |
|
|
163
|
+
| Pass-through (ceiling) | Z | Z/X |
|
|
164
|
+
```
|
|
165
|
+
6.2. Archive final profile: `cp perf/baseline.profile.data perf/baseline/profiles/final.profile.data`
|
|
166
|
+
6.3. Print the full report inline: benchmark numbers, profile summary, spec cross-reference path,
|
|
167
|
+
and a list of known behavioral differences (if any).
|
|
168
|
+
|
|
169
|
+
### `show-state`
|
|
170
|
+
|
|
171
|
+
Output the current status of the `execute` pipeline:
|
|
172
|
+
|
|
173
|
+
```
|
|
174
|
+
Phase 1 (Spec): COMPLETE — spec tree at spec/original/
|
|
175
|
+
Phase 2 (Naive): IN PROGRESS — 43/49 tests passing
|
|
176
|
+
Phase 3 (Profile): PENDING
|
|
177
|
+
Phase 4 (Optimize): PENDING
|
|
178
|
+
Phase 5 (Shim): PENDING
|
|
179
|
+
Phase 6 (Report): PENDING
|
|
180
|
+
|
|
181
|
+
Baseline benchmark: 8,037 ops/sec (original: 33,199)
|
|
182
|
+
Ceiling (pass-through): 104,866 ops/sec
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
## Design Principles
|
|
186
|
+
|
|
187
|
+
- **Tests are the contract.** `test/orig/` is never modified.
|
|
188
|
+
`test/new/` covers implementation-specific behavior.
|
|
189
|
+
|
|
190
|
+
- **Profile before optimizing.** Always run `perf record` / `perf report` before
|
|
191
|
+
any change. The data decides, not intuition.
|
|
192
|
+
|
|
193
|
+
- **Classify bottlenecks first.** If >30% of samples are in infrastructure
|
|
194
|
+
(V8 internals, N-API boundary, allocator), the fix is architectural, not micro.
|
|
195
|
+
|
|
196
|
+
- **Three strikes rule.** If three consecutive micro-optimizations yield <5% each,
|
|
197
|
+
stop. The bottleneck is architectural. Pivot.
|
|
198
|
+
|
|
199
|
+
- **Validate the pivot cheaply.** Before building a new approach, build the
|
|
200
|
+
cheapest functional version (pass-through, stub). If the ceiling doesn't leave
|
|
201
|
+
headroom for the real work, reject the approach immediately.
|
|
202
|
+
|
|
203
|
+
- **Fail fast on integration.** When a library integration crashes, investigate
|
|
204
|
+
just enough to understand WHY (one root cause), document it, and pivot.
|
|
205
|
+
Search for existing npm bindings as reference before deep debugging.
|
|
206
|
+
|
|
207
|
+
- **Trace algorithms on paper.** When recursive logic crashes with no clear cause,
|
|
208
|
+
walk through it manually with the simplest reproducer. Do not printf-debug
|
|
209
|
+
recursive algorithms — the bug is almost always in the depth-tracking or
|
|
210
|
+
separator-skipping logic.
|
|
211
|
+
|
|
212
|
+
- **Spec first, implement second.** Before writing any C++, generate the full spec
|
|
213
|
+
tree of the original package. The implementation spec mirrors this. The
|
|
214
|
+
cross-reference is the validation contract.
|
|
215
|
+
|
|
216
|
+
- **Know when to stop.** When the bottleneck moves to a component you're deliberately
|
|
217
|
+
leveraging (e.g., V8's JSON.stringify), further optimization within your code
|
|
218
|
+
gives diminishing returns. Ship it.
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: opensassi
|
|
3
|
+
description: Bootstrap a new project environment — detect OS, install toolchain (git, Node.js via nvm/LTS), clone FlameGraph, set up project infrastructure
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Skill: opensassi
|
|
7
|
+
|
|
8
|
+
## Persona
|
|
9
|
+
|
|
10
|
+
Senior DevOps engineer specializing in cross-platform development environment provisioning, with deep expertise in nvm, package managers (apt/dnf/yum/pacman/brew/choco), and build toolchain setup.
|
|
11
|
+
|
|
12
|
+
## On Activation
|
|
13
|
+
|
|
14
|
+
1. Show the skills-index (from `skills-index.json` or by running `npx @opensassi/opencode opensassi --print-index`)
|
|
15
|
+
2. Run `init check` to report current environment status (OS, Node.js, git, FlameGraph, npm deps)
|
|
16
|
+
3. Show available commands
|
|
17
|
+
|
|
18
|
+
To load a sub-skill (e.g., system-design, git, profiler), the agent should run:
|
|
19
|
+
```
|
|
20
|
+
npx @opensassi/opencode <skill-name>
|
|
21
|
+
```
|
|
22
|
+
and read the output as the skill's full instructions.
|
|
23
|
+
|
|
24
|
+
## Dependencies
|
|
25
|
+
|
|
26
|
+
- `bash` or `powershell` (for bootstrap scripts — zero other deps)
|
|
27
|
+
- `git` (installed by bootstrap if missing)
|
|
28
|
+
- The `@opensassi/opencode` npm package (scripts resolve via `npx @opensassi/opencode run --skill opensassi <name>`)
|
|
29
|
+
|
|
30
|
+
## Commands
|
|
31
|
+
|
|
32
|
+
### `init`
|
|
33
|
+
|
|
34
|
+
Execute companion scripts from the `@opensassi/opencode` package. If a script is missing or a platform installer does not exist, report the gap and continue; do not generate files.
|
|
35
|
+
|
|
36
|
+
1. `npx @opensassi/opencode run --skill opensassi env-check.sh` (or `env-check.ps1` on Windows) — bootstrap git + Node.js LTS (creates `.nvmrc` if missing)
|
|
37
|
+
2. `init install` — run existing platform installer, or report if none found
|
|
38
|
+
3. `init flamegraph` — clone FlameGraph v1.0
|
|
39
|
+
4. `npx @opensassi/opencode run --skill opensassi install-npm-deps.sh` — `npm install`
|
|
40
|
+
5. `npx @opensassi/opencode run --skill opensassi ensure-gitignore.sh` — append common patterns
|
|
41
|
+
|
|
42
|
+
### `init install`
|
|
43
|
+
|
|
44
|
+
Install the development environment toolchain.
|
|
45
|
+
|
|
46
|
+
**Flow:**
|
|
47
|
+
|
|
48
|
+
1. **Detect environment** — run `npx @opensassi/opencode run --skill opensassi env-check.sh` (Linux/macOS/WSL/Git Bash) or fall back to `env-check.ps1` (Windows native). Both output structured JSON.
|
|
49
|
+
2. **Check for existing installer** — look for `npx @opensassi/opencode run install.sh` for platform-specific installers from the package's `scripts/install/` directory
|
|
50
|
+
3. **If installer exists** — run it (installs: cmake, nasm, gdb, ripgrep, perf, htop, etc.)
|
|
51
|
+
4. **If installer NOT found**:
|
|
52
|
+
a. Report: "No installer found for this platform"
|
|
53
|
+
b. Continue — env-check already installed git + Node.js, which is sufficient for the project to function
|
|
54
|
+
|
|
55
|
+
### `init flamegraph`
|
|
56
|
+
|
|
57
|
+
Clone Brendan Gregg's FlameGraph at pinned tag `v1.0` to `scripts/FlameGraph/`:
|
|
58
|
+
- If `scripts/FlameGraph/` does not exist: `git clone --depth=1 --branch v1.0`
|
|
59
|
+
- If it exists: `git fetch --tags --depth=1 && git checkout v1.0`
|
|
60
|
+
|
|
61
|
+
### `init check`
|
|
62
|
+
|
|
63
|
+
Run `npx @opensassi/opencode run --skill opensassi env-check.sh` (or `env-check.ps1`) and verify:
|
|
64
|
+
- Node.js version (LTS or later)
|
|
65
|
+
- git availability
|
|
66
|
+
- FlameGraph presence at `scripts/FlameGraph/`
|
|
67
|
+
- npm deps installed (`node_modules/` exists)
|
|
68
|
+
- `.gitignore` has common patterns
|
|
69
|
+
|
|
70
|
+
## Design Principles
|
|
71
|
+
|
|
72
|
+
- **No circular dependencies on Node.js** — Bootstrap scripts use only bash or PowerShell. Node.js is installed BY the bootstrap.
|
|
73
|
+
- **nvm is additive, not destructive** — `nvm install --lts` installs alongside existing Node versions. `nvm use --lts` scopes to the current shell only. System default node is never touched.
|
|
74
|
+
- **`.nvmrc` for the project** — Written with `--lts` so `nvm use` auto-selects when entering the project directory.
|
|
75
|
+
- **FlameGraph pinned at v1.0** — Tag is stable; pinned clones are idempotent.
|
|
76
|
+
- **`install.ps1` is WSL-only** — Not modified by this skill. Windows-native installer is a future extension.
|
|
77
|
+
- **env-check scripts output JSON** — Structured `{os, distro, version, codename, pkg_manager, shell, is_wsl, arch, node_version, nvm_version, git_version}` for AI agent consumption.
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# ensure-gitignore.sh — Add common .gitignore patterns if missing.
|
|
3
|
+
# Usage: bash ensure-gitignore.sh
|
|
4
|
+
|
|
5
|
+
set -euo pipefail
|
|
6
|
+
|
|
7
|
+
PROJECT_ROOT="$(git rev-parse --show-toplevel 2>/dev/null || (cd "$(dirname "$0")/../../.." && pwd))"
|
|
8
|
+
GITIGNORE="$PROJECT_ROOT/.gitignore"
|
|
9
|
+
|
|
10
|
+
PATTERNS=(
|
|
11
|
+
"# Build directories"
|
|
12
|
+
"/build*/"
|
|
13
|
+
"/bin/"
|
|
14
|
+
"/lib/"
|
|
15
|
+
"/install/"
|
|
16
|
+
|
|
17
|
+
"# IDE"
|
|
18
|
+
".vscode/"
|
|
19
|
+
".idea/"
|
|
20
|
+
"*.swp"
|
|
21
|
+
"*.swo"
|
|
22
|
+
|
|
23
|
+
"# Dependencies"
|
|
24
|
+
"node_modules/"
|
|
25
|
+
|
|
26
|
+
"# Generated artifacts"
|
|
27
|
+
".artifacts/"
|
|
28
|
+
"src/**/.artifacts/"
|
|
29
|
+
|
|
30
|
+
"# FlameGraph (cloned by opensassi skill at v1.0)"
|
|
31
|
+
"scripts/FlameGraph/"
|
|
32
|
+
|
|
33
|
+
"# Browser automation"
|
|
34
|
+
".playwright-mcp/"
|
|
35
|
+
|
|
36
|
+
"# Profiling and performance data"
|
|
37
|
+
".profiler/"
|
|
38
|
+
|
|
39
|
+
"# Sessions"
|
|
40
|
+
"sessions/"
|
|
41
|
+
"!sessions/export-session.sh"
|
|
42
|
+
"!sessions/.gitkeep"
|
|
43
|
+
"!sessions/daily/.gitkeep"
|
|
44
|
+
|
|
45
|
+
"# Performance experiments"
|
|
46
|
+
"perf/experiments/"
|
|
47
|
+
"perf/baseline/"
|
|
48
|
+
|
|
49
|
+
"# Test data"
|
|
50
|
+
"test/data/"
|
|
51
|
+
|
|
52
|
+
"# CTest temporary files"
|
|
53
|
+
"Testing/"
|
|
54
|
+
|
|
55
|
+
"# External project clones"
|
|
56
|
+
"/external/"
|
|
57
|
+
|
|
58
|
+
"# OS files"
|
|
59
|
+
".DS_Store"
|
|
60
|
+
"Thumbs.db"
|
|
61
|
+
|
|
62
|
+
"# Core dumps"
|
|
63
|
+
"core"
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
ensure_pattern() {
|
|
67
|
+
local pattern="$1"
|
|
68
|
+
# Skip comment lines
|
|
69
|
+
if [[ "$pattern" == \#* ]]; then
|
|
70
|
+
return 0
|
|
71
|
+
fi
|
|
72
|
+
# Check for existing pattern with optional leading /
|
|
73
|
+
local alt="${pattern#!}"
|
|
74
|
+
[[ "$pattern" == \!* ]] && alt="!/${alt#/}" || alt="/${alt#/}"
|
|
75
|
+
if grep -qxF "$pattern" "$GITIGNORE" 2>/dev/null || grep -qxF "$alt" "$GITIGNORE" 2>/dev/null; then
|
|
76
|
+
return 0
|
|
77
|
+
fi
|
|
78
|
+
echo "$pattern" >> "$GITIGNORE"
|
|
79
|
+
echo " [added] $pattern"
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
# Ensure file exists
|
|
83
|
+
touch "$GITIGNORE"
|
|
84
|
+
|
|
85
|
+
echo "[INFO] Ensuring .gitignore patterns..."
|
|
86
|
+
for p in "${PATTERNS[@]}"; do
|
|
87
|
+
ensure_pattern "$p"
|
|
88
|
+
done
|
|
89
|
+
echo "[INFO] .gitignore is up to date"
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
# env-check.ps1 — Bootstrap environment detection for opencode opensassi skill (Windows native).
|
|
2
|
+
# Detects OS, ensures git, installs Node.js LTS via nvm-windows if needed.
|
|
3
|
+
# Outputs JSON to stdout: {os, distro, version, codename, pkg_manager, shell,
|
|
4
|
+
# is_wsl, arch, node_version, nvm_version, git_version}
|
|
5
|
+
#
|
|
6
|
+
# Usage: powershell -ExecutionPolicy Bypass -File env-check.ps1
|
|
7
|
+
|
|
8
|
+
$ErrorActionPreference = "Stop"
|
|
9
|
+
|
|
10
|
+
# --- OS Detection ---
|
|
11
|
+
$os = "win32"
|
|
12
|
+
$distro = "windows"
|
|
13
|
+
$version = ""
|
|
14
|
+
$codename = ""
|
|
15
|
+
$arch = [Environment]::GetEnvironmentVariable("PROCESSOR_ARCHITECTURE")
|
|
16
|
+
if ($arch -match "AMD64|x86_64") { $arch = "x64" }
|
|
17
|
+
elseif ($arch -match "ARM64") { $arch = "arm64" }
|
|
18
|
+
$shell = "powershell"
|
|
19
|
+
$is_wsl = $false
|
|
20
|
+
|
|
21
|
+
# Detect package manager
|
|
22
|
+
$pkg_manager = ""
|
|
23
|
+
if (Get-Command winget -ErrorAction SilentlyContinue) { $pkg_manager = "winget" }
|
|
24
|
+
elseif (Get-Command choco -ErrorAction SilentlyContinue) { $pkg_manager = "choco" }
|
|
25
|
+
elseif (Get-Command scoop -ErrorAction SilentlyContinue) { $pkg_manager = "scoop" }
|
|
26
|
+
|
|
27
|
+
# --- Ensure git ---
|
|
28
|
+
$git_version = ""
|
|
29
|
+
try {
|
|
30
|
+
$git_out = & git --version 2>$null
|
|
31
|
+
if ($git_out) {
|
|
32
|
+
$git_version = ($git_out -replace 'git version ', '').Trim()
|
|
33
|
+
}
|
|
34
|
+
} catch {
|
|
35
|
+
Write-Host "[INFO] git not found. Installing via winget..." -ForegroundColor Yellow
|
|
36
|
+
if ($pkg_manager -eq "winget") {
|
|
37
|
+
& winget install Git.Git --silent --accept-package-agreements 2>$null
|
|
38
|
+
# Refresh PATH so git is available
|
|
39
|
+
$env:Path = [Environment]::GetEnvironmentVariable("Path", "Machine") + ";" + [Environment]::GetEnvironmentVariable("Path", "User")
|
|
40
|
+
$git_out = & git --version 2>$null
|
|
41
|
+
if ($git_out) { $git_version = ($git_out -replace 'git version ', '').Trim() }
|
|
42
|
+
} else {
|
|
43
|
+
Write-Host "[WARN] Cannot install git automatically. Install from https://git-scm.com/" -ForegroundColor Red
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
# --- Ensure Node.js (LTS via nvm-windows) ---
|
|
48
|
+
$node_version = ""
|
|
49
|
+
$nvm_version = ""
|
|
50
|
+
|
|
51
|
+
function Setup-Node {
|
|
52
|
+
# Check if node is already at LTS or later
|
|
53
|
+
try {
|
|
54
|
+
$current = & node --version 2>$null
|
|
55
|
+
if ($current) {
|
|
56
|
+
$current = $current -replace '^v', ''
|
|
57
|
+
$major = ($current -split '\.')[0]
|
|
58
|
+
if ($major -ge 18) {
|
|
59
|
+
$script:node_version = $current
|
|
60
|
+
Write-Host "[INFO] Node.js v$node_version already available" -ForegroundColor Green
|
|
61
|
+
return
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
} catch {
|
|
65
|
+
# node not found, continue
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
# Check for nvm-windows
|
|
69
|
+
$nvm_path = Get-Command nvm -ErrorAction SilentlyContinue
|
|
70
|
+
if (-not $nvm_path) {
|
|
71
|
+
Write-Host "[INFO] nvm-windows not found. Installing via winget..." -ForegroundColor Yellow
|
|
72
|
+
try {
|
|
73
|
+
if ($pkg_manager -eq "winget") {
|
|
74
|
+
& winget install CoreyButler.NVMforWindows --silent --accept-package-agreements 2>$null
|
|
75
|
+
# nvm-windows adds to PATH; need a new shell or reload
|
|
76
|
+
$env:Path = [Environment]::GetEnvironmentVariable("Path", "Machine") + ";" + [Environment]::GetEnvironmentVariable("Path", "User")
|
|
77
|
+
# nvm-windows may need a refresh
|
|
78
|
+
$env:NVM_HOME = "$env:USERPROFILE\AppData\Roaming\nvm"
|
|
79
|
+
$env:NVM_SYMLINK = "$env:ProgramFiles\nodejs"
|
|
80
|
+
$env:Path = "$env:NVM_HOME;$env:NVM_SYMLINK;$env:Path"
|
|
81
|
+
} else {
|
|
82
|
+
Write-Host "[WARN] Cannot install nvm-windows automatically. Install from:" -ForegroundColor Red
|
|
83
|
+
Write-Host " https://github.com/coreybutler/nvm-windows/releases" -ForegroundColor Red
|
|
84
|
+
return
|
|
85
|
+
}
|
|
86
|
+
} catch {
|
|
87
|
+
Write-Host "[ERROR] Failed to install nvm-windows." -ForegroundColor Red
|
|
88
|
+
return
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
# Verify nvm is available
|
|
93
|
+
try {
|
|
94
|
+
$nvm_ver = & nvm version 2>$null
|
|
95
|
+
if ($nvm_ver) {
|
|
96
|
+
$script:nvm_version = $nvm_ver.Trim()
|
|
97
|
+
Write-Host "[INFO] nvm-windows v$nvm_version found" -ForegroundColor Green
|
|
98
|
+
}
|
|
99
|
+
} catch {
|
|
100
|
+
Write-Host "[WARN] nvm command not available after install. Restart terminal and retry." -ForegroundColor Red
|
|
101
|
+
return
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
# Install LTS node
|
|
105
|
+
Write-Host "[INFO] Installing latest Node.js LTS via nvm-windows..." -ForegroundColor Yellow
|
|
106
|
+
try {
|
|
107
|
+
& nvm install lts 2>$null
|
|
108
|
+
& nvm use lts 2>$null
|
|
109
|
+
# Write .nvmrc for the project
|
|
110
|
+
$project_root = if (Test-Path ".git") { (Get-Location).Path } else { "." }
|
|
111
|
+
"--lts" | Out-File -FilePath "$project_root\.nvmrc" -Encoding utf8 -Force
|
|
112
|
+
$node_ver = & node --version 2>$null
|
|
113
|
+
if ($node_ver) {
|
|
114
|
+
$script:node_version = ($node_ver -replace '^v', '').Trim()
|
|
115
|
+
Write-Host "[INFO] Node.js v$node_version (LTS) ready via nvm-windows" -ForegroundColor Green
|
|
116
|
+
}
|
|
117
|
+
} catch {
|
|
118
|
+
Write-Host "[ERROR] Failed to install Node.js LTS." -ForegroundColor Red
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
Setup-Node
|
|
123
|
+
|
|
124
|
+
# --- Output JSON ---
|
|
125
|
+
$json = @{
|
|
126
|
+
os = $os
|
|
127
|
+
distro = $distro
|
|
128
|
+
version = $version
|
|
129
|
+
codename = $codename
|
|
130
|
+
pkg_manager = $pkg_manager
|
|
131
|
+
shell = $shell
|
|
132
|
+
is_wsl = $is_wsl
|
|
133
|
+
arch = $arch
|
|
134
|
+
node_version = $node_version
|
|
135
|
+
nvm_version = $nvm_version
|
|
136
|
+
git_version = $git_version
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
Write-Output ($json | ConvertTo-Json -Compress)
|