blacksmith-organization-system 0.4.2 → 1.0.0-dev.3
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/.claude-plugin/marketplace.json +17 -0
- package/.claude-plugin/mcp.json +8 -0
- package/.claude-plugin/plugin.json +16 -0
- package/AGENTS.md +114 -0
- package/CLAUDE.md +1 -0
- package/LICENSE +1 -1
- package/README.md +74 -57
- package/bin/bos +3 -0
- package/hooks/hooks.json +40 -0
- package/package.json +82 -22
- package/resources/house/HOUSE.md +22 -0
- package/resources/house/bloodlines.json +35 -0
- package/resources/house/children/deepseeks-of-anubis.json +4 -0
- package/resources/house/children/eon.json +7 -0
- package/resources/house/children/hermetic-officer.json +1 -0
- package/resources/house/children/ifrit.json +1 -0
- package/resources/house/children/license-keepers.json +4 -0
- package/resources/house/children/sebas.json +10 -0
- package/resources/house/children/shakespeare.json +10 -0
- package/resources/house/orders/ravensarmy.json +6 -0
- package/resources/house/orders/seiaic-ucdi.json +5 -0
- package/resources/ravens/skryba.md +19 -0
- package/resources/workshop-root/AGENTS.md +92 -0
- package/resources/workshop-root/CLAUDE.md +1 -0
- package/resources/workshop.default.json +6 -0
- package/skills/bos-archive/SKILL.md +28 -0
- package/skills/bos-craftbook/SKILL.md +32 -0
- package/skills/bos-craftset/SKILL.md +36 -0
- package/skills/bos-devarmory/SKILL.md +34 -0
- package/skills/bos-exhibit/SKILL.md +28 -0
- package/skills/bos-forge/SKILL.md +28 -0
- package/skills/bos-house/SKILL.md +52 -0
- package/skills/bos-project/SKILL.md +27 -0
- package/skills/bos-sarcophag/SKILL.md +26 -0
- package/skills/bos-scope/SKILL.md +33 -0
- package/skills/bos-sheme/SKILL.md +38 -0
- package/skills/bos-throwbox/SKILL.md +27 -0
- package/skills/bos-workshop/SKILL.md +65 -0
- package/{config/README.md → skills/bos-workshop/assets/.gitkeep} +0 -0
- package/skills/bos-workshop/references/bos-codebase.md +116 -0
- package/skills/bos-workshop/references/bos-concept.md +121 -0
- package/skills/bos-workshop/scripts/find-workshop.sh +30 -0
- package/src/agent-hook.mjs +28 -0
- package/src/bridge/_index.mjs +24 -0
- package/src/bridge/bos-instances-link/_index.mjs +18 -0
- package/src/bridge/docker-host/_index.mjs +43 -0
- package/src/bridge/docker-host/container.mjs +32 -0
- package/src/bridge/docker-host/image.mjs +23 -0
- package/src/bridge/docker-host/volume.mjs +12 -0
- package/src/bridge/docker-publish/_index.mjs +24 -0
- package/src/bridge/git-client/_index.mjs +121 -0
- package/src/bridge/git-client/author.mjs +26 -0
- package/src/bridge/gitea-api/_index.mjs +62 -0
- package/src/bridge/github-api/_index.mjs +45 -0
- package/src/bridge/npm-publish/_index.mjs +19 -0
- package/src/bridge/ollama-link/_index.mjs +93 -0
- package/src/bridge/ollama-link/ravens.mjs +29 -0
- package/src/bridge/ssh-link/_index.mjs +33 -0
- package/src/bridge/subprocess-runner/_index.mjs +33 -0
- package/src/cli.mjs +29 -0
- package/src/commands/_index.mjs +51 -0
- package/src/commands/bootstrap/exec.mjs +7 -0
- package/src/commands/bootstrap/help.md +5 -0
- package/src/commands/bootstrap/index.json +7 -0
- package/src/commands/close/exec.mjs +4 -0
- package/src/commands/close/help.md +5 -0
- package/src/commands/close/index.json +7 -0
- package/src/commands/describe/exec.mjs +11 -0
- package/src/commands/describe/help.md +5 -0
- package/src/commands/describe/index.json +7 -0
- package/src/commands/help/exec.mjs +6 -0
- package/src/commands/help/help.md +3 -0
- package/src/commands/help/index.json +6 -0
- package/src/commands/hook/exec.mjs +3 -0
- package/src/commands/hook/help.md +4 -0
- package/src/commands/hook/index.json +7 -0
- package/src/commands/hooks/exec.mjs +5 -0
- package/src/commands/hooks/help.md +4 -0
- package/src/commands/hooks/index.json +7 -0
- package/src/commands/house/exec.mjs +8 -0
- package/src/commands/house/help.md +8 -0
- package/src/commands/house/index.json +7 -0
- package/src/commands/locate/exec.mjs +2 -0
- package/src/commands/locate/help.md +6 -0
- package/src/commands/locate/index.json +6 -0
- package/src/commands/mode/exec.mjs +17 -0
- package/src/commands/mode/help.md +14 -0
- package/src/commands/mode/index.json +8 -0
- package/src/commands/mode/repl.mjs +18 -0
- package/src/commands/open/exec.mjs +5 -0
- package/src/commands/open/help.md +4 -0
- package/src/commands/open/index.json +7 -0
- package/src/commands/promote/exec.mjs +5 -0
- package/src/commands/promote/help.md +6 -0
- package/src/commands/promote/index.json +7 -0
- package/src/commands/repl/exec.mjs +3 -0
- package/src/commands/repl/help.md +4 -0
- package/src/commands/repl/index.json +6 -0
- package/src/commands/seal/exec.mjs +8 -0
- package/src/commands/seal/help.md +4 -0
- package/src/commands/seal/index.json +7 -0
- package/src/commands/sink/exec.mjs +2 -0
- package/src/commands/sink/help.md +6 -0
- package/src/commands/sink/index.json +7 -0
- package/src/commands/skills/exec.mjs +5 -0
- package/src/commands/skills/help.md +5 -0
- package/src/commands/skills/index.json +7 -0
- package/src/commands/status/exec.mjs +2 -0
- package/src/commands/status/help.md +6 -0
- package/src/commands/status/index.json +7 -0
- package/src/commands/status/repl.mjs +14 -0
- package/src/commands/verify/exec.mjs +9 -0
- package/src/commands/verify/help.md +4 -0
- package/src/commands/verify/index.json +7 -0
- package/src/controllers/_index.mjs +5 -0
- package/src/controllers/skills-controll.mjs +13 -0
- package/src/controllers/workshop-controll.mjs +48 -0
- package/src/core/basic-bridge.mjs +29 -0
- package/src/core/basic-controll.mjs +26 -0
- package/src/core/basic-element.mjs +149 -0
- package/src/core/basic-model.mjs +7 -0
- package/src/core/basic-procedure.mjs +37 -0
- package/src/core/basic-submodule.mjs +21 -0
- package/src/core/basic-view.mjs +21 -0
- package/src/core/self.mjs +10 -0
- package/src/index.mjs +24 -0
- package/src/main.ts +82 -0
- package/src/mcp.mjs +8 -0
- package/src/models/_index.mjs +43 -0
- package/src/models/archive/class.mjs +9 -0
- package/src/models/craftbook/class.mjs +11 -0
- package/src/models/craftbook/hang.scrapnotes.mjs +10 -0
- package/src/models/craftset/class.mjs +14 -0
- package/src/models/devarmory/class.mjs +10 -0
- package/src/models/exhibit/class.mjs +8 -0
- package/src/models/forge/class.mjs +19 -0
- package/src/models/house/bloodlines.mjs +27 -0
- package/src/models/house/class.mjs +53 -0
- package/src/models/house/groups.mjs +38 -0
- package/src/models/project/anatomy.mjs +11 -0
- package/src/models/project/class.mjs +20 -0
- package/src/models/sarcophag/class.mjs +8 -0
- package/src/models/scope/class.mjs +19 -0
- package/src/models/sheme/class.mjs +8 -0
- package/src/models/throwbox/class.mjs +9 -0
- package/src/models/workshop/class.mjs +30 -0
- package/src/models/workshop/hang.data.mjs +10 -0
- package/src/models/workshop/hang.nests.mjs +14 -0
- package/src/models/workshop/hang.setup.mjs +10 -0
- package/src/models/workshop/hang.storylines.logs.mjs +10 -0
- package/src/models/workshop/hang.storylines.manifests.mjs +10 -0
- package/src/models/workshop/hang.storylines.mjs +39 -0
- package/src/models/workshop/hang.storylines.ttystories.mjs +10 -0
- package/src/models/workshop/hang.system.mjs +25 -0
- package/src/models/workshop/host-roles.mjs +9 -0
- package/src/models/workshop/locate.mjs +60 -0
- package/src/models/workshop/modes.mjs +31 -0
- package/src/models/workshop/taskfile.mjs +21 -0
- package/src/procedures/_index.mjs +32 -0
- package/src/procedures/agent-recording/_index.mjs +34 -0
- package/src/procedures/agent-recording/situate.mjs +11 -0
- package/src/procedures/bootstrapping/DESCRIPTION.md +6 -0
- package/src/procedures/bootstrapping/_index.mjs +13 -0
- package/src/procedures/bootstrapping/deploy-guides.mjs +15 -0
- package/src/procedures/bootstrapping/ensure-tree.mjs +4 -0
- package/src/procedures/closing/DESCRIPTION.md +6 -0
- package/src/procedures/closing/_index.mjs +11 -0
- package/src/procedures/closing/capture-ttystory.mjs +14 -0
- package/src/procedures/closing/record-closing.mjs +6 -0
- package/src/procedures/describing/DESCRIPTION.md +23 -0
- package/src/procedures/describing/_index.mjs +15 -0
- package/src/procedures/describing/ask-skryba.mjs +82 -0
- package/src/procedures/describing/compose-message.mjs +25 -0
- package/src/procedures/describing/read-staged.mjs +7 -0
- package/src/procedures/describing/scopes.mjs +38 -0
- package/src/procedures/describing/staged-diff.mjs +25 -0
- package/src/procedures/describing/write-message.mjs +15 -0
- package/src/procedures/gathering/DESCRIPTION.md +13 -0
- package/src/procedures/gathering/_index.mjs +13 -0
- package/src/procedures/gathering/list-served.mjs +9 -0
- package/src/procedures/gathering/merge-residents.mjs +31 -0
- package/src/procedures/gathering/read-registry.mjs +7 -0
- package/src/procedures/hooking/DESCRIPTION.md +6 -0
- package/src/procedures/hooking/_index.mjs +12 -0
- package/src/procedures/hooking/hooks.mjs +10 -0
- package/src/procedures/hooking/install-hooks.mjs +34 -0
- package/src/procedures/hooking/record-hook.mjs +13 -0
- package/src/procedures/inspecting/DESCRIPTION.md +3 -0
- package/src/procedures/inspecting/_index.mjs +9 -0
- package/src/procedures/loading/DESCRIPTION.md +4 -0
- package/src/procedures/loading/_index.mjs +15 -0
- package/src/procedures/loading/load-config.mjs +16 -0
- package/src/procedures/loading/validate-mode.mjs +8 -0
- package/src/procedures/loading/validate-role.mjs +8 -0
- package/src/procedures/locating/DESCRIPTION.md +6 -0
- package/src/procedures/locating/_index.mjs +13 -0
- package/src/procedures/locating/locate-self.mjs +7 -0
- package/src/procedures/locating/locate-workshop.mjs +16 -0
- package/src/procedures/locating/read-environment.mjs +12 -0
- package/src/procedures/mode-switching/DESCRIPTION.md +7 -0
- package/src/procedures/mode-switching/_index.mjs +10 -0
- package/src/procedures/mode-switching/record-mode.mjs +8 -0
- package/src/procedures/mode-switching/switch-mode.mjs +16 -0
- package/src/procedures/opening/DESCRIPTION.md +6 -0
- package/src/procedures/opening/_index.mjs +8 -0
- package/src/procedures/opening/record-opening.mjs +4 -0
- package/src/procedures/promoting/DESCRIPTION.md +8 -0
- package/src/procedures/promoting/_index.mjs +14 -0
- package/src/procedures/promoting/apply.mjs +28 -0
- package/src/procedures/promoting/branch-flow.mjs +23 -0
- package/src/procedures/promoting/plan.mjs +14 -0
- package/src/procedures/promoting/read-position.mjs +15 -0
- package/src/procedures/sinking/DESCRIPTION.md +8 -0
- package/src/procedures/sinking/_index.mjs +12 -0
- package/src/procedures/sinking/inventory-forge.mjs +18 -0
- package/src/procedures/sinking/inventory-tools.mjs +7 -0
- package/src/procedures/skilling/DESCRIPTION.md +11 -0
- package/src/procedures/skilling/_index.mjs +15 -0
- package/src/procedures/skilling/collect-models.mjs +15 -0
- package/src/procedures/skilling/compose-skill.mjs +49 -0
- package/src/procedures/skilling/glossary.mjs +23 -0
- package/src/procedures/skilling/register-skills.mjs +21 -0
- package/src/procedures/skilling/write-skills.mjs +19 -0
- package/src/views/_index.mjs +23 -0
- package/src/views/agent/_index.mjs +2 -0
- package/src/views/agent/brief.mjs +34 -0
- package/src/views/help/_index.mjs +41 -0
- package/src/views/house/_index.mjs +56 -0
- package/src/views/inventory/_index.mjs +27 -0
- package/src/views/mcp/_index.mjs +31 -0
- package/src/views/mcp/tools.mjs +87 -0
- package/src/views/mode/_index.mjs +34 -0
- package/src/views/mode/chooser.mjs +37 -0
- package/src/views/promotion/_index.mjs +20 -0
- package/src/views/repl/_index.mjs +30 -0
- package/src/views/skills/_index.mjs +24 -0
- package/src/views/status/_index.mjs +57 -0
- package/src/views/status/tree.mjs +19 -0
- package/src/views/terminal/paint.mjs +22 -0
- package/template/SKILL.md +16 -0
- package/docs/README.md +0 -15
- package/docs/devlog.md +0 -20
- package/invoke-api.js +0 -0
- package/invoke-cli.js +0 -105
- package/invoke-desktop.js +0 -0
- package/invoke-exec.js +0 -0
- package/invoke-webapp.js +0 -0
- package/main.js +0 -33
- package/shell-procedures/deploy-new-workshop.sh +0 -15
- package/shell-procedures/new-project.sh +0 -0
- package/shell-procedures/new-sheme.sh +0 -0
- package/shell-procedures/new-superproject.sh +0 -6
- package/shell-procedures/open-project.sh +0 -0
- package/shell-procedures/pack-backup.sh +0 -22
- package/shell-procedures/project-to-sarcophag.sh +0 -0
- package/shell-procedures/publicate.sh +0 -0
- package/shell-procedures/pull-archive.sh +0 -0
- package/shell-procedures/purge-workshop.sh +0 -4
- package/shell-procedures/push-to-bos-server.sh +0 -0
- package/shell-procedures/start-cli-interface.sh +0 -1
- package/shell-procedures/sweep-into-throwbox.sh +0 -0
- package/shell-procedures/synchronize.sh +0 -7
- package/system/bridges/README.md +0 -4
- package/system/bridges/main.js +0 -41
- package/system/commands/README.md +0 -0
- package/system/commands/debug.js +0 -20
- package/system/commands/exit.js +0 -19
- package/system/core/README.md +0 -0
- package/system/core/basic-subject-model.js +0 -200
- package/system/core/config-controll.js +0 -51
- package/system/core/contain-controll.js +0 -28
- package/system/core/event-controll.js +0 -12
- package/system/core/extending-mod.js +0 -145
- package/system/core/main.js +0 -184
- package/system/core/raport-controll.js +0 -10
- package/system/core/static-extender.js +0 -19
- package/system/factors/README.md +0 -0
- package/system/factors/bridge-factory.js +0 -5
- package/system/factors/command-factory.js +0 -45
- package/system/factors/config-factory.js +0 -6
- package/system/factors/controller-factory.js +0 -5
- package/system/factors/interface-factory.js +0 -70
- package/system/factors/model-factory.js +0 -0
- package/system/interfaces/README.md +0 -28
- package/system/interfaces/cli/index.js +0 -96
- package/system/interfaces/cli/init.js +0 -47
- package/system/interfaces/cli/loop.js +0 -7
- package/system/interfaces/cli/on-close.js +0 -17
- package/system/interfaces/cli/on-line.js +0 -24
- package/system/interfaces/cli/on-resume.js +0 -15
- package/system/interfaces/cli/setup.js +0 -8
- package/system/models/README.md +0 -47
- package/system/models/archive/README.md +0 -0
- package/system/models/archive/actions/README.md +0 -0
- package/system/models/archive/class.js +0 -23
- package/system/models/archive/events/README.md +0 -0
- package/system/models/archive/index.json +0 -18
- package/system/models/archive/listeners/README.md +0 -0
- package/system/models/archive/methods/README.md +0 -0
- package/system/models/forge/README.md +0 -0
- package/system/models/forge/actions/README.md +0 -0
- package/system/models/forge/class.js +0 -23
- package/system/models/forge/events/README.md +0 -0
- package/system/models/forge/index.json +0 -18
- package/system/models/forge/listeners/README.md +0 -0
- package/system/models/forge/methods/README.md +0 -0
- package/system/models/project/README.md +0 -0
- package/system/models/project/actions/README.md +0 -0
- package/system/models/project/class.js +0 -23
- package/system/models/project/events/README.md +0 -0
- package/system/models/project/index.json +0 -18
- package/system/models/project/listeners/README.md +0 -0
- package/system/models/project/methods/README.md +0 -0
- package/system/models/sarcophag/README.md +0 -0
- package/system/models/sarcophag/actions/README.md +0 -0
- package/system/models/sarcophag/class.js +0 -22
- package/system/models/sarcophag/events/README.md +0 -0
- package/system/models/sarcophag/index.json +0 -18
- package/system/models/sarcophag/listeners/README.md +0 -0
- package/system/models/sarcophag/methods/README.md +0 -0
- package/system/models/sheme/README.md +0 -0
- package/system/models/sheme/actions/README.md +0 -0
- package/system/models/sheme/class.js +0 -23
- package/system/models/sheme/events/README.md +0 -0
- package/system/models/sheme/index.json +0 -18
- package/system/models/sheme/listeners/README.md +0 -0
- package/system/models/sheme/methods/README.md +0 -0
- package/system/models/superproject/README.md +0 -0
- package/system/models/superproject/actions/README.md +0 -0
- package/system/models/superproject/class.js +0 -23
- package/system/models/superproject/events/README.md +0 -0
- package/system/models/superproject/index.json +0 -18
- package/system/models/superproject/listeners/README.md +0 -0
- package/system/models/superproject/methods/README.md +0 -0
- package/system/models/throwbox/README.md +0 -0
- package/system/models/throwbox/actions/README.md +0 -0
- package/system/models/throwbox/class.js +0 -23
- package/system/models/throwbox/events/README.md +0 -0
- package/system/models/throwbox/index.json +0 -18
- package/system/models/throwbox/listeners/README.md +0 -0
- package/system/models/throwbox/methods/README.md +0 -0
- package/system/models/workshop/README.md +0 -0
- package/system/models/workshop/actions/README.md +0 -0
- package/system/models/workshop/class.js +0 -22
- package/system/models/workshop/events/README.md +0 -0
- package/system/models/workshop/index.json +0 -18
- package/system/models/workshop/listeners/README.md +0 -0
- package/system/models/workshop/methods/README.md +0 -0
- package/system/resources/textarts/big-logo-title.txt +0 -24
- package/system/resources/textarts/big-shortcut-logo-title.txt +0 -10
- package/system/resources/textarts/medium-logo-title.txt +0 -13
- package/system/resources/textarts/minimenu-header.ptxml +0 -13
- package/system/resources/textarts/minimenu-header.txt +0 -11
- package/system/resources/textarts/small-logo-title.txt +0 -10
- package/system/resources/textarts/wellcome.txt +0 -10
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
# BOS codebase map
|
|
2
|
+
|
|
3
|
+
## New core: this repository (bos-skillset → Sarverott/blacksmith-organization-system)
|
|
4
|
+
|
|
5
|
+
Node ≥ 22.18, ESM plus `src/main.ts` (run directly via type stripping). Read the
|
|
6
|
+
root `AGENTS.md` first: it has the architecture and the one-concern-per-file rule.
|
|
7
|
+
|
|
8
|
+
- `src/main.ts`: the spine. `class BOS` holds `BOS.Bridge/Model/Procedure/Controll/View`; `bos.load()` loads the parts; `bos.workshop` is the controller; `bos.command(name)`.
|
|
9
|
+
- `src/bridge/<name>/`: docker-host (dockerode: containers, images, volumes), github-api (octokit), git-client (isomorphic-git), gitea-api, subprocess-runner, docker-publish, npm-publish, ssh-link, bos-instances-link ([`TODO`])
|
|
10
|
+
- `src/models/<element>/class.mjs`: standalone assets (`BOS.Model`); organs hang on their owner as `models/<owner>/hang.<name>.mjs` (`BOS.Submodule`, built from the owner: `workshop.storylines.logs`); shared anatomy in `core/basic-element.mjs`; `models/workshop/locate.mjs` finds workshops
|
|
11
|
+
- `bos skills`: drafts `skills/bos-<type>/SKILL.md` per model from the glossary (procedure `skilling`), never overwrites
|
|
12
|
+
- `src/procedures/<name>/`: DESCRIPTION.md + a step per file: locating, loading, inspecting, bootstrapping, opening, closing, sinking, hooking, promoting
|
|
13
|
+
- `src/commands/<name>/index.json`: `{path, info, help, inline, repl}`; `bos help` lists them
|
|
14
|
+
- storylines log: `.BOS/storylines/logs/workshop.jsonl`; tests: `npm test` (vitest)
|
|
15
|
+
- commits: husky (`.husky/`) → `bos describe --hook` drafts a conventional commit, Skryba (raven, `resources/ravens/skryba.md`, via ollama-link) refines it, commitlint checks it, post-* hooks → storylines; `npm run commit` = commitizen (cz-commitlint)
|
|
16
|
+
- releases: semantic-release (`release.config.mjs`), baseline tag v0.7.0; channels dev (developement), beta (testing), rc (releasing), latest (master); npm + GitHub Packages (@sarverott/…) + ghcr.io
|
|
17
|
+
|
|
18
|
+
Everything below describes the **old core**.
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
Local clone: `~/__WORKSHOP/forge/blacksmith-organization-system/blacksmith-organization-system`
|
|
23
|
+
Remote: https://github.com/Sarverott/OLD-VERSIONS_blacksmith-organization-system (renamed; the name now belongs to the new core)
|
|
24
|
+
Node.js (CommonJS). Entry: `src/_index.js`. Run: `npm start`.
|
|
25
|
+
|
|
26
|
+
The owner works in this repo in parallel with agents: new commits, removed
|
|
27
|
+
files and changed remote branches between sessions are normal. Always re-check
|
|
28
|
+
`git status`, `git log --all` and the tree before acting. Don't assume an
|
|
29
|
+
earlier state.
|
|
30
|
+
|
|
31
|
+
## Branches (as of 2026-09-30)
|
|
32
|
+
|
|
33
|
+
| Branch | State |
|
|
34
|
+
| ------ | ----- |
|
|
35
|
+
| `developement` | Main dev line. Being cleaned radically by the owner ("massive removal of junk codes from dark past", c7da0df) |
|
|
36
|
+
| `dev/reforge` | The agent's reforge work (4d71a58): the component-submodule layout, booting |
|
|
37
|
+
| `dev/submodule-gits` | `developement` before the reforge (ade23b9): 14 component submodules, not booting |
|
|
38
|
+
| `drafting`, `moderation`, `publishing`, `testing`, `revision`, `releasing` | Workflow branches, created at ade23b9, not used yet |
|
|
39
|
+
| `master` | Old, single-repo version (767aa95). Boots, but builds the workshop inside the repo |
|
|
40
|
+
|
|
41
|
+
`developement/…` names are impossible while a `developement` branch exists
|
|
42
|
+
(a git ref can't be both a branch and a folder), so sub-branches use `dev/…`.
|
|
43
|
+
|
|
44
|
+
Commit messages marked `░▒▓BOS.helper.tulu3╚╣Skryba╠╗UNIXUSAT=…` come from an
|
|
45
|
+
automated commit-message helper. Several are garbled noise.
|
|
46
|
+
|
|
47
|
+
## Layout of `developement` after the clean-up (c7da0df)
|
|
48
|
+
|
|
49
|
+
Submodules are gone. The component code is flat again in `src/<type>/`:
|
|
50
|
+
|
|
51
|
+
```
|
|
52
|
+
src/
|
|
53
|
+
├── _index.js runner.js spawner.js includer.js
|
|
54
|
+
├── core/ bos.js (base class + INITIALIZE/SETUP), bos.controller.js,
|
|
55
|
+
│ bos.command.js, bos.interface.js, helperFunctions.js
|
|
56
|
+
├── controllers/ Config, Models, Commands, Interfaces, Scope, … (*Controll.js)
|
|
57
|
+
├── commands/ <name>/{call.js,index.json,manual.md}
|
|
58
|
+
├── models/ <type>/{class.js,data.json[,README.md]}; archive keeps actions/events/…
|
|
59
|
+
├── factors/ command-factory.js
|
|
60
|
+
├── bridges/ integration stubs (publishers, extensions, integrators)
|
|
61
|
+
└── toolsets/ old shell scripts + dev/_index.js save/test runner
|
|
62
|
+
resources/cli-art/ text-art logos
|
|
63
|
+
docs/ README, devlog, about-*.md, glossary/
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Removed in the clean-up: `config/` (main/workshop/startup defaults),
|
|
67
|
+
`src/interfaces/` (cli-repl, http-api, socket-server), `libs/py`, `apps/`,
|
|
68
|
+
`examples/`, `.crovley`, all submodules.
|
|
69
|
+
|
|
70
|
+
## Boot sequence (design)
|
|
71
|
+
|
|
72
|
+
1. `_index.js` runs `runner.js` when executed directly, or exports `includer.js` (the library API) when required.
|
|
73
|
+
2. `runner.js` calls `BOS.INITIALIZE(repoRoot)`, `BOS.SETUP()`, `BOS.EXECUTE()` (EXECUTE is empty).
|
|
74
|
+
3. INITIALIZE loads every controller class and calls `loadAll()`: Config → Models → Commands → Interfaces → Scope → Scrapbook → Projects → Bridges → Factors → Sandbox → Publication → Deployment.
|
|
75
|
+
4. Config loads `config/*.json` (copied from `*.default` if missing) into `BOS.CONFIG`.
|
|
76
|
+
5. Models are exposed as `BOS.<Type>` and `BOS.MODELS[type]`.
|
|
77
|
+
6. Scope builds the workshop tree from `BOS.CONFIG.workshop.content` and creates missing areas.
|
|
78
|
+
7. SETUP runs `<workshop>/.SETUP/startup.bos`: one command per line, `<command> <args…>`. The default is `use-interface cli-repl open`.
|
|
79
|
+
8. `cli-repl` is Node's REPL. BOS commands are dot-commands (`.show-status`).
|
|
80
|
+
|
|
81
|
+
## Current boot state of `developement` (c7da0df): does not start
|
|
82
|
+
|
|
83
|
+
Leftovers from the reforge still point at the removed layout:
|
|
84
|
+
|
|
85
|
+
- `core/helperFunctions.js` `componentPath()` returns `src/components/<type>/ITEMS/…`. It should become `src/<type>/…`.
|
|
86
|
+
- `controllers/InterfacesControll.js`, `ModelsControll.js`, `CommandsControll.js` join `"src","components",<type>,"ITEMS"`.
|
|
87
|
+
- `require("blacksmith-organization-system/core/…")` (package self-reference) still works while `package.json` has `exports`. Relative `../core/…` would work again now too.
|
|
88
|
+
- `config/` is gone, but ConfigControll, Scope and SETUP need `main.json` and `workshop.json` (defaults).
|
|
89
|
+
- `src/interfaces/` is gone, but the startup script and InterfacesControll expect it.
|
|
90
|
+
- `commands/new-component` still does `git submodule add … src/components/<name>`.
|
|
91
|
+
|
|
92
|
+
Workshop root resolution (still in `helperFunctions.findWorkshopRoot`):
|
|
93
|
+
`$BOS_WORKSHOP` → nearest ancestor `__WORKSHOP` → `~/__WORKSHOP`.
|
|
94
|
+
Test safely with `BOS_WORKSHOP=/tmp/x/__WORKSHOP npm start`. Without it,
|
|
95
|
+
running from inside `~/__WORKSHOP` uses the real workshop.
|
|
96
|
+
|
|
97
|
+
## Commands (src/commands)
|
|
98
|
+
|
|
99
|
+
| Command | Does |
|
|
100
|
+
| ------- | ---- |
|
|
101
|
+
| `show-status [workshop\|workshops\|forge\|archive\|interfaces\|tree]` | readable status |
|
|
102
|
+
| `deploy-workshop` | create missing areas, write `bos-workshop.log` (port of deploy-new-workshop.sh) |
|
|
103
|
+
| `new-scope <name>` | `forge/<name>` + `git init` (port of new-superproject.sh; the old one made a bare `<name>.git`) |
|
|
104
|
+
| `pull-archive` | clone or fetch the repos in `.DATA/*.gitlist` into `archive/<pack>/` (port of archive_mirrors.sh) |
|
|
105
|
+
| `new-component <name>` | `gh repo create bos.<name>` from template + submodule (outdated since submodules were removed) |
|
|
106
|
+
| `exit` | closes the REPL |
|
|
107
|
+
| `use-interface <name> open` | starts an interface |
|
|
108
|
+
| `create-item`, `load-workshop` | empty stubs |
|
|
109
|
+
|
|
110
|
+
## Historic defects fixed in `dev/reforge`
|
|
111
|
+
|
|
112
|
+
- master built the workshop inside the repo (`BOS.PathTo(context-path)`) but wrote the startup script to `~/__WORKSHOP/setup`.
|
|
113
|
+
- SETUP copied the startup file without creating its directory (ENOENT on a fresh run).
|
|
114
|
+
- A stub `exit` command overrode the REPL's built-in `.exit`.
|
|
115
|
+
- CLI command arguments arrived as one unsplit string.
|
|
116
|
+
- A recursive `fs.watch` on every model; every file change dumped whole objects to the console.
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
# What BOS is
|
|
2
|
+
|
|
3
|
+
**Blacksmith Organization System (BOS)** by Sett Sarverott (2019–), MIT license.
|
|
4
|
+
Part of the R-tier superproject "ANUBIS". Repositories:
|
|
5
|
+
|
|
6
|
+
- old core: https://github.com/Sarverott/OLD-VERSIONS_blacksmith-organization-system (local: `forge/blacksmith-organization-system/blacksmith-organization-system`)
|
|
7
|
+
- root of the new BOS (this skillset): https://github.com/Sarverott/blacksmith-organization-system (local: `forge/blacksmith-organization-system/bos-skillset`)
|
|
8
|
+
|
|
9
|
+
The goal is to automate the management of a personal "forest of projects"
|
|
10
|
+
across many machines, servers and publication targets, without version drift
|
|
11
|
+
("variantogeddon"). The author's rule: *"if it is good thinking then it will be
|
|
12
|
+
automated"*.
|
|
13
|
+
|
|
14
|
+
**Authoritative definitions:** `docs/glossary/<element>.md` in this repository
|
|
15
|
+
(bos-skillset), one page per element, index in `docs/glossary/README.md`.
|
|
16
|
+
Expressed as code in `src/models/<element>/class.mjs`. The old core repo holds an older copy. This file is a
|
|
17
|
+
summary; if the two disagree, the glossary wins. The author annotates the
|
|
18
|
+
glossary directly: read their changes (`git diff`) before summarizing.
|
|
19
|
+
|
|
20
|
+
## The skeleton: three layers
|
|
21
|
+
|
|
22
|
+
### 1. Network
|
|
23
|
+
|
|
24
|
+
- **Setternet (snet):** the owner's network of BOS hosts. Setup lives in `.BOS/setup/setternet/`.
|
|
25
|
+
- **Host roles** (PL originals): master's outpost (Posterunek Mistrza: remote
|
|
26
|
+
management), forging point (Punkt Kuźniczy: development), trial hall (Sala
|
|
27
|
+
Prób: VMs, testing), market stall (Kram Targowy: publication only), canon
|
|
28
|
+
monolith (Monolit Kanonu: the master archive; exactly one per setternet),
|
|
29
|
+
side catacomb (Katakumb Poboczny: single-purpose archive, e.g. Ollama or deployments).
|
|
30
|
+
- **Canon:** the complete, authoritative record, held by the canon monolith, and
|
|
31
|
+
in git by the `canonical` branch, which the Canon Keeper confirms.
|
|
32
|
+
|
|
33
|
+
### 2. Workshop: one per host or partition
|
|
34
|
+
|
|
35
|
+
```
|
|
36
|
+
__WORKSHOP/
|
|
37
|
+
├── .BOS/ internal, mandatory: workshop.json Taskfile.yaml .omnis.toml package.json Dockerfile compose.yaml
|
|
38
|
+
│ ├── setup/ keys, VPN, routing, DNS/SSH aliases, tokens, setternet/ (mandatory)
|
|
39
|
+
│ ├── data/ e.g. <pack>.gitlist
|
|
40
|
+
│ ├── nests/ container/VM volumes; always .index.json + .manifest.json (mandatory)
|
|
41
|
+
│ └── storylines/ ttystories/ logs/ manifests/ metadata.json (created during use)
|
|
42
|
+
├── devarmory/ tools: manifest-listed, auto-downloaded, checksum-verified, linked to PATH/desktop
|
|
43
|
+
├── forge/ active work (the desk): <scope>/<project|sheme>, throwbox; defines the working branch
|
|
44
|
+
├── craftbook/ knowledge: scrapnotes/, craftsets, collections, recipes
|
|
45
|
+
└── archive/ at rest: sarcophags, exhibits, <pack>/<mirror>
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
The four crafting areas and `.BOS/` must always exist; BOS creates them at
|
|
49
|
+
boot. Older layouts had `.SETUP`, `.DATA`, `.NESTRELM`, `.STORYLINES` and
|
|
50
|
+
`.__BOS` as separate top-level dirs, `~/.__WORKSHOP` as the root, and `notes/`
|
|
51
|
+
or scrapbook instead of craftbook.
|
|
52
|
+
|
|
53
|
+
Views (dashboards over CLI, web, mobile, Chrome extension, Electron, OpenAPI,
|
|
54
|
+
MCP, with one shared handler class) has no settled location yet.
|
|
55
|
+
|
|
56
|
+
### Modes of work (`.BOS/workshop.json` → "mode"; `bos mode`)
|
|
57
|
+
|
|
58
|
+
1 ALMANAC: emergency (sinking) · 2 CONFORM: establish, migrate, clean, verify,
|
|
59
|
+
sync workshops · 3 SMELTRY: code, development, publishing changes ·
|
|
60
|
+
4 COMMANDORATE: rules, privileges, roles, mode switching · 5 PROVISION:
|
|
61
|
+
presenting what a source of truth (e.g. GitHub) delivers. Defaults for a new
|
|
62
|
+
workshop: role `forging-point`, mode `conform` (`resources/workshop.default.json`;
|
|
63
|
+
null = not set → default). Commands declare
|
|
64
|
+
their mode in `index.json`; `bos help` groups them. Glossary: mode.md.
|
|
65
|
+
|
|
66
|
+
### 3. Elements
|
|
67
|
+
|
|
68
|
+
- **scope** (formerly superproject): a private repository with submodules,
|
|
69
|
+
holding a family of projects and shemes plus a throwbox. Synced through a
|
|
70
|
+
self-hosted server (e.g. Gitea) that also keeps pre-public drafts.
|
|
71
|
+
- **project:** one concrete project repository.
|
|
72
|
+
- **sheme:** source material that isn't code: graphics/GIMP, Blender/CAD, photos,
|
|
73
|
+
templates, third-party reference docs. A design template is a sheme; the code
|
|
74
|
+
realizing it is a project. (The old scrapnote used sheme for processing
|
|
75
|
+
routes: HF uploaders, publish and deploy routines. Unresolved.)
|
|
76
|
+
- **throwbox:** automated collector of loose files per scope; swept on close into an anonymous sarcophag.
|
|
77
|
+
- **sarcophag:** encrypted container holding one bare repository (archive).
|
|
78
|
+
- **exhibit:** view built from sarcophags (archive). [`TODO`]
|
|
79
|
+
- **scrapnote:** any note not yet promoted to a document; changelogs and release notes stay scrapnotes.
|
|
80
|
+
- **craftset:** reusable kit of notes, notebooks, one-off scripts and session
|
|
81
|
+
setup; mandatory `.omnis.toml`, `metadata.json`, `manifest.json`, `Taskfile.yaml`.
|
|
82
|
+
- **collection**, **postroad:** meaning unresolved.
|
|
83
|
+
|
|
84
|
+
**Element anatomy** (pattern awaiting confirmation): a directory plus descriptor
|
|
85
|
+
files: `metadata.json` (identity/origin), `manifest.json` (checksums/integrity),
|
|
86
|
+
`.index.json` (map), `Taskfile.yaml` (procedures), `.omnis.toml` ([`TODO`]).
|
|
87
|
+
|
|
88
|
+
## Lifecycles
|
|
89
|
+
|
|
90
|
+
- work: forge → archive (sarcophag) → canon monolith
|
|
91
|
+
- loose files: throwbox → anonymous sarcophag → sorted, reused or deleted
|
|
92
|
+
- notes: scrapnote → document (or stays a scrapnote)
|
|
93
|
+
- tools: manifest → download → verify checksum → link
|
|
94
|
+
|
|
95
|
+
## Storylines naming
|
|
96
|
+
|
|
97
|
+
`ttystory.txt`, `ttystory-$UNIXUSAT.txt`, `ttystory-$HOSTNAME-$UNIXUSAT.txt`.
|
|
98
|
+
`UNIXUSAT` = Unix timestamp in milliseconds. The purpose is to reuse command
|
|
99
|
+
patterns and to teach AI to use the shell the BOS way.
|
|
100
|
+
|
|
101
|
+
## Ideas on record
|
|
102
|
+
|
|
103
|
+
Autocommit on save; GIMP history bound to VCS (a branch per session, a commit
|
|
104
|
+
per action); releases trigger social media posts; Taskfile + Husky + a standard
|
|
105
|
+
command set; history proven via OpenTimestamps.
|
|
106
|
+
|
|
107
|
+
## Branches and versioning
|
|
108
|
+
|
|
109
|
+
Every repository (docs/infographics/branch-movement-procedures.md): `master`
|
|
110
|
+
(spine of canon) → `developement` (here we code) → `revision` (approval) →
|
|
111
|
+
`testing` (QA, nightly builds) → `releasing` (stamp, publish, announce) →
|
|
112
|
+
`master` via pull request. Rejections go back to `developement`.
|
|
113
|
+
The old core repo additionally has `drafting`, `moderation`, `publishing` and
|
|
114
|
+
`dev/<topic>`; their place in the flow: [`TODO`]
|
|
115
|
+
|
|
116
|
+
Versioning is `{G}.{R}.{I}.{H}`: Generation, Reconstruction, Integration, Hooking.
|
|
117
|
+
|
|
118
|
+
## Related repositories
|
|
119
|
+
|
|
120
|
+
Apps: bos-desktop, bos-mobile, bos-server, bos-gui, bos-vscode-extension.
|
|
121
|
+
Components: `Sarverott/bos.<component>`. Library: carnival-toolbox.
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Locate BOS workshops. First line: active workshop root.
|
|
3
|
+
# Remaining lines: all other workshops found (home + /media partitions).
|
|
4
|
+
set -euo pipefail
|
|
5
|
+
|
|
6
|
+
active=""
|
|
7
|
+
|
|
8
|
+
if [[ -n "${BOS_WORKSHOP:-}" && -d "$BOS_WORKSHOP" ]]; then
|
|
9
|
+
active="$BOS_WORKSHOP"
|
|
10
|
+
else
|
|
11
|
+
dir="$PWD"
|
|
12
|
+
while [[ "$dir" != "/" ]]; do
|
|
13
|
+
if [[ "$(basename "$dir")" == "__WORKSHOP" ]]; then
|
|
14
|
+
active="$dir"
|
|
15
|
+
break
|
|
16
|
+
fi
|
|
17
|
+
dir="$(dirname "$dir")"
|
|
18
|
+
done
|
|
19
|
+
fi
|
|
20
|
+
|
|
21
|
+
if [[ -z "$active" && -d "$HOME/__WORKSHOP" ]]; then
|
|
22
|
+
active="$HOME/__WORKSHOP"
|
|
23
|
+
fi
|
|
24
|
+
|
|
25
|
+
[[ -n "$active" ]] && echo "$active"
|
|
26
|
+
|
|
27
|
+
{
|
|
28
|
+
[[ -d "$HOME/__WORKSHOP" ]] && echo "$HOME/__WORKSHOP"
|
|
29
|
+
[[ -d /media ]] && find /media -maxdepth 4 -type d -name __WORKSHOP 2>/dev/null
|
|
30
|
+
} | sort -u | grep -vxF "${active:-/nonexistent}" || true
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Claude Code hooks → BOS (hooks/hooks.json). Reads the hook's JSON from stdin.
|
|
3
|
+
// session-start prints a short brief (becomes the agent's context) and records the session
|
|
4
|
+
// bash appends the agent's shell command to its ttystory in storylines
|
|
5
|
+
// session-end records the end of the session
|
|
6
|
+
// Loads no bridges, so it stays fast; never fails the agent (always exits 0).
|
|
7
|
+
import { brief, recordAgentCommand, recordAgentEvent } from "./views/agent/_index.mjs";
|
|
8
|
+
|
|
9
|
+
const event = process.argv[2];
|
|
10
|
+
let input = {};
|
|
11
|
+
try {
|
|
12
|
+
const chunks = [];
|
|
13
|
+
for await (const chunk of process.stdin) chunks.push(chunk);
|
|
14
|
+
input = JSON.parse(Buffer.concat(chunks).toString("utf8") || "{}");
|
|
15
|
+
} catch {}
|
|
16
|
+
|
|
17
|
+
try {
|
|
18
|
+
if (event === "session-start") {
|
|
19
|
+
const text = await brief(input);
|
|
20
|
+
if (text) process.stdout.write(text);
|
|
21
|
+
await recordAgentEvent(input, "agent-session-start");
|
|
22
|
+
} else if (event === "bash") {
|
|
23
|
+
await recordAgentCommand(input);
|
|
24
|
+
} else if (event === "session-end") {
|
|
25
|
+
await recordAgentEvent(input, "agent-session-end");
|
|
26
|
+
}
|
|
27
|
+
} catch {}
|
|
28
|
+
process.exit(0);
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
// Every bridge, by name. Each one shapes an outside system into plain methods.
|
|
2
|
+
import BosInstancesLink from "./bos-instances-link/_index.mjs";
|
|
3
|
+
import DockerHost from "./docker-host/_index.mjs";
|
|
4
|
+
import DockerPublish from "./docker-publish/_index.mjs";
|
|
5
|
+
import GitClient from "./git-client/_index.mjs";
|
|
6
|
+
import GiteaApi from "./gitea-api/_index.mjs";
|
|
7
|
+
import GithubApi from "./github-api/_index.mjs";
|
|
8
|
+
import NpmPublish from "./npm-publish/_index.mjs";
|
|
9
|
+
import OllamaLink from "./ollama-link/_index.mjs";
|
|
10
|
+
import SshLink from "./ssh-link/_index.mjs";
|
|
11
|
+
import SubprocessRunner from "./subprocess-runner/_index.mjs";
|
|
12
|
+
|
|
13
|
+
export default {
|
|
14
|
+
subprocessRunner: SubprocessRunner,
|
|
15
|
+
dockerHost: DockerHost,
|
|
16
|
+
dockerPublish: DockerPublish,
|
|
17
|
+
gitClient: GitClient,
|
|
18
|
+
giteaApi: GiteaApi,
|
|
19
|
+
githubApi: GithubApi,
|
|
20
|
+
npmPublish: NpmPublish,
|
|
21
|
+
ollamaLink: OllamaLink,
|
|
22
|
+
sshLink: SshLink,
|
|
23
|
+
BOSLINK: BosInstancesLink,
|
|
24
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
// Links between BOS instances of one setternet (glossary: setternet, host-role).
|
|
2
|
+
// [TODO] transport and protocol are not decided yet; this names the handler.
|
|
3
|
+
import { BOS } from "../../main.ts";
|
|
4
|
+
|
|
5
|
+
export class BosInstancesLink extends BOS.Bridge {
|
|
6
|
+
static id = "bos-instances-link";
|
|
7
|
+
|
|
8
|
+
async available() {
|
|
9
|
+
return false;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
// hosts known to this workshop, from .BOS/setup/setternet/ [TODO] format
|
|
13
|
+
hosts() {
|
|
14
|
+
return [];
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export default BosInstancesLink;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
// The docker host (local socket or $DOCKER_HOST) through dockerode.
|
|
2
|
+
// const docker = new DockerHost(); await docker.containers.list()
|
|
3
|
+
import Docker from "dockerode";
|
|
4
|
+
|
|
5
|
+
import { BOS } from "../../main.ts";
|
|
6
|
+
import * as container from "./container.mjs";
|
|
7
|
+
import * as image from "./image.mjs";
|
|
8
|
+
import * as volume from "./volume.mjs";
|
|
9
|
+
|
|
10
|
+
// bind every helper to this host's client: containers.run(image, …)
|
|
11
|
+
const bound = (bridge, helpers) =>
|
|
12
|
+
Object.fromEntries(
|
|
13
|
+
Object.entries(helpers).map(([name, helper]) => [name, (...args) => helper(bridge.client, ...args)]),
|
|
14
|
+
);
|
|
15
|
+
|
|
16
|
+
export class DockerHost extends BOS.Bridge {
|
|
17
|
+
static id = "docker-host";
|
|
18
|
+
|
|
19
|
+
connect() {
|
|
20
|
+
return new Docker(this.options); // no options: $DOCKER_HOST or /var/run/docker.sock
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
async available() {
|
|
24
|
+
try {
|
|
25
|
+
await this.client.ping();
|
|
26
|
+
return true;
|
|
27
|
+
} catch {
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
get containers() {
|
|
33
|
+
return bound(this, container);
|
|
34
|
+
}
|
|
35
|
+
get images() {
|
|
36
|
+
return bound(this, image);
|
|
37
|
+
}
|
|
38
|
+
get volumes() {
|
|
39
|
+
return bound(this, volume);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export default DockerHost;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
// Containers of a docker host (dockerode client in, plain data out).
|
|
2
|
+
|
|
3
|
+
export const list = async (docker, { all = true } = {}) =>
|
|
4
|
+
(await docker.listContainers({ all })).map((c) => ({
|
|
5
|
+
id: c.Id.slice(0, 12),
|
|
6
|
+
name: c.Names[0]?.replace(/^\//, ""),
|
|
7
|
+
image: c.Image,
|
|
8
|
+
state: c.State,
|
|
9
|
+
status: c.Status,
|
|
10
|
+
}));
|
|
11
|
+
|
|
12
|
+
export async function run(docker, image, { name, cmd, env = {}, binds = [], labels = {} } = {}) {
|
|
13
|
+
const container = await docker.createContainer({
|
|
14
|
+
Image: image,
|
|
15
|
+
name,
|
|
16
|
+
Cmd: cmd,
|
|
17
|
+
Env: Object.entries(env).map(([key, value]) => `${key}=${value}`),
|
|
18
|
+
Labels: { "bos.managed": "true", ...labels },
|
|
19
|
+
HostConfig: { Binds: binds },
|
|
20
|
+
});
|
|
21
|
+
await container.start();
|
|
22
|
+
return container.id;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export const start = (docker, id) => docker.getContainer(id).start();
|
|
26
|
+
export const stop = (docker, id) => docker.getContainer(id).stop();
|
|
27
|
+
export const remove = (docker, id, { force = false } = {}) => docker.getContainer(id).remove({ force });
|
|
28
|
+
|
|
29
|
+
export async function logs(docker, id, { tail = 100 } = {}) {
|
|
30
|
+
const buffer = await docker.getContainer(id).logs({ stdout: true, stderr: true, tail });
|
|
31
|
+
return buffer.toString("utf8");
|
|
32
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
// Images of a docker host.
|
|
2
|
+
|
|
3
|
+
export const list = async (docker) =>
|
|
4
|
+
(await docker.listImages()).map((i) => ({
|
|
5
|
+
id: i.Id.replace(/^sha256:/, "").slice(0, 12),
|
|
6
|
+
tags: i.RepoTags ?? [],
|
|
7
|
+
size: i.Size,
|
|
8
|
+
}));
|
|
9
|
+
|
|
10
|
+
// resolve when every layer is pulled / pushed
|
|
11
|
+
const follow = (docker, stream) =>
|
|
12
|
+
new Promise((resolve, reject) =>
|
|
13
|
+
docker.modem.followProgress(stream, (error, output) => (error ? reject(error) : resolve(output))),
|
|
14
|
+
);
|
|
15
|
+
|
|
16
|
+
export const pull = async (docker, name) => follow(docker, await docker.pull(name));
|
|
17
|
+
|
|
18
|
+
export const tag = (docker, name, repo, tagName = "latest") => docker.getImage(name).tag({ repo, tag: tagName });
|
|
19
|
+
|
|
20
|
+
export const push = async (docker, name, auth) =>
|
|
21
|
+
follow(docker, await docker.getImage(name).push({ authconfig: auth }));
|
|
22
|
+
|
|
23
|
+
export const remove = (docker, name, { force = false } = {}) => docker.getImage(name).remove({ force });
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
// Volumes of a docker host. BOS nests (glossary: nestrelm) are volumes labeled bos.nest.
|
|
2
|
+
|
|
3
|
+
export const list = async (docker, { nestsOnly = false } = {}) => {
|
|
4
|
+
const { Volumes = [] } = await docker.listVolumes(nestsOnly ? { filters: { label: ["bos.nest"] } } : {});
|
|
5
|
+
return Volumes.map((v) => ({ name: v.Name, driver: v.Driver, mountpoint: v.Mountpoint, labels: v.Labels ?? {} }));
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
export const create = (docker, name, { nest = true, labels = {} } = {}) =>
|
|
9
|
+
docker.createVolume({ Name: name, Labels: { ...(nest ? { "bos.nest": name } : {}), ...labels } });
|
|
10
|
+
|
|
11
|
+
export const inspect = (docker, name) => docker.getVolume(name).inspect();
|
|
12
|
+
export const remove = (docker, name) => docker.getVolume(name).remove();
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
// Publishing an image: tag it for a registry and push it, over the docker host.
|
|
2
|
+
import { BOS } from "../../main.ts";
|
|
3
|
+
import DockerHost from "../docker-host/_index.mjs";
|
|
4
|
+
|
|
5
|
+
export class DockerPublish extends BOS.Bridge {
|
|
6
|
+
static id = "docker-publish";
|
|
7
|
+
|
|
8
|
+
get host() {
|
|
9
|
+
this._host ??= new DockerHost(this.options.docker);
|
|
10
|
+
return this._host;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
available() {
|
|
14
|
+
return this.host.available();
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// publish("bos:local", "ghcr.io/sarverott/bos", "0.0.1")
|
|
18
|
+
async publish(localImage, repo, tag = "latest", auth = this.options.auth) {
|
|
19
|
+
await this.host.images.tag(localImage, repo, tag);
|
|
20
|
+
return this.host.images.push(`${repo}:${tag}`, auth);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export default DockerPublish;
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
// Local repositories through isomorphic-git (no git binary needed); remotes over
|
|
2
|
+
// http(s), e.g. the internal Gitea. Every method takes the repository dir first.
|
|
3
|
+
import fs from "node:fs";
|
|
4
|
+
|
|
5
|
+
import git from "isomorphic-git";
|
|
6
|
+
import http from "isomorphic-git/http/node";
|
|
7
|
+
|
|
8
|
+
import { BOS } from "../../main.ts";
|
|
9
|
+
import { resolveAuthor } from "./author.mjs";
|
|
10
|
+
|
|
11
|
+
export class GitClient extends BOS.Bridge {
|
|
12
|
+
static id = "git-client";
|
|
13
|
+
|
|
14
|
+
// credentials for remotes: options.token / $GITEA_TOKEN (username optional)
|
|
15
|
+
get auth() {
|
|
16
|
+
const password = this.options.token ?? process.env.GITEA_TOKEN;
|
|
17
|
+
return password ? () => ({ username: this.options.username ?? "bos", password }) : undefined;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
root(path) {
|
|
21
|
+
return git.findRoot({ fs, filepath: path }).catch(() => null);
|
|
22
|
+
}
|
|
23
|
+
init(dir) {
|
|
24
|
+
return git.init({ fs, dir, defaultBranch: "master" });
|
|
25
|
+
}
|
|
26
|
+
branch(dir) {
|
|
27
|
+
return git.currentBranch({ fs, dir });
|
|
28
|
+
}
|
|
29
|
+
branches(dir) {
|
|
30
|
+
return git.listBranches({ fs, dir });
|
|
31
|
+
}
|
|
32
|
+
hasBranch(dir, ref) {
|
|
33
|
+
return this.branches(dir).then((all) => all.includes(ref));
|
|
34
|
+
}
|
|
35
|
+
createBranch(dir, ref, from) {
|
|
36
|
+
return git.branch({ fs, dir, ref, object: from });
|
|
37
|
+
}
|
|
38
|
+
checkout(dir, ref) {
|
|
39
|
+
return git.checkout({ fs, dir, ref });
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
async log(dir, depth = 10) {
|
|
43
|
+
return (await git.log({ fs, dir, depth })).map(({ oid, commit }) => ({
|
|
44
|
+
oid,
|
|
45
|
+
message: commit.message.trim(),
|
|
46
|
+
author: commit.author.name,
|
|
47
|
+
at: commit.author.timestamp * 1000,
|
|
48
|
+
}));
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// changed files only: [path, "modified" | "added" | "deleted" | "untracked"]
|
|
52
|
+
async changes(dir) {
|
|
53
|
+
const names = {
|
|
54
|
+
"0,2,0": "untracked",
|
|
55
|
+
"0,2,2": "added",
|
|
56
|
+
"1,2,1": "modified",
|
|
57
|
+
"1,2,2": "modified",
|
|
58
|
+
"1,0,1": "deleted",
|
|
59
|
+
"1,0,0": "deleted",
|
|
60
|
+
"1,1,0": "deleted",
|
|
61
|
+
};
|
|
62
|
+
return (await git.statusMatrix({ fs, dir }))
|
|
63
|
+
.filter(([, head, work, stage]) => !(head === 1 && work === 1 && stage === 1))
|
|
64
|
+
.map(([path, ...state]) => [path, names[state.join(",")] ?? state.join(",")]);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// what the next commit will contain: [path, "added" | "modified" | "deleted"]
|
|
68
|
+
async staged(dir) {
|
|
69
|
+
const status = (head, stage) =>
|
|
70
|
+
head === 0 && stage > 0
|
|
71
|
+
? "added"
|
|
72
|
+
: head === 1 && stage === 0
|
|
73
|
+
? "deleted"
|
|
74
|
+
: head === 1 && stage > 1
|
|
75
|
+
? "modified"
|
|
76
|
+
: null;
|
|
77
|
+
return (await git.statusMatrix({ fs, dir }))
|
|
78
|
+
.map(([path, head, , stage]) => [path, status(head, stage)])
|
|
79
|
+
.filter(([, state]) => state);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
hooksPath(dir) {
|
|
83
|
+
return git.getConfig({ fs, dir, path: "core.hooksPath" });
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
async commit(dir, message, paths = ["."]) {
|
|
87
|
+
for (const filepath of paths) await git.add({ fs, dir, filepath });
|
|
88
|
+
return git.commit({ fs, dir, message, author: await resolveAuthor(git, fs, dir) });
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// merge `from` into `to` as a merge commit, then leave `to` checked out
|
|
92
|
+
async merge(dir, from, to, message = `${from} → ${to}`) {
|
|
93
|
+
await this.checkout(dir, to);
|
|
94
|
+
const result = await git.merge({
|
|
95
|
+
fs,
|
|
96
|
+
dir,
|
|
97
|
+
ours: to,
|
|
98
|
+
theirs: from,
|
|
99
|
+
fastForward: false,
|
|
100
|
+
message,
|
|
101
|
+
author: await resolveAuthor(git, fs, dir),
|
|
102
|
+
});
|
|
103
|
+
await this.checkout(dir, to);
|
|
104
|
+
return result;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
addRemote(dir, remote, url) {
|
|
108
|
+
return git.addRemote({ fs, dir, remote, url });
|
|
109
|
+
}
|
|
110
|
+
clone(url, dir, { ref, depth } = {}) {
|
|
111
|
+
return git.clone({ fs, http, dir, url, ref, depth, singleBranch: Boolean(ref), onAuth: this.auth });
|
|
112
|
+
}
|
|
113
|
+
fetch(dir, remote = "origin") {
|
|
114
|
+
return git.fetch({ fs, http, dir, remote, onAuth: this.auth });
|
|
115
|
+
}
|
|
116
|
+
push(dir, ref, remote = "origin") {
|
|
117
|
+
return git.push({ fs, http, dir, remote, ref, onAuth: this.auth });
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
export default GitClient;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
// Who signs commits: repository config, then ~/.gitconfig, then the system user.
|
|
2
|
+
// (isomorphic-git reads only the repository's own config.)
|
|
3
|
+
import { readFileSync } from "node:fs";
|
|
4
|
+
import { homedir, userInfo } from "node:os";
|
|
5
|
+
import { join } from "node:path";
|
|
6
|
+
|
|
7
|
+
function globalConfig() {
|
|
8
|
+
try {
|
|
9
|
+
const text = readFileSync(join(homedir(), ".gitconfig"), "utf8");
|
|
10
|
+
const user = text.split(/^\[/m).find((section) => section.startsWith("user]")) ?? "";
|
|
11
|
+
const value = (key) => user.match(new RegExp(`^\\s*${key}\\s*=\\s*(.+)$`, "m"))?.[1].trim();
|
|
12
|
+
return { name: value("name"), email: value("email") };
|
|
13
|
+
} catch {
|
|
14
|
+
return {};
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export async function resolveAuthor(git, fs, dir) {
|
|
19
|
+
const local = {
|
|
20
|
+
name: await git.getConfig({ fs, dir, path: "user.name" }),
|
|
21
|
+
email: await git.getConfig({ fs, dir, path: "user.email" }),
|
|
22
|
+
};
|
|
23
|
+
const global = globalConfig();
|
|
24
|
+
const name = local.name ?? global.name ?? userInfo().username;
|
|
25
|
+
return { name, email: local.email ?? global.email ?? `${name}@localhost` };
|
|
26
|
+
}
|