@hybridlabor-api/aos 4.8.0 โ†’ 4.9.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 (166) hide show
  1. package/.agents/agents.md +1 -1
  2. package/.agents/nodes.json +1 -1
  3. package/.agents/vendor-manifest.json +23 -1
  4. package/.claude/agents/godmode-media-eventtech.md +1 -1
  5. package/.claude/hooks/conventional-commits.mjs +125 -0
  6. package/.claude/hooks/env-file-protection.mjs +105 -0
  7. package/.claude/hooks/go-gate.mjs +101 -81
  8. package/.claude/settings.json +13 -0
  9. package/.opencode/agents/godmode-media-eventtech.md +1 -1
  10. package/.opencode/plugins/bdb-aos.js +31 -4
  11. package/README.de.md +1 -1
  12. package/README.md +1 -1
  13. package/README.pt.md +1 -1
  14. package/THIRD_PARTY_NOTICES.md +88 -0
  15. package/docs/skills_table.md +1 -1
  16. package/installer.js +174 -46
  17. package/package.json +6 -2
  18. package/packages/aos-cli/README.md +80 -0
  19. package/packages/aos-cli/bin/aos-cli.mjs +134 -0
  20. package/packages/aos-cli/core-skills.json +12 -0
  21. package/packages/aos-cli/extensions/aos.ts +321 -0
  22. package/packages/aos-cli/package-lock.json +1923 -0
  23. package/packages/aos-cli/package.json +29 -0
  24. package/packages/aos-cli/scripts/check-theme.mjs +63 -0
  25. package/packages/aos-cli/themes/aos.json +97 -0
  26. package/scripts/build-plugin-manifest.mjs +131 -0
  27. package/scripts/validate-skills.mjs +81 -6
  28. package/skills/basic/ao-orchestrator/SKILL.md +116 -0
  29. package/skills/global_config/agenttrail/SKILL.md +6 -1
  30. package/skills/global_config/ask-tim/SKILL.md +4 -4
  31. package/skills/global_config/bash-script-generator/SKILL.md +201 -0
  32. package/skills/global_config/bash-script-generator/assets/templates/standard-template.sh +96 -0
  33. package/skills/global_config/bash-script-generator/docs/bash-scripting-guide.md +729 -0
  34. package/skills/global_config/bash-script-generator/docs/generation-best-practices.md +193 -0
  35. package/skills/global_config/bash-script-generator/docs/script-patterns.md +566 -0
  36. package/skills/global_config/bash-script-generator/docs/text-processing-guide.md +437 -0
  37. package/skills/global_config/bash-script-generator/examples/log-analyzer.sh +92 -0
  38. package/skills/global_config/bash-script-generator/scripts/generate_script_template.sh +123 -0
  39. package/skills/global_config/bash-script-generator/scripts/run_ci_checks.sh +172 -0
  40. package/skills/global_config/bash-script-generator/scripts/test_generator.sh +413 -0
  41. package/skills/global_config/bash-script-validator/SKILL.md +249 -0
  42. package/skills/global_config/bash-script-validator/docs/awk-reference.md +449 -0
  43. package/skills/global_config/bash-script-validator/docs/bash-reference.md +468 -0
  44. package/skills/global_config/bash-script-validator/docs/common-mistakes.md +623 -0
  45. package/skills/global_config/bash-script-validator/docs/grep-reference.md +395 -0
  46. package/skills/global_config/bash-script-validator/docs/regex-reference.md +391 -0
  47. package/skills/global_config/bash-script-validator/docs/sed-reference.md +454 -0
  48. package/skills/global_config/bash-script-validator/docs/shell-reference.md +463 -0
  49. package/skills/global_config/bash-script-validator/docs/shellcheck-reference.md +399 -0
  50. package/skills/global_config/bash-script-validator/examples/bad-bash.sh +55 -0
  51. package/skills/global_config/bash-script-validator/examples/bad-shell.sh +54 -0
  52. package/skills/global_config/bash-script-validator/examples/good-bash.sh +71 -0
  53. package/skills/global_config/bash-script-validator/examples/good-shell.sh +69 -0
  54. package/skills/global_config/bash-script-validator/scripts/run_ci_checks.sh +23 -0
  55. package/skills/global_config/bash-script-validator/scripts/shellcheck_wrapper.sh +174 -0
  56. package/skills/global_config/bash-script-validator/scripts/test_validate.sh +446 -0
  57. package/skills/global_config/bash-script-validator/scripts/validate.sh +512 -0
  58. package/skills/global_config/ci-pipeline/SKILL.md +135 -0
  59. package/skills/global_config/dispatching-parallel-agents/SKILL.md +170 -0
  60. package/skills/global_config/dockerfile-generator/SKILL.md +1038 -0
  61. package/skills/global_config/dockerfile-generator/examples/example.dockerignore +95 -0
  62. package/skills/global_config/dockerfile-generator/examples/golang-distroless.Dockerfile +34 -0
  63. package/skills/global_config/dockerfile-generator/examples/java-springboot.Dockerfile +45 -0
  64. package/skills/global_config/dockerfile-generator/examples/nextjs-production.Dockerfile +49 -0
  65. package/skills/global_config/dockerfile-generator/examples/nodejs-multistage.Dockerfile +55 -0
  66. package/skills/global_config/dockerfile-generator/examples/python-fastapi.Dockerfile +48 -0
  67. package/skills/global_config/dockerfile-generator/references/language_specific_guides.md +510 -0
  68. package/skills/global_config/dockerfile-generator/references/multistage_builds.md +570 -0
  69. package/skills/global_config/dockerfile-generator/references/optimization_patterns.md +492 -0
  70. package/skills/global_config/dockerfile-generator/references/security_best_practices.md +375 -0
  71. package/skills/global_config/dockerfile-generator/scripts/generate_dockerignore.sh +199 -0
  72. package/skills/global_config/dockerfile-generator/scripts/generate_golang.sh +172 -0
  73. package/skills/global_config/dockerfile-generator/scripts/generate_java.sh +185 -0
  74. package/skills/global_config/dockerfile-generator/scripts/generate_nodejs.sh +279 -0
  75. package/skills/global_config/dockerfile-generator/scripts/generate_python.sh +218 -0
  76. package/skills/global_config/dockerfile-generator/scripts/test_generator.sh +210 -0
  77. package/skills/global_config/dockerfile-validator/SKILL.md +300 -0
  78. package/skills/global_config/dockerfile-validator/examples/.dockerignore.example +34 -0
  79. package/skills/global_config/dockerfile-validator/examples/bad-example.Dockerfile +37 -0
  80. package/skills/global_config/dockerfile-validator/examples/golang-distroless.Dockerfile +50 -0
  81. package/skills/global_config/dockerfile-validator/examples/good-example.Dockerfile +52 -0
  82. package/skills/global_config/dockerfile-validator/examples/python-optimized.Dockerfile +53 -0
  83. package/skills/global_config/dockerfile-validator/examples/security-issues.Dockerfile +42 -0
  84. package/skills/global_config/dockerfile-validator/references/docker_best_practices.md +348 -0
  85. package/skills/global_config/dockerfile-validator/references/optimization_guide.md +473 -0
  86. package/skills/global_config/dockerfile-validator/references/security_checklist.md +208 -0
  87. package/skills/global_config/dockerfile-validator/scripts/dockerfile-validate.sh +699 -0
  88. package/skills/global_config/dockerfile-validator/scripts/test_validate.sh +35 -0
  89. package/skills/global_config/dockerfile-validator/tests/fixtures/copy-before-yarn-lock-read.Dockerfile +6 -0
  90. package/skills/global_config/dockerfile-validator/tests/fixtures/copy-before-yarn.Dockerfile +6 -0
  91. package/skills/global_config/dockerfile-validator/tests/fixtures/from-platform-nonroot.Dockerfile +7 -0
  92. package/skills/global_config/dockerfile-validator/tests/test_regression.sh +164 -0
  93. package/skills/global_config/finishing-a-development-branch/SKILL.md +228 -0
  94. package/skills/global_config/github-actions-generator/SKILL.md +353 -0
  95. package/skills/global_config/github-actions-generator/assets/templates/action/composite/action.yml +82 -0
  96. package/skills/global_config/github-actions-generator/assets/templates/action/docker/Dockerfile +25 -0
  97. package/skills/global_config/github-actions-generator/assets/templates/action/docker/action.yml +42 -0
  98. package/skills/global_config/github-actions-generator/assets/templates/action/docker/entrypoint.sh +27 -0
  99. package/skills/global_config/github-actions-generator/assets/templates/action/javascript/action.yml +33 -0
  100. package/skills/global_config/github-actions-generator/assets/templates/action/javascript/index.js +50 -0
  101. package/skills/global_config/github-actions-generator/assets/templates/action/javascript/package.json +27 -0
  102. package/skills/global_config/github-actions-generator/assets/templates/workflow/basic_workflow.yml +242 -0
  103. package/skills/global_config/github-actions-generator/assets/templates/workflow/reusable_workflow.yml +106 -0
  104. package/skills/global_config/github-actions-generator/examples/README.md +147 -0
  105. package/skills/global_config/github-actions-generator/examples/actions/setup-node-cached/action.yml +93 -0
  106. package/skills/global_config/github-actions-generator/examples/caching/docker-buildkit.yml +256 -0
  107. package/skills/global_config/github-actions-generator/examples/security/dependency-review.yml +62 -0
  108. package/skills/global_config/github-actions-generator/examples/security/sbom-attestation.yml +119 -0
  109. package/skills/global_config/github-actions-generator/examples/triggers/chatops-commands.yml +475 -0
  110. package/skills/global_config/github-actions-generator/examples/triggers/repository-dispatch.yml +418 -0
  111. package/skills/global_config/github-actions-generator/examples/triggers/workflow-orchestration.yml +404 -0
  112. package/skills/global_config/github-actions-generator/examples/workflows/docker-build-push.yml +68 -0
  113. package/skills/global_config/github-actions-generator/examples/workflows/go-ci.yml +161 -0
  114. package/skills/global_config/github-actions-generator/examples/workflows/monorepo-ci.yml +340 -0
  115. package/skills/global_config/github-actions-generator/examples/workflows/multi-environment-deploy.yml +406 -0
  116. package/skills/global_config/github-actions-generator/examples/workflows/nodejs-ci.yml +122 -0
  117. package/skills/global_config/github-actions-generator/examples/workflows/python-ci.yml +157 -0
  118. package/skills/global_config/github-actions-generator/examples/workflows/scheduled-tasks.yml +376 -0
  119. package/skills/global_config/github-actions-generator/references/advanced-triggers.md +917 -0
  120. package/skills/global_config/github-actions-generator/references/best-practices.md +755 -0
  121. package/skills/global_config/github-actions-generator/references/common-actions.md +715 -0
  122. package/skills/global_config/github-actions-generator/references/custom-actions.md +320 -0
  123. package/skills/global_config/github-actions-generator/references/expressions-and-contexts.md +688 -0
  124. package/skills/global_config/github-actions-generator/references/modern-features.md +421 -0
  125. package/skills/global_config/github-actions-generator/scripts/test_generator.sh +344 -0
  126. package/skills/global_config/github-actions-templates/SKILL.md +7 -0
  127. package/skills/global_config/github-actions-validator/SKILL.md +576 -0
  128. package/skills/global_config/github-actions-validator/examples/README.md +88 -0
  129. package/skills/global_config/github-actions-validator/examples/outdated-versions.yml +76 -0
  130. package/skills/global_config/github-actions-validator/examples/valid-ci.yml +79 -0
  131. package/skills/global_config/github-actions-validator/examples/with-errors.yml +47 -0
  132. package/skills/global_config/github-actions-validator/references/act_usage.md +233 -0
  133. package/skills/global_config/github-actions-validator/references/action_versions.md +122 -0
  134. package/skills/global_config/github-actions-validator/references/actionlint_usage.md +343 -0
  135. package/skills/global_config/github-actions-validator/references/common_errors.md +512 -0
  136. package/skills/global_config/github-actions-validator/references/modern_features.md +384 -0
  137. package/skills/global_config/github-actions-validator/references/runners.md +317 -0
  138. package/skills/global_config/github-actions-validator/scripts/install_tools.sh +113 -0
  139. package/skills/global_config/github-actions-validator/scripts/validate_workflow.sh +910 -0
  140. package/skills/global_config/github-actions-validator/tests/test_validate_workflow.sh +237 -0
  141. package/skills/global_config/makefile-generator/SKILL.md +614 -0
  142. package/skills/global_config/makefile-generator/assets/templates/.gitkeep +1 -0
  143. package/skills/global_config/makefile-generator/docs/makefile-structure.md +530 -0
  144. package/skills/global_config/makefile-generator/docs/optimization-guide.md +784 -0
  145. package/skills/global_config/makefile-generator/docs/patterns-guide.md +642 -0
  146. package/skills/global_config/makefile-generator/docs/security-guide.md +361 -0
  147. package/skills/global_config/makefile-generator/docs/targets-guide.md +642 -0
  148. package/skills/global_config/makefile-generator/docs/variables-guide.md +596 -0
  149. package/skills/global_config/makefile-generator/scripts/add_standard_targets.sh +539 -0
  150. package/skills/global_config/makefile-generator/scripts/generate_makefile_template.sh +690 -0
  151. package/skills/global_config/makefile-generator/test/test_helper_scripts.sh +190 -0
  152. package/skills/global_config/makefile-validator/SKILL.md +244 -0
  153. package/skills/global_config/makefile-validator/docs/bake-tool.md +1000 -0
  154. package/skills/global_config/makefile-validator/docs/best-practices.md +858 -0
  155. package/skills/global_config/makefile-validator/docs/common-mistakes.md +944 -0
  156. package/skills/global_config/makefile-validator/examples/bad-makefile.mk +77 -0
  157. package/skills/global_config/makefile-validator/examples/good-makefile.mk +103 -0
  158. package/skills/global_config/makefile-validator/scripts/test_validate.sh +382 -0
  159. package/skills/global_config/makefile-validator/scripts/validate_makefile.sh +712 -0
  160. package/skills/global_config/{MCP_Manage โ†’ mcp-manage}/SKILL.md +3 -3
  161. package/skills/global_config/requesting-code-review/SKILL.md +98 -0
  162. package/skills/global_config/requesting-code-review/code-reviewer.md +198 -0
  163. package/skills/global_config/using-git-worktrees/SKILL.md +170 -0
  164. package/skills/global_config/verification-before-completion/SKILL.md +123 -0
  165. package/skills/global_config/writing-plans/SKILL.md +126 -46
  166. package/skills/global_config/writing-plans-legacy/SKILL.md +139 -0
@@ -287,6 +287,94 @@ the upstream offensive exploit content is stripped and not carried over.
287
287
 
288
288
  ---
289
289
 
290
+ ## obra/superpowers
291
+
292
+ <https://github.com/obra/superpowers> โ€” MIT. Copyright (c) 2025 Jesse Vincent.
293
+
294
+ Tracked in `.agents/vendor-manifest.json` at pinned commit
295
+ `8ca22dba9a94f28898bbce59f2537ff4d87c747d` (v6.4.2).
296
+
297
+ Five workflow skills are vendored under `skills/global_config/`, each carried
298
+ whole with its companion files: `verification-before-completion`,
299
+ `requesting-code-review` (plus `code-reviewer.md`),
300
+ `finishing-a-development-branch`, `using-git-worktrees`, and
301
+ `dispatching-parallel-agents`. A sixth, `writing-plans`, **replaces** the AOS
302
+ version of that skill; the superseded AOS original is kept alongside it as
303
+ `writing-plans-legacy` (`source: community`, marked `deprecated_by`) rather than
304
+ deleted.
305
+
306
+ AOS modifications: `category:`, `source:` and `date_added:` added to the
307
+ frontmatter; the `superpowers:` namespace prefix stripped from cross-skill
308
+ references so they resolve to AOS skill names. AOS adaptations to
309
+ `writing-plans`: the plan output path is kept at AOS's `docs/plans/` rather
310
+ than upstream's `docs/superpowers/plans/`, and the AOS `risk: critical` marker
311
+ is carried over.
312
+
313
+ AOS already vendored four other skills from this repository earlier
314
+ (`brainstorming`, `test-driven-development`, `executing-plans`,
315
+ `subagent-driven-development`) without recording it here. Those imports still
316
+ carry the `superpowers:` prefix in their cross-references.
317
+
318
+ ---
319
+
320
+ ## akin-ozer/cc-devops-skills
321
+
322
+ <https://github.com/akin-ozer/cc-devops-skills> โ€” Apache-2.0.
323
+ Copyright [yyyy] [name of copyright owner] (upstream ships the unfilled
324
+ Apache-2.0 notice).
325
+
326
+ Tracked in `.agents/vendor-manifest.json` at pinned commit
327
+ `276af751e659315aaf56d3ad13d7c26f4e72e28a`.
328
+
329
+ Four generator/validator pairs are vendored under `skills/global_config/`, each
330
+ carried whole including its `references/`, `scripts/`, `examples/`, `docs/` and
331
+ `test/` subtrees: `github-actions-generator` + `github-actions-validator`,
332
+ `dockerfile-generator` + `dockerfile-validator`, `bash-script-generator` +
333
+ `bash-script-validator`, `makefile-generator` + `makefile-validator`.
334
+
335
+ AOS modifications: `category:`, `source:` and `date_added:` added to the
336
+ frontmatter; the `devops-skills:` namespace prefix stripped from cross-skill
337
+ references so they resolve to AOS skill names; the Docker example user
338
+ `appuser` renamed to `app` throughout `dockerfile-generator` and
339
+ `dockerfile-validator` to satisfy the E-PATH01 username check.
340
+
341
+ ---
342
+
343
+ ## davila7/claude-code-templates
344
+
345
+ <https://github.com/davila7/claude-code-templates> โ€” MIT.
346
+ Copyright (c) 2025 Daniel (San) รvila.
347
+
348
+ `conventional-commits` (`.claude/hooks/conventional-commits.mjs`) and
349
+ `env-file-protection` (`.claude/hooks/env-file-protection.mjs`) are ported from
350
+ upstream's `conventional-commits.py` and `env-file-protection.json`, selected
351
+ from a set of 62 hooks. Tracked in `.agents/vendor-manifest.json`.
352
+
353
+ Both are ports, not verbatim copies, and the differences are behavioural:
354
+
355
+ - **Python to .mjs.** Upstream ships Python. Node is already a hard AOS install
356
+ dependency and every other AOS hook is `.mjs`; `python3` is absent on a stock
357
+ Windows install, where the installer also runs.
358
+ - **Both harnesses.** Upstream's `env-file-protection` is an inline `echo`
359
+ guarded by a matcher `if` field, which Antigravity and the Gemini CLI ignore โ€”
360
+ there it would fire on every write. The check lives in code instead, and both
361
+ hooks emit the Antigravity `{"decision":...}` stdout form as well as the
362
+ Claude Code stderr/exit-2 form.
363
+ - **`.env.example` and friends are allowed.** Upstream's matcher blocks
364
+ `.env*`, which contradicts its own advice to put new values in
365
+ `.env.example`. Templates (`example`, `sample`, `template`, `dist`) are
366
+ committed and hold no live secret, so they are exempt here.
367
+ - **Both hooks fail open.** An unreadable payload or an unextractable commit
368
+ message allows the call, unlike `go-gate`, which fails closed. A regex miss
369
+ must not wedge a commit.
370
+
371
+ Upstream's `secret-scanner`, `tdd-gate`, and `dangerous-command-blocker` were
372
+ reviewed and **not** shipped; they remain available on demand from the ECC
373
+ store. Reasons are in `docs/handover/` and the branch description for
374
+ `feat/cicd-skills-import`.
375
+
376
+ ---
377
+
290
378
  ## Note on `mcps/`
291
379
 
292
380
  Sub-repositories vendored under `mcps/` carry their own `LICENSE` files in
@@ -52,7 +52,7 @@
52
52
  #### ๐ŸŽจ Frontend & UI/UX
53
53
  | Skill Name | Description |
54
54
  |------------|-------------|
55
- | `MCP_Manage` | Manages the BDB specialized MCP servers including Unreal Engine, Rhino 7/8, DaVinci Resolve, grandMA3, Resolume, GitHub, Chrome DevTools, and TouchDesigner. |
55
+ | `mcp-manage` | Manages the BDB specialized MCP servers including Unreal Engine, Rhino 7/8, DaVinci Resolve, grandMA3, Resolume, GitHub, Chrome DevTools, and TouchDesigner. |
56
56
  | `api-design-principles` | Master REST and GraphQL API design principles to build intuitive, scalable, and maintainable APIs that delight developers and stand the test of time. |
57
57
  | `api-patterns` | API design principles and decision-making. REST vs GraphQL vs tRPC selection, response formats, versioning, pagination. |
58
58
  | `bdbdesignpro` | Use when choosing an animation engine, defining motion tokens, adding scroll effects or micro-interactions, or auditing motion for accessibility and performance in BDB projects. Covers engine selection (GSAP, Motion.dev, Anime.js, React-Spring, Three.js, CSS Native), BDB brand-locked motion tokens, and the anti-slop/a11y quality gate. |
package/installer.js CHANGED
@@ -115,8 +115,8 @@ if (mcpsArgRaw && mcpsArg === null) {
115
115
  // not express that in a script or CI, and got Antigravity as their primary
116
116
  // target instead. Values match the menu: 0 universal, 1 Antigravity,
117
117
  // 2 Claude Desktop/Code, 3 Cursor, 4 custom, 5 Codex, 6 Windsurf, 7 Roo/Cline,
118
- // 8 Aider (9 = project harness has its own --project-harness flag).
119
- const VALID_PLATFORMS = ['0', '1', '2', '3', '4', '5', '6', '7', '8'];
118
+ // 8 Aider, 10 AOS CLI (9 = project harness has its own --project-harness flag).
119
+ const VALID_PLATFORMS = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '10'];
120
120
  const platformsArgRaw = process.argv.find(a => a === '--platforms' || a.startsWith('--platforms='));
121
121
  let PLATFORMS_ARG = null;
122
122
  if (platformsArgRaw) {
@@ -1257,6 +1257,7 @@ function syncSkillsToGlobalHarnesses(excludeSkills = []) {
1257
1257
  { dir: path.join(homeDir, '.codex', 'skills'), key: 'codex' },
1258
1258
  { dir: path.join(homeDir, '.cursor', 'skills'), key: 'cursor' },
1259
1259
  { dir: path.join(homeDir, '.roo', 'skills'), key: 'vscode' },
1260
+ { dir: process.platform === 'win32' ? path.join(process.env.APPDATA || homeDir, 'opencode', 'skills') : path.join(homeDir, '.config', 'opencode', 'skills'), key: 'opencode' },
1260
1261
  ].filter((d) => d.key === null || detectedKeys.has(d.key));
1261
1262
 
1262
1263
  for (const { dir: dest } of extraSkillDestinations) {
@@ -1709,8 +1710,12 @@ function checkModuleUpdate(pkgName, targetDir) {
1709
1710
  let remoteVer = null;
1710
1711
  let checkFailed = false;
1711
1712
  try {
1712
- const npmBin = process.platform === 'win32' ? 'npm.cmd' : 'npm';
1713
- remoteVer = execFileSync(npmBin, ['view', pkgName, 'version'], { stdio: ['ignore', 'pipe', 'ignore'], encoding: 'utf8', timeout: 4000, shell: process.platform === 'win32' }).trim();
1713
+ const npmCmd = process.platform === 'win32' ? 'npm.cmd' : 'npm';
1714
+ if (process.platform === 'win32') {
1715
+ remoteVer = execSync(`"${npmCmd}" view ${pkgName} version`, { stdio: ['ignore', 'pipe', 'ignore'], encoding: 'utf8', timeout: 4000 }).trim();
1716
+ } else {
1717
+ remoteVer = execFileSync(npmCmd, ['view', pkgName, 'version'], { stdio: ['ignore', 'pipe', 'ignore'], encoding: 'utf8', timeout: 4000 }).trim();
1718
+ }
1714
1719
  } catch (e) {
1715
1720
  // Offline, a proxy, or a misconfigured registry. Swallowing this
1716
1721
  // made every module report "up to date" forever on such a machine,
@@ -1805,15 +1810,40 @@ function downloadOrUpdateModule(pkgName, targetDir, displayName) {
1805
1810
  }
1806
1811
  }
1807
1812
 
1813
+ // Phase 1: retire the live tree. On Windows a running daemon holds open
1814
+ // file handles into targetDir โ€” retry with brief backoff before failing.
1815
+ // ponytail: 3 retries ร— 600ms; escalate to process kill if this ceiling matters
1816
+ let phase1Done = false;
1817
+ for (let attempt = 0; attempt < 3 && !phase1Done; attempt++) {
1818
+ try {
1819
+ fs.renameSync(targetDir, retiredDir);
1820
+ phase1Done = true;
1821
+ } catch (retireError) {
1822
+ const retriable = retireError.code === 'EPERM' || retireError.code === 'EBUSY';
1823
+ if (retriable && attempt < 2) {
1824
+ const delayMs = 600 * (attempt + 1);
1825
+ try {
1826
+ if (process.platform === 'win32') {
1827
+ execSync(`powershell -NoProfile -Command "Start-Sleep -Milliseconds ${delayMs}"`, { stdio: 'ignore' });
1828
+ } else {
1829
+ execSync(`sleep ${delayMs / 1000}`, { stdio: 'ignore' });
1830
+ }
1831
+ } catch (_) {}
1832
+ continue;
1833
+ }
1834
+ safeRmDirSync(stagingDir);
1835
+ throw retireError;
1836
+ }
1837
+ }
1838
+
1839
+ // Phase 2: promote the staging tree. stagingDir was just unpacked and
1840
+ // has no open handles, so a single attempt is sufficient.
1808
1841
  try {
1809
- fs.renameSync(targetDir, retiredDir);
1810
1842
  fs.renameSync(stagingDir, targetDir);
1811
- } catch (swapError) {
1812
- if (fs.existsSync(retiredDir) && !fs.existsSync(targetDir)) {
1813
- try { fs.renameSync(retiredDir, targetDir); } catch (_) {}
1814
- }
1843
+ } catch (promoteError) {
1844
+ try { fs.renameSync(retiredDir, targetDir); } catch (_) {}
1815
1845
  safeRmDirSync(stagingDir);
1816
- throw swapError;
1846
+ throw promoteError;
1817
1847
  }
1818
1848
 
1819
1849
  // On Windows especially, deleting a directory that was just renamed or contains
@@ -1886,6 +1916,21 @@ async function installMemB(interactive) {
1886
1916
  }));
1887
1917
  }
1888
1918
  const membDir = path.join(moduleBasePath(), 'memB');
1919
+ // On Windows the memB WebUI process holds open file handles inside membDir.
1920
+ // The atomic rename inside downloadOrUpdateModule fails with EPERM as long as
1921
+ // those handles are live โ€” retry backoff cannot help. Kill the process on
1922
+ // port 8088 before attempting the download so the rename succeeds.
1923
+ if (process.platform === 'win32') {
1924
+ try {
1925
+ execSync(
1926
+ 'powershell -NoProfile -Command "' +
1927
+ 'Get-NetTCPConnection -LocalPort 8088 -ErrorAction SilentlyContinue |' +
1928
+ ' Select-Object -ExpandProperty OwningProcess |' +
1929
+ ' ForEach-Object { Stop-Process -Id $_ -Force -ErrorAction SilentlyContinue }"',
1930
+ { stdio: 'ignore' }
1931
+ );
1932
+ } catch (_) {}
1933
+ }
1889
1934
  // A failed download used to fall through into venv setup and daemon
1890
1935
  // registration, each of which then failed on its own terms or, worse,
1891
1936
  // "succeeded" against a stale tree -- and the run still ended in a success
@@ -2561,10 +2606,15 @@ async function installOSAgentWorkspace() {
2561
2606
  execFileSync(binTarget, ['service', 'install'], { stdio: 'ignore' });
2562
2607
  }, 'Start it by hand with: ao service install');
2563
2608
 
2564
- if (await verifyDaemonListening(3101, 'AO Orchestrator', 8000)) {
2609
+ // Windows startup entries fire asynchronously โ€” give the service more time
2610
+ const aoTimeout = process.platform === 'win32' ? 20000 : 8000;
2611
+ if (await verifyDaemonListening(3101, 'AO Orchestrator', aoTimeout)) {
2565
2612
  log.success('AO Orchestrator running on http://localhost:3101');
2566
2613
  } else {
2567
- log.warn('AO did not answer on :3101 โ€” check `ao service status` and `ao service logs`.');
2614
+ const hint = process.platform === 'win32'
2615
+ ? 'Run `ao service install` again or log out and back in, then check `ao service status`.'
2616
+ : 'Check `ao service status` and `ao service logs`.';
2617
+ log.warn(`AO did not answer on :3101 โ€” ${hint}`);
2568
2618
  }
2569
2619
  }
2570
2620
  async function promptMemBIngestion(mcpCodeTarget) {
@@ -2638,8 +2688,10 @@ function verifyEcosystemInstallation() {
2638
2688
  let newerVersion = null;
2639
2689
  let newerTag = null;
2640
2690
  try {
2641
- const npmBin = process.platform === 'win32' ? 'npm.cmd' : 'npm';
2642
- const distTagsJson = execFileSync(npmBin, ['view', mod.pkg, 'dist-tags', '--json'], { stdio: ['ignore', 'pipe', 'ignore'], encoding: 'utf8', timeout: 4000, shell: process.platform === 'win32' }).trim();
2691
+ const npmCmd = process.platform === 'win32' ? 'npm.cmd' : 'npm';
2692
+ const distTagsJson = process.platform === 'win32'
2693
+ ? execSync(`"${npmCmd}" view ${mod.pkg} dist-tags --json`, { stdio: ['ignore', 'pipe', 'ignore'], encoding: 'utf8', timeout: 4000 }).trim()
2694
+ : execFileSync(npmCmd, ['view', mod.pkg, 'dist-tags', '--json'], { stdio: ['ignore', 'pipe', 'ignore'], encoding: 'utf8', timeout: 4000 }).trim();
2643
2695
  const distTags = JSON.parse(distTagsJson);
2644
2696
  for (const [tag, ver] of Object.entries(distTags)) {
2645
2697
  if (isNewerVersion(localVer, ver)) {
@@ -2685,7 +2737,7 @@ function verifyEcosystemInstallation() {
2685
2737
 
2686
2738
  console.log('');
2687
2739
  console.log(` ${colors.bold}โ”โ”โ” BDB Agent OS Dashboard โ”โ”โ”${colors.reset}`);
2688
- console.log(` Interactive Control Center: npx aos-dashboard`);
2740
+ console.log(` Interactive Control Center: aos-dashboard`);
2689
2741
  console.log(` ${colors.dim}(Live status & service control at http://127.0.0.1:7900)${colors.reset}`);
2690
2742
  }
2691
2743
 
@@ -3625,23 +3677,23 @@ function injectHarnessRules() {
3625
3677
  // that adds or changes a hook silently never received it -- which is exactly
3626
3678
  // what happened to memb-inject.mjs in v4.4.0, on the machines that needed it
3627
3679
  // most (a fresh install got it; every machine that already had AOS did not).
3628
- function installGlobalHooks() {
3680
+ function installGlobalHooks({ targetHome = homeDir, targetGemini = geminiDir } = {}) {
3629
3681
  const hooksSrc = path.join(srcDir, '.claude', 'hooks');
3630
3682
  const workflowsSrc = path.join(srcDir, '.claude', 'workflows');
3631
3683
 
3632
3684
  // 1. Claude Code
3633
3685
  if (fs.existsSync(hooksSrc)) {
3634
- copyDirRecursiveSync(hooksSrc, path.join(homeDir, '.claude', 'hooks'));
3635
- log.step(`Installed hooks to ${path.join(homeDir, '.claude', 'hooks')}`);
3686
+ copyDirRecursiveSync(hooksSrc, path.join(targetHome, '.claude', 'hooks'));
3687
+ log.step(`Installed hooks to ${path.join(targetHome, '.claude', 'hooks')}`);
3636
3688
  }
3637
3689
  if (fs.existsSync(workflowsSrc)) {
3638
- copyDirRecursiveSync(workflowsSrc, path.join(homeDir, '.claude', 'workflows'));
3690
+ copyDirRecursiveSync(workflowsSrc, path.join(targetHome, '.claude', 'workflows'));
3639
3691
  }
3640
- mergeBdbSettingsHooks(path.join(homeDir, '.claude', 'settings.json'));
3692
+ mergeBdbSettingsHooks(path.join(targetHome, '.claude', 'settings.json'));
3641
3693
 
3642
3694
  // 2. Google Antigravity
3643
- const agyHooksDir = path.join(geminiDir, 'config', 'hooks');
3644
- const agyWorkflowsDir = path.join(geminiDir, 'config', 'workflows');
3695
+ const agyHooksDir = path.join(targetGemini, 'config', 'hooks');
3696
+ const agyWorkflowsDir = path.join(targetGemini, 'config', 'workflows');
3645
3697
  if (fs.existsSync(hooksSrc)) {
3646
3698
  copyDirRecursiveSync(hooksSrc, agyHooksDir);
3647
3699
  log.step(`Installed hooks to ${agyHooksDir}`);
@@ -3649,14 +3701,24 @@ function installGlobalHooks() {
3649
3701
  if (fs.existsSync(workflowsSrc)) {
3650
3702
  copyDirRecursiveSync(workflowsSrc, agyWorkflowsDir);
3651
3703
  }
3652
- mergeAntigravityHooks(path.join(geminiDir, 'config', 'hooks.json'));
3653
- if (fs.existsSync(path.join(geminiDir, 'antigravity-cli'))) {
3654
- mergeAntigravityHooks(path.join(geminiDir, 'antigravity-cli', 'hooks.json'));
3704
+ mergeAntigravityHooks(path.join(targetGemini, 'config', 'hooks.json'));
3705
+ const agyCliDir = path.join(targetGemini, 'antigravity-cli');
3706
+ if (fs.existsSync(agyCliDir)) {
3707
+ const agyCliHooksDir = path.join(agyCliDir, 'hooks');
3708
+ const agyCliWorkflowsDir = path.join(agyCliDir, 'workflows');
3709
+ if (fs.existsSync(hooksSrc)) {
3710
+ copyDirRecursiveSync(hooksSrc, agyCliHooksDir);
3711
+ log.step(`Installed hooks to ${agyCliHooksDir}`);
3712
+ }
3713
+ if (fs.existsSync(workflowsSrc)) {
3714
+ copyDirRecursiveSync(workflowsSrc, agyCliWorkflowsDir);
3715
+ }
3716
+ mergeAntigravityHooks(path.join(agyCliDir, 'hooks.json'));
3655
3717
  }
3656
3718
 
3657
3719
  // 3. OpenAI Codex CLI
3658
- const codexHooksDir = path.join(homeDir, '.codex', 'hooks');
3659
- const codexWorkflowsDir = path.join(homeDir, '.codex', 'workflows');
3720
+ const codexHooksDir = path.join(targetHome, '.codex', 'hooks');
3721
+ const codexWorkflowsDir = path.join(targetHome, '.codex', 'workflows');
3660
3722
  if (fs.existsSync(hooksSrc)) {
3661
3723
  copyDirRecursiveSync(hooksSrc, codexHooksDir);
3662
3724
  log.step(`Installed hooks to ${codexHooksDir}`);
@@ -3664,12 +3726,12 @@ function installGlobalHooks() {
3664
3726
  if (fs.existsSync(workflowsSrc)) {
3665
3727
  copyDirRecursiveSync(workflowsSrc, codexWorkflowsDir);
3666
3728
  }
3667
- mergeCodexTomlHooks(path.join(homeDir, '.codex', 'config.toml'));
3729
+ mergeCodexTomlHooks(path.join(targetHome, '.codex', 'config.toml'));
3668
3730
 
3669
3731
  // 4. OpenCode CLI
3670
3732
  const opencodeDir = process.platform === 'win32'
3671
- ? path.join(process.env.APPDATA || homeDir, 'opencode')
3672
- : path.join(homeDir, '.config', 'opencode');
3733
+ ? path.join(process.env.APPDATA || targetHome, 'opencode')
3734
+ : path.join(targetHome, '.config', 'opencode');
3673
3735
  const opencodePluginSrc = path.join(srcDir, '.opencode', 'plugins', 'bdb-aos.js');
3674
3736
  if (fs.existsSync(opencodePluginSrc)) {
3675
3737
  const opencodePluginsDir = path.join(opencodeDir, 'plugins');
@@ -3745,7 +3807,7 @@ function installGlobalBinaries() {
3745
3807
  // merged result goes to a .bdb-new.json sidecar -- the same recovery pattern
3746
3808
  // the MCP config merge in installMcpsForTarget uses.
3747
3809
  function mergeBdbSettingsHooks(settingsPath, { projectLocal = false } = {}) {
3748
- const bdbHookScripts = ['go-gate.mjs', 'graph-gate.mjs', 'memb-inject.mjs', 'trail-relay.mjs'];
3810
+ const bdbHookScripts = ['go-gate.mjs', 'graph-gate.mjs', 'memb-inject.mjs', 'trail-relay.mjs', 'conventional-commits.mjs', 'env-file-protection.mjs'];
3749
3811
  // memb-inject reads the machine-global memB store under $HOME and is
3750
3812
  // installed once per machine, so it stays $HOME-anchored even inside a
3751
3813
  // project harness -- unlike the two gate hooks, which are per-checkout by
@@ -3817,7 +3879,7 @@ function mergeBdbSettingsHooks(settingsPath, { projectLocal = false } = {}) {
3817
3879
  // Merge the BDB hooks into Google Antigravity's hooks.json (.agents/hooks.json or
3818
3880
  // ~/.gemini/config/hooks.json), preserving user-defined foreign hooks.
3819
3881
  function mergeAntigravityHooks(hooksPath, { projectLocal = false } = {}) {
3820
- const bdbHookScripts = ['go-gate.mjs', 'graph-gate.mjs', 'memb-inject.mjs', 'startcycle-dispatch.mjs', 'trail-relay.mjs'];
3882
+ const bdbHookScripts = ['go-gate.mjs', 'graph-gate.mjs', 'memb-inject.mjs', 'startcycle-dispatch.mjs', 'trail-relay.mjs', 'conventional-commits.mjs', 'env-file-protection.mjs'];
3821
3883
  const isBdbEntry = (entry) => {
3822
3884
  const cmds = (entry && Array.isArray(entry.hooks) ? entry.hooks : [entry])
3823
3885
  .map((h) => (h && typeof h.command === 'string' ? h.command : (typeof h === 'string' ? h : '')))
@@ -3834,7 +3896,14 @@ function mergeAntigravityHooks(hooksPath, { projectLocal = false } = {}) {
3834
3896
  PreToolUse: [
3835
3897
  {
3836
3898
  matcher: "run_command|Bash",
3837
- hooks: [{ type: "command", command: `node "${path.join(hooksDir, 'go-gate.mjs')}"`, timeout: 10000 }]
3899
+ hooks: [
3900
+ { type: "command", command: `node "${path.join(hooksDir, 'go-gate.mjs')}"`, timeout: 10000 },
3901
+ { type: "command", command: `node "${path.join(hooksDir, 'conventional-commits.mjs')}"`, timeout: 10000 }
3902
+ ]
3903
+ },
3904
+ {
3905
+ matcher: "write_file|edit_file|replace|Write|Edit|MultiEdit",
3906
+ hooks: [{ type: "command", command: `node "${path.join(hooksDir, 'env-file-protection.mjs')}"`, timeout: 10000 }]
3838
3907
  },
3839
3908
  {
3840
3909
  hooks: [{ type: "command", command: `node "${path.join(globalHooksDir, 'trail-relay.mjs')}" --agent agy --event PreToolUse`, timeout: 2000 }]
@@ -4856,18 +4925,24 @@ async function runQuickUpdate(installState) {
4856
4925
  injectHarnessRules();
4857
4926
  }, 'Harness files keep whatever version this machine already had.');
4858
4927
 
4859
- // OpenWiki setup only ever ran on a brand-new install (main()'s fresh-install
4860
- // branch below) -- an existing install running Quick Update never got offered
4861
- // it and never had its daemon schedule refreshed. promptCredentials() already
4862
- // detects an existing key and collapses to a single "keep existing" prompt in
4863
- // that case, so this is a no-op confirm for anyone already configured and a
4864
- // real one-time offer for anyone who isn't (including installs from before
4865
- // this feature existed).
4928
+ // OpenWiki: if already configured, refresh the daemon silently (no prompt).
4929
+ // Only ask when there is no key yet โ€” i.e. a first-time offer or a machine
4930
+ // that predates this feature. This avoids the "keep existing?" confirmation
4931
+ // on every Quick Update for users who have already set up OpenWiki.
4866
4932
  if (!isAutoYes) {
4867
- const creds = await promptCredentials(paths.targetMcpDir);
4868
- if (creds !== BACK) {
4869
- await installOpenWikiDaemon(creds.gemini, paths.targetSkillDir, { provider: creds.openwikiProvider, model: creds.openwikiModel, baseUrl: creds.openwikiBaseUrl });
4933
+ const _owEnv = loadExistingEnv(paths.targetMcpDir);
4934
+ const _owProvider = _owEnv['OPENWIKI_PROVIDER'] || 'google';
4935
+ const _owKeyName = PROVIDER_KEY_ENV_NAMES[_owProvider] || 'GEMINI_API_KEY';
4936
+ const _owKey = _owEnv[_owKeyName] || _owEnv['GEMINI_API_KEY'] || _owEnv['GOOGLE_API_KEY'] || _owEnv['OPENWIKI_API_KEY'] || '';
4937
+ if (_owKey || _owProvider === 'ollama') {
4938
+ await installOpenWikiDaemon(_owKey, paths.targetSkillDir, { provider: _owProvider, model: _owEnv['OPENWIKI_MODEL'] || '', baseUrl: _owEnv['OPENWIKI_BASE_URL'] || '' });
4870
4939
  await installOpenWikiVisualizer();
4940
+ } else {
4941
+ const creds = await promptCredentials(paths.targetMcpDir);
4942
+ if (creds !== BACK) {
4943
+ await installOpenWikiDaemon(creds.gemini, paths.targetSkillDir, { provider: creds.openwikiProvider, model: creds.openwikiModel, baseUrl: creds.openwikiBaseUrl });
4944
+ await installOpenWikiVisualizer();
4945
+ }
4871
4946
  }
4872
4947
  }
4873
4948
 
@@ -4920,6 +4995,40 @@ function buildAoAnnouncementBanner() {
4920
4995
  ].join('\n');
4921
4996
  }
4922
4997
 
4998
+ // AOS CLI ships as a separate npm package under packages/ for one reason: pi
4999
+ // updates on its own cadence, and folding it into this release cycle would turn
5000
+ // every pi bump into a full AOS reinstall. So it installs as an ordinary global
5001
+ // package and pulls pi in as its own dependency -- and it writes nothing to
5002
+ // ~/.agents, because it reads that directory rather than owning it.
5003
+ function installAosCli() {
5004
+ const pkgDir = path.join(srcDir, 'packages', 'aos-cli');
5005
+ const manual = 'cd packages/aos-cli && npm install -g .';
5006
+
5007
+ if (!fs.existsSync(path.join(pkgDir, 'package.json'))) {
5008
+ log.warn(`AOS CLI package missing at ${pkgDir} -- skipped. Install it later: ${manual}`);
5009
+ return;
5010
+ }
5011
+ if (hasExecutable('aos-cli')) {
5012
+ log.step('aos-cli is already on PATH.');
5013
+ return;
5014
+ }
5015
+ if (DRY_RUN) {
5016
+ log.step('[dry-run] would run: npm install -g <packages/aos-cli>');
5017
+ return;
5018
+ }
5019
+
5020
+ const res = installStep('install AOS CLI', () => {
5021
+ log.step('Installing AOS CLI globally (pi is installed as its dependency)...');
5022
+ execSync(`npm install -g ${JSON.stringify(pkgDir)}`, { stdio: 'ignore' });
5023
+ }, `The rest of AOS is installed. Install AOS CLI later: ${manual}`);
5024
+
5025
+ if (res.ok && hasExecutable('aos-cli')) {
5026
+ log.success('AOS CLI installed -- run `aos-cli`.');
5027
+ } else if (res.ok) {
5028
+ log.warn('AOS CLI is installed but `aos-cli` is not on PATH. launchd and some Windows shells start with a PATH that omits npm\'s global bin.');
5029
+ }
5030
+ }
5031
+
4923
5032
  async function main() {
4924
5033
  if (process.argv[2] === 'store') {
4925
5034
  const storeScript = path.join(srcDir, 'bin', 'aos-store.mjs');
@@ -5061,6 +5170,7 @@ async function main() {
5061
5170
  { value: '7', label: 'Roo Code / Cline / VS Code', hint: '~/.roo' },
5062
5171
  { value: '8', label: 'Aider CLI', hint: '~/.aider' },
5063
5172
  { value: '9', label: '๐Ÿ“ Local Project Harness', hint: 'copy dispatcher contract to current project' },
5173
+ { value: '10', label: '๐Ÿ–ฅ๏ธ AOS CLI', hint: 'pi harness -- reads ~/.agents, no own skill copy' },
5064
5174
  { value: '4', label: 'โš™๏ธ Custom Installation', hint: 'specify paths manually' }
5065
5175
  ];
5066
5176
 
@@ -5090,7 +5200,7 @@ async function main() {
5090
5200
  selectedMcps = await promptMcpSelection(tier);
5091
5201
  } else {
5092
5202
  const ctx = { tier: '1', selectedPlatforms: ['0'], mode: 'merge', customPaths: null, creds: null, selectedMcps: null };
5093
- const platformNames = { '0': '๐ŸŒ Universal Harness', '1': 'Google Antigravity', '2': 'Claude Desktop/Code', '3': 'Cursor/Generic IDE', '4': 'Custom Paths', '5': 'ChatGPT Codex CLI', '6': 'Windsurf', '7': 'Roo Code / Cline / VS Code', '8': 'Aider CLI', '9': 'Local Project Harness' };
5203
+ const platformNames = { '0': '๐ŸŒ Universal Harness', '1': 'Google Antigravity', '2': 'Claude Desktop/Code', '3': 'Cursor/Generic IDE', '4': 'Custom Paths', '5': 'ChatGPT Codex CLI', '6': 'Windsurf', '7': 'Roo Code / Cline / VS Code', '8': 'Aider CLI', '9': 'Local Project Harness', '10': 'AOS CLI' };
5094
5204
 
5095
5205
  const stepTier = async () => {
5096
5206
  const t = await selectWithBack({
@@ -5256,7 +5366,22 @@ async function main() {
5256
5366
  fs.mkdirSync(backupDir, { recursive: true, mode: 0o700 });
5257
5367
  }, 'The installation continues, but existing files are not backed up.');
5258
5368
 
5259
- const targets = specificPlatforms.map(p => ({
5369
+ // '10' is an action, not a directory target. AOS CLI reads
5370
+ // ~/.agents/skills, which syncSkillsToGlobalHarnesses() already writes --
5371
+ // left in this list it would fall through resolveTargetPaths()'s universal
5372
+ // defaults and install a second full copy of every skill somewhere nobody
5373
+ // reads them from.
5374
+ const aosCliRequested = specificPlatforms.includes('10');
5375
+ const dirPlatforms = specificPlatforms.filter(p => p !== '10');
5376
+
5377
+ if (aosCliRequested && dirPlatforms.length === 0) {
5378
+ // AOS CLI alone would have no skills to load, and an empty target list
5379
+ // leaves primaryTarget undefined for everything downstream of it.
5380
+ log.warn('AOS CLI was the only target -- adding the universal skill target so it has something to load.');
5381
+ dirPlatforms.push('1');
5382
+ }
5383
+
5384
+ const targets = dirPlatforms.map(p => ({
5260
5385
  value: p,
5261
5386
  ...resolveTargetPaths(p, customPaths)
5262
5387
  }));
@@ -5343,10 +5468,13 @@ async function main() {
5343
5468
  // Flush file-level install manifest after all writes are done.
5344
5469
  flushSessionManifest();
5345
5470
 
5471
+ // After the skill sync, because AOS CLI is useless without ~/.agents.
5472
+ if (aosCliRequested) installAosCli();
5473
+
5346
5474
  console.log('');
5347
5475
  verifyEcosystemInstallation();
5348
5476
 
5349
- outro(`๐ŸŽ‰ Installation complete! Targets: ${targets.map(t => t.value).join(', ')} ยท Tier: ${tier === '1' ? 'Pro MEDIA' : 'Basic'}${DRY_RUN ? ' ยท DRY-RUN (nothing was modified)' : ''}`);
5477
+ outro(`๐ŸŽ‰ Installation complete! Targets: ${targets.map(t => t.value).join(', ')}${aosCliRequested ? ' + AOS CLI' : ''} ยท Tier: ${tier === '1' ? 'Pro MEDIA' : 'Basic'}${DRY_RUN ? ' ยท DRY-RUN (nothing was modified)' : ''}`);
5350
5478
  }
5351
5479
 
5352
5480
  if (require.main === module) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hybridlabor-api/aos",
3
- "version": "4.8.0",
3
+ "version": "4.9.0",
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": {
@@ -24,8 +24,10 @@
24
24
  "validate": "node scripts/validate-skills.mjs",
25
25
  "validate:strict": "node scripts/validate-skills.mjs --strict",
26
26
  "store:index": "node scripts/build-ecc-store-index.mjs",
27
+ "plugin:build": "node scripts/build-plugin-manifest.mjs",
28
+ "plugin:check": "node scripts/build-plugin-manifest.mjs --check",
27
29
  "doctor": "node bin/aos-doctor.mjs",
28
- "test": "node scripts/validate-skills.mjs --selftest && node scripts/validate-skills.mjs && node tests/aos-store.test.mjs && node tests/aos-doctor.test.mjs"
30
+ "test": "node scripts/validate-skills.mjs --selftest && node scripts/validate-skills.mjs && node scripts/build-plugin-manifest.mjs --check && node tests/aos-store.test.mjs && node tests/aos-doctor.test.mjs && node tests/build-plugin-manifest.test.mjs"
29
31
  },
30
32
  "publishConfig": {
31
33
  "access": "public"
@@ -58,6 +60,8 @@
58
60
  "mcps/",
59
61
  "scripts/",
60
62
  "vendor/",
63
+ "packages/aos-cli/",
64
+ "!packages/aos-cli/node_modules",
61
65
  "!mcps/**/*.png",
62
66
  "!mcps/**/*.jpg",
63
67
  "!mcps/**/*.jpeg",
@@ -0,0 +1,80 @@
1
+ # AOS CLI
2
+
3
+ The AOS dispatcher contract and AOS skills, on the [pi](https://github.com/earendil-works/pi) coding agent.
4
+
5
+ ```
6
+ aos-cli
7
+ aos-cli "why is the go build failing"
8
+ aos-cli --continue
9
+ ```
10
+
11
+ ## Which skills are loaded
12
+
13
+ **Ten, not all of them.** pi advertises every discovered skill by name and description in *every* system prompt. Measured on this machine: 210 skills, **~11,150 tokens per request**, of which the four `firecrawl` entries alone are ~2,250. That is a permanent tax on every turn.
14
+
15
+ `core-skills.json` narrows that to the handful worth having always:
16
+
17
+ ```
18
+ ask-tim aos-setup aos-project-init mcp-manage systematic-debugging
19
+ planning-with-files token-saver-config archify deja-memory grill-me
20
+ ```
21
+
22
+ Edit the file. It is a flat list of directory names under `~/.agents/skills/`, nothing more.
23
+
24
+ **The tradeoff, stated plainly:** a skill outside that list is not merely unadvertised โ€” it is unreachable, `/skill:name` included. That is the cost of `--no-skills`, and it is why `aos-store` is how one gets added. If you want a skill in every session, put it in the list.
25
+
26
+ Names that are not installed are skipped with a note rather than being fatal: the list should quietly shrink when a skill is pruned, not stop pi from starting.
27
+
28
+ ## In-session commands
29
+
30
+ | | |
31
+ |---|---|
32
+ | `/aos-status` | Runs `aos-doctor --json` and shows every check, with the failing ones marked |
33
+ | `/aos` | Menu: status, or the command to run outside for install / update / uninstall |
34
+
35
+ Both are **read-only**. `aos-doctor --json` exits 1 whenever a check is not ok, which is the normal "something needs attention" answer, so the exit code is ignored and the report's own `ok` field decides. The install, update and uninstall entries do not spawn the installer: it animates and prompts, and nesting it inside pi's TUI corrupts both renderers. They report the command to run in a separate terminal instead.
36
+
37
+ ## What it actually is
38
+
39
+ A launcher, not a reimplementation. It adds three things to a plain `pi`:
40
+
41
+ | | |
42
+ |---|---|
43
+ | **AOS theme** | `themes/aos.json` โ€” pi's `dark`, with the AOS palette (purple, amethyst, gold, forge, emerald, beige) |
44
+ | **Dispatcher graph** | `~/.agents/AGENTS.md` appended to the system prompt |
45
+ | **AOS skills** | nothing to do โ€” pi already discovers `~/.agents/skills` (Agent Skills spec) |
46
+
47
+ Everything else โ€” the agent loop, the model providers, the TUI, sessions, MCP-less tool use โ€” is pi's. AOS CLI does not fork pi and does not wrap it; it starts it with three flags.
48
+
49
+ ## What it deliberately does not do
50
+
51
+ **It does not depend on `@hybridlabor-api/aos`.** It reads `~/.agents/` at runtime, which the `aos` installer writes. That is the whole contract:
52
+
53
+ - AOS CLI and the AOS installer version and update independently. A pi update never drags in a 98 MB AOS reinstall.
54
+ - AOS CLI runs without AOS installed โ€” it just starts with no AOS skills and says so.
55
+ - **It is not a pipeline executor.** The 7-node dispatcher graph reaches pi as instructions in `~/.agents/AGENTS.md`, not as machinery: the nodes are agent definitions, and the main session acts as the dispatcher, which is what `.agents/graph.md` specifies anyway. There is no `state.json` loop.
56
+ - **No MCP.** pi has no MCP client, so memB, deja and mcsc are not available here. AOS CLI is a chat + skills harness; the other seven harnesses remain the machinery.
57
+
58
+ ## Install
59
+
60
+ Through the AOS installer (picks this up automatically once the menu entry lands), or directly:
61
+
62
+ ```sh
63
+ npm i -g @earendil-works/pi-coding-agent # if you do not have pi yet
64
+ cd packages/aos-cli && npm i && npm link
65
+ ```
66
+
67
+ Requires Node >= 22.19 โ€” pi's floor. The AOS installer itself still supports Node >= 20, because AOS CLI is a separate install step.
68
+
69
+ ## Layout
70
+
71
+ ```
72
+ bin/aos-cli.mjs the launcher (~40 lines)
73
+ themes/aos.json pi dark theme, AOS palette
74
+ extensions/aos.ts /aos and /aos-status
75
+ scripts/check-theme.mjs theme contract guard, run by `npm test`
76
+ ```
77
+
78
+ ## Licence
79
+
80
+ MIT, same as AOS. pi is MIT, ยฉ the pi authors.