@ouro.bot/cli 0.0.1-alpha.0 → 0.1.0-alpha.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AdoptionSpecialist.ouro/agent.json +20 -0
- package/AdoptionSpecialist.ouro/psyche/SOUL.md +22 -0
- package/AdoptionSpecialist.ouro/psyche/identities/basilisk.md +31 -0
- package/AdoptionSpecialist.ouro/psyche/identities/jafar.md +31 -0
- package/AdoptionSpecialist.ouro/psyche/identities/jormungandr.md +31 -0
- package/AdoptionSpecialist.ouro/psyche/identities/kaa.md +31 -0
- package/AdoptionSpecialist.ouro/psyche/identities/medusa.md +31 -0
- package/AdoptionSpecialist.ouro/psyche/identities/monty.md +31 -0
- package/AdoptionSpecialist.ouro/psyche/identities/nagini.md +31 -0
- package/AdoptionSpecialist.ouro/psyche/identities/ouroboros.md +31 -0
- package/AdoptionSpecialist.ouro/psyche/identities/python.md +31 -0
- package/AdoptionSpecialist.ouro/psyche/identities/quetzalcoatl.md +31 -0
- package/AdoptionSpecialist.ouro/psyche/identities/sir-hiss.md +31 -0
- package/AdoptionSpecialist.ouro/psyche/identities/the-serpent.md +31 -0
- package/AdoptionSpecialist.ouro/psyche/identities/the-snake.md +31 -0
- package/README.md +224 -6
- package/dist/heart/agent-entry.js +17 -0
- package/dist/heart/api-error.js +34 -0
- package/dist/heart/config.js +296 -0
- package/dist/heart/core.js +515 -0
- package/dist/heart/daemon/daemon-cli.js +675 -0
- package/dist/heart/daemon/daemon-entry.js +74 -0
- package/dist/heart/daemon/daemon.js +313 -0
- package/dist/heart/daemon/hatch-flow.js +285 -0
- package/dist/heart/daemon/hatch-specialist.js +107 -0
- package/dist/heart/daemon/health-monitor.js +79 -0
- package/dist/heart/daemon/log-tailer.js +146 -0
- package/dist/heart/daemon/message-router.js +98 -0
- package/dist/heart/daemon/os-cron.js +260 -0
- package/dist/heart/daemon/ouro-bot-entry.js +23 -0
- package/dist/heart/daemon/ouro-bot-wrapper.js +90 -0
- package/dist/heart/daemon/ouro-entry.js +23 -0
- package/dist/heart/daemon/ouro-uti.js +212 -0
- package/dist/heart/daemon/process-manager.js +237 -0
- package/dist/heart/daemon/runtime-logging.js +98 -0
- package/dist/heart/daemon/subagent-installer.js +125 -0
- package/dist/heart/daemon/task-scheduler.js +240 -0
- package/dist/heart/harness.js +26 -0
- package/dist/heart/identity.js +281 -0
- package/dist/heart/kicks.js +144 -0
- package/dist/heart/primitives.js +4 -0
- package/dist/heart/providers/anthropic.js +329 -0
- package/dist/heart/providers/azure.js +66 -0
- package/dist/heart/providers/minimax.js +53 -0
- package/dist/heart/providers/openai-codex.js +162 -0
- package/dist/heart/streaming.js +412 -0
- package/dist/heart/turn-coordinator.js +62 -0
- package/dist/inner-worker-entry.js +4 -0
- package/dist/mind/associative-recall.js +197 -0
- package/dist/mind/bundle-manifest.js +118 -0
- package/dist/mind/context.js +302 -0
- package/dist/mind/first-impressions.js +43 -0
- package/dist/mind/format.js +56 -0
- package/dist/mind/friends/channel.js +41 -0
- package/dist/mind/friends/resolver.js +84 -0
- package/dist/mind/friends/store-file.js +171 -0
- package/dist/mind/friends/store.js +4 -0
- package/dist/mind/friends/tokens.js +26 -0
- package/dist/mind/friends/types.js +21 -0
- package/dist/mind/memory.js +388 -0
- package/dist/mind/pending.js +93 -0
- package/dist/mind/phrases.js +43 -0
- package/dist/mind/prompt-refresh.js +20 -0
- package/dist/mind/prompt.js +352 -0
- package/dist/mind/token-estimate.js +119 -0
- package/dist/nerves/cli-logging.js +31 -0
- package/dist/nerves/coverage/audit-rules.js +81 -0
- package/dist/nerves/coverage/audit.js +200 -0
- package/dist/nerves/coverage/cli-main.js +5 -0
- package/dist/nerves/coverage/cli.js +51 -0
- package/dist/nerves/coverage/contract.js +23 -0
- package/dist/nerves/coverage/file-completeness.js +56 -0
- package/dist/nerves/coverage/run-artifacts.js +77 -0
- package/dist/nerves/coverage/source-scanner.js +34 -0
- package/dist/nerves/index.js +152 -0
- package/dist/nerves/runtime.js +38 -0
- package/dist/repertoire/ado-client.js +211 -0
- package/dist/repertoire/ado-context.js +73 -0
- package/dist/repertoire/ado-semantic.js +841 -0
- package/dist/repertoire/ado-templates.js +146 -0
- package/dist/repertoire/coding/index.js +36 -0
- package/dist/repertoire/coding/manager.js +489 -0
- package/dist/repertoire/coding/monitor.js +60 -0
- package/dist/repertoire/coding/reporter.js +45 -0
- package/dist/repertoire/coding/spawner.js +102 -0
- package/dist/repertoire/coding/tools.js +167 -0
- package/dist/repertoire/coding/types.js +2 -0
- package/dist/repertoire/data/ado-endpoints.json +122 -0
- package/dist/repertoire/data/graph-endpoints.json +212 -0
- package/dist/repertoire/github-client.js +64 -0
- package/dist/repertoire/graph-client.js +118 -0
- package/dist/repertoire/skills.js +156 -0
- package/dist/repertoire/tasks/board.js +122 -0
- package/dist/repertoire/tasks/index.js +210 -0
- package/dist/repertoire/tasks/lifecycle.js +80 -0
- package/dist/repertoire/tasks/middleware.js +65 -0
- package/dist/repertoire/tasks/parser.js +173 -0
- package/dist/repertoire/tasks/scanner.js +132 -0
- package/dist/repertoire/tasks/transitions.js +145 -0
- package/dist/repertoire/tasks/types.js +2 -0
- package/dist/repertoire/tools-base.js +714 -0
- package/dist/repertoire/tools-github.js +53 -0
- package/dist/repertoire/tools-teams.js +308 -0
- package/dist/repertoire/tools.js +199 -0
- package/dist/senses/cli-entry.js +15 -0
- package/dist/senses/cli.js +604 -0
- package/dist/senses/commands.js +98 -0
- package/dist/senses/inner-dialog-worker.js +61 -0
- package/dist/senses/inner-dialog.js +231 -0
- package/dist/senses/session-lock.js +119 -0
- package/dist/senses/teams-entry.js +15 -0
- package/dist/senses/teams.js +696 -0
- package/dist/senses/trust-gate.js +150 -0
- package/package.json +34 -11
- package/subagents/README.md +73 -0
- package/subagents/work-doer.md +233 -0
- package/subagents/work-merger.md +624 -0
- package/subagents/work-planner.md +373 -0
- package/bin/ouro.js +0 -6
|
@@ -0,0 +1,125 @@
|
|
|
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 ensureSymlink(source, target) {
|
|
59
|
+
fs.mkdirSync(path.dirname(target), { recursive: true });
|
|
60
|
+
if (fs.existsSync(target)) {
|
|
61
|
+
const stats = fs.lstatSync(target);
|
|
62
|
+
if (stats.isSymbolicLink()) {
|
|
63
|
+
const linkedPath = fs.readlinkSync(target);
|
|
64
|
+
if (linkedPath === source)
|
|
65
|
+
return false;
|
|
66
|
+
}
|
|
67
|
+
fs.unlinkSync(target);
|
|
68
|
+
}
|
|
69
|
+
fs.symlinkSync(source, target);
|
|
70
|
+
return true;
|
|
71
|
+
}
|
|
72
|
+
async function installSubagentsForAvailableCli(options = {}) {
|
|
73
|
+
const repoRoot = options.repoRoot ?? path.resolve(__dirname, "..", "..", "..");
|
|
74
|
+
const homeDir = options.homeDir ?? os.homedir();
|
|
75
|
+
const which = options.which ?? detectCliBinary;
|
|
76
|
+
const subagentsDir = path.join(repoRoot, "subagents");
|
|
77
|
+
const sources = listSubagentSources(subagentsDir);
|
|
78
|
+
const notes = [];
|
|
79
|
+
(0, runtime_1.emitNervesEvent)({
|
|
80
|
+
component: "daemon",
|
|
81
|
+
event: "daemon.subagent_install_start",
|
|
82
|
+
message: "starting subagent auto-install",
|
|
83
|
+
meta: { sources: sources.length },
|
|
84
|
+
});
|
|
85
|
+
if (sources.length === 0) {
|
|
86
|
+
notes.push(`no subagent files found at ${subagentsDir}`);
|
|
87
|
+
return { claudeInstalled: 0, codexInstalled: 0, notes };
|
|
88
|
+
}
|
|
89
|
+
let claudeInstalled = 0;
|
|
90
|
+
let codexInstalled = 0;
|
|
91
|
+
const claudePath = which("claude");
|
|
92
|
+
if (!claudePath) {
|
|
93
|
+
notes.push("claude CLI not found; skipping subagent install");
|
|
94
|
+
}
|
|
95
|
+
else {
|
|
96
|
+
const claudeAgentsDir = path.join(homeDir, ".claude", "agents");
|
|
97
|
+
for (const source of sources) {
|
|
98
|
+
const target = path.join(claudeAgentsDir, path.basename(source));
|
|
99
|
+
if (ensureSymlink(source, target)) {
|
|
100
|
+
claudeInstalled += 1;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
const codexPath = which("codex");
|
|
105
|
+
if (!codexPath) {
|
|
106
|
+
notes.push("codex CLI not found; skipping subagent install");
|
|
107
|
+
}
|
|
108
|
+
else {
|
|
109
|
+
const codexSkillsDir = path.join(homeDir, ".codex", "skills");
|
|
110
|
+
for (const source of sources) {
|
|
111
|
+
const skillName = path.basename(source, ".md");
|
|
112
|
+
const target = path.join(codexSkillsDir, skillName, "SKILL.md");
|
|
113
|
+
if (ensureSymlink(source, target)) {
|
|
114
|
+
codexInstalled += 1;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
(0, runtime_1.emitNervesEvent)({
|
|
119
|
+
component: "daemon",
|
|
120
|
+
event: "daemon.subagent_install_end",
|
|
121
|
+
message: "completed subagent auto-install",
|
|
122
|
+
meta: { claudeInstalled, codexInstalled, notes: notes.length },
|
|
123
|
+
});
|
|
124
|
+
return { claudeInstalled, codexInstalled, notes };
|
|
125
|
+
}
|
|
@@ -0,0 +1,240 @@
|
|
|
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.TaskDrivenScheduler = void 0;
|
|
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 parser_1 = require("../../repertoire/tasks/parser");
|
|
42
|
+
function walkMarkdownFiles(root, readdirSync, existsSync, files) {
|
|
43
|
+
if (!existsSync(root))
|
|
44
|
+
return;
|
|
45
|
+
for (const entry of readdirSync(root, { withFileTypes: true })) {
|
|
46
|
+
const fullPath = path.join(root, entry.name);
|
|
47
|
+
if (entry.isDirectory()) {
|
|
48
|
+
walkMarkdownFiles(fullPath, readdirSync, existsSync, files);
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
if (entry.name.endsWith(".md")) {
|
|
52
|
+
files.push(fullPath);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
function parseCadence(raw) {
|
|
57
|
+
if (typeof raw !== "string")
|
|
58
|
+
return null;
|
|
59
|
+
const value = raw.trim();
|
|
60
|
+
if (!value)
|
|
61
|
+
return null;
|
|
62
|
+
// Cron format (minute hour day month weekday)
|
|
63
|
+
if (/^\S+\s+\S+\s+\S+\s+\S+\s+\S+$/.test(value)) {
|
|
64
|
+
return value;
|
|
65
|
+
}
|
|
66
|
+
const cadenceMatch = /^(\d+)(m|h|d)$/.exec(value);
|
|
67
|
+
if (!cadenceMatch)
|
|
68
|
+
return null;
|
|
69
|
+
const interval = Number.parseInt(cadenceMatch[1], 10);
|
|
70
|
+
if (!Number.isFinite(interval) || interval <= 0)
|
|
71
|
+
return null;
|
|
72
|
+
const unit = cadenceMatch[2];
|
|
73
|
+
if (unit === "m")
|
|
74
|
+
return `*/${interval} * * * *`;
|
|
75
|
+
if (unit === "h")
|
|
76
|
+
return `0 */${interval} * * *`;
|
|
77
|
+
return `0 0 */${interval} * *`;
|
|
78
|
+
}
|
|
79
|
+
function parseScheduledAt(raw) {
|
|
80
|
+
if (typeof raw !== "string")
|
|
81
|
+
return null;
|
|
82
|
+
const value = raw.trim();
|
|
83
|
+
if (!value)
|
|
84
|
+
return null;
|
|
85
|
+
const date = new Date(value);
|
|
86
|
+
if (Number.isNaN(date.getTime()))
|
|
87
|
+
return null;
|
|
88
|
+
const minute = date.getUTCMinutes();
|
|
89
|
+
const hour = date.getUTCHours();
|
|
90
|
+
const day = date.getUTCDate();
|
|
91
|
+
const month = date.getUTCMonth() + 1;
|
|
92
|
+
return `${minute} ${hour} ${day} ${month} *`;
|
|
93
|
+
}
|
|
94
|
+
function removeRuntimeFrontmatter(frontmatter) {
|
|
95
|
+
const { _isCanonicalFilename, ...clean } = frontmatter;
|
|
96
|
+
return clean;
|
|
97
|
+
}
|
|
98
|
+
class TaskDrivenScheduler {
|
|
99
|
+
agents;
|
|
100
|
+
bundlesRoot;
|
|
101
|
+
nowIso;
|
|
102
|
+
existsSync;
|
|
103
|
+
readFileSync;
|
|
104
|
+
writeFileSync;
|
|
105
|
+
readdirSync;
|
|
106
|
+
osCronManager;
|
|
107
|
+
jobs = new Map();
|
|
108
|
+
taskPathByKey = new Map();
|
|
109
|
+
constructor(options) {
|
|
110
|
+
this.agents = [...options.agents];
|
|
111
|
+
this.bundlesRoot = options.bundlesRoot ?? (0, identity_1.getAgentBundlesRoot)();
|
|
112
|
+
this.nowIso = options.nowIso ?? (() => new Date().toISOString());
|
|
113
|
+
this.existsSync = options.existsSync ?? fs.existsSync;
|
|
114
|
+
this.readFileSync = options.readFileSync ?? fs.readFileSync;
|
|
115
|
+
this.writeFileSync = options.writeFileSync ?? fs.writeFileSync;
|
|
116
|
+
this.readdirSync = options.readdirSync ?? fs.readdirSync;
|
|
117
|
+
this.osCronManager = options.osCronManager;
|
|
118
|
+
}
|
|
119
|
+
start() {
|
|
120
|
+
void this.reconcile();
|
|
121
|
+
}
|
|
122
|
+
stop() {
|
|
123
|
+
this.osCronManager?.removeAll();
|
|
124
|
+
}
|
|
125
|
+
listJobs() {
|
|
126
|
+
return [...this.jobs.values()]
|
|
127
|
+
.map((job) => ({ id: job.id, schedule: job.schedule, lastRun: job.lastRun }))
|
|
128
|
+
.sort((a, b) => a.id.localeCompare(b.id));
|
|
129
|
+
}
|
|
130
|
+
async triggerJob(jobId) {
|
|
131
|
+
const job = this.jobs.get(jobId);
|
|
132
|
+
if (!job) {
|
|
133
|
+
return { ok: false, message: `unknown scheduled job: ${jobId}` };
|
|
134
|
+
}
|
|
135
|
+
await this.recordTaskRun(job.agent, job.taskId);
|
|
136
|
+
return { ok: true, message: `triggered ${jobId}` };
|
|
137
|
+
}
|
|
138
|
+
async reconcile() {
|
|
139
|
+
const nextJobs = new Map();
|
|
140
|
+
const nextTaskPaths = new Map();
|
|
141
|
+
for (const agent of this.agents) {
|
|
142
|
+
const taskRoot = path.join(this.bundlesRoot, `${agent}.ouro`, "tasks");
|
|
143
|
+
const collections = ["one-shots", "ongoing", "habits"];
|
|
144
|
+
const files = [];
|
|
145
|
+
for (const collection of collections) {
|
|
146
|
+
walkMarkdownFiles(path.join(taskRoot, collection), this.readdirSync, this.existsSync, files);
|
|
147
|
+
}
|
|
148
|
+
for (const filePath of files) {
|
|
149
|
+
let task;
|
|
150
|
+
try {
|
|
151
|
+
task = (0, parser_1.parseTaskFile)(this.readFileSync(filePath, "utf-8"), filePath);
|
|
152
|
+
}
|
|
153
|
+
catch {
|
|
154
|
+
continue;
|
|
155
|
+
}
|
|
156
|
+
const taskId = task.stem;
|
|
157
|
+
nextTaskPaths.set(`${agent}:${taskId}`, filePath);
|
|
158
|
+
if (task.status === "done")
|
|
159
|
+
continue;
|
|
160
|
+
const cadence = parseCadence(task.frontmatter.cadence);
|
|
161
|
+
if (cadence) {
|
|
162
|
+
const id = `${agent}:${taskId}:cadence`;
|
|
163
|
+
nextJobs.set(id, {
|
|
164
|
+
id,
|
|
165
|
+
agent,
|
|
166
|
+
taskId,
|
|
167
|
+
schedule: cadence,
|
|
168
|
+
lastRun: typeof task.frontmatter.lastRun === "string" ? task.frontmatter.lastRun : null,
|
|
169
|
+
command: `ouro poke ${agent} --task ${taskId}`,
|
|
170
|
+
taskPath: filePath,
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
const scheduledAt = parseScheduledAt(task.frontmatter.scheduledAt);
|
|
174
|
+
if (scheduledAt) {
|
|
175
|
+
const id = `${agent}:${taskId}:scheduledAt`;
|
|
176
|
+
nextJobs.set(id, {
|
|
177
|
+
id,
|
|
178
|
+
agent,
|
|
179
|
+
taskId,
|
|
180
|
+
schedule: scheduledAt,
|
|
181
|
+
lastRun: typeof task.frontmatter.lastRun === "string" ? task.frontmatter.lastRun : null,
|
|
182
|
+
command: `ouro poke ${agent} --task ${taskId}`,
|
|
183
|
+
taskPath: filePath,
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
this.jobs.clear();
|
|
189
|
+
for (const [id, job] of nextJobs.entries()) {
|
|
190
|
+
this.jobs.set(id, job);
|
|
191
|
+
}
|
|
192
|
+
this.taskPathByKey.clear();
|
|
193
|
+
for (const [key, filePath] of nextTaskPaths.entries()) {
|
|
194
|
+
this.taskPathByKey.set(key, filePath);
|
|
195
|
+
}
|
|
196
|
+
(0, runtime_1.emitNervesEvent)({
|
|
197
|
+
component: "daemon",
|
|
198
|
+
event: "daemon.scheduler_reconciled",
|
|
199
|
+
message: "reconciled task-driven schedule jobs",
|
|
200
|
+
meta: { jobCount: this.jobs.size, agents: this.agents.length },
|
|
201
|
+
});
|
|
202
|
+
this.osCronManager?.sync([...this.jobs.values()]);
|
|
203
|
+
}
|
|
204
|
+
async recordTaskRun(agent, taskId) {
|
|
205
|
+
const key = `${agent}:${taskId}`;
|
|
206
|
+
let taskPath = this.taskPathByKey.get(key);
|
|
207
|
+
if (!taskPath) {
|
|
208
|
+
await this.reconcile();
|
|
209
|
+
taskPath = this.taskPathByKey.get(key);
|
|
210
|
+
if (!taskPath)
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
213
|
+
let parsed;
|
|
214
|
+
try {
|
|
215
|
+
parsed = (0, parser_1.parseTaskFile)(this.readFileSync(taskPath, "utf-8"), taskPath);
|
|
216
|
+
}
|
|
217
|
+
catch {
|
|
218
|
+
return;
|
|
219
|
+
}
|
|
220
|
+
const now = this.nowIso();
|
|
221
|
+
const frontmatter = removeRuntimeFrontmatter(parsed.frontmatter);
|
|
222
|
+
frontmatter.lastRun = now;
|
|
223
|
+
if (typeof frontmatter.updated === "string") {
|
|
224
|
+
frontmatter.updated = now.slice(0, 10);
|
|
225
|
+
}
|
|
226
|
+
this.writeFileSync(taskPath, (0, parser_1.renderTaskFile)(frontmatter, parsed.body), "utf-8");
|
|
227
|
+
for (const job of this.jobs.values()) {
|
|
228
|
+
if (job.agent === agent && job.taskId === taskId) {
|
|
229
|
+
job.lastRun = now;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
(0, runtime_1.emitNervesEvent)({
|
|
233
|
+
component: "daemon",
|
|
234
|
+
event: "daemon.scheduler_task_run_recorded",
|
|
235
|
+
message: "recorded scheduled task run",
|
|
236
|
+
meta: { agent, taskId, at: now },
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
exports.TaskDrivenScheduler = TaskDrivenScheduler;
|
|
@@ -0,0 +1,26 @@
|
|
|
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 __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
exports.HARNESS_PRIMITIVES_ENTRYPOINT = void 0;
|
|
18
|
+
const runtime_1 = require("../nerves/runtime");
|
|
19
|
+
__exportStar(require("./primitives"), exports);
|
|
20
|
+
exports.HARNESS_PRIMITIVES_ENTRYPOINT = "harness/primitives";
|
|
21
|
+
(0, runtime_1.emitNervesEvent)({
|
|
22
|
+
component: "harness",
|
|
23
|
+
event: "harness.module_entry_loaded",
|
|
24
|
+
message: "harness primitives entrypoint loaded",
|
|
25
|
+
meta: {},
|
|
26
|
+
});
|
|
@@ -0,0 +1,281 @@
|
|
|
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.DEFAULT_AGENT_PHRASES = exports.DEFAULT_AGENT_CONTEXT = void 0;
|
|
37
|
+
exports.buildDefaultAgentTemplate = buildDefaultAgentTemplate;
|
|
38
|
+
exports.getAgentName = getAgentName;
|
|
39
|
+
exports.getRepoRoot = getRepoRoot;
|
|
40
|
+
exports.getAgentBundlesRoot = getAgentBundlesRoot;
|
|
41
|
+
exports.getAgentRoot = getAgentRoot;
|
|
42
|
+
exports.getAgentSecretsPath = getAgentSecretsPath;
|
|
43
|
+
exports.loadAgentConfig = loadAgentConfig;
|
|
44
|
+
exports.setAgentName = setAgentName;
|
|
45
|
+
exports.resetIdentity = resetIdentity;
|
|
46
|
+
const fs = __importStar(require("fs"));
|
|
47
|
+
const os = __importStar(require("os"));
|
|
48
|
+
const path = __importStar(require("path"));
|
|
49
|
+
const runtime_1 = require("../nerves/runtime");
|
|
50
|
+
exports.DEFAULT_AGENT_CONTEXT = {
|
|
51
|
+
maxTokens: 80000,
|
|
52
|
+
contextMargin: 20,
|
|
53
|
+
};
|
|
54
|
+
exports.DEFAULT_AGENT_PHRASES = {
|
|
55
|
+
thinking: ["working"],
|
|
56
|
+
tool: ["running tool"],
|
|
57
|
+
followup: ["processing"],
|
|
58
|
+
};
|
|
59
|
+
function buildDefaultAgentTemplate(_agentName) {
|
|
60
|
+
return {
|
|
61
|
+
version: 1,
|
|
62
|
+
enabled: true,
|
|
63
|
+
provider: "anthropic",
|
|
64
|
+
context: { ...exports.DEFAULT_AGENT_CONTEXT },
|
|
65
|
+
phrases: {
|
|
66
|
+
thinking: [...exports.DEFAULT_AGENT_PHRASES.thinking],
|
|
67
|
+
tool: [...exports.DEFAULT_AGENT_PHRASES.tool],
|
|
68
|
+
followup: [...exports.DEFAULT_AGENT_PHRASES.followup],
|
|
69
|
+
},
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
let _cachedAgentName = null;
|
|
73
|
+
let _cachedAgentConfig = null;
|
|
74
|
+
/**
|
|
75
|
+
* Parse `--agent <name>` from process.argv.
|
|
76
|
+
* Caches the result after first parse.
|
|
77
|
+
* Throws if --agent is missing or has no value.
|
|
78
|
+
*/
|
|
79
|
+
function getAgentName() {
|
|
80
|
+
if (_cachedAgentName) {
|
|
81
|
+
(0, runtime_1.emitNervesEvent)({
|
|
82
|
+
event: "identity.resolve",
|
|
83
|
+
component: "config/identity",
|
|
84
|
+
message: "resolved agent name from cache",
|
|
85
|
+
meta: { source: "cache" },
|
|
86
|
+
});
|
|
87
|
+
return _cachedAgentName;
|
|
88
|
+
}
|
|
89
|
+
const idx = process.argv.indexOf("--agent");
|
|
90
|
+
if (idx === -1 || idx + 1 >= process.argv.length) {
|
|
91
|
+
throw new Error("Missing required --agent <name> argument. Usage: node cli-entry.js --agent ouroboros");
|
|
92
|
+
}
|
|
93
|
+
_cachedAgentName = process.argv[idx + 1];
|
|
94
|
+
(0, runtime_1.emitNervesEvent)({
|
|
95
|
+
event: "identity.resolve",
|
|
96
|
+
component: "config/identity",
|
|
97
|
+
message: "resolved agent name from argv",
|
|
98
|
+
meta: { source: "argv" },
|
|
99
|
+
});
|
|
100
|
+
return _cachedAgentName;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Resolve repo root from __dirname.
|
|
104
|
+
* In dev (tsx): __dirname is `<repo>/src/heart`, so repo root is two levels up.
|
|
105
|
+
* In compiled (node dist/): __dirname is `<repo>/dist/heart`, so repo root is two levels up.
|
|
106
|
+
*/
|
|
107
|
+
function getRepoRoot() {
|
|
108
|
+
return path.resolve(__dirname, "../..");
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Returns the shared bundle root directory: `~/AgentBundles/`
|
|
112
|
+
*/
|
|
113
|
+
function getAgentBundlesRoot() {
|
|
114
|
+
return path.join(os.homedir(), "AgentBundles");
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Returns the agent-specific bundle directory: `~/AgentBundles/<agentName>.ouro/`
|
|
118
|
+
*/
|
|
119
|
+
function getAgentRoot() {
|
|
120
|
+
return path.join(getAgentBundlesRoot(), `${getAgentName()}.ouro`);
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Returns the conventional secrets path: `~/.agentsecrets/<agentName>/secrets.json`
|
|
124
|
+
*/
|
|
125
|
+
function getAgentSecretsPath(agentName = getAgentName()) {
|
|
126
|
+
return path.join(os.homedir(), ".agentsecrets", agentName, "secrets.json");
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Load and parse `<agentRoot>/agent.json`.
|
|
130
|
+
* Caches the result after first load.
|
|
131
|
+
* Throws descriptive error if file is missing or contains invalid JSON.
|
|
132
|
+
*/
|
|
133
|
+
function loadAgentConfig() {
|
|
134
|
+
if (_cachedAgentConfig) {
|
|
135
|
+
(0, runtime_1.emitNervesEvent)({
|
|
136
|
+
event: "identity.resolve",
|
|
137
|
+
component: "config/identity",
|
|
138
|
+
message: "loaded agent config from cache",
|
|
139
|
+
meta: { source: "cache" },
|
|
140
|
+
});
|
|
141
|
+
return _cachedAgentConfig;
|
|
142
|
+
}
|
|
143
|
+
const agentRoot = getAgentRoot();
|
|
144
|
+
const configFile = path.join(agentRoot, "agent.json");
|
|
145
|
+
let raw;
|
|
146
|
+
try {
|
|
147
|
+
raw = fs.readFileSync(configFile, "utf-8");
|
|
148
|
+
}
|
|
149
|
+
catch (error) {
|
|
150
|
+
(0, runtime_1.emitNervesEvent)({
|
|
151
|
+
level: "error",
|
|
152
|
+
event: "config_identity.error",
|
|
153
|
+
component: "config/identity",
|
|
154
|
+
message: "failed reading agent.json",
|
|
155
|
+
meta: {
|
|
156
|
+
path: configFile,
|
|
157
|
+
reason: error instanceof Error ? error.message : String(error),
|
|
158
|
+
},
|
|
159
|
+
});
|
|
160
|
+
throw new Error(`Cannot read agent.json at ${configFile}. Does the agent directory exist?`);
|
|
161
|
+
}
|
|
162
|
+
let parsed;
|
|
163
|
+
try {
|
|
164
|
+
parsed = JSON.parse(raw);
|
|
165
|
+
}
|
|
166
|
+
catch (error) {
|
|
167
|
+
(0, runtime_1.emitNervesEvent)({
|
|
168
|
+
level: "error",
|
|
169
|
+
event: "config_identity.error",
|
|
170
|
+
component: "config/identity",
|
|
171
|
+
message: "invalid agent.json syntax",
|
|
172
|
+
meta: {
|
|
173
|
+
path: configFile,
|
|
174
|
+
reason: error instanceof Error ? error.message : String(error),
|
|
175
|
+
},
|
|
176
|
+
});
|
|
177
|
+
throw new Error(`Invalid JSON in agent.json at ${configFile}. Check syntax.`);
|
|
178
|
+
}
|
|
179
|
+
const existingPhrases = parsed.phrases;
|
|
180
|
+
const needsFill = !existingPhrases ||
|
|
181
|
+
!existingPhrases.thinking ||
|
|
182
|
+
!existingPhrases.tool ||
|
|
183
|
+
!existingPhrases.followup;
|
|
184
|
+
if (needsFill) {
|
|
185
|
+
const filled = {
|
|
186
|
+
thinking: existingPhrases?.thinking ?? exports.DEFAULT_AGENT_PHRASES.thinking,
|
|
187
|
+
tool: existingPhrases?.tool ?? exports.DEFAULT_AGENT_PHRASES.tool,
|
|
188
|
+
followup: existingPhrases?.followup ?? exports.DEFAULT_AGENT_PHRASES.followup,
|
|
189
|
+
};
|
|
190
|
+
parsed.phrases = filled;
|
|
191
|
+
(0, runtime_1.emitNervesEvent)({
|
|
192
|
+
level: "warn",
|
|
193
|
+
event: "config_identity.error",
|
|
194
|
+
component: "config/identity",
|
|
195
|
+
message: "agent config missing phrase pools; placeholders applied",
|
|
196
|
+
meta: { path: configFile },
|
|
197
|
+
});
|
|
198
|
+
fs.writeFileSync(configFile, JSON.stringify(parsed, null, 2) + "\n", "utf-8");
|
|
199
|
+
}
|
|
200
|
+
const rawProvider = parsed.provider;
|
|
201
|
+
if (rawProvider !== "azure" &&
|
|
202
|
+
rawProvider !== "minimax" &&
|
|
203
|
+
rawProvider !== "anthropic" &&
|
|
204
|
+
rawProvider !== "openai-codex") {
|
|
205
|
+
(0, runtime_1.emitNervesEvent)({
|
|
206
|
+
level: "error",
|
|
207
|
+
event: "config_identity.error",
|
|
208
|
+
component: "config/identity",
|
|
209
|
+
message: "agent config missing or invalid provider",
|
|
210
|
+
meta: {
|
|
211
|
+
path: configFile,
|
|
212
|
+
provider: rawProvider,
|
|
213
|
+
},
|
|
214
|
+
});
|
|
215
|
+
throw new Error(`agent.json at ${configFile} must include provider: "azure", "minimax", "anthropic", or "openai-codex".`);
|
|
216
|
+
}
|
|
217
|
+
const rawVersion = parsed.version;
|
|
218
|
+
const version = rawVersion === undefined ? 1 : rawVersion;
|
|
219
|
+
if (typeof version !== "number" ||
|
|
220
|
+
!Number.isInteger(version) ||
|
|
221
|
+
version < 1) {
|
|
222
|
+
(0, runtime_1.emitNervesEvent)({
|
|
223
|
+
level: "error",
|
|
224
|
+
event: "config_identity.error",
|
|
225
|
+
component: "config/identity",
|
|
226
|
+
message: "agent config missing or invalid version",
|
|
227
|
+
meta: {
|
|
228
|
+
path: configFile,
|
|
229
|
+
version: rawVersion,
|
|
230
|
+
},
|
|
231
|
+
});
|
|
232
|
+
throw new Error(`agent.json at ${configFile} must include version as integer >= 1.`);
|
|
233
|
+
}
|
|
234
|
+
const rawEnabled = parsed.enabled;
|
|
235
|
+
const enabled = rawEnabled === undefined ? true : rawEnabled;
|
|
236
|
+
if (typeof enabled !== "boolean") {
|
|
237
|
+
(0, runtime_1.emitNervesEvent)({
|
|
238
|
+
level: "error",
|
|
239
|
+
event: "config_identity.error",
|
|
240
|
+
component: "config/identity",
|
|
241
|
+
message: "agent config has invalid enabled flag",
|
|
242
|
+
meta: {
|
|
243
|
+
path: configFile,
|
|
244
|
+
enabled: rawEnabled,
|
|
245
|
+
},
|
|
246
|
+
});
|
|
247
|
+
throw new Error(`agent.json at ${configFile} must include enabled as boolean.`);
|
|
248
|
+
}
|
|
249
|
+
_cachedAgentConfig = {
|
|
250
|
+
version,
|
|
251
|
+
enabled,
|
|
252
|
+
provider: rawProvider,
|
|
253
|
+
context: parsed.context,
|
|
254
|
+
logging: parsed.logging,
|
|
255
|
+
phrases: parsed.phrases,
|
|
256
|
+
};
|
|
257
|
+
(0, runtime_1.emitNervesEvent)({
|
|
258
|
+
event: "identity.resolve",
|
|
259
|
+
component: "config/identity",
|
|
260
|
+
message: "loaded agent config from disk",
|
|
261
|
+
meta: { source: "disk" },
|
|
262
|
+
});
|
|
263
|
+
return _cachedAgentConfig;
|
|
264
|
+
}
|
|
265
|
+
/**
|
|
266
|
+
* Prime the agent name cache explicitly.
|
|
267
|
+
* Used when agent name is known via parameter (e.g., `ouro` CLI routing)
|
|
268
|
+
* rather than `--agent` argv. All downstream calls to `getAgentName()`
|
|
269
|
+
* will return this value until `resetIdentity()` is called.
|
|
270
|
+
*/
|
|
271
|
+
function setAgentName(name) {
|
|
272
|
+
_cachedAgentName = name;
|
|
273
|
+
}
|
|
274
|
+
/**
|
|
275
|
+
* Clear all cached identity state.
|
|
276
|
+
* Used in tests and when switching agent context.
|
|
277
|
+
*/
|
|
278
|
+
function resetIdentity() {
|
|
279
|
+
_cachedAgentName = null;
|
|
280
|
+
_cachedAgentConfig = null;
|
|
281
|
+
}
|