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,6 @@
|
|
|
1
|
+
# promote
|
|
2
|
+
|
|
3
|
+
`bos promote [--reject] [--apply]` moves the current branch one station:
|
|
4
|
+
`master → developement → revision → testing → releasing → master`.
|
|
5
|
+
`--reject` sends work back to `developement`. Without `--apply` it only shows
|
|
6
|
+
the plan. `releasing → master` opens a GitHub pull request (needs `$GITHUB_TOKEN`).
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { resolve } from "node:path";
|
|
2
|
+
|
|
3
|
+
import { BOS } from "../../main.ts";
|
|
4
|
+
|
|
5
|
+
export default ({ operands: [dir = "."], flags }) => {
|
|
6
|
+
const manifest = new BOS.Model(resolve(dir)).seal({ dryRun: Boolean(flags.dryRun) });
|
|
7
|
+
return flags.json ? manifest : `sealed ${Object.keys(manifest.files).length} files`;
|
|
8
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// status, then offer to create what is missing
|
|
2
|
+
import { paint } from "../../views/terminal/paint.mjs";
|
|
3
|
+
|
|
4
|
+
const missing = (node) => [...(!node.exists && node.mandatory ? [node.path] : []), ...node.children.flatMap(missing)];
|
|
5
|
+
|
|
6
|
+
export default async ({ bos, io }) => {
|
|
7
|
+
const context = await bos.workshop.status();
|
|
8
|
+
console.log(new bos.views.StatusView().text(context));
|
|
9
|
+
const absent = missing(context.tree);
|
|
10
|
+
if (!absent.length) return paint.green("\nnothing missing");
|
|
11
|
+
const answer = await io.question(`\n${absent.length} missing: create them now? [y/N] `);
|
|
12
|
+
if (!/^y(es)?$/i.test(answer.trim())) return paint.dim("left as it is");
|
|
13
|
+
return new bos.views.StatusView().text(await bos.workshop.bootstrap());
|
|
14
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
// Agent skills of this repository, one per model.
|
|
2
|
+
import { BOS } from "../main.ts";
|
|
3
|
+
import procedures from "../procedures/_index.mjs";
|
|
4
|
+
|
|
5
|
+
export class SkillsControll extends BOS.Controll {
|
|
6
|
+
static flows = procedures;
|
|
7
|
+
|
|
8
|
+
scaffold(options) {
|
|
9
|
+
return this.run("skilling", options);
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export default SkillsControll;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
// The workshop as a handful of plain methods; each one runs a procedure.
|
|
2
|
+
// const workshop = new WorkshopControll({ workshop: "/tmp/x/__WORKSHOP" });
|
|
3
|
+
// await workshop.open();
|
|
4
|
+
import { BOS } from "../main.ts";
|
|
5
|
+
import procedures from "../procedures/_index.mjs";
|
|
6
|
+
|
|
7
|
+
export class WorkshopControll extends BOS.Controll {
|
|
8
|
+
static flows = procedures;
|
|
9
|
+
|
|
10
|
+
locate() {
|
|
11
|
+
return this.run("locating");
|
|
12
|
+
}
|
|
13
|
+
status() {
|
|
14
|
+
return this.run("inspecting");
|
|
15
|
+
}
|
|
16
|
+
bootstrap(options) {
|
|
17
|
+
return this.run("bootstrapping", options);
|
|
18
|
+
}
|
|
19
|
+
open(options) {
|
|
20
|
+
return this.run("opening", options);
|
|
21
|
+
}
|
|
22
|
+
close(options) {
|
|
23
|
+
return this.run("closing", options);
|
|
24
|
+
}
|
|
25
|
+
sink() {
|
|
26
|
+
return this.run("sinking");
|
|
27
|
+
}
|
|
28
|
+
hook(hook) {
|
|
29
|
+
return this.run("hooking", { hook });
|
|
30
|
+
}
|
|
31
|
+
installHooks() {
|
|
32
|
+
return this.run("installingHooks");
|
|
33
|
+
}
|
|
34
|
+
gather(options) {
|
|
35
|
+
return this.run("gathering", options);
|
|
36
|
+
}
|
|
37
|
+
describe(options) {
|
|
38
|
+
return this.run("describing", options);
|
|
39
|
+
}
|
|
40
|
+
mode(mode) {
|
|
41
|
+
return this.run("modeSwitching", { mode });
|
|
42
|
+
}
|
|
43
|
+
promote({ reject = false, apply = false } = {}) {
|
|
44
|
+
return this.run("promoting", { reject, dryRun: !apply });
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export default WorkshopControll;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
// A bridge shapes one outside system (docker host, github, git, a subprocess…)
|
|
2
|
+
// into a few plain methods. The SDK client is created lazily, on first use.
|
|
3
|
+
|
|
4
|
+
export class BasicBridge {
|
|
5
|
+
static id = "bridge";
|
|
6
|
+
|
|
7
|
+
constructor(options = {}) {
|
|
8
|
+
this.options = options;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
get client() {
|
|
12
|
+
this._client ??= this.connect();
|
|
13
|
+
return this._client;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// create the SDK client (dockerode, octokit, …); null when the bridge needs none
|
|
17
|
+
connect() {
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// can this bridge be used on this machine right now?
|
|
22
|
+
async available() {
|
|
23
|
+
return true;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
toString() {
|
|
27
|
+
return `[<BOS.Bridge::${this.constructor.id}>]`;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
// A controll owns a set of logicflows and runs them with a prepared context.
|
|
2
|
+
import { EventEmitter } from "node:events";
|
|
3
|
+
|
|
4
|
+
export class BasicControll extends EventEmitter {
|
|
5
|
+
static flows = {};
|
|
6
|
+
|
|
7
|
+
constructor(options = {}) {
|
|
8
|
+
super();
|
|
9
|
+
this.options = options;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
get flowNames() {
|
|
13
|
+
return Object.keys(this.constructor.flows);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
async run(flowName, options = {}) {
|
|
17
|
+
const flow = this.constructor.flows[flowName];
|
|
18
|
+
if (!flow) throw new Error(`unknown logicflow "${flowName}" (known: ${this.flowNames.join(", ")})`);
|
|
19
|
+
const merged = { ...this.options, ...options };
|
|
20
|
+
const context = { options: merged, dryRun: Boolean(merged.dryRun), changes: [], trace: [] };
|
|
21
|
+
this.emit("start", flowName, context);
|
|
22
|
+
await flow.run(context);
|
|
23
|
+
this.emit("done", flowName, context);
|
|
24
|
+
return context;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
// Element anatomy shared by models and submodules: a directory plus descriptor
|
|
2
|
+
// files (metadata.json, manifest.json, .index.json, Taskfile.yaml, .omnis.toml…).
|
|
3
|
+
// A model stands on its own (built from a path); a submodule hangs on its owner
|
|
4
|
+
// (built from the owner). Moving a class between the two is one `extends` line.
|
|
5
|
+
import { createHash } from "node:crypto";
|
|
6
|
+
import { existsSync, mkdirSync, readdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
7
|
+
import { basename, join, relative, sep } from "node:path";
|
|
8
|
+
|
|
9
|
+
const MANIFEST_NAMES = ["manifest.json", ".manifest.json"];
|
|
10
|
+
const NEVER_SEALED = new Set([".git", "node_modules", ...MANIFEST_NAMES]);
|
|
11
|
+
|
|
12
|
+
export class BasicElement {
|
|
13
|
+
static type = "element";
|
|
14
|
+
static dirname = null; // fixed directory name (relative to the parent or owner); null for freely named assets
|
|
15
|
+
static mandatory = true; // created together with its parent when missing
|
|
16
|
+
static children = []; // fixed child models (areas)
|
|
17
|
+
static submodules = {}; // { property: Submodule } organs hanging on this element
|
|
18
|
+
static descriptors = {}; // { filename: (element, context) => default content }
|
|
19
|
+
|
|
20
|
+
constructor(path, parent = null) {
|
|
21
|
+
this.path = path;
|
|
22
|
+
this.parent = parent;
|
|
23
|
+
// every submodule becomes a lazy property: workshop.storylines
|
|
24
|
+
for (const [name, Submodule] of Object.entries(this.constructor.submodules)) {
|
|
25
|
+
let cached;
|
|
26
|
+
Object.defineProperty(this, name, { get: () => (cached ??= new Submodule(this)), enumerable: false });
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
get type() {
|
|
31
|
+
return this.constructor.type;
|
|
32
|
+
}
|
|
33
|
+
get name() {
|
|
34
|
+
return basename(this.path);
|
|
35
|
+
}
|
|
36
|
+
file(...names) {
|
|
37
|
+
return join(this.path, ...names);
|
|
38
|
+
}
|
|
39
|
+
exists() {
|
|
40
|
+
return existsSync(this.path);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// fixed children: areas first, then organs, in declaration order
|
|
44
|
+
childElements() {
|
|
45
|
+
return [
|
|
46
|
+
...this.constructor.children.map((Child) => new Child(this.file(Child.dirname), this)),
|
|
47
|
+
...Object.keys(this.constructor.submodules).map((name) => this[name]),
|
|
48
|
+
];
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// create what is missing and never overwrite; with context.dryRun only plan it
|
|
52
|
+
ensure(context = {}) {
|
|
53
|
+
createIfMissing(this.path, () => mkdirSync(this.path, { recursive: true }), context);
|
|
54
|
+
for (const [name, content] of Object.entries(this.constructor.descriptors)) {
|
|
55
|
+
const target = this.file(name);
|
|
56
|
+
createIfMissing(target, () => writeFileSync(target, serialize(content(this, context))), context);
|
|
57
|
+
}
|
|
58
|
+
for (const child of this.childElements()) {
|
|
59
|
+
if (child.constructor.mandatory) child.ensure(context);
|
|
60
|
+
}
|
|
61
|
+
return this;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// state of this element and its fixed areas, without touching the disk
|
|
65
|
+
inspect(parentMandatory = true) {
|
|
66
|
+
const mandatory = parentMandatory && this.constructor.mandatory;
|
|
67
|
+
const nodes = this.childElements().map((child) => child.inspect(mandatory));
|
|
68
|
+
return { type: this.type, path: this.path, exists: this.exists(), mandatory, children: nest(nodes) };
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
readJSON(name, fallback = null) {
|
|
72
|
+
try {
|
|
73
|
+
return JSON.parse(readFileSync(this.file(name), "utf8"));
|
|
74
|
+
} catch {
|
|
75
|
+
return fallback;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
get manifestName() {
|
|
80
|
+
return (
|
|
81
|
+
MANIFEST_NAMES.find((name) => existsSync(this.file(name))) ??
|
|
82
|
+
Object.keys(this.constructor.descriptors).find((name) => MANIFEST_NAMES.includes(name)) ??
|
|
83
|
+
MANIFEST_NAMES[0]
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// record checksums of every file into the manifest (integrity guard)
|
|
88
|
+
seal(context = {}) {
|
|
89
|
+
const manifest = this.readJSON(this.manifestName, {});
|
|
90
|
+
manifest.files = Object.fromEntries(walkFiles(this.path).map((path) => [relative(this.path, path), sha256(path)]));
|
|
91
|
+
manifest.sealedAt = Date.now();
|
|
92
|
+
if (!context.dryRun) writeFileSync(this.file(this.manifestName), serialize(manifest));
|
|
93
|
+
return manifest;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// compare the manifest checksums with the files on disk
|
|
97
|
+
verify() {
|
|
98
|
+
const manifest = this.readJSON(this.manifestName);
|
|
99
|
+
if (!manifest) return { ok: false, reason: `no ${this.manifestName}`, missing: [], changed: [], unlisted: [] };
|
|
100
|
+
const listed = manifest.files ?? {};
|
|
101
|
+
const missing = [];
|
|
102
|
+
const changed = [];
|
|
103
|
+
for (const [rel, expected] of Object.entries(listed)) {
|
|
104
|
+
const target = this.file(rel);
|
|
105
|
+
if (!existsSync(target)) missing.push(rel);
|
|
106
|
+
else if (sha256(target) !== expected) changed.push(rel);
|
|
107
|
+
}
|
|
108
|
+
const unlisted = walkFiles(this.path)
|
|
109
|
+
.map((path) => relative(this.path, path))
|
|
110
|
+
.filter((rel) => !(rel in listed));
|
|
111
|
+
return { ok: !missing.length && !changed.length, missing, changed, unlisted };
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// organs declared with deeper paths (.BOS/storylines) sit under the node of their folder (.BOS)
|
|
116
|
+
function nest(nodes) {
|
|
117
|
+
const inside = (node, other) => node !== other && node.path.startsWith(other.path + sep);
|
|
118
|
+
const tops = nodes.filter((node) => !nodes.some((other) => inside(node, other)));
|
|
119
|
+
return tops.map((top) => ({
|
|
120
|
+
...top,
|
|
121
|
+
children: [...top.children, ...nest(nodes.filter((node) => inside(node, top)))],
|
|
122
|
+
}));
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
export function createIfMissing(target, create, context = {}) {
|
|
126
|
+
context.changes ??= [];
|
|
127
|
+
if (existsSync(target)) return false;
|
|
128
|
+
if (!context.dryRun) create();
|
|
129
|
+
context.changes.push(target);
|
|
130
|
+
return true;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
export function sha256(path) {
|
|
134
|
+
return createHash("sha256").update(readFileSync(path)).digest("hex");
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
export function walkFiles(root) {
|
|
138
|
+
if (!existsSync(root)) return [];
|
|
139
|
+
return readdirSync(root, { withFileTypes: true }).flatMap((entry) => {
|
|
140
|
+
if (NEVER_SEALED.has(entry.name)) return [];
|
|
141
|
+
const path = join(root, entry.name);
|
|
142
|
+
if (entry.isDirectory()) return walkFiles(path);
|
|
143
|
+
return entry.isFile() ? [path] : [];
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
function serialize(content) {
|
|
148
|
+
return typeof content === "string" ? content : `${JSON.stringify(content, null, 2)}\n`;
|
|
149
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
// A model is an asset of the workshop that stands on its own: built from any path.
|
|
2
|
+
// new Project("/home/smith/__WORKSHOP/forge/scope/project")
|
|
3
|
+
import { BasicElement } from "./basic-element.mjs";
|
|
4
|
+
|
|
5
|
+
export class BasicModel extends BasicElement {}
|
|
6
|
+
|
|
7
|
+
export { createIfMissing, sha256, walkFiles } from "./basic-element.mjs";
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
// A procedure is an ordered list of named steps sharing one context object.
|
|
2
|
+
// Every logicflow is a procedure; every run leaves a trace in context.trace.
|
|
3
|
+
|
|
4
|
+
export class BasicProcedure {
|
|
5
|
+
constructor(name, steps = [], { description = "" } = {}) {
|
|
6
|
+
this.name = name;
|
|
7
|
+
this.steps = steps;
|
|
8
|
+
this.description = description;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
step(name, action) {
|
|
12
|
+
this.steps.push({ name, action, owner: this.name });
|
|
13
|
+
return this;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// a new procedure made of this one's steps followed by the other's
|
|
17
|
+
chain(other, name = `${this.name}+${other.name}`) {
|
|
18
|
+
return new BasicProcedure(name, [...this.steps, ...other.steps], { description: this.description });
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
async run(context = {}) {
|
|
22
|
+
context.trace ??= [];
|
|
23
|
+
context.changes ??= [];
|
|
24
|
+
for (const { name, action, owner } of this.steps) {
|
|
25
|
+
const started = Date.now();
|
|
26
|
+
try {
|
|
27
|
+
await action(context);
|
|
28
|
+
context.trace.push({ procedure: owner, step: name, ok: true, ms: Date.now() - started });
|
|
29
|
+
} catch (error) {
|
|
30
|
+
context.trace.push({ procedure: owner, step: name, ok: false, error: error.message });
|
|
31
|
+
error.procedure ??= `${owner} › ${name}`;
|
|
32
|
+
throw error;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return context;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
// A submodule is an organ of its owner: it exists only inside that owner and is
|
|
2
|
+
// built from it, never from a bare path. Its dirname is relative to the owner.
|
|
3
|
+
// workshop.storylines (declared as static submodules = { storylines: Storylines })
|
|
4
|
+
import { BasicElement } from "./basic-element.mjs";
|
|
5
|
+
|
|
6
|
+
export class BasicSubmodule extends BasicElement {
|
|
7
|
+
static ownerType = null; // the type of element this organ belongs to, e.g. "workshop"
|
|
8
|
+
|
|
9
|
+
constructor(owner) {
|
|
10
|
+
const { ownerType, dirname, name } = new.target;
|
|
11
|
+
if (!owner || !(owner instanceof BasicElement))
|
|
12
|
+
throw new Error(`${name} is a submodule: build it from its owner, not from a path`);
|
|
13
|
+
if (ownerType && owner.type !== ownerType)
|
|
14
|
+
throw new Error(`${name} hangs on a ${ownerType}, not on a ${owner.type}`);
|
|
15
|
+
super(owner.file(dirname), owner);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
get owner() {
|
|
19
|
+
return this.parent;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
// One shared handler for every way BOS presents state (CLI text, JSON for
|
|
2
|
+
// web / OpenAPI / MCP, ...). Subclasses only describe how state reads as text.
|
|
3
|
+
|
|
4
|
+
export class BasicView {
|
|
5
|
+
static formats = ["text", "json"];
|
|
6
|
+
|
|
7
|
+
render(state, format = "text") {
|
|
8
|
+
if (format === "json") return JSON.stringify(this.data(state), null, 2);
|
|
9
|
+
if (format === "text") return this.text(state);
|
|
10
|
+
throw new Error(`unknown view format "${format}" (known: ${this.constructor.formats.join(", ")})`);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
// what a machine interface receives; defaults to the whole state
|
|
14
|
+
data(state) {
|
|
15
|
+
return state;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
text(state) {
|
|
19
|
+
return String(state);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
// Where this BOS installation itself lives on the machine, and which version it is.
|
|
2
|
+
// BOS is a project like any other: normally forge/<scope>/<project> inside a workshop.
|
|
3
|
+
import { readFileSync } from "node:fs";
|
|
4
|
+
import { join, resolve } from "node:path";
|
|
5
|
+
import { fileURLToPath } from "node:url";
|
|
6
|
+
|
|
7
|
+
export const REPO_ROOT = resolve(fileURLToPath(new URL("../..", import.meta.url)));
|
|
8
|
+
export const RESOURCES = join(REPO_ROOT, "resources");
|
|
9
|
+
export const CLI = join(REPO_ROOT, "src", "cli.mjs");
|
|
10
|
+
export const VERSION = JSON.parse(readFileSync(join(REPO_ROOT, "package.json"), "utf8")).version;
|
package/src/index.mjs
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
// Library entry: the spine, and every part by name.
|
|
2
|
+
// import { BOS } from "blacksmith-organization-system";
|
|
3
|
+
// const bos = await new BOS().load(); await bos.workshop.status();
|
|
4
|
+
|
|
5
|
+
export { default as bridges } from "./bridge/_index.mjs";
|
|
6
|
+
export { loadCommands } from "./commands/_index.mjs";
|
|
7
|
+
export { default as controllers } from "./controllers/_index.mjs";
|
|
8
|
+
export { createIfMissing, sha256, walkFiles } from "./core/basic-element.mjs";
|
|
9
|
+
export { CLI, REPO_ROOT, RESOURCES, VERSION } from "./core/self.mjs";
|
|
10
|
+
export { BOS, default } from "./main.ts";
|
|
11
|
+
export {
|
|
12
|
+
default as models,
|
|
13
|
+
findAncestorWorkshop,
|
|
14
|
+
HOST_ROLES,
|
|
15
|
+
listWorkshops,
|
|
16
|
+
MODES,
|
|
17
|
+
modeByDigit,
|
|
18
|
+
placeOf,
|
|
19
|
+
resolveWorkshop,
|
|
20
|
+
submodules,
|
|
21
|
+
} from "./models/_index.mjs";
|
|
22
|
+
export { default as procedures } from "./procedures/_index.mjs";
|
|
23
|
+
export { BRANCHES, PROMOTION, REJECTION } from "./procedures/promoting/branch-flow.mjs";
|
|
24
|
+
export { default as views } from "./views/_index.mjs";
|