@openlife/cli 1.7.7 → 1.7.10

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/dist/index.js CHANGED
@@ -568,15 +568,41 @@ program
568
568
  program
569
569
  .command('phase1-check')
570
570
  .description('Roda os checks mínimos da Fase 1 para validar o runtime principal')
571
- .action(async () => {
571
+ .option('--deep', 'inclui checks vivos de LLM/TTS/Gateway (pode demorar e depender de credenciais/quota)', false)
572
+ .action(async (options) => {
572
573
  let exitCode = 0;
573
- const MASTER_TIMEOUT_MS = Number(process.env.OPENLIFE_PHASE1_TIMEOUT_MS || 30000);
574
+ const deep = Boolean(options.deep);
575
+ const MASTER_TIMEOUT_MS = Number(process.env.OPENLIFE_PHASE1_TIMEOUT_MS || (deep ? 120000 : 30000));
574
576
  const masterTimeout = new Promise((_, reject) => setTimeout(() => reject(new Error(`PHASE1_CHECK_TIMEOUT after ${MASTER_TIMEOUT_MS}ms — provavelmente Gatekeeper/Brain/Gateway constructor ou check travou esperando LLM/recurso externo`)), MASTER_TIMEOUT_MS));
575
577
  try {
576
- // Wrap both construction and run inside race TestHarness constructor instantiates
577
- // Brain/Gatekeeper/Gateway/etc which may block synchronously
578
+ // Default smoke mode avoids live LLM/TTS/Gateway calls so this command stays deterministic.
579
+ // Use --deep for the original live harness behavior.
578
580
  const results = await Promise.race([
579
581
  (async () => {
582
+ if (!deep) {
583
+ const { ModelManager } = require('./orchestrator/ModelManager');
584
+ const { RuntimePolicy } = require('./orchestrator/RuntimePolicy');
585
+ const modelManager = new ModelManager();
586
+ const runtimePolicy = new RuntimePolicy();
587
+ const config = modelManager.getModelConfig();
588
+ const chain = [config.primary, ...config.fallbacks].map((m) => m.raw);
589
+ const research = runtimePolicy.decide('RESEARCH_ANALYSIS');
590
+ const engineering = runtimePolicy.decide('ENGINEERING_BUILD');
591
+ return [
592
+ {
593
+ name: 'model-config',
594
+ ok: chain.length > 0 && chain.every(Boolean) && chain.length === new Set(chain).size,
595
+ detail: `Primário: ${config.primary.raw} | Fallbacks: ${config.fallbacks.map((f) => f.raw).join(', ') || 'nenhum'}`,
596
+ },
597
+ { name: 'runtime-executors', ok: true, detail: 'SKIPPED: probe real pulado em modo smoke. Use --deep para testar executores externos.' },
598
+ {
599
+ name: 'runtime-policy-chain',
600
+ ok: research.preferred.length > 0 && engineering.preferred.length > 0,
601
+ detail: `research=${research.preferred.join('>')} | engineering=${engineering.preferred.join('>')}`,
602
+ },
603
+ { name: 'live-llm-gateway', ok: true, detail: 'SKIPPED: pulados em modo smoke. Use --deep para validar LLM/TTS/Gateway reais.' },
604
+ ];
605
+ }
580
606
  const { TestHarness } = require('./orchestrator/TestHarness');
581
607
  const harness = new TestHarness();
582
608
  return await harness.runPhase1Checks();
@@ -597,9 +623,8 @@ program
597
623
  console.error('phase1-check failed:', errMsg(error));
598
624
  exitCode = 1;
599
625
  }
600
- // Force deterministic exit TestHarness instantiates GatewayTelegraf, leaving
601
- // event-loop handles open. Same root-cause pattern as Story 1.2 `ask` exit fix.
602
- // Override timeout via OPENLIFE_PHASE1_TIMEOUT_MS (default 30s).
626
+ // Force deterministic exit. In --deep mode TestHarness can instantiate Gateway/Telegraf,
627
+ // leaving event-loop handles open; smoke mode exits the same way for a stable CLI contract.
603
628
  process.exit(exitCode);
604
629
  });
605
630
  const systemCmd = program.command('system').description('Instalação, bootstrap e status do OpenLife');
@@ -2082,32 +2107,196 @@ aiobuilderCmd.command('mode')
2082
2107
  }
2083
2108
  console.log(JSON.stringify(r.setMode(options.set, options.profile), null, 2));
2084
2109
  });
2110
+ // Story 5.5 (M5) — real authoring pipeline. Replaces the 6-line placeholder
2111
+ // stub. Accepts rich flags + optional --interactive readline prompts, then
2112
+ // delegates to AgentCreator / SquadCreator for atomic write.
2113
+ const splitCsv = (s) => (s || '')
2114
+ .split(',')
2115
+ .map((v) => v.trim())
2116
+ .filter((v) => v.length > 0);
2085
2117
  aiobuilderCmd.command('create-agent <id>')
2086
- .option('--role <role>', 'papel', 'specialist')
2087
- .option('--notes <notes>', 'notas', '')
2088
- .action((id, options) => {
2089
- const base = path.join(process.cwd(), '.catalog', 'agents', id);
2090
- fs.mkdirSync(base, { recursive: true });
2091
- const out = path.join(base, 'AGENT.md');
2092
- fs.writeFileSync(out, `---\nid: ${id}\nname: ${id}\nrole: ${options.role}\nsource: aiobuilder\n---\n\n# ${id}\n\n${options.notes || 'Criado pelo AIOBUILDER.'}\n`, 'utf-8');
2093
- console.log(JSON.stringify({ ok: true, type: 'agent', path: out }, null, 2));
2118
+ .description('Author a new agent in .catalog/agents/<id>/AGENT.md (status: draft)')
2119
+ .option('--role <role>', 'role label (e.g. specialist, planner)', 'specialist')
2120
+ .option('--name <name>', 'display name (defaults to id)')
2121
+ .option('--domain <domain>', 'business domain')
2122
+ .option('--expertise <csv>', 'comma-separated expertise tags')
2123
+ .option('--skills <csv>', 'comma-separated primary skill ids (must exist in .catalog/skills/)')
2124
+ .option('--parent-squad <id>', 'parent squad id (must exist in .catalog/squads/)')
2125
+ .option('--persona <text>', 'free-form persona description')
2126
+ .option('--when-to-use <text>', 'goal / when-to-use sentence')
2127
+ .option('--status <status>', 'active | draft | archived', 'draft')
2128
+ .option('--interactive', 'prompt for missing fields via readline', false)
2129
+ .action(async (id, options) => {
2130
+ const { AgentCreator } = require('./orchestrator/AgentCreator');
2131
+ let name = options.name || id;
2132
+ let role = options.role;
2133
+ let domain = options.domain;
2134
+ let expertise = splitCsv(options.expertise);
2135
+ let primarySkills = splitCsv(options.skills);
2136
+ let parentSquad = options.parentSquad;
2137
+ let persona = options.persona;
2138
+ let whenToUse = options.whenToUse;
2139
+ if (options.interactive && process.stdin.isTTY) {
2140
+ const { ReadlineAnswerProvider } = require('./cli/InstallWizard');
2141
+ const provider = new ReadlineAnswerProvider();
2142
+ try {
2143
+ console.log(`\n📝 Authoring agent: ${id}\n`);
2144
+ name = await provider.text('Display name', name);
2145
+ role = await provider.text('Role (e.g. specialist, planner, reviewer)', role);
2146
+ domain = await provider.text('Business domain (optional, Enter to skip)', domain || '');
2147
+ const expertiseRaw = await provider.text('Expertise tags (comma-separated, optional)', expertise.join(','));
2148
+ expertise = splitCsv(expertiseRaw);
2149
+ const skillsRaw = await provider.text('Primary skill ids (comma-separated, optional)', primarySkills.join(','));
2150
+ primarySkills = splitCsv(skillsRaw);
2151
+ parentSquad = await provider.text('Parent squad id (optional)', parentSquad || '');
2152
+ whenToUse = await provider.text('When to use this agent (one sentence)', whenToUse || `Execute the ${role} role on demand.`);
2153
+ }
2154
+ finally {
2155
+ provider.close?.();
2156
+ }
2157
+ }
2158
+ else if (options.interactive) {
2159
+ console.error('⚠️ --interactive ignored (no TTY). Using flag values + defaults.');
2160
+ }
2161
+ const creator = new AgentCreator();
2162
+ const result = creator.create({
2163
+ id,
2164
+ name,
2165
+ role,
2166
+ domain: domain || undefined,
2167
+ expertise: expertise.length ? expertise : undefined,
2168
+ primarySkills: primarySkills.length ? primarySkills : undefined,
2169
+ parentSquad: parentSquad || undefined,
2170
+ persona,
2171
+ whenToUse,
2172
+ status: options.status,
2173
+ });
2174
+ if (!result.ok) {
2175
+ console.log(JSON.stringify({ ok: false, type: 'agent', ...result }, null, 2));
2176
+ process.exitCode = 1;
2177
+ return;
2178
+ }
2179
+ const validation = creator.validate(id);
2180
+ console.log(JSON.stringify({
2181
+ ok: true,
2182
+ type: 'agent',
2183
+ agentId: result.agentId,
2184
+ path: result.filePath,
2185
+ warnings: validation.warnings,
2186
+ }, null, 2));
2094
2187
  });
2095
2188
  aiobuilderCmd.command('create-squad <id>')
2096
- .option('--domain <domain>', 'domínio', 'general')
2097
- .option('--notes <notes>', 'notas', '')
2098
- .action((id, options) => {
2099
- const base = path.join(process.cwd(), '.catalog', 'squads', id);
2100
- fs.mkdirSync(base, { recursive: true });
2101
- const out = path.join(base, 'SQUAD.md');
2102
- fs.writeFileSync(out, `---\nid: ${id}\ndomain: ${options.domain}\nsource: aiobuilder\n---\n\n# ${id}\n\n${options.notes || 'Criada pelo AIOBUILDER.'}\n`, 'utf-8');
2103
- console.log(JSON.stringify({ ok: true, type: 'squad', path: out }, null, 2));
2189
+ .description('Author a new squad in .catalog/squads/<id>/ with at least one agent')
2190
+ .option('--name <name>', 'display name (defaults to id)')
2191
+ .option('--domain <domain>', 'business domain', 'general')
2192
+ .option('--description <text>', 'short description', '')
2193
+ .option('--agents <csv>', 'comma-separated initial agent ids', '')
2194
+ .option('--status <status>', 'active | draft', 'draft')
2195
+ .option('--interactive', 'prompt for missing fields via readline', false)
2196
+ .action(async (id, options) => {
2197
+ const { SquadCreator } = require('./orchestrator/SquadCreator');
2198
+ let name = options.name || id;
2199
+ let domain = options.domain;
2200
+ let description = options.description;
2201
+ let agentIds = splitCsv(options.agents);
2202
+ if (options.interactive && process.stdin.isTTY) {
2203
+ const { ReadlineAnswerProvider } = require('./cli/InstallWizard');
2204
+ const provider = new ReadlineAnswerProvider();
2205
+ try {
2206
+ console.log(`\n📝 Authoring squad: ${id}\n`);
2207
+ name = await provider.text('Display name', name);
2208
+ domain = await provider.text('Domain', domain);
2209
+ description = await provider.text('Description (one sentence)', description || `${name} squad — ${domain} domain`);
2210
+ const agentsRaw = await provider.text('Initial agent ids (comma-separated, at least one)', agentIds.join(','));
2211
+ agentIds = splitCsv(agentsRaw);
2212
+ }
2213
+ finally {
2214
+ provider.close?.();
2215
+ }
2216
+ }
2217
+ else if (options.interactive) {
2218
+ console.error('⚠️ --interactive ignored (no TTY). Using flag values + defaults.');
2219
+ }
2220
+ if (agentIds.length === 0) {
2221
+ agentIds = [`${id}-lead`];
2222
+ }
2223
+ const creator = new SquadCreator();
2224
+ const result = creator.create({
2225
+ id,
2226
+ name,
2227
+ description: description || `${name} squad`,
2228
+ agents: agentIds.map((agentId) => ({
2229
+ id: agentId,
2230
+ name: agentId,
2231
+ role: 'specialist',
2232
+ })),
2233
+ status: options.status,
2234
+ source: 'aiobuilder',
2235
+ });
2236
+ if (!result.ok) {
2237
+ console.log(JSON.stringify({ ok: false, type: 'squad', ...result }, null, 2));
2238
+ process.exitCode = 1;
2239
+ return;
2240
+ }
2241
+ console.log(JSON.stringify({
2242
+ ok: true,
2243
+ type: 'squad',
2244
+ squadId: result.squadId,
2245
+ squadDir: result.squadDir,
2246
+ filesCreated: result.filesCreated.length,
2247
+ }, null, 2));
2104
2248
  });
2105
- aiobuilderCmd.command('validate-catalog').action(() => {
2106
- const agents = countCatalogFiles('agents', 'AGENT.md');
2107
- const squads = countCatalogFiles('squads', 'SQUAD.md');
2108
- const ok = agents.total >= 300 && squads.total >= 2;
2109
- console.log(JSON.stringify({ ok, agents, squads }, null, 2));
2110
- if (!ok)
2249
+ aiobuilderCmd.command('validate-catalog')
2250
+ .description('Semantic validation of .catalog/ agents + squads (JSON by default)')
2251
+ .option('--human', 'emit human-readable text instead of JSON', false)
2252
+ .option('--json', 'emit machine-readable JSON only (backward-compatible no-op; JSON is default)', false)
2253
+ .action((options) => {
2254
+ const { AgentCreator } = require('./orchestrator/AgentCreator');
2255
+ const { SquadCreator } = require('./orchestrator/SquadCreator');
2256
+ const agentCreator = new AgentCreator();
2257
+ const squadCreator = new SquadCreator();
2258
+ const agentList = agentCreator.list();
2259
+ const squadList = squadCreator.list();
2260
+ const errors = [];
2261
+ const warnings = [];
2262
+ for (const a of agentList) {
2263
+ const v = agentCreator.validate(a.id);
2264
+ for (const err of v.errors)
2265
+ errors.push({ kind: 'agent', id: a.id, error: err });
2266
+ for (const w of v.warnings)
2267
+ warnings.push({ kind: 'agent', id: a.id, warning: w });
2268
+ }
2269
+ for (const s of squadList) {
2270
+ const v = squadCreator.validate(s.id);
2271
+ for (const err of v.errors)
2272
+ errors.push({ kind: 'squad', id: s.id, error: err });
2273
+ for (const w of v.warnings)
2274
+ warnings.push({ kind: 'squad', id: s.id, warning: w });
2275
+ }
2276
+ const report = {
2277
+ ok: errors.length === 0,
2278
+ parsed: { agents: agentList.length, squads: squadList.length },
2279
+ // Back-compat shape (consumed by test_openlife_evolution_surface and
2280
+ // any operator script that grew up under the old threshold output).
2281
+ agents: { total: agentList.length },
2282
+ squads: { total: squadList.length },
2283
+ errors,
2284
+ warnings,
2285
+ };
2286
+ if (options.human) {
2287
+ console.log(`Catalog validation — agents: ${agentList.length}, squads: ${squadList.length}`);
2288
+ console.log(` errors: ${errors.length}, warnings: ${warnings.length}`);
2289
+ for (const e of errors)
2290
+ console.log(` ❌ [${e.kind}/${e.id}] ${e.error}`);
2291
+ for (const w of warnings.slice(0, 10))
2292
+ console.log(` ⚠️ [${w.kind}/${w.id}] ${w.warning}`);
2293
+ if (warnings.length > 10)
2294
+ console.log(` ... and ${warnings.length - 10} more warnings`);
2295
+ }
2296
+ else {
2297
+ console.log(JSON.stringify(report, null, 2));
2298
+ }
2299
+ if (!report.ok)
2111
2300
  process.exitCode = 1;
2112
2301
  });
2113
2302
  aiobuilderCmd.command('generate-ui <featureName>')
@@ -2271,16 +2460,6 @@ aiobuilderCmd.command('test')
2271
2460
  if (r.status !== 0)
2272
2461
  process.exitCode = 1;
2273
2462
  });
2274
- aiobuilderCmd.command('preview')
2275
- .description('Prepare a preview URL for the current branch (v1.3 will wire to Vercel/Railway)')
2276
- .action(() => {
2277
- console.log(JSON.stringify({
2278
- ok: true,
2279
- action: 'aiobuilder.preview',
2280
- note: 'preview deployment integration deferred to v1.3 capability genesis epic',
2281
- next: 'manually push to feature branch + open PR for now',
2282
- }, null, 2));
2283
- });
2284
2463
  aiobuilderCmd.command('release')
2285
2464
  .description('Run QA loop + open PR (delegates to qa-loop workflow)')
2286
2465
  .action(async () => {
@@ -2297,16 +2476,6 @@ aiobuilderCmd.command('release')
2297
2476
  const state = await engine.run(r.workflow);
2298
2477
  console.log(JSON.stringify({ ok: state.status === 'completed', action: 'aiobuilder.release', state }, null, 2));
2299
2478
  });
2300
- aiobuilderCmd.command('infra')
2301
- .description('Infrastructure report (placeholder — real integration v1.3)')
2302
- .action(() => {
2303
- console.log(JSON.stringify({
2304
- ok: true,
2305
- action: 'aiobuilder.infra',
2306
- note: 'infra integration deferred to v1.3',
2307
- checks: ['supabase: TBD', 'railway: TBD', 'env: TBD'],
2308
- }, null, 2));
2309
- });
2310
2479
  aiobuilderCmd.command('score')
2311
2480
  .description('Show squad/skill scores from .artifacts/squad-scores.json')
2312
2481
  .action(() => {
@@ -0,0 +1,362 @@
1
+ "use strict";
2
+ /**
3
+ * AgentCreator — authoring system for standalone agents under `.catalog/agents/`.
4
+ *
5
+ * Story 5.5 — OpenLife v1.8 (M5 of Hit-10 sprint).
6
+ *
7
+ * Replaces the 6-line placeholder previously inlined in
8
+ * `aiobuilder create-agent` with a real authoring pipeline that produces
9
+ * an AGENT.md with complete frontmatter + structured sections (Goal,
10
+ * Commands, Dependencies, Persona, Guardrails). Mirrors SkillCreator
11
+ * (single-file output) rather than SquadCreator (multi-file directory),
12
+ * since standalone agents live as one AGENT.md inside their own directory.
13
+ *
14
+ * Methods:
15
+ * - create(proposal) — render full AGENT.md from a proposal
16
+ * - validate(id) — semantic frontmatter + cross-ref check
17
+ * - list(filter?) — direct read of `.catalog/agents/`
18
+ * - analyze(id) — surface missing/orphan references
19
+ */
20
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
21
+ if (k2 === undefined) k2 = k;
22
+ var desc = Object.getOwnPropertyDescriptor(m, k);
23
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
24
+ desc = { enumerable: true, get: function() { return m[k]; } };
25
+ }
26
+ Object.defineProperty(o, k2, desc);
27
+ }) : (function(o, m, k, k2) {
28
+ if (k2 === undefined) k2 = k;
29
+ o[k2] = m[k];
30
+ }));
31
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
32
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
33
+ }) : function(o, v) {
34
+ o["default"] = v;
35
+ });
36
+ var __importStar = (this && this.__importStar) || (function () {
37
+ var ownKeys = function(o) {
38
+ ownKeys = Object.getOwnPropertyNames || function (o) {
39
+ var ar = [];
40
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
41
+ return ar;
42
+ };
43
+ return ownKeys(o);
44
+ };
45
+ return function (mod) {
46
+ if (mod && mod.__esModule) return mod;
47
+ var result = {};
48
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
49
+ __setModuleDefault(result, mod);
50
+ return result;
51
+ };
52
+ })();
53
+ Object.defineProperty(exports, "__esModule", { value: true });
54
+ exports.AgentCreator = void 0;
55
+ const fs = __importStar(require("fs"));
56
+ const path = __importStar(require("path"));
57
+ const AtomicWriter_1 = require("./util/AtomicWriter");
58
+ const ID_PATTERN = /^[a-z0-9][a-z0-9._-]+$/i;
59
+ const VALID_STATUSES = new Set(['active', 'draft', 'archived']);
60
+ class AgentCreator {
61
+ catalogRoot;
62
+ skillsCatalogRoot;
63
+ squadsCatalogRoot;
64
+ constructor(opts = {}) {
65
+ const cwd = process.cwd();
66
+ this.catalogRoot = opts.catalogRoot || path.join(cwd, '.catalog', 'agents');
67
+ this.skillsCatalogRoot = opts.skillsCatalogRoot || path.join(cwd, '.catalog', 'skills');
68
+ this.squadsCatalogRoot = opts.squadsCatalogRoot || path.join(cwd, '.catalog', 'squads');
69
+ }
70
+ // ─────────────────────────────────────────────────────────
71
+ // create
72
+ // ─────────────────────────────────────────────────────────
73
+ create(proposal) {
74
+ if (!proposal.id || !ID_PATTERN.test(proposal.id)) {
75
+ return { ok: false, error: 'invalid_agent_id', detail: 'must match /^[a-z0-9][a-z0-9._-]+$/i' };
76
+ }
77
+ if (!proposal.name?.trim()) {
78
+ return { ok: false, error: 'missing_name' };
79
+ }
80
+ if (!proposal.role?.trim()) {
81
+ return { ok: false, error: 'missing_role' };
82
+ }
83
+ if (proposal.status && !VALID_STATUSES.has(proposal.status)) {
84
+ return { ok: false, error: 'invalid_status', detail: `must be one of: ${Array.from(VALID_STATUSES).join(', ')}` };
85
+ }
86
+ const agentDir = path.join(this.catalogRoot, proposal.id);
87
+ if (fs.existsSync(agentDir)) {
88
+ return { ok: false, error: 'agent_already_exists', detail: agentDir };
89
+ }
90
+ try {
91
+ fs.mkdirSync(agentDir, { recursive: true });
92
+ const content = this.renderAgentMd(proposal);
93
+ const filePath = path.join(agentDir, 'AGENT.md');
94
+ (0, AtomicWriter_1.writeStringAtomic)(filePath, content);
95
+ return { ok: true, agentId: proposal.id, agentDir, filePath };
96
+ }
97
+ catch (err) {
98
+ try {
99
+ fs.rmSync(agentDir, { recursive: true, force: true });
100
+ }
101
+ catch { /* ignore */ }
102
+ return { ok: false, error: 'render_failed', detail: err instanceof Error ? err.message : String(err) };
103
+ }
104
+ }
105
+ // ─────────────────────────────────────────────────────────
106
+ // validate
107
+ // ─────────────────────────────────────────────────────────
108
+ validate(agentId) {
109
+ const errors = [];
110
+ const warnings = [];
111
+ const agentDir = path.join(this.catalogRoot, agentId);
112
+ const agentFile = path.join(agentDir, 'AGENT.md');
113
+ if (!fs.existsSync(agentDir)) {
114
+ errors.push(`agent directory not found: ${agentDir}`);
115
+ return { ok: false, agentId, errors, warnings };
116
+ }
117
+ if (!fs.existsSync(agentFile)) {
118
+ errors.push('AGENT.md missing');
119
+ return { ok: false, agentId, errors, warnings };
120
+ }
121
+ const content = fs.readFileSync(agentFile, 'utf-8');
122
+ const fm = this.parseFrontmatter(content);
123
+ if (!fm.id)
124
+ errors.push('frontmatter missing id');
125
+ if (!fm.name)
126
+ errors.push('frontmatter missing name');
127
+ if (!fm.role)
128
+ errors.push('frontmatter missing role');
129
+ if (fm.id && fm.id !== agentId) {
130
+ errors.push(`frontmatter id '${fm.id}' does not match directory '${agentId}'`);
131
+ }
132
+ if (fm.status && !VALID_STATUSES.has(fm.status)) {
133
+ errors.push(`invalid status '${fm.status}' (must be active|draft|archived)`);
134
+ }
135
+ // Cross-reference: parent squad
136
+ if (fm.parentSquad) {
137
+ const squadPath = path.join(this.squadsCatalogRoot, fm.parentSquad);
138
+ if (!fs.existsSync(squadPath)) {
139
+ warnings.push(`parent squad '${fm.parentSquad}' not found in catalog`);
140
+ }
141
+ }
142
+ // Cross-reference: primary skills
143
+ const skillRefs = this.parseListField(content, 'primarySkills');
144
+ for (const skillId of skillRefs) {
145
+ const skillPath = path.join(this.skillsCatalogRoot, skillId);
146
+ if (!fs.existsSync(skillPath)) {
147
+ warnings.push(`primary skill '${skillId}' not found in catalog`);
148
+ }
149
+ }
150
+ return { ok: errors.length === 0, agentId, errors, warnings };
151
+ }
152
+ // ─────────────────────────────────────────────────────────
153
+ // list
154
+ // ─────────────────────────────────────────────────────────
155
+ list(filter) {
156
+ if (!fs.existsSync(this.catalogRoot))
157
+ return [];
158
+ const out = [];
159
+ for (const entry of fs.readdirSync(this.catalogRoot)) {
160
+ const agentFile = path.join(this.catalogRoot, entry, 'AGENT.md');
161
+ if (!fs.existsSync(agentFile))
162
+ continue;
163
+ const fm = this.parseFrontmatter(fs.readFileSync(agentFile, 'utf-8'));
164
+ const item = {
165
+ id: fm.id || entry,
166
+ name: fm.name || entry,
167
+ role: fm.role || 'unknown',
168
+ status: fm.status || 'unknown',
169
+ parentSquad: fm.parentSquad || null,
170
+ };
171
+ if (filter?.status && item.status !== filter.status)
172
+ continue;
173
+ if (filter?.squad && item.parentSquad !== filter.squad)
174
+ continue;
175
+ out.push(item);
176
+ }
177
+ return out;
178
+ }
179
+ // ─────────────────────────────────────────────────────────
180
+ // analyze
181
+ // ─────────────────────────────────────────────────────────
182
+ analyze(agentId) {
183
+ const agentDir = path.join(this.catalogRoot, agentId);
184
+ const agentFile = path.join(agentDir, 'AGENT.md');
185
+ if (!fs.existsSync(agentFile))
186
+ return null;
187
+ const content = fs.readFileSync(agentFile, 'utf-8');
188
+ const fm = this.parseFrontmatter(content);
189
+ const hasPersona = /^## Persona\b/m.test(content);
190
+ const commandLines = content.match(/^\s*-\s*name:\s*[\w-]+/gm) || [];
191
+ const skillRefs = this.parseListField(content, 'primarySkills');
192
+ const orphanSkills = [];
193
+ for (const skillId of skillRefs) {
194
+ if (!fs.existsSync(path.join(this.skillsCatalogRoot, skillId))) {
195
+ orphanSkills.push(skillId);
196
+ }
197
+ }
198
+ const squadReference = fm.parentSquad || null;
199
+ const squadExists = squadReference
200
+ ? fs.existsSync(path.join(this.squadsCatalogRoot, squadReference))
201
+ : null;
202
+ const suggestions = [];
203
+ if (!hasPersona)
204
+ suggestions.push('add a Persona section to clarify behavior under load');
205
+ if (commandLines.length === 0)
206
+ suggestions.push('declare at least one command so operators know how to invoke');
207
+ if (orphanSkills.length > 0)
208
+ suggestions.push(`${orphanSkills.length} skill reference(s) not in catalog`);
209
+ if (squadReference && squadExists === false)
210
+ suggestions.push(`parent squad '${squadReference}' not in catalog`);
211
+ return {
212
+ agentId,
213
+ hasPersona,
214
+ commandCount: commandLines.length,
215
+ skillReferences: skillRefs.length,
216
+ orphanSkills,
217
+ squadReference,
218
+ squadExists,
219
+ suggestions,
220
+ };
221
+ }
222
+ // ─────────────────────────────────────────────────────────
223
+ // render — AGENT.md body
224
+ // ─────────────────────────────────────────────────────────
225
+ renderAgentMd(p) {
226
+ const status = p.status || 'draft';
227
+ const version = p.version || '0.1.0';
228
+ const source = p.source || 'aiobuilder';
229
+ const createdAt = new Date().toISOString();
230
+ const frontmatterLines = [
231
+ '---',
232
+ `id: ${p.id}`,
233
+ `name: ${p.name}`,
234
+ `role: ${p.role}`,
235
+ ];
236
+ if (p.domain)
237
+ frontmatterLines.push(`domain: ${p.domain}`);
238
+ if (p.parentSquad)
239
+ frontmatterLines.push(`parentSquad: ${p.parentSquad}`);
240
+ if (p.expertise?.length) {
241
+ frontmatterLines.push('expertise:');
242
+ for (const tag of p.expertise)
243
+ frontmatterLines.push(` - ${tag}`);
244
+ }
245
+ if (p.primarySkills?.length) {
246
+ frontmatterLines.push('primarySkills:');
247
+ for (const skillId of p.primarySkills)
248
+ frontmatterLines.push(` - ${skillId}`);
249
+ }
250
+ frontmatterLines.push(`status: ${status}`);
251
+ frontmatterLines.push(`version: ${version}`);
252
+ frontmatterLines.push(`source: ${source}`);
253
+ frontmatterLines.push(`createdAt: ${createdAt}`);
254
+ frontmatterLines.push('---');
255
+ const commands = p.commands?.length
256
+ ? p.commands
257
+ : [{ name: 'help', description: 'Show available commands and capabilities' }];
258
+ const dependencies = p.dependencies?.length
259
+ ? p.dependencies
260
+ : ['(none declared yet — list skills, tools, or services this agent relies on)'];
261
+ const guardrails = p.guardrails?.length
262
+ ? p.guardrails
263
+ : [
264
+ 'Respect toolset boundaries from parent squad policies',
265
+ 'Emit audit events for state-changing actions',
266
+ 'Defer to human approval for actions outside autonomy budget',
267
+ ];
268
+ const sections = [];
269
+ sections.push(`# ${p.name}`);
270
+ sections.push('');
271
+ sections.push(`> Role: ${p.role}${p.domain ? ` · Domain: ${p.domain}` : ''}`);
272
+ sections.push('');
273
+ sections.push('## Goal');
274
+ sections.push('');
275
+ sections.push(p.whenToUse || `Define and execute work in the ${p.role} role.`);
276
+ sections.push('');
277
+ sections.push('## Commands');
278
+ sections.push('');
279
+ sections.push('```yaml');
280
+ sections.push('commands:');
281
+ for (const c of commands) {
282
+ sections.push(` - name: ${c.name}`);
283
+ sections.push(` description: ${JSON.stringify(c.description)}`);
284
+ }
285
+ sections.push('```');
286
+ sections.push('');
287
+ sections.push('## Dependencies');
288
+ sections.push('');
289
+ for (const d of dependencies)
290
+ sections.push(`- ${d}`);
291
+ sections.push('');
292
+ sections.push('## Persona');
293
+ sections.push('');
294
+ if (p.identity || p.style || p.focus || p.persona) {
295
+ if (p.identity)
296
+ sections.push(`- **Identity:** ${p.identity}`);
297
+ if (p.style)
298
+ sections.push(`- **Style:** ${p.style}`);
299
+ if (p.focus)
300
+ sections.push(`- **Focus:** ${p.focus}`);
301
+ if (p.persona) {
302
+ sections.push('');
303
+ sections.push(p.persona);
304
+ }
305
+ }
306
+ else {
307
+ sections.push(`Embodies the ${p.role} discipline with rigor and clarity. Speaks in concrete steps,`);
308
+ sections.push('not abstractions. Defers to operator judgment on irreversible decisions.');
309
+ }
310
+ sections.push('');
311
+ sections.push('## Guardrails');
312
+ sections.push('');
313
+ for (const g of guardrails)
314
+ sections.push(`- ${g}`);
315
+ sections.push('');
316
+ sections.push('---');
317
+ sections.push('*Generated by OpenLife AgentCreator.*');
318
+ return frontmatterLines.join('\n') + '\n\n' + sections.join('\n') + '\n';
319
+ }
320
+ // ─────────────────────────────────────────────────────────
321
+ // parsing helpers
322
+ // ─────────────────────────────────────────────────────────
323
+ parseFrontmatter(content) {
324
+ const match = content.match(/^---\n([\s\S]*?)\n---/);
325
+ if (!match)
326
+ return {};
327
+ const out = {};
328
+ for (const line of match[1].split('\n')) {
329
+ const m = line.match(/^([a-zA-Z][a-zA-Z0-9_]*):\s*(.+)$/);
330
+ if (m)
331
+ out[m[1]] = m[2].trim();
332
+ }
333
+ return out;
334
+ }
335
+ parseListField(content, field) {
336
+ const fmMatch = content.match(/^---\n([\s\S]*?)\n---/);
337
+ if (!fmMatch)
338
+ return [];
339
+ const lines = fmMatch[1].split('\n');
340
+ const out = [];
341
+ let capturing = false;
342
+ const fieldRe = new RegExp(`^${field}:\\s*$`);
343
+ for (const line of lines) {
344
+ if (fieldRe.test(line)) {
345
+ capturing = true;
346
+ continue;
347
+ }
348
+ if (capturing) {
349
+ const m = line.match(/^\s+-\s+(.+)$/);
350
+ if (m) {
351
+ out.push(m[1].trim());
352
+ continue;
353
+ }
354
+ // any non-list line ends the capture
355
+ if (/^[a-zA-Z]/.test(line))
356
+ capturing = false;
357
+ }
358
+ }
359
+ return out;
360
+ }
361
+ }
362
+ exports.AgentCreator = AgentCreator;
@@ -0,0 +1,237 @@
1
+ "use strict";
2
+ // test_agent_creator — verifies the authoring pipeline for standalone agents.
3
+ // Each scenario uses a temp catalog root so we don't touch the maintainer's
4
+ // real `.catalog/agents/`.
5
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
6
+ if (k2 === undefined) k2 = k;
7
+ var desc = Object.getOwnPropertyDescriptor(m, k);
8
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
9
+ desc = { enumerable: true, get: function() { return m[k]; } };
10
+ }
11
+ Object.defineProperty(o, k2, desc);
12
+ }) : (function(o, m, k, k2) {
13
+ if (k2 === undefined) k2 = k;
14
+ o[k2] = m[k];
15
+ }));
16
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
17
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
18
+ }) : function(o, v) {
19
+ o["default"] = v;
20
+ });
21
+ var __importStar = (this && this.__importStar) || (function () {
22
+ var ownKeys = function(o) {
23
+ ownKeys = Object.getOwnPropertyNames || function (o) {
24
+ var ar = [];
25
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
26
+ return ar;
27
+ };
28
+ return ownKeys(o);
29
+ };
30
+ return function (mod) {
31
+ if (mod && mod.__esModule) return mod;
32
+ var result = {};
33
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
34
+ __setModuleDefault(result, mod);
35
+ return result;
36
+ };
37
+ })();
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ const fs = __importStar(require("fs"));
40
+ const os = __importStar(require("os"));
41
+ const path = __importStar(require("path"));
42
+ const AgentCreator_1 = require("./orchestrator/AgentCreator");
43
+ function assert(cond, msg) {
44
+ if (!cond) {
45
+ console.error(`❌ ASSERT FAILED: ${msg}`);
46
+ process.exit(1);
47
+ }
48
+ }
49
+ function tempCatalog() {
50
+ const root = fs.mkdtempSync(path.join(os.tmpdir(), 'openlife-agentcreator-'));
51
+ const agents = path.join(root, 'agents');
52
+ const skills = path.join(root, 'skills');
53
+ const squads = path.join(root, 'squads');
54
+ fs.mkdirSync(agents, { recursive: true });
55
+ fs.mkdirSync(skills, { recursive: true });
56
+ fs.mkdirSync(squads, { recursive: true });
57
+ return { root, agents, skills, squads };
58
+ }
59
+ function cleanup(root) {
60
+ try {
61
+ fs.rmSync(root, { recursive: true, force: true });
62
+ }
63
+ catch { /* best effort */ }
64
+ }
65
+ function scenarioMinimalProposal() {
66
+ const cat = tempCatalog();
67
+ try {
68
+ const creator = new AgentCreator_1.AgentCreator({ catalogRoot: cat.agents, skillsCatalogRoot: cat.skills, squadsCatalogRoot: cat.squads });
69
+ const result = creator.create({ id: 'minimal-agent', name: 'Minimal', role: 'specialist' });
70
+ assert(result.ok === true, 'minimal proposal should succeed');
71
+ if (!result.ok)
72
+ return;
73
+ assert(fs.existsSync(result.filePath), 'AGENT.md file written');
74
+ const body = fs.readFileSync(result.filePath, 'utf-8');
75
+ assert(body.includes('id: minimal-agent'), 'frontmatter contains id');
76
+ assert(body.includes('## Goal'), 'has Goal section');
77
+ assert(body.includes('## Commands'), 'has Commands section');
78
+ assert(body.includes('## Dependencies'), 'has Dependencies section');
79
+ assert(body.includes('## Persona'), 'has Persona section');
80
+ assert(body.includes('## Guardrails'), 'has Guardrails section');
81
+ console.log('✅ scenario 1: minimal proposal renders full 5-section AGENT.md');
82
+ }
83
+ finally {
84
+ cleanup(cat.root);
85
+ }
86
+ }
87
+ function scenarioFullProposalWithCrossRefs() {
88
+ const cat = tempCatalog();
89
+ try {
90
+ // Create a referenced skill + squad first so cross-refs resolve.
91
+ fs.mkdirSync(path.join(cat.skills, 'planning-skill'), { recursive: true });
92
+ fs.writeFileSync(path.join(cat.skills, 'planning-skill', 'SKILL.md'), '---\nid: planning-skill\n---\n', 'utf-8');
93
+ fs.mkdirSync(path.join(cat.squads, 'ops-squad'), { recursive: true });
94
+ fs.writeFileSync(path.join(cat.squads, 'ops-squad', 'SQUAD.md'), '---\nid: ops-squad\nname: ops\nstatus: active\n---\n', 'utf-8');
95
+ const creator = new AgentCreator_1.AgentCreator({ catalogRoot: cat.agents, skillsCatalogRoot: cat.skills, squadsCatalogRoot: cat.squads });
96
+ const result = creator.create({
97
+ id: 'full-agent',
98
+ name: 'Full Agent',
99
+ role: 'planner',
100
+ domain: 'ops',
101
+ expertise: ['planning', 'routing'],
102
+ primarySkills: ['planning-skill'],
103
+ parentSquad: 'ops-squad',
104
+ whenToUse: 'When operators need a structured plan.',
105
+ identity: 'Methodical planner.',
106
+ style: 'Concrete, step-driven.',
107
+ focus: 'Operational planning.',
108
+ });
109
+ assert(result.ok === true, 'full proposal should succeed');
110
+ if (!result.ok)
111
+ return;
112
+ const validation = creator.validate('full-agent');
113
+ assert(validation.ok === true, `validation should pass, got errors: ${validation.errors.join(',')}`);
114
+ assert(validation.warnings.length === 0, `no warnings expected, got: ${validation.warnings.join(',')}`);
115
+ console.log('✅ scenario 2: full proposal with valid cross-refs passes validation cleanly');
116
+ }
117
+ finally {
118
+ cleanup(cat.root);
119
+ }
120
+ }
121
+ function scenarioOrphanCrossRefsBecomeWarnings() {
122
+ const cat = tempCatalog();
123
+ try {
124
+ const creator = new AgentCreator_1.AgentCreator({ catalogRoot: cat.agents, skillsCatalogRoot: cat.skills, squadsCatalogRoot: cat.squads });
125
+ const result = creator.create({
126
+ id: 'orphan-agent',
127
+ name: 'Orphan',
128
+ role: 'specialist',
129
+ primarySkills: ['missing-skill'],
130
+ parentSquad: 'missing-squad',
131
+ });
132
+ assert(result.ok === true, 'creation succeeds even with orphan refs (validation surfaces them later)');
133
+ const v = creator.validate('orphan-agent');
134
+ assert(v.ok === true, 'validation passes — orphans are warnings, not errors');
135
+ assert(v.warnings.length === 2, `expected 2 warnings, got ${v.warnings.length}`);
136
+ assert(v.warnings.some((w) => w.includes('missing-skill')), 'warning mentions missing skill');
137
+ assert(v.warnings.some((w) => w.includes('missing-squad')), 'warning mentions missing squad');
138
+ console.log('✅ scenario 3: orphan skill/squad refs become warnings, not errors');
139
+ }
140
+ finally {
141
+ cleanup(cat.root);
142
+ }
143
+ }
144
+ function scenarioInvalidIdRejected() {
145
+ const cat = tempCatalog();
146
+ try {
147
+ const creator = new AgentCreator_1.AgentCreator({ catalogRoot: cat.agents, skillsCatalogRoot: cat.skills, squadsCatalogRoot: cat.squads });
148
+ const result = creator.create({ id: '!invalid id!', name: 'X', role: 'specialist' });
149
+ assert(result.ok === false, 'invalid id should be rejected');
150
+ if (result.ok)
151
+ return;
152
+ assert(result.error === 'invalid_agent_id', `expected invalid_agent_id, got ${result.error}`);
153
+ console.log('✅ scenario 4: invalid id (special chars / spaces) rejected up front');
154
+ }
155
+ finally {
156
+ cleanup(cat.root);
157
+ }
158
+ }
159
+ function scenarioDuplicateAgentRejected() {
160
+ const cat = tempCatalog();
161
+ try {
162
+ const creator = new AgentCreator_1.AgentCreator({ catalogRoot: cat.agents, skillsCatalogRoot: cat.skills, squadsCatalogRoot: cat.squads });
163
+ creator.create({ id: 'dup-test', name: 'Dup', role: 'specialist' });
164
+ const second = creator.create({ id: 'dup-test', name: 'Dup2', role: 'specialist' });
165
+ assert(second.ok === false, 'second create should fail');
166
+ if (second.ok)
167
+ return;
168
+ assert(second.error === 'agent_already_exists', `expected agent_already_exists, got ${second.error}`);
169
+ console.log('✅ scenario 5: duplicate agent rejected without overwriting');
170
+ }
171
+ finally {
172
+ cleanup(cat.root);
173
+ }
174
+ }
175
+ function scenarioListAndAnalyze() {
176
+ const cat = tempCatalog();
177
+ try {
178
+ const creator = new AgentCreator_1.AgentCreator({ catalogRoot: cat.agents, skillsCatalogRoot: cat.skills, squadsCatalogRoot: cat.squads });
179
+ creator.create({ id: 'agent-a', name: 'A', role: 'specialist', status: 'active' });
180
+ creator.create({ id: 'agent-b', name: 'B', role: 'planner', status: 'draft' });
181
+ const all = creator.list();
182
+ assert(all.length === 2, `expected 2 agents, got ${all.length}`);
183
+ const onlyDraft = creator.list({ status: 'draft' });
184
+ assert(onlyDraft.length === 1, 'filter by status=draft returns 1');
185
+ assert(onlyDraft[0].id === 'agent-b', 'correct one returned');
186
+ const analysis = creator.analyze('agent-a');
187
+ assert(analysis !== null, 'analyze finds existing agent');
188
+ assert(analysis.commandCount >= 1, 'at least one command (help fallback) reported');
189
+ assert(analysis.suggestions.length >= 0, 'suggestions array returned (may be empty)');
190
+ console.log('✅ scenario 6: list + analyze report accurate catalog shape');
191
+ }
192
+ finally {
193
+ cleanup(cat.root);
194
+ }
195
+ }
196
+ function scenarioCustomCommandsAndGuardrails() {
197
+ const cat = tempCatalog();
198
+ try {
199
+ const creator = new AgentCreator_1.AgentCreator({ catalogRoot: cat.agents, skillsCatalogRoot: cat.skills, squadsCatalogRoot: cat.squads });
200
+ const result = creator.create({
201
+ id: 'rich-cmds',
202
+ name: 'Rich',
203
+ role: 'specialist',
204
+ commands: [
205
+ { name: 'plan', description: 'Generate a step-by-step plan' },
206
+ { name: 'review', description: 'Review work against criteria' },
207
+ ],
208
+ guardrails: ['Never push without operator approval', 'Always log audit events'],
209
+ });
210
+ assert(result.ok === true, 'create succeeds');
211
+ if (!result.ok)
212
+ return;
213
+ const body = fs.readFileSync(result.filePath, 'utf-8');
214
+ assert(body.includes('name: plan'), 'custom plan command rendered');
215
+ assert(body.includes('name: review'), 'custom review command rendered');
216
+ assert(body.includes('Never push without operator approval'), 'custom guardrail rendered');
217
+ const analysis = creator.analyze('rich-cmds');
218
+ assert(analysis.commandCount === 2, `expected 2 commands counted, got ${analysis.commandCount}`);
219
+ console.log('✅ scenario 7: custom commands + guardrails flow through to AGENT.md');
220
+ }
221
+ finally {
222
+ cleanup(cat.root);
223
+ }
224
+ }
225
+ function main() {
226
+ console.log('🧪 test_agent_creator — authoring pipeline for standalone agents');
227
+ scenarioMinimalProposal();
228
+ scenarioFullProposalWithCrossRefs();
229
+ scenarioOrphanCrossRefsBecomeWarnings();
230
+ scenarioInvalidIdRejected();
231
+ scenarioDuplicateAgentRejected();
232
+ scenarioListAndAnalyze();
233
+ scenarioCustomCommandsAndGuardrails();
234
+ console.log('');
235
+ console.log('TEST_AGENT_CREATOR_OK');
236
+ }
237
+ main();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openlife/cli",
3
- "version": "1.7.7",
3
+ "version": "1.7.10",
4
4
  "description": "OPEN-LIFE Córtex Orquestrador Dual-Core",
5
5
  "main": "dist/index.js",
6
6
  "files": [
@@ -158,8 +158,9 @@
158
158
  "test:forecast-brain-wiring": "npm run build && node dist/test_forecast_brain_wiring.js",
159
159
  "test:status-command": "npm run build && node dist/test_status_command.js",
160
160
  "test:logs-command": "npm run build && node dist/test_logs_command.js",
161
+ "test:agent-creator": "npm run build && node dist/test_agent_creator.js",
161
162
  "pretest:all": "node scripts/clean-test-pollution.js",
162
- "test:all": "npm run build && node dist/test_distribution_installability.js && node dist/test_orchestration_assets_lifecycle.js && node dist/test_openlife_runtime_source_truth.js && node dist/test_openlife_evolution_surface.js && node dist/test_openlife_routing_surface.js && node dist/test_openlife_auto_creator_routing.js && node dist/test_openlife_gatekeeper_routing.js && node dist/test_enterprise_agentic_core.js && node dist/test_admin_teams_networks.js && node dist/test_agent_team_skill_network.js && node dist/test_benchmark_engine.js && node dist/test_cli_service_commands.js && node dist/test_consequence_forecaster.js && node dist/test_conversation_memory.js && node dist/test_create_entities.js && node dist/test_designmd_import_registry.js && node dist/test_designmd_mode.js && node dist/test_designmd_mode_workspace.js && node dist/test_dream_organizer.js && node dist/test_dual_mode.js && node dist/test_governance.js && node dist/test_governance_advanced.js && node dist/test_install_flow.js && node dist/test_job_lifecycle.js && node dist/test_memory_orchestrator.js && node dist/test_memory_promotion.js && node dist/test_memory_retention.js && node dist/test_operating_system.js && node dist/test_optimization_loop.js && node dist/test_outcome_simulator.js && node dist/test_performance_scorecard.js && node dist/test_phase6_board.js && node dist/test_phase6_cadence.js && node dist/test_phase6_ops.js && node dist/test_release_gate.js && node dist/test_reversa_contracts_e2e.js && node dist/test_reversa_export_and_strict.js && node dist/test_reversa_full_execution.js && node dist/test_reversa_lite.js && node dist/test_runtime_policy.js && node dist/test_runtime_probe.js && node dist/test_runtime_registry.js && node dist/test_security_download_guard.js && node dist/test_service_command_surface.js && node dist/test_service_completion_policy.js && node dist/test_service_guardrails_delete.js && node dist/test_sources_import_ref.js && node dist/test_sources_scaffold.js && node dist/test_teammate_learning.js && node dist/test_telegram_delete_guardrail.js && node dist/test_daemon_sigterm.js && node dist/test_ask_exit.js && node dist/test_brain_error_diagnostics.js && node dist/test_cli_doc_parity.js && node dist/test_trigger_basic_auth.js && node dist/test_brain_fallback_chain.js && node dist/test_cli_help_surface.js && node dist/test_cli_diagnostics.js && node dist/test_cli_crud_roundtrip.js && node dist/test_subsystems_routing_governance.js && node dist/test_subsystems_org_state.js && node dist/test_subsystems_promotion_memory_assets.js && node dist/test_phase1_check_exit.js && node dist/test_install_flow_host_validation.js && node dist/test_dist_templates_layout.js && node dist/test_host_installer.js && node dist/test_host_uninstaller.js && node dist/test_install_wizard.js && node dist/test_multi_host_docs_parity.js && node dist/test_host_install_e2e.js && node dist/test_runtime_profile_oauth_only.js && node dist/test_atomic_writer.js && node dist/test_mission_checkpoint.js && node dist/test_workflow_parser.js && node dist/test_workflow_engine.js && node dist/test_workflow_e2e.js && node dist/test_distributed_lock.js && node dist/test_watchdog_heartbeat.js && node dist/test_runtime_health_backoff.js && node dist/test_queue_scheduler.js && node dist/test_squad_skill_creator.js && node dist/test_aiobuilder_cli_parity.js && node dist/test_catalog_quality.js && node dist/test_royal_stack_golden.js && node dist/test_capability_pack_schema.js && node dist/test_capability_genesis_engine.js && node dist/test_workflow_schema_backward_compat.js && node dist/test_service_mode_explicit_only.js && node dist/test_deep_research_capability.js && node dist/test_guided_creator_cli.js && node dist/test_governance_v13_policies.js && node dist/test_gateway_telegram_guardrails.js && node dist/test_cron_manager.js && node dist/test_profile_toolset_mcp.js && node dist/test_squad_skill_design_llm.js && node dist/test_workflow_condition_parser.js && node dist/test_security_download_and_scan.js && node dist/test_host_installers_gemini_codex.js && node dist/test_toolset_enforcement.js && node dist/test_creator_placeholders_completed.js && node dist/test_performance_latency.js && node dist/test_post_mission_evaluation.js && node dist/test_governance_scope_ledger.js && node dist/test_consequence_forecast_brain.js && node dist/test_remote_publish.js && node dist/test_process_sandbox.js && node dist/test_v15_e2e_integration.js && node dist/test_doctor_sandbox_check.js && node dist/test_task_executor_sandbox_optin.js && node dist/test_forecast_brain_wiring.js && node dist/test_status_command.js && node dist/test_logs_command.js",
163
+ "test:all": "npm run build && node dist/test_distribution_installability.js && node dist/test_orchestration_assets_lifecycle.js && node dist/test_openlife_runtime_source_truth.js && node dist/test_openlife_evolution_surface.js && node dist/test_openlife_routing_surface.js && node dist/test_openlife_auto_creator_routing.js && node dist/test_openlife_gatekeeper_routing.js && node dist/test_enterprise_agentic_core.js && node dist/test_admin_teams_networks.js && node dist/test_agent_team_skill_network.js && node dist/test_benchmark_engine.js && node dist/test_cli_service_commands.js && node dist/test_consequence_forecaster.js && node dist/test_conversation_memory.js && node dist/test_create_entities.js && node dist/test_designmd_import_registry.js && node dist/test_designmd_mode.js && node dist/test_designmd_mode_workspace.js && node dist/test_dream_organizer.js && node dist/test_dual_mode.js && node dist/test_governance.js && node dist/test_governance_advanced.js && node dist/test_install_flow.js && node dist/test_job_lifecycle.js && node dist/test_memory_orchestrator.js && node dist/test_memory_promotion.js && node dist/test_memory_retention.js && node dist/test_operating_system.js && node dist/test_optimization_loop.js && node dist/test_outcome_simulator.js && node dist/test_performance_scorecard.js && node dist/test_phase6_board.js && node dist/test_phase6_cadence.js && node dist/test_phase6_ops.js && node dist/test_release_gate.js && node dist/test_reversa_contracts_e2e.js && node dist/test_reversa_export_and_strict.js && node dist/test_reversa_full_execution.js && node dist/test_reversa_lite.js && node dist/test_runtime_policy.js && node dist/test_runtime_probe.js && node dist/test_runtime_registry.js && node dist/test_security_download_guard.js && node dist/test_service_command_surface.js && node dist/test_service_completion_policy.js && node dist/test_service_guardrails_delete.js && node dist/test_sources_import_ref.js && node dist/test_sources_scaffold.js && node dist/test_teammate_learning.js && node dist/test_telegram_delete_guardrail.js && node dist/test_daemon_sigterm.js && node dist/test_ask_exit.js && node dist/test_brain_error_diagnostics.js && node dist/test_cli_doc_parity.js && node dist/test_trigger_basic_auth.js && node dist/test_brain_fallback_chain.js && node dist/test_cli_help_surface.js && node dist/test_cli_diagnostics.js && node dist/test_cli_crud_roundtrip.js && node dist/test_subsystems_routing_governance.js && node dist/test_subsystems_org_state.js && node dist/test_subsystems_promotion_memory_assets.js && node dist/test_phase1_check_exit.js && node dist/test_install_flow_host_validation.js && node dist/test_dist_templates_layout.js && node dist/test_host_installer.js && node dist/test_host_uninstaller.js && node dist/test_install_wizard.js && node dist/test_multi_host_docs_parity.js && node dist/test_host_install_e2e.js && node dist/test_runtime_profile_oauth_only.js && node dist/test_atomic_writer.js && node dist/test_mission_checkpoint.js && node dist/test_workflow_parser.js && node dist/test_workflow_engine.js && node dist/test_workflow_e2e.js && node dist/test_distributed_lock.js && node dist/test_watchdog_heartbeat.js && node dist/test_runtime_health_backoff.js && node dist/test_queue_scheduler.js && node dist/test_squad_skill_creator.js && node dist/test_aiobuilder_cli_parity.js && node dist/test_catalog_quality.js && node dist/test_royal_stack_golden.js && node dist/test_capability_pack_schema.js && node dist/test_capability_genesis_engine.js && node dist/test_workflow_schema_backward_compat.js && node dist/test_service_mode_explicit_only.js && node dist/test_deep_research_capability.js && node dist/test_guided_creator_cli.js && node dist/test_governance_v13_policies.js && node dist/test_gateway_telegram_guardrails.js && node dist/test_cron_manager.js && node dist/test_profile_toolset_mcp.js && node dist/test_squad_skill_design_llm.js && node dist/test_workflow_condition_parser.js && node dist/test_security_download_and_scan.js && node dist/test_host_installers_gemini_codex.js && node dist/test_toolset_enforcement.js && node dist/test_creator_placeholders_completed.js && node dist/test_performance_latency.js && node dist/test_post_mission_evaluation.js && node dist/test_governance_scope_ledger.js && node dist/test_consequence_forecast_brain.js && node dist/test_remote_publish.js && node dist/test_process_sandbox.js && node dist/test_v15_e2e_integration.js && node dist/test_doctor_sandbox_check.js && node dist/test_task_executor_sandbox_optin.js && node dist/test_forecast_brain_wiring.js && node dist/test_status_command.js && node dist/test_logs_command.js && node dist/test_agent_creator.js",
163
164
  "prepublishOnly": "npm run test:all"
164
165
  },
165
166
  "dependencies": {