@hybridlabor-api/aos 4.6.0 → 4.6.2
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/installer.js +95 -5
- package/package.json +1 -1
- package/skills/basic/godmode-hardware-pcb/SKILL.md +64 -10
package/installer.js
CHANGED
|
@@ -2002,8 +2002,27 @@ async function installOpenWikiVisualizer() {
|
|
|
2002
2002
|
return;
|
|
2003
2003
|
}
|
|
2004
2004
|
if (!hasExecutable('openwiki')) {
|
|
2005
|
-
|
|
2006
|
-
|
|
2005
|
+
// Fresh machines always land here -- skipping leaves :4321 dead with
|
|
2006
|
+
// only a warn line. Offer the global install instead.
|
|
2007
|
+
let installCli = isAutoYes;
|
|
2008
|
+
if (!isAutoYes) {
|
|
2009
|
+
const answer = await askConfirm({
|
|
2010
|
+
message: 'OpenWiki CLI not found. Install it globally (npm install -g openwiki@latest) so the :4321 visualizer daemon can run?',
|
|
2011
|
+
initialValue: true,
|
|
2012
|
+
});
|
|
2013
|
+
installCli = !isCancel(answer) && !!answer;
|
|
2014
|
+
}
|
|
2015
|
+
if (installCli) {
|
|
2016
|
+
try {
|
|
2017
|
+
log.step('Installing OpenWiki CLI globally (npm install -g openwiki@latest)...');
|
|
2018
|
+
execSync('npm install -g openwiki@latest', { stdio: 'ignore' });
|
|
2019
|
+
} catch (e) { logDebug(e, 'openwiki cli install'); }
|
|
2020
|
+
}
|
|
2021
|
+
if (!hasExecutable('openwiki')) {
|
|
2022
|
+
log.warn('Skipping OpenWiki Visualizer setup: the openwiki CLI is not on PATH. Install it with: npm install -g openwiki@latest');
|
|
2023
|
+
return;
|
|
2024
|
+
}
|
|
2025
|
+
log.ok('OpenWiki CLI installed.');
|
|
2007
2026
|
}
|
|
2008
2027
|
// launchd starts agents with a minimal PATH that never includes npm's global
|
|
2009
2028
|
// bin dir, so resolve the absolute binary path now instead of relying on PATH at boot.
|
|
@@ -2013,6 +2032,79 @@ async function installOpenWikiVisualizer() {
|
|
|
2013
2032
|
openwikiBin = execSync(lookup, { encoding: 'utf8' }).split(/\r?\n/)[0].trim() || 'openwiki';
|
|
2014
2033
|
} catch (e) { logDebug(e, 'openwiki path lookup'); }
|
|
2015
2034
|
|
|
2035
|
+
// The openwiki CLI is a Node script (#!/usr/bin/env node shebang). Under
|
|
2036
|
+
// launchd's minimal PATH there is no node either, so the agent died with
|
|
2037
|
+
// "env: node: No such file or directory" (exit 127) on every boot until
|
|
2038
|
+
// the interpreter itself is baked in as an absolute path.
|
|
2039
|
+
let nodeBin = 'node';
|
|
2040
|
+
try {
|
|
2041
|
+
const lookup = process.platform === 'win32' ? 'where node' : 'command -v node';
|
|
2042
|
+
nodeBin = execSync(lookup, { encoding: 'utf8' }).split(/\r?\n/)[0].trim() || 'node';
|
|
2043
|
+
} catch (e) { logDebug(e, 'node path lookup'); }
|
|
2044
|
+
|
|
2045
|
+
// Which wiki :4321 serves is per-machine setup configuration, not a
|
|
2046
|
+
// hardcoded path: every computer tracks different projects, and bare
|
|
2047
|
+
// `openwiki visualize` only serves ~/openwiki, which never exists (the
|
|
2048
|
+
// agent then exits 1 with "Wiki directory not found"). The choice is
|
|
2049
|
+
// persisted in ~/.openwiki/visualizer.json so Quick Update reuses it
|
|
2050
|
+
// without asking again; the bundled ecosystem aggregate is only the
|
|
2051
|
+
// first-run default.
|
|
2052
|
+
const visualizerConfigPath = path.join(homeDir, '.openwiki', 'visualizer.json');
|
|
2053
|
+
const looksLikeWiki = (dir) => fs.existsSync(path.join(dir, 'index.md'))
|
|
2054
|
+
|| fs.existsSync(path.join(dir, 'openwiki'))
|
|
2055
|
+
|| fs.existsSync(path.join(dir, '.openwiki'));
|
|
2056
|
+
const readVisualizerConfig = () => {
|
|
2057
|
+
try {
|
|
2058
|
+
const raw = JSON.parse(fs.readFileSync(visualizerConfigPath, 'utf8'));
|
|
2059
|
+
if (raw && typeof raw.wikiPath === 'string' && fs.existsSync(raw.wikiPath)) return raw.wikiPath;
|
|
2060
|
+
} catch (e) { logDebug(e, 'visualizer config read'); }
|
|
2061
|
+
return null;
|
|
2062
|
+
};
|
|
2063
|
+
const writeVisualizerConfig = (wikiPath) => {
|
|
2064
|
+
try {
|
|
2065
|
+
fs.mkdirSync(path.dirname(visualizerConfigPath), { recursive: true });
|
|
2066
|
+
fs.writeFileSync(visualizerConfigPath, JSON.stringify({ wikiPath, updatedAt: new Date().toISOString() }, null, 2));
|
|
2067
|
+
} catch (e) { logDebug(e, 'visualizer config write'); }
|
|
2068
|
+
};
|
|
2069
|
+
let wikiPath = readVisualizerConfig();
|
|
2070
|
+
const ecosystemWiki = path.join(homeDir, '.openwiki', 'ecosystem-wiki');
|
|
2071
|
+
const syncScript = path.join(srcDir, 'skills', 'global_config', 'openwiki-skill', 'scripts', 'sync_ecosystem_wiki.py');
|
|
2072
|
+
if (!wikiPath) {
|
|
2073
|
+
if (looksLikeWiki(ecosystemWiki)) {
|
|
2074
|
+
wikiPath = ecosystemWiki;
|
|
2075
|
+
} else if (fs.existsSync(syncScript) && hasExecutable('python3')) {
|
|
2076
|
+
try {
|
|
2077
|
+
execSync(`python3 "${syncScript}"`, { stdio: 'ignore' });
|
|
2078
|
+
if (looksLikeWiki(ecosystemWiki)) wikiPath = ecosystemWiki;
|
|
2079
|
+
} catch (e) { logDebug(e, 'ecosystem wiki sync'); }
|
|
2080
|
+
}
|
|
2081
|
+
if (!wikiPath && !isAutoYes) {
|
|
2082
|
+
const answer = await text({
|
|
2083
|
+
message: `Which wiki should the :4321 visualizer serve? (directory) [default: ${ecosystemWiki}]`,
|
|
2084
|
+
placeholder: ecosystemWiki,
|
|
2085
|
+
});
|
|
2086
|
+
if (!isCancel(answer) && answer && answer.trim()) {
|
|
2087
|
+
const candidate = answer.trim().replace(/^~(?=$|\/|\\)/, homeDir);
|
|
2088
|
+
if (fs.existsSync(candidate) && fs.statSync(candidate).isDirectory()) {
|
|
2089
|
+
wikiPath = candidate;
|
|
2090
|
+
if (!looksLikeWiki(candidate)) {
|
|
2091
|
+
log.warn(`No wiki markers found in ${candidate} — the daemon may exit until a wiki is generated there.`);
|
|
2092
|
+
}
|
|
2093
|
+
} else {
|
|
2094
|
+
log.warn(`Directory not found: ${candidate} — continuing without a visualizer path.`);
|
|
2095
|
+
}
|
|
2096
|
+
}
|
|
2097
|
+
}
|
|
2098
|
+
}
|
|
2099
|
+
if (wikiPath) {
|
|
2100
|
+
writeVisualizerConfig(wikiPath);
|
|
2101
|
+
} else {
|
|
2102
|
+
log.warn('OpenWiki Visualizer: no servable wiki configured — registering without a path, the daemon will exit until a wiki exists.');
|
|
2103
|
+
}
|
|
2104
|
+
const visualizeArgs = wikiPath
|
|
2105
|
+
? `<string>${nodeBin}</string>\n <string>${openwikiBin}</string>\n <string>visualize</string>\n <string>${wikiPath}</string>\n <string>--port</string>`
|
|
2106
|
+
: `<string>${nodeBin}</string>\n <string>${openwikiBin}</string>\n <string>visualize</string>\n <string>--port</string>`;
|
|
2107
|
+
|
|
2016
2108
|
if (process.platform === 'darwin') {
|
|
2017
2109
|
const plistPath = path.join(homeDir, 'Library', 'LaunchAgents', 'com.bdb.openwiki-visualize.plist');
|
|
2018
2110
|
const plistContent = `<?xml version="1.0" encoding="UTF-8"?>
|
|
@@ -2023,9 +2115,7 @@ async function installOpenWikiVisualizer() {
|
|
|
2023
2115
|
<string>com.bdb.openwiki-visualize</string>
|
|
2024
2116
|
<key>ProgramArguments</key>
|
|
2025
2117
|
<array>
|
|
2026
|
-
|
|
2027
|
-
<string>visualize</string>
|
|
2028
|
-
<string>--port</string>
|
|
2118
|
+
${visualizeArgs}
|
|
2029
2119
|
<string>4321</string>
|
|
2030
2120
|
<string>--no-open</string>
|
|
2031
2121
|
</array>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hybridlabor-api/aos",
|
|
3
|
-
"version": "4.6.
|
|
3
|
+
"version": "4.6.2",
|
|
4
4
|
"description": "AOS — A Curated AI AGENT OS. Optimized agent skills and add-ons like memB, OpenWiki, Heimdall Token Saver, and Godmode architectures.",
|
|
5
5
|
"main": "installer.js",
|
|
6
6
|
"engines": {
|
|
@@ -57,46 +57,100 @@ Before issuing schematic edits, layout changes, or fabrication exports, the agen
|
|
|
57
57
|
|
|
58
58
|
---
|
|
59
59
|
|
|
60
|
+
## 6. Iterative Visual Loop — Render as Complement, Not Gate
|
|
61
|
+
|
|
62
|
+
A render never replaces ERC/DRC, but every edit must be seen before the next
|
|
63
|
+
one lands. Generate in small batches, render after each batch, and compare
|
|
64
|
+
against the reference with a vision-capable model before continuing:
|
|
65
|
+
|
|
66
|
+
1. **Orient first:** locate project files (the kicad-project-find helper in
|
|
67
|
+
the companion module, or raw `find` for `*.kicad_pro`, `*.kicad_sch`,
|
|
68
|
+
`*.kicad_pcb`), then report `kicad-cli` path and version. If `kicad-cli`
|
|
69
|
+
is absent, stop and say `BLOCKED` — do not emit commands that will fail
|
|
70
|
+
downstream.
|
|
71
|
+
2. **Small batches:** place or edit at most 5–10 components per batch, on a
|
|
72
|
+
fixed 0.5mm or 1mm placement grid. Never generate a whole schematic or
|
|
73
|
+
board in one shot.
|
|
74
|
+
3. **Render after every batch:**
|
|
75
|
+
- schematic: `kicad-cli sch export svg --output out/ design.kicad_sch`
|
|
76
|
+
- board layers: `kicad-cli pcb export svg --output out/ board.kicad_pcb`
|
|
77
|
+
- board 3D: `kicad-cli pcb render --output board-top.png board.kicad_pcb`
|
|
78
|
+
- The companion module ships these as the kicad-render, kicad-drc-json,
|
|
79
|
+
and kicad-erc-json helper scripts.
|
|
80
|
+
4. **Vision diff:** load the fresh render into the vision model alongside the
|
|
81
|
+
reference (photo, datasheet figure, or schematic from the web). On chaos —
|
|
82
|
+
overlapping symbols, nets crossing the sheet, decoupling far from pins —
|
|
83
|
+
fix before the next batch.
|
|
84
|
+
5. **Machine checks per batch:** `kicad-cli sch erc` and `kicad-cli pcb drc`
|
|
85
|
+
with `--exit-code-violations`. Unconnected-pin warnings after a messy
|
|
86
|
+
batch are worked off systematically, not batched up for the end.
|
|
87
|
+
6. **Substrate routing:** live board/session edits prefer `kicad-python` IPC;
|
|
88
|
+
render, export, DRC/ERC, and fabrication outputs use `kicad-cli`;
|
|
89
|
+
deterministic offline file edits use a structured S-expression parser
|
|
90
|
+
(e.g. `kiutils`), never hand-rolled regex on `.kicad_sch` / `.kicad_pcb`.
|
|
91
|
+
7. **Evidence report:** close every batch with target, commands run, artifact
|
|
92
|
+
paths, check outputs, and one of
|
|
93
|
+
`DONE` / `DONE_WITH_CONCERNS` / `BLOCKED` / `NEEDS_CONTEXT`.
|
|
94
|
+
|
|
95
|
+
### Shared placement preamble (applies to every schematic/layout batch)
|
|
96
|
+
|
|
97
|
+
- Schematic flow goes left to right (inputs left, outputs right); VCC points
|
|
98
|
+
up, GND points down; use global labels or hierarchical sheets instead of
|
|
99
|
+
dragging dozens of wires across the sheet.
|
|
100
|
+
- Every decoupling capacitor sits on the same layer as its IC, within 1.5mm
|
|
101
|
+
of the power pin, in the sequence rail-via → cap pad → IC pin.
|
|
102
|
+
- Reverse-engineering work (rebuilding a board photo or web schematic in
|
|
103
|
+
KiCad) routes to `schematic-reverse-engineering` first: identify parts via
|
|
104
|
+
a parts source, record manufacturer part numbers, verify symbol/footprint
|
|
105
|
+
visually before use, and never invent pinouts from memory.
|
|
106
|
+
|
|
60
107
|
## Universal Agent Harness Integration
|
|
61
108
|
|
|
62
|
-
This Godmode rulebook is universally available across the BDB ecosystem, installed alongside the `@hybridlabor-api/bdb-hardware-pcb` module (KiCad + OpenSCAD MCP servers,
|
|
109
|
+
This Godmode rulebook is universally available across the BDB ecosystem, installed alongside the `@hybridlabor-api/bdb-hardware-pcb` module (KiCad + OpenSCAD MCP servers, 6 companion skills under the `engineering-hardware` category):
|
|
63
110
|
* **Claude Code / CLI Agents:** loaded during electrical, PCB, and enclosure design sessions.
|
|
64
|
-
* **Peer skills:** `code-first-hardware-design`, `pcb-constraint-definition`, `pcb-layout-routing-automation`, `pcb-validation-dfm-signoff`, `schematic-datasheet-analysis`.
|
|
111
|
+
* **Peer skills:** `code-first-hardware-design`, `pcb-constraint-definition`, `pcb-layout-routing-automation`, `pcb-validation-dfm-signoff`, `schematic-datasheet-analysis`, `schematic-reverse-engineering`.
|
|
65
112
|
|
|
66
113
|
## Overview
|
|
67
|
-
This skill acts as the architectural authority for electrical and PCB design, enforcing IPC-standard physical constraints, headless validation gates, and hardware/software co-design boundaries.
|
|
114
|
+
This skill acts as the architectural authority for electrical and PCB design, enforcing IPC-standard physical constraints, iterative visual verification, headless validation gates, and hardware/software co-design boundaries.
|
|
68
115
|
|
|
69
116
|
## When to Use
|
|
70
|
-
- **Trigger:** The user is designing or modifying a schematic, PCB layout, layer stackup, netclass, or an OpenSCAD enclosure meant to house the board.
|
|
117
|
+
- **Trigger:** The user is designing or modifying a schematic, PCB layout, layer stackup, netclass, or an OpenSCAD enclosure meant to house the board — including rebuilding a board photo or web schematic in KiCad.
|
|
71
118
|
- **Exclude:** Do not use for firmware/register-level software running on the board (hand off to `godmode-engineering`), or for live show-control signal routing in the field (hand off to `godmode-eventtech`).
|
|
72
119
|
|
|
73
120
|
## Core Process
|
|
74
121
|
1. Derive every trace width, impedance target, and clearance from the formulas above or a cited IPC standard — never from a rounded-up guess.
|
|
75
|
-
2. Validate KiCad and OpenSCAD MCP servers are actually responsive before issuing edits.
|
|
76
|
-
3.
|
|
77
|
-
4.
|
|
78
|
-
5.
|
|
122
|
+
2. Validate KiCad and OpenSCAD MCP servers are actually responsive before issuing edits; confirm `kicad-cli` path and version.
|
|
123
|
+
3. Work in batches of at most 5–10 components on a fixed grid; render after every batch and vision-diff against the reference before continuing (see section 6).
|
|
124
|
+
4. Run headless ERC and DRC with `--exit-code-violations` per batch; treat any non-zero exit as a hard stop.
|
|
125
|
+
5. Benchmark the layout against the real target fab house's DFM limits before calling a design release-ready.
|
|
126
|
+
6. Cross-check the enclosure (OpenSCAD) against the board outline and connector placements (KiCad) before sign-off.
|
|
79
127
|
|
|
80
128
|
## Common Rationalizations
|
|
81
129
|
|
|
82
130
|
| Rationalization | Reality |
|
|
83
131
|
|---|---|
|
|
84
132
|
| "0.25mm default trace width is fine for a power rail." | IPC-2152 current-capacity math, not the CAD tool's default, sets minimum trace width — a 2.5A rail needs ~0.79mm at 1oz copper, not the default. |
|
|
85
|
-
| "The 3D viewer looks correct, so the board is done." | A
|
|
133
|
+
| "The 3D viewer looks correct, so the board is done." | A render complements ERC/DRC, it never replaces them. A clean render with a non-zero ERC/DRC exit code is still BLOCKED; a passing exit code with no render is DONE_WITH_CONCERNS. |
|
|
134
|
+
| "Rendering every few components slows me down; one big generation is faster." | One-shot generation produces overlapping symbols and unconnected pins that cost more to untangle than batches of 5–10 with a render between them. |
|
|
86
135
|
| "USB and Ethernet differential pairs can use the same spacing." | USB targets 90Ω differential, Ethernet/PCIe targets 100Ω — same formula, different required spacing for the same dielectric height. |
|
|
87
136
|
| "The GPIO can be reassigned in layout; firmware can just adapt." | A pin reassignment is a breaking change to any firmware that already assumed the old pinout — it must be flagged to the software side, not silently absorbed. |
|
|
88
137
|
|
|
89
138
|
## Red Flags
|
|
90
139
|
|
|
91
140
|
- Proceeding to layout with unconstrained nets or no defined netclasses.
|
|
141
|
+
- Generating a whole schematic or board in one shot with no intermediate render.
|
|
92
142
|
- Treating a clean-looking 3D render as equivalent to a passing ERC/DRC exit code.
|
|
143
|
+
- Skipping the vision diff against the reference photo or schematic after a batch.
|
|
93
144
|
- Skipping DFM benchmarking against the actual target fab house's capabilities.
|
|
94
145
|
- Changing a pinout or connector placement without flagging the firmware or enclosure impact.
|
|
146
|
+
- Inventing a footprint or pinout from memory when a parts source was available.
|
|
95
147
|
|
|
96
148
|
## Verification
|
|
97
149
|
|
|
98
150
|
- [ ] Every load-bearing trace width/impedance/clearance traces back to a formula or IPC standard, not a default or a guess.
|
|
151
|
+
- [ ] Work proceeded in batches of at most 5–10 components with a render and vision diff per batch; artifact paths are reported.
|
|
99
152
|
- [ ] ERC and DRC were run headless with `--exit-code-violations`, and the actual exit code — not a description of the run — was checked.
|
|
100
|
-
- [ ] KiCad and OpenSCAD MCP tool availability was validated before issuing edits.
|
|
153
|
+
- [ ] KiCad and OpenSCAD MCP tool availability was validated before issuing edits; `kicad-cli` path and version are on record.
|
|
101
154
|
- [ ] DFM limits were checked against the real target fab house, not a generic assumption.
|
|
102
155
|
- [ ] Any pinout/connector change was cross-checked against firmware assumptions and enclosure geometry.
|
|
156
|
+
- [ ] Reverse-engineered parts cite a real manufacturer part number and source, not memory.
|