@ouro.bot/cli 0.1.0-alpha.60 → 0.1.0-alpha.61

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/README.md CHANGED
@@ -48,7 +48,7 @@ Other important top-level paths:
48
48
  - `AdoptionSpecialist.ouro/`
49
49
  Packaged specialist bundle used by `ouro hatch`.
50
50
  - `subagents/`
51
- Source-of-truth workflow definitions for planner/doer/merger.
51
+ Workflow skills have moved to [github.com/ouroborosbot/ouroboros-skills](https://github.com/ouroborosbot/ouroboros-skills). Use the skill-management skill for installation and updates.
52
52
  - `scripts/teams-sense/`
53
53
  Operator scripts for the Teams deployment path.
54
54
  - `docs/`
package/changelog.json CHANGED
@@ -1,6 +1,15 @@
1
1
  {
2
2
  "_note": "This changelog is maintained as part of the PR/version-bump workflow. Agent-curated, not auto-generated. Agents read this file directly via read_file to understand what changed between versions.",
3
3
  "versions": [
4
+ {
5
+ "version": "0.1.0-alpha.61",
6
+ "changes": [
7
+ "Workflow skills (work-planner, work-doer, work-merger) migrated to the shared ouroboros-skills repo at github.com/ouroborosbot/ouroboros-skills.",
8
+ "Removed the subagent-installer. Skills are now installed via the skill-management bootstrap skill or manual download.",
9
+ "Skills loading simplified from 3-source to 2-source model. Canonical-protocol fallback to subagents/ removed.",
10
+ "New ensureSkillManagement() auto-installs the skill-management bootstrap skill from the shared repo on ouro up."
11
+ ]
12
+ },
4
13
  {
5
14
  "version": "0.1.0-alpha.60",
6
15
  "changes": [
@@ -49,7 +49,7 @@ const store_file_1 = require("../../mind/friends/store-file");
49
49
  const types_1 = require("../../mind/friends/types");
50
50
  const ouro_uti_1 = require("./ouro-uti");
51
51
  const ouro_path_installer_1 = require("./ouro-path-installer");
52
- const subagent_installer_1 = require("./subagent-installer");
52
+ const skill_management_installer_1 = require("./skill-management-installer");
53
53
  const hatch_flow_1 = require("./hatch-flow");
54
54
  const specialist_orchestrator_1 = require("./specialist-orchestrator");
55
55
  const specialist_prompt_1 = require("./specialist-prompt");
@@ -799,11 +799,6 @@ function defaultEnsureDaemonBootPersistence(socketPath) {
799
799
  envPath: process.env.PATH,
800
800
  });
801
801
  }
802
- async function defaultInstallSubagents() {
803
- return (0, subagent_installer_1.installSubagentsForAvailableCli)({
804
- repoRoot: (0, identity_1.getRepoRoot)(),
805
- });
806
- }
807
802
  async function defaultPromptInput(question) {
808
803
  const readline = await Promise.resolve().then(() => __importStar(require("readline/promises")));
809
804
  const rl = readline.createInterface({
@@ -1075,7 +1070,6 @@ function createDefaultOuroCliDeps(socketPath = socket_client_1.DEFAULT_DAEMON_SO
1075
1070
  checkSocketAlive: socket_client_1.checkDaemonSocketAlive,
1076
1071
  cleanupStaleSocket: defaultCleanupStaleSocket,
1077
1072
  fallbackPendingMessage: defaultFallbackPendingMessage,
1078
- installSubagents: defaultInstallSubagents,
1079
1073
  listDiscoveredAgents: defaultListDiscoveredAgents,
1080
1074
  runHatchFlow: hatch_flow_1.runHatchFlow,
1081
1075
  promptInput: defaultPromptInput,
@@ -1084,6 +1078,7 @@ function createDefaultOuroCliDeps(socketPath = socket_client_1.DEFAULT_DAEMON_SO
1084
1078
  registerOuroBundleType: ouro_uti_1.registerOuroBundleUti,
1085
1079
  installOuroCommand: ouro_path_installer_1.installOuroCommand,
1086
1080
  syncGlobalOuroBotWrapper: ouro_bot_global_installer_1.syncGlobalOuroBotWrapper,
1081
+ ensureSkillManagement: skill_management_installer_1.ensureSkillManagement,
1087
1082
  ensureDaemonBootPersistence: defaultEnsureDaemonBootPersistence,
1088
1083
  /* v8 ignore next 3 -- integration: launches interactive CLI session @preserve */
1089
1084
  startChat: async (agentName) => {
@@ -1179,18 +1174,20 @@ async function performSystemSetup(deps) {
1179
1174
  });
1180
1175
  }
1181
1176
  }
1182
- // Install subagents (claude/codex skills)
1183
- try {
1184
- await deps.installSubagents();
1185
- }
1186
- catch (error) {
1187
- (0, runtime_1.emitNervesEvent)({
1188
- level: "warn",
1189
- component: "daemon",
1190
- event: "daemon.subagent_install_error",
1191
- message: "subagent auto-install failed",
1192
- meta: { error: error instanceof Error ? error.message : /* v8 ignore next -- defensive: non-Error catch branch @preserve */ String(error) },
1193
- });
1177
+ // Ensure skill-management skill is available
1178
+ if (deps.ensureSkillManagement) {
1179
+ try {
1180
+ await deps.ensureSkillManagement();
1181
+ }
1182
+ catch (error) {
1183
+ (0, runtime_1.emitNervesEvent)({
1184
+ level: "warn",
1185
+ component: "daemon",
1186
+ event: "daemon.system_setup_skill_management_error",
1187
+ message: "failed to ensure skill-management skill",
1188
+ meta: { error: error instanceof Error ? error.message : /* v8 ignore next -- defensive: non-Error catch branch @preserve */ String(error) },
1189
+ });
1190
+ }
1194
1191
  }
1195
1192
  // Register .ouro bundle type (UTI on macOS)
1196
1193
  await registerOuroBundleTypeNonBlocking(deps);
@@ -0,0 +1,73 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.ensureSkillManagement = ensureSkillManagement;
37
+ const fs = __importStar(require("fs"));
38
+ const path = __importStar(require("path"));
39
+ const identity_1 = require("../identity");
40
+ const runtime_1 = require("../../nerves/runtime");
41
+ const SKILL_MANAGEMENT_URL = "https://raw.githubusercontent.com/ouroborosbot/ouroboros-skills/main/skills/skill-management/SKILL.md";
42
+ async function ensureSkillManagement() {
43
+ const skillsDir = path.join((0, identity_1.getAgentRoot)(), "skills");
44
+ const targetPath = path.join(skillsDir, "skill-management.md");
45
+ if (fs.existsSync(targetPath)) {
46
+ return;
47
+ }
48
+ try {
49
+ const response = await fetch(SKILL_MANAGEMENT_URL);
50
+ if (!response.ok) {
51
+ (0, runtime_1.emitNervesEvent)({
52
+ level: "warn",
53
+ component: "daemon",
54
+ event: "daemon.skill_management_install_error",
55
+ message: "failed to fetch skill-management from GitHub",
56
+ meta: { status: response.status, url: SKILL_MANAGEMENT_URL },
57
+ });
58
+ return;
59
+ }
60
+ const content = await response.text();
61
+ fs.mkdirSync(skillsDir, { recursive: true });
62
+ fs.writeFileSync(targetPath, content, "utf-8");
63
+ }
64
+ catch (error) {
65
+ (0, runtime_1.emitNervesEvent)({
66
+ level: "warn",
67
+ component: "daemon",
68
+ event: "daemon.skill_management_install_error",
69
+ message: "failed to install skill-management skill",
70
+ meta: { error: error instanceof Error ? error.message : String(error) },
71
+ });
72
+ }
73
+ }
@@ -50,10 +50,6 @@ function getSkillsDir() {
50
50
  function getProtocolMirrorDir() {
51
51
  return path.join(getSkillsDir(), "protocols");
52
52
  }
53
- // Canonical protocol source lives in {repoRoot}/subagents/.
54
- function getCanonicalProtocolsDir() {
55
- return path.join((0, identity_1.getRepoRoot)(), "subagents");
56
- }
57
53
  function listMarkdownBasenames(dir) {
58
54
  if (!fs.existsSync(dir))
59
55
  return [];
@@ -74,8 +70,7 @@ function listSkills() {
74
70
  });
75
71
  const baseSkills = listMarkdownBasenames(getSkillsDir());
76
72
  const protocolMirrors = listMarkdownBasenames(getProtocolMirrorDir());
77
- const canonicalProtocols = listMarkdownBasenames(getCanonicalProtocolsDir());
78
- const skills = [...new Set([...baseSkills, ...protocolMirrors, ...canonicalProtocols])].sort();
73
+ const skills = [...new Set([...baseSkills, ...protocolMirrors])].sort();
79
74
  (0, runtime_1.emitNervesEvent)({
80
75
  event: "repertoire.load_end",
81
76
  component: "repertoire",
@@ -93,7 +88,6 @@ function loadSkill(skillName) {
93
88
  });
94
89
  const directSkillPath = path.join(getSkillsDir(), `${skillName}.md`);
95
90
  const protocolMirrorPath = path.join(getProtocolMirrorDir(), `${skillName}.md`);
96
- const canonicalProtocolPath = path.join(getCanonicalProtocolsDir(), `${skillName}.md`);
97
91
  let resolvedPath = null;
98
92
  // 1) Direct agent skill.
99
93
  if (fs.existsSync(directSkillPath)) {
@@ -103,22 +97,6 @@ function loadSkill(skillName) {
103
97
  else if (fs.existsSync(protocolMirrorPath)) {
104
98
  resolvedPath = protocolMirrorPath;
105
99
  }
106
- // 3) Canonical protocol fallback.
107
- else if (fs.existsSync(canonicalProtocolPath)) {
108
- (0, runtime_1.emitNervesEvent)({
109
- level: "warn",
110
- event: "repertoire.error",
111
- component: "repertoire",
112
- message: "protocol mirror missing; using canonical fallback",
113
- meta: {
114
- operation: "loadSkill",
115
- skill: skillName,
116
- mirrorPath: protocolMirrorPath,
117
- canonicalPath: canonicalProtocolPath,
118
- },
119
- });
120
- resolvedPath = canonicalProtocolPath;
121
- }
122
100
  if (!resolvedPath) {
123
101
  (0, runtime_1.emitNervesEvent)({
124
102
  level: "error",
@@ -128,13 +106,12 @@ function loadSkill(skillName) {
128
106
  meta: {
129
107
  operation: "loadSkill",
130
108
  skill: skillName,
131
- checkedPaths: [directSkillPath, protocolMirrorPath, canonicalProtocolPath],
109
+ checkedPaths: [directSkillPath, protocolMirrorPath],
132
110
  },
133
111
  });
134
112
  throw new Error(`skill '${skillName}' not found in:\n` +
135
113
  `- ${directSkillPath}\n` +
136
- `- ${protocolMirrorPath}\n` +
137
- `- ${canonicalProtocolPath}`);
114
+ `- ${protocolMirrorPath}`);
138
115
  }
139
116
  const content = fs.readFileSync(resolvedPath, "utf-8");
140
117
  if (!loadedSkills.includes(skillName)) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ouro.bot/cli",
3
- "version": "0.1.0-alpha.60",
3
+ "version": "0.1.0-alpha.61",
4
4
  "main": "dist/heart/daemon/ouro-entry.js",
5
5
  "bin": {
6
6
  "cli": "dist/heart/daemon/ouro-bot-entry.js",
@@ -1,86 +1,7 @@
1
- # Workflow Helpers
1
+ # Workflow Skills (Moved)
2
2
 
3
- These files are the source-of-truth workflow helpers for:
3
+ The workflow skills (`work-planner`, `work-doer`, `work-merger`) have moved to the shared skills repository:
4
4
 
5
- - `work-planner`
6
- - `work-doer`
7
- - `work-merger`
5
+ **https://github.com/ouroborosbot/ouroboros-skills**
8
6
 
9
- They are written to stay generic enough for different agent shells, while following this repo’s local rules through `AGENTS.md`.
10
-
11
- ## What They Do
12
-
13
- - `work-planner.md`
14
- Creates and refines planning docs, then converts approved plans into doing docs.
15
- - `work-doer.md`
16
- Executes approved doing docs unit by unit with strict validation discipline.
17
- - `work-merger.md`
18
- Syncs with `main`, resolves conflicts, creates the PR, handles CI, and merges.
19
-
20
- ## Important Repo-Specific Truth
21
-
22
- These helpers do not hardcode task-doc paths. They are expected to read project instructions to discover them.
23
-
24
- In this repo, that means:
25
-
26
- - task docs live in `~/AgentBundles/<agent>.ouro/tasks/one-shots/`
27
- - not inside the repo
28
-
29
- ## Installing For Claude Code
30
-
31
- ```bash
32
- mkdir -p ~/.claude/agents
33
- cp subagents/*.md ~/.claude/agents/
34
- ```
35
-
36
- ## Installing For Codex-Style Skills
37
-
38
- ```bash
39
- mkdir -p ~/.agents/skills/work-planner ~/.agents/skills/work-doer ~/.agents/skills/work-merger
40
-
41
- # Hard-link to keep one source of truth
42
- ln -f "$(pwd)/subagents/work-planner.md" ~/.agents/skills/work-planner/SKILL.md
43
- ln -f "$(pwd)/subagents/work-doer.md" ~/.agents/skills/work-doer/SKILL.md
44
- ln -f "$(pwd)/subagents/work-merger.md" ~/.agents/skills/work-merger/SKILL.md
45
- ```
46
-
47
- **Important:** For Codex/OpenAI skill installs, use the generic `~/.agents/skills` root and use hard links (`ln`, not `ln -s`). Installing the same skill into both `~/.agents/skills` and `~/.codex/skills` can produce duplicate entries in Codex. Symlinked `SKILL.md` files may load but are not advertised reliably by Codex surfaces. Hard-links break when editors save by replacing the file (new inode). After editing any `subagents/*.md` file, re-run the `ln -f` command for that file to restore the link. You can verify with `stat -f '%i'` — both files should share the same inode.
48
-
49
- Optional UI metadata:
50
-
51
- ```bash
52
- mkdir -p ~/.agents/skills/work-planner/agents ~/.agents/skills/work-doer/agents ~/.agents/skills/work-merger/agents
53
- cat > ~/.agents/skills/work-planner/agents/openai.yaml << 'EOF'
54
- interface:
55
- display_name: "Work Planner"
56
- short_description: "Create and gate planning/doing task docs"
57
- default_prompt: "Use $work-planner to create or update a planning doc, then stop at NEEDS_REVIEW."
58
- EOF
59
- cat > ~/.agents/skills/work-doer/agents/openai.yaml << 'EOF'
60
- interface:
61
- display_name: "Work Doer"
62
- short_description: "Execute approved doing docs with strict TDD"
63
- default_prompt: "Use $work-doer to execute an approved doing doc unit by unit."
64
- EOF
65
- cat > ~/.agents/skills/work-merger/agents/openai.yaml << 'EOF'
66
- interface:
67
- display_name: "Work Merger"
68
- short_description: "Merge feature branch into main via PR after work-doer completes"
69
- default_prompt: "Use $work-merger to merge the current feature branch into main."
70
- EOF
71
- ```
72
-
73
- ## Keeping Local Skill Copies Fresh
74
-
75
- After editing any `subagents/*.md` file, resync your local installed copies.
76
-
77
- The repo workflow usually checks this with diffs like:
78
-
79
- ```bash
80
- diff -q ~/.agents/skills/work-planner/SKILL.md subagents/work-planner.md
81
- diff -q ~/.agents/skills/work-doer/SKILL.md subagents/work-doer.md
82
- ```
83
-
84
- ## Restart Behavior
85
-
86
- Some tools only discover new skills on startup. If a shell/app does not see updates immediately, restart that shell/app after syncing.
7
+ To install or update these skills, use the **skill-management** skill from that repo. It covers browsing available skills, installing them into your agent's local skills directory, and keeping them up to date.
@@ -1,166 +0,0 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || (function () {
19
- var ownKeys = function(o) {
20
- ownKeys = Object.getOwnPropertyNames || function (o) {
21
- var ar = [];
22
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
- return ar;
24
- };
25
- return ownKeys(o);
26
- };
27
- return function (mod) {
28
- if (mod && mod.__esModule) return mod;
29
- var result = {};
30
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
- __setModuleDefault(result, mod);
32
- return result;
33
- };
34
- })();
35
- Object.defineProperty(exports, "__esModule", { value: true });
36
- exports.installSubagentsForAvailableCli = installSubagentsForAvailableCli;
37
- const fs = __importStar(require("fs"));
38
- const os = __importStar(require("os"));
39
- const path = __importStar(require("path"));
40
- const child_process_1 = require("child_process");
41
- const runtime_1 = require("../../nerves/runtime");
42
- function detectCliBinary(binary) {
43
- const result = (0, child_process_1.spawnSync)("which", [binary], { encoding: "utf-8" });
44
- if (result.status !== 0)
45
- return null;
46
- const resolved = result.stdout.trim();
47
- return resolved.length > 0 ? resolved : null;
48
- }
49
- function listSubagentSources(subagentsDir) {
50
- if (!fs.existsSync(subagentsDir))
51
- return [];
52
- return fs.readdirSync(subagentsDir)
53
- .filter((name) => name.endsWith(".md"))
54
- .filter((name) => name !== "README.md")
55
- .map((name) => path.join(subagentsDir, name))
56
- .sort((a, b) => a.localeCompare(b));
57
- }
58
- function pathExists(target) {
59
- try {
60
- fs.lstatSync(target);
61
- return true;
62
- }
63
- catch {
64
- return false;
65
- }
66
- }
67
- function isSameFile(source, target) {
68
- try {
69
- const sourceStats = fs.statSync(source);
70
- const targetStats = fs.statSync(target);
71
- return sourceStats.dev === targetStats.dev && sourceStats.ino === targetStats.ino;
72
- }
73
- catch {
74
- return false;
75
- }
76
- }
77
- function ensureSymlink(source, target) {
78
- fs.mkdirSync(path.dirname(target), { recursive: true });
79
- if (pathExists(target)) {
80
- const stats = fs.lstatSync(target);
81
- if (stats.isSymbolicLink()) {
82
- const linkedPath = fs.readlinkSync(target);
83
- if (linkedPath === source)
84
- return false;
85
- }
86
- fs.unlinkSync(target);
87
- }
88
- fs.symlinkSync(source, target);
89
- return true;
90
- }
91
- function ensureHardLink(source, target) {
92
- fs.mkdirSync(path.dirname(target), { recursive: true });
93
- if (pathExists(target)) {
94
- const stats = fs.lstatSync(target);
95
- if (!stats.isSymbolicLink() && isSameFile(source, target)) {
96
- return false;
97
- }
98
- fs.unlinkSync(target);
99
- }
100
- fs.linkSync(source, target);
101
- return true;
102
- }
103
- function hasOpenAiSkillHome(homeDir) {
104
- return pathExists(path.join(homeDir, ".codex")) || pathExists(path.join(homeDir, ".agents"));
105
- }
106
- function openAiSkillTargets(homeDir, source) {
107
- const skillName = path.basename(source, ".md");
108
- return [path.join(homeDir, ".agents", "skills", skillName, "SKILL.md")];
109
- }
110
- async function installSubagentsForAvailableCli(options = {}) {
111
- const repoRoot = options.repoRoot ?? path.resolve(__dirname, "..", "..", "..");
112
- const homeDir = options.homeDir ?? os.homedir();
113
- const which = options.which ?? detectCliBinary;
114
- const subagentsDir = path.join(repoRoot, "subagents");
115
- const sources = listSubagentSources(subagentsDir);
116
- const notes = [];
117
- (0, runtime_1.emitNervesEvent)({
118
- component: "daemon",
119
- event: "daemon.subagent_install_start",
120
- message: "starting subagent auto-install",
121
- meta: { sources: sources.length },
122
- });
123
- if (sources.length === 0) {
124
- notes.push(`no subagent files found at ${subagentsDir}`);
125
- return { claudeInstalled: 0, codexInstalled: 0, notes };
126
- }
127
- let claudeInstalled = 0;
128
- let codexInstalled = 0;
129
- const claudePath = which("claude");
130
- if (!claudePath) {
131
- notes.push("claude CLI not found; skipping subagent install");
132
- }
133
- else {
134
- const claudeAgentsDir = path.join(homeDir, ".claude", "agents");
135
- for (const source of sources) {
136
- const target = path.join(claudeAgentsDir, path.basename(source));
137
- if (ensureSymlink(source, target)) {
138
- claudeInstalled += 1;
139
- }
140
- }
141
- }
142
- const codexPath = which("codex");
143
- if (!codexPath && !hasOpenAiSkillHome(homeDir)) {
144
- notes.push("codex CLI/config not found; skipping subagent install");
145
- }
146
- else {
147
- for (const source of sources) {
148
- let installedForSkill = false;
149
- for (const target of openAiSkillTargets(homeDir, source)) {
150
- if (ensureHardLink(source, target)) {
151
- installedForSkill = true;
152
- }
153
- }
154
- if (installedForSkill) {
155
- codexInstalled += 1;
156
- }
157
- }
158
- }
159
- (0, runtime_1.emitNervesEvent)({
160
- component: "daemon",
161
- event: "daemon.subagent_install_end",
162
- message: "completed subagent auto-install",
163
- meta: { claudeInstalled, codexInstalled, notes: notes.length },
164
- });
165
- return { claudeInstalled, codexInstalled, notes };
166
- }