@jaimevalasek/aioson 1.3.0 → 1.4.0
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 +19 -2
- package/docs/pt/README.md +62 -2
- package/docs/pt/advisor-spec.md +5 -5
- package/docs/pt/agentes-customizados.md +670 -0
- package/docs/pt/agentes.md +111 -13
- package/docs/pt/automacao-squads.md +407 -0
- package/docs/pt/cenarios.md +3 -3
- package/docs/pt/clientes-ai.md +62 -0
- package/docs/pt/comandos-cli.md +167 -17
- package/docs/pt/deyvin.md +115 -0
- package/docs/pt/genome-3.0-spec.md +11 -11
- package/docs/pt/inicio-rapido.md +45 -0
- package/docs/pt/memoria-contexto.md +255 -0
- package/docs/pt/output-strategy-delivery.md +655 -0
- package/docs/pt/profiler-system.md +17 -17
- package/docs/pt/runtime-observability.md +5 -1
- package/docs/pt/skills.md +175 -0
- package/docs/pt/{squad-genoma.md → squad-genome.md} +81 -75
- package/docs/testing/genome-2.0-rollout.md +1 -1
- package/package.json +3 -3
- package/src/agents.js +21 -5
- package/src/backup-provider.js +303 -0
- package/src/cli.js +178 -2
- package/src/commands/agents.js +22 -4
- package/src/commands/backup.js +533 -0
- package/src/commands/cloud.js +17 -17
- package/src/commands/context-pack.js +45 -0
- package/src/commands/implementation-plan.js +340 -0
- package/src/commands/learning.js +134 -0
- package/src/commands/live.js +1583 -0
- package/src/commands/runtime.js +833 -2
- package/src/commands/scan-project.js +288 -24
- package/src/commands/setup-context.js +23 -0
- package/src/commands/skill.js +558 -0
- package/src/commands/squad-agent-create.js +788 -0
- package/src/commands/squad-doctor.js +51 -1
- package/src/commands/squad-investigate.js +261 -0
- package/src/commands/squad-learning.js +209 -0
- package/src/commands/squad-pipeline.js +247 -1
- package/src/commands/squad-plan.js +329 -0
- package/src/commands/squad-status.js +1 -1
- package/src/commands/squad-validate.js +57 -1
- package/src/commands/test-agents.js +6 -1
- package/src/commands/workflow-next.js +8 -1
- package/src/commands/workflow-status.js +250 -0
- package/src/constants.js +80 -16
- package/src/context-memory.js +837 -0
- package/src/context-writer.js +2 -0
- package/src/delivery-runner.js +319 -0
- package/src/genome-files.js +1 -1
- package/src/genome-format.js +1 -1
- package/src/i18n/messages/en.js +206 -7
- package/src/i18n/messages/es.js +123 -6
- package/src/i18n/messages/fr.js +122 -5
- package/src/i18n/messages/pt-BR.js +205 -12
- package/src/installer.js +30 -2
- package/src/lib/genomes/compat.js +1 -1
- package/src/runtime-store.js +780 -42
- package/src/session-handoff.js +77 -0
- package/template/.aioson/agents/analyst.md +36 -9
- package/template/.aioson/agents/architect.md +20 -5
- package/template/.aioson/agents/dev.md +135 -15
- package/template/.aioson/agents/deyvin.md +166 -0
- package/template/.aioson/agents/discovery-design-doc.md +25 -1
- package/template/.aioson/agents/{genoma.md → genome.md} +20 -20
- package/template/.aioson/agents/orache.md +371 -0
- package/template/.aioson/agents/orchestrator.md +37 -2
- package/template/.aioson/agents/pair.md +5 -0
- package/template/.aioson/agents/pm.md +17 -5
- package/template/.aioson/agents/product.md +58 -22
- package/template/.aioson/agents/profiler-enricher.md +1 -1
- package/template/.aioson/agents/profiler-forge.md +9 -9
- package/template/.aioson/agents/profiler-researcher.md +1 -1
- package/template/.aioson/agents/qa.md +17 -5
- package/template/.aioson/agents/setup.md +81 -5
- package/template/.aioson/agents/squad.md +675 -28
- package/template/.aioson/agents/ux-ui.md +277 -34
- package/template/.aioson/config.md +175 -0
- package/template/.aioson/context/spec.md.template +17 -0
- package/template/.aioson/genomes/.gitkeep +0 -0
- package/template/.aioson/installed-skills/.gitkeep +0 -0
- package/template/.aioson/locales/en/agents/analyst.md +26 -4
- package/template/.aioson/locales/en/agents/architect.md +10 -0
- package/template/.aioson/locales/en/agents/dev.md +89 -4
- package/template/.aioson/locales/en/agents/deyvin.md +129 -0
- package/template/.aioson/locales/en/agents/{genoma.md → genome.md} +14 -14
- package/template/.aioson/locales/en/agents/orchestrator.md +36 -2
- package/template/.aioson/locales/en/agents/pair.md +5 -0
- package/template/.aioson/locales/en/agents/pm.md +7 -0
- package/template/.aioson/locales/en/agents/product.md +35 -17
- package/template/.aioson/locales/en/agents/qa.md +7 -0
- package/template/.aioson/locales/en/agents/setup.md +51 -5
- package/template/.aioson/locales/en/agents/squad.md +203 -15
- package/template/.aioson/locales/en/agents/ux-ui.md +375 -35
- package/template/.aioson/locales/es/agents/analyst.md +16 -4
- package/template/.aioson/locales/es/agents/architect.md +10 -0
- package/template/.aioson/locales/es/agents/dev.md +70 -2
- package/template/.aioson/locales/es/agents/deyvin.md +89 -0
- package/template/.aioson/locales/es/agents/{genoma.md → genome.md} +13 -13
- package/template/.aioson/locales/es/agents/orache.md +103 -0
- package/template/.aioson/locales/es/agents/orchestrator.md +36 -2
- package/template/.aioson/locales/es/agents/pair.md +5 -0
- package/template/.aioson/locales/es/agents/pm.md +7 -0
- package/template/.aioson/locales/es/agents/product.md +13 -3
- package/template/.aioson/locales/es/agents/qa.md +7 -0
- package/template/.aioson/locales/es/agents/setup.md +28 -5
- package/template/.aioson/locales/es/agents/squad.md +221 -15
- package/template/.aioson/locales/es/agents/ux-ui.md +26 -25
- package/template/.aioson/locales/fr/agents/analyst.md +16 -4
- package/template/.aioson/locales/fr/agents/architect.md +10 -0
- package/template/.aioson/locales/fr/agents/dev.md +70 -2
- package/template/.aioson/locales/fr/agents/deyvin.md +89 -0
- package/template/.aioson/locales/fr/agents/{genoma.md → genome.md} +7 -7
- package/template/.aioson/locales/fr/agents/orache.md +104 -0
- package/template/.aioson/locales/fr/agents/orchestrator.md +36 -2
- package/template/.aioson/locales/fr/agents/pair.md +5 -0
- package/template/.aioson/locales/fr/agents/pm.md +7 -0
- package/template/.aioson/locales/fr/agents/product.md +13 -3
- package/template/.aioson/locales/fr/agents/qa.md +7 -0
- package/template/.aioson/locales/fr/agents/setup.md +28 -5
- package/template/.aioson/locales/fr/agents/squad.md +216 -10
- package/template/.aioson/locales/fr/agents/ux-ui.md +26 -25
- package/template/.aioson/locales/pt-BR/agents/analyst.md +26 -4
- package/template/.aioson/locales/pt-BR/agents/architect.md +10 -0
- package/template/.aioson/locales/pt-BR/agents/dev.md +93 -4
- package/template/.aioson/locales/pt-BR/agents/deyvin.md +129 -0
- package/template/.aioson/locales/pt-BR/agents/{genoma.md → genome.md} +49 -49
- package/template/.aioson/locales/pt-BR/agents/orache.md +137 -0
- package/template/.aioson/locales/pt-BR/agents/orchestrator.md +36 -2
- package/template/.aioson/locales/pt-BR/agents/pair.md +5 -0
- package/template/.aioson/locales/pt-BR/agents/pm.md +7 -0
- package/template/.aioson/locales/pt-BR/agents/product.md +35 -17
- package/template/.aioson/locales/pt-BR/agents/qa.md +7 -0
- package/template/.aioson/locales/pt-BR/agents/setup.md +51 -5
- package/template/.aioson/locales/pt-BR/agents/squad.md +486 -47
- package/template/.aioson/locales/pt-BR/agents/ux-ui.md +361 -22
- package/template/.aioson/my-agents/.gitkeep +0 -0
- package/template/.aioson/rules/.gitkeep +0 -0
- package/template/.aioson/rules/squad/.gitkeep +0 -0
- package/template/.aioson/rules/squad/README.md +50 -0
- package/template/.aioson/schemas/genome-meta.schema.json +1 -1
- package/template/.aioson/schemas/genome.schema.json +1 -1
- package/template/.aioson/schemas/squad-blueprint.schema.json +11 -0
- package/template/.aioson/schemas/squad-manifest.schema.json +257 -1
- package/template/.aioson/skills/design/cognitive-core-ui/SKILL.md +157 -0
- package/template/.aioson/skills/design/cognitive-core-ui/references/components.md +407 -0
- package/template/.aioson/skills/design/cognitive-core-ui/references/dashboards.md +172 -0
- package/template/.aioson/skills/design/cognitive-core-ui/references/design-tokens.md +490 -0
- package/template/.aioson/skills/design/cognitive-core-ui/references/motion.md +237 -0
- package/template/.aioson/skills/design/cognitive-core-ui/references/patterns.md +289 -0
- package/template/.aioson/skills/design/cognitive-core-ui/references/websites.md +350 -0
- package/template/.aioson/skills/design/interface-design/SKILL.md +47 -0
- package/template/.aioson/skills/design/interface-design/references/components-and-states.md +105 -0
- package/template/.aioson/skills/design/interface-design/references/design-directions.md +101 -0
- package/template/.aioson/skills/design/interface-design/references/handoff-and-quality.md +71 -0
- package/template/.aioson/skills/design/interface-design/references/intent-and-domain.md +74 -0
- package/template/.aioson/skills/design/interface-design/references/tokens-and-depth.md +173 -0
- package/template/.aioson/skills/design/premium-command-center-ui/SKILL.md +62 -0
- package/template/.aioson/skills/design/premium-command-center-ui/references/operations.md +74 -0
- package/template/.aioson/skills/design/premium-command-center-ui/references/patterns.md +116 -0
- package/template/.aioson/skills/design/premium-command-center-ui/references/validation.md +47 -0
- package/template/.aioson/skills/design/premium-command-center-ui/references/visual-system.md +215 -0
- package/template/.aioson/skills/design-system/SKILL.md +92 -0
- package/template/.aioson/skills/design-system/cognitive-core-ui.skill +0 -0
- package/template/.aioson/skills/design-system/components/SKILL.md +274 -0
- package/template/.aioson/skills/design-system/components/SKILL.md:Zone.Identifier +0 -0
- package/template/.aioson/skills/design-system/dashboards/SKILL.md +184 -0
- package/template/.aioson/skills/design-system/dashboards/SKILL.md:Zone.Identifier +0 -0
- package/template/.aioson/skills/design-system/foundations/SKILL.md +250 -0
- package/template/.aioson/skills/design-system/foundations/SKILL.md:Zone.Identifier +0 -0
- package/template/.aioson/skills/design-system/motion/SKILL.md +197 -0
- package/template/.aioson/skills/design-system/motion/SKILL.md:Zone.Identifier +0 -0
- package/template/.aioson/skills/design-system/patterns/SKILL.md +231 -0
- package/template/.aioson/skills/design-system/patterns/SKILL.md:Zone.Identifier +0 -0
- package/template/.aioson/skills/squad/SKILL.md +58 -0
- package/template/.aioson/skills/squad/domains/.gitkeep +0 -0
- package/template/.aioson/skills/squad/formats/.gitkeep +0 -0
- package/template/.aioson/skills/squad/patterns/.gitkeep +0 -0
- package/template/.aioson/skills/squad/references/.gitkeep +0 -0
- package/template/.aioson/tasks/implementation-plan.md +288 -0
- package/template/.aioson/tasks/squad-create.md +1 -1
- package/template/.aioson/tasks/squad-execution-plan.md +279 -0
- package/template/.aioson/tasks/squad-export.md +1 -1
- package/template/.aioson/tasks/squad-investigate.md +44 -0
- package/template/.aioson/tasks/squad-learning-review.md +44 -0
- package/template/.aioson/tasks/squad-output-config.md +177 -0
- package/template/.aioson/tasks/squad-validate.md +1 -1
- package/template/.claude/commands/aioson/agent/deyvin.md +5 -0
- package/template/.claude/commands/aioson/agent/discovery-design-doc.md +5 -0
- package/template/.claude/commands/aioson/agent/genome.md +5 -0
- package/template/.claude/commands/aioson/agent/product.md +5 -0
- package/template/.claude/commands/aioson/agent/profiler-enricher.md +5 -0
- package/template/.claude/commands/aioson/agent/profiler-forge.md +5 -0
- package/template/.claude/commands/aioson/agent/profiler-researcher.md +5 -0
- package/template/.claude/commands/aioson/agent/squad.md +5 -0
- package/template/.gemini/GEMINI.md +2 -0
- package/template/.gemini/commands/aios-deyvin.toml +6 -0
- package/template/.gemini/commands/aios-pair.toml +6 -0
- package/template/AGENTS.md +34 -6
- package/template/CLAUDE.md +31 -4
- package/template/OPENCODE.md +6 -2
- package/template/squad-searches/.gitkeep +0 -0
- package/template/.aioson/skills/static/interface-design.md +0 -372
- package/template/.aioson/skills/static/premium-command-center-ui.md +0 -190
- /package/template/.aioson/{genomas → docs}/.gitkeep +0 -0
- /package/template/.claude/commands/aioson/{analyst.md → agent/analyst.md} +0 -0
- /package/template/.claude/commands/aioson/{architect.md → agent/architect.md} +0 -0
- /package/template/.claude/commands/aioson/{dev.md → agent/dev.md} +0 -0
- /package/template/.claude/commands/aioson/{orchestrator.md → agent/orchestrator.md} +0 -0
- /package/template/.claude/commands/aioson/{pm.md → agent/pm.md} +0 -0
- /package/template/.claude/commands/aioson/{qa.md → agent/qa.md} +0 -0
- /package/template/.claude/commands/aioson/{setup.md → agent/setup.md} +0 -0
- /package/template/.claude/commands/aioson/{ux-ui.md → agent/ux-ui.md} +0 -0
|
@@ -0,0 +1,533 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const fs = require('node:fs/promises');
|
|
4
|
+
const path = require('node:path');
|
|
5
|
+
const {
|
|
6
|
+
resolveRuntimePaths,
|
|
7
|
+
openRuntimeDb,
|
|
8
|
+
runtimeStoreExists
|
|
9
|
+
} = require('../runtime-store');
|
|
10
|
+
const { createProvider, contentHash } = require('../backup-provider');
|
|
11
|
+
|
|
12
|
+
function resolveTargetDir(args) {
|
|
13
|
+
return path.resolve(process.cwd(), args[0] || '.');
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
async function readBackupConfig(targetDir) {
|
|
17
|
+
try {
|
|
18
|
+
const raw = await fs.readFile(path.join(targetDir, '.aioson/install.json'), 'utf8');
|
|
19
|
+
const meta = JSON.parse(raw);
|
|
20
|
+
return meta.backup || null;
|
|
21
|
+
} catch {
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function nowIso() {
|
|
27
|
+
return new Date().toISOString();
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// ── Backup manifest helpers ──
|
|
31
|
+
|
|
32
|
+
function getManifestEntry(db, recordKey) {
|
|
33
|
+
return db.prepare('SELECT * FROM backup_manifest WHERE record_key = ?').get(recordKey);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function upsertManifest(db, recordKey, recordType, hash, remoteKey) {
|
|
37
|
+
db.prepare(`
|
|
38
|
+
INSERT INTO backup_manifest (record_key, record_type, content_hash, backed_up_at, remote_key)
|
|
39
|
+
VALUES (?, ?, ?, ?, ?)
|
|
40
|
+
ON CONFLICT(record_key) DO UPDATE SET
|
|
41
|
+
content_hash = excluded.content_hash,
|
|
42
|
+
backed_up_at = excluded.backed_up_at,
|
|
43
|
+
remote_key = excluded.remote_key
|
|
44
|
+
`).run(recordKey, recordType, hash, nowIso(), remoteKey);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function needsBackup(db, recordKey, currentHash) {
|
|
48
|
+
const existing = getManifestEntry(db, recordKey);
|
|
49
|
+
if (!existing) return true;
|
|
50
|
+
return existing.content_hash !== currentHash;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// ── Table exporters ──
|
|
54
|
+
|
|
55
|
+
function exportTasks(db) {
|
|
56
|
+
return db.prepare('SELECT * FROM tasks ORDER BY created_at').all();
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function exportRuns(db) {
|
|
60
|
+
return db.prepare('SELECT * FROM agent_runs ORDER BY started_at').all();
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function exportAgentEvents(db) {
|
|
64
|
+
return db.prepare('SELECT * FROM agent_events ORDER BY created_at').all();
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function exportExecutionEvents(db, since) {
|
|
68
|
+
if (since) {
|
|
69
|
+
return db.prepare('SELECT * FROM execution_events WHERE created_at >= ? ORDER BY created_at').all(since);
|
|
70
|
+
}
|
|
71
|
+
return db.prepare('SELECT * FROM execution_events ORDER BY created_at').all();
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function exportArtifacts(db) {
|
|
75
|
+
return db.prepare('SELECT * FROM artifacts ORDER BY created_at').all();
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function exportContentItems(db) {
|
|
79
|
+
return db.prepare('SELECT * FROM content_items ORDER BY created_at').all();
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function exportDeliveryLog(db) {
|
|
83
|
+
return db.prepare('SELECT * FROM delivery_log ORDER BY created_at').all();
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// ── Tables filter ──
|
|
87
|
+
|
|
88
|
+
const ALL_BACKUP_TABLES = ['tasks', 'runs', 'agent_events', 'execution_events', 'artifacts', 'content_items', 'delivery_log', 'devlogs'];
|
|
89
|
+
|
|
90
|
+
function parseTables(option) {
|
|
91
|
+
if (!option) return ALL_BACKUP_TABLES;
|
|
92
|
+
const requested = String(option).split(',').map(s => s.trim()).filter(Boolean);
|
|
93
|
+
return requested.length > 0 ? requested : ALL_BACKUP_TABLES;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// ── Main backup command ──
|
|
97
|
+
|
|
98
|
+
async function runRuntimeBackup({ args, options = {}, logger, t }) {
|
|
99
|
+
const targetDir = resolveTargetDir(args);
|
|
100
|
+
const dryRun = Boolean(options['dry-run'] || options.dryRun);
|
|
101
|
+
const force = Boolean(options.force);
|
|
102
|
+
const tables = parseTables(options.tables);
|
|
103
|
+
|
|
104
|
+
// Read backup config
|
|
105
|
+
const config = await readBackupConfig(targetDir);
|
|
106
|
+
if (!config) {
|
|
107
|
+
logger.error('No backup config found in .aioson/install.json. Add a "backup" section with provider settings.');
|
|
108
|
+
return { ok: false, error: 'missing_backup_config' };
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Verify runtime store exists
|
|
112
|
+
if (!(await runtimeStoreExists(targetDir))) {
|
|
113
|
+
const { dbPath } = resolveRuntimePaths(targetDir);
|
|
114
|
+
logger.error(`Runtime store not found at ${dbPath}. Run 'aioson runtime:init' first.`);
|
|
115
|
+
return { ok: false, error: 'store_missing' };
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const provider = createProvider(config);
|
|
119
|
+
const { db, dbPath } = await openRuntimeDb(targetDir);
|
|
120
|
+
|
|
121
|
+
let uploaded = 0;
|
|
122
|
+
let skipped = 0;
|
|
123
|
+
const errors = [];
|
|
124
|
+
|
|
125
|
+
try {
|
|
126
|
+
// ── Tasks ──
|
|
127
|
+
if (tables.includes('tasks')) {
|
|
128
|
+
const tasks = exportTasks(db);
|
|
129
|
+
for (const task of tasks) {
|
|
130
|
+
const key = `tasks/${task.task_key}`;
|
|
131
|
+
const hash = contentHash(task);
|
|
132
|
+
if (!force && !needsBackup(db, `task:${task.task_key}`, hash)) {
|
|
133
|
+
skipped++;
|
|
134
|
+
continue;
|
|
135
|
+
}
|
|
136
|
+
if (!dryRun) {
|
|
137
|
+
try {
|
|
138
|
+
const remoteKey = `${key}.json`;
|
|
139
|
+
await provider.upload(remoteKey, Buffer.from(JSON.stringify(task, null, 2)), 'application/json');
|
|
140
|
+
upsertManifest(db, `task:${task.task_key}`, 'task', hash, remoteKey);
|
|
141
|
+
uploaded++;
|
|
142
|
+
} catch (err) {
|
|
143
|
+
errors.push(`task:${task.task_key}: ${err.message}`);
|
|
144
|
+
}
|
|
145
|
+
} else {
|
|
146
|
+
uploaded++;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
logger.log(` tasks: ${tasks.length} found`);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// ── Agent runs ──
|
|
153
|
+
if (tables.includes('runs')) {
|
|
154
|
+
const runs = exportRuns(db);
|
|
155
|
+
for (const run of runs) {
|
|
156
|
+
const key = `runs/${run.run_key}`;
|
|
157
|
+
const hash = contentHash(run);
|
|
158
|
+
if (!force && !needsBackup(db, `run:${run.run_key}`, hash)) {
|
|
159
|
+
skipped++;
|
|
160
|
+
continue;
|
|
161
|
+
}
|
|
162
|
+
if (!dryRun) {
|
|
163
|
+
try {
|
|
164
|
+
const remoteKey = `${key}.json`;
|
|
165
|
+
await provider.upload(remoteKey, Buffer.from(JSON.stringify(run, null, 2)), 'application/json');
|
|
166
|
+
upsertManifest(db, `run:${run.run_key}`, 'run', hash, remoteKey);
|
|
167
|
+
uploaded++;
|
|
168
|
+
} catch (err) {
|
|
169
|
+
errors.push(`run:${run.run_key}: ${err.message}`);
|
|
170
|
+
}
|
|
171
|
+
} else {
|
|
172
|
+
uploaded++;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
logger.log(` runs: ${runs.length} found`);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// ── Events (batched) ──
|
|
179
|
+
if (tables.includes('agent_events')) {
|
|
180
|
+
const events = exportAgentEvents(db);
|
|
181
|
+
if (events.length > 0) {
|
|
182
|
+
const batchKey = `events/agent-events-${Date.now()}`;
|
|
183
|
+
const hash = contentHash(events);
|
|
184
|
+
if (force || needsBackup(db, 'agent_events:batch', hash)) {
|
|
185
|
+
if (!dryRun) {
|
|
186
|
+
try {
|
|
187
|
+
const remoteKey = `${batchKey}.json`;
|
|
188
|
+
await provider.upload(remoteKey, Buffer.from(JSON.stringify(events, null, 2)), 'application/json');
|
|
189
|
+
upsertManifest(db, 'agent_events:batch', 'agent_events', hash, remoteKey);
|
|
190
|
+
uploaded++;
|
|
191
|
+
} catch (err) {
|
|
192
|
+
errors.push(`agent_events: ${err.message}`);
|
|
193
|
+
}
|
|
194
|
+
} else {
|
|
195
|
+
uploaded++;
|
|
196
|
+
}
|
|
197
|
+
} else {
|
|
198
|
+
skipped++;
|
|
199
|
+
}
|
|
200
|
+
logger.log(` agent_events: ${events.length} found`);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
if (tables.includes('execution_events')) {
|
|
205
|
+
// Get last backup time for incremental
|
|
206
|
+
const lastEntry = getManifestEntry(db, 'execution_events:batch');
|
|
207
|
+
const since = (!force && lastEntry) ? lastEntry.backed_up_at : null;
|
|
208
|
+
const events = exportExecutionEvents(db, since);
|
|
209
|
+
if (events.length > 0) {
|
|
210
|
+
const batchKey = `events/execution-events-${Date.now()}`;
|
|
211
|
+
const hash = contentHash(events);
|
|
212
|
+
if (force || needsBackup(db, 'execution_events:batch', hash)) {
|
|
213
|
+
if (!dryRun) {
|
|
214
|
+
try {
|
|
215
|
+
const remoteKey = `${batchKey}.json`;
|
|
216
|
+
await provider.upload(remoteKey, Buffer.from(JSON.stringify(events, null, 2)), 'application/json');
|
|
217
|
+
upsertManifest(db, 'execution_events:batch', 'execution_events', hash, remoteKey);
|
|
218
|
+
uploaded++;
|
|
219
|
+
} catch (err) {
|
|
220
|
+
errors.push(`execution_events: ${err.message}`);
|
|
221
|
+
}
|
|
222
|
+
} else {
|
|
223
|
+
uploaded++;
|
|
224
|
+
}
|
|
225
|
+
} else {
|
|
226
|
+
skipped++;
|
|
227
|
+
}
|
|
228
|
+
logger.log(` execution_events: ${events.length} found${since ? ' (incremental)' : ''}`);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// ── Artifacts ──
|
|
233
|
+
if (tables.includes('artifacts')) {
|
|
234
|
+
const artifacts = exportArtifacts(db);
|
|
235
|
+
for (const art of artifacts) {
|
|
236
|
+
const key = `artifacts/${art.id}`;
|
|
237
|
+
const hash = contentHash(art);
|
|
238
|
+
if (!force && !needsBackup(db, `artifact:${art.id}`, hash)) {
|
|
239
|
+
skipped++;
|
|
240
|
+
continue;
|
|
241
|
+
}
|
|
242
|
+
if (!dryRun) {
|
|
243
|
+
try {
|
|
244
|
+
// Upload metadata
|
|
245
|
+
const metaKey = `${key}.json`;
|
|
246
|
+
await provider.upload(metaKey, Buffer.from(JSON.stringify(art, null, 2)), 'application/json');
|
|
247
|
+
|
|
248
|
+
// Upload file if it exists and is under 10MB
|
|
249
|
+
if (art.file_path) {
|
|
250
|
+
const absPath = path.isAbsolute(art.file_path)
|
|
251
|
+
? art.file_path
|
|
252
|
+
: path.join(targetDir, art.file_path);
|
|
253
|
+
try {
|
|
254
|
+
const stat = await fs.stat(absPath);
|
|
255
|
+
if (stat.isFile() && stat.size < 10 * 1024 * 1024) {
|
|
256
|
+
const fileBuffer = await fs.readFile(absPath);
|
|
257
|
+
const ext = path.extname(art.file_path) || '';
|
|
258
|
+
await provider.upload(`${key}/file${ext}`, fileBuffer);
|
|
259
|
+
}
|
|
260
|
+
} catch {
|
|
261
|
+
// File may not exist locally — skip
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
upsertManifest(db, `artifact:${art.id}`, 'artifact', hash, metaKey);
|
|
266
|
+
uploaded++;
|
|
267
|
+
} catch (err) {
|
|
268
|
+
errors.push(`artifact:${art.id}: ${err.message}`);
|
|
269
|
+
}
|
|
270
|
+
} else {
|
|
271
|
+
uploaded++;
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
logger.log(` artifacts: ${artifacts.length} found`);
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
// ── Content items ──
|
|
278
|
+
if (tables.includes('content_items')) {
|
|
279
|
+
const items = exportContentItems(db);
|
|
280
|
+
for (const item of items) {
|
|
281
|
+
const key = `content/${item.content_key}`;
|
|
282
|
+
const hash = contentHash(item);
|
|
283
|
+
if (!force && !needsBackup(db, `content:${item.content_key}`, hash)) {
|
|
284
|
+
skipped++;
|
|
285
|
+
continue;
|
|
286
|
+
}
|
|
287
|
+
if (!dryRun) {
|
|
288
|
+
try {
|
|
289
|
+
const remoteKey = `${key}.json`;
|
|
290
|
+
await provider.upload(remoteKey, Buffer.from(JSON.stringify(item, null, 2)), 'application/json');
|
|
291
|
+
upsertManifest(db, `content:${item.content_key}`, 'content', hash, remoteKey);
|
|
292
|
+
uploaded++;
|
|
293
|
+
} catch (err) {
|
|
294
|
+
errors.push(`content:${item.content_key}: ${err.message}`);
|
|
295
|
+
}
|
|
296
|
+
} else {
|
|
297
|
+
uploaded++;
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
logger.log(` content_items: ${items.length} found`);
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
// ── Delivery log ──
|
|
304
|
+
if (tables.includes('delivery_log')) {
|
|
305
|
+
const logs = exportDeliveryLog(db);
|
|
306
|
+
if (logs.length > 0) {
|
|
307
|
+
const hash = contentHash(logs);
|
|
308
|
+
if (force || needsBackup(db, 'delivery_log:batch', hash)) {
|
|
309
|
+
if (!dryRun) {
|
|
310
|
+
try {
|
|
311
|
+
const remoteKey = `delivery/delivery-log-${Date.now()}.json`;
|
|
312
|
+
await provider.upload(remoteKey, Buffer.from(JSON.stringify(logs, null, 2)), 'application/json');
|
|
313
|
+
upsertManifest(db, 'delivery_log:batch', 'delivery_log', hash, remoteKey);
|
|
314
|
+
uploaded++;
|
|
315
|
+
} catch (err) {
|
|
316
|
+
errors.push(`delivery_log: ${err.message}`);
|
|
317
|
+
}
|
|
318
|
+
} else {
|
|
319
|
+
uploaded++;
|
|
320
|
+
}
|
|
321
|
+
} else {
|
|
322
|
+
skipped++;
|
|
323
|
+
}
|
|
324
|
+
logger.log(` delivery_log: ${logs.length} found`);
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
// ── Devlogs (files from aioson-logs/) ──
|
|
329
|
+
if (tables.includes('devlogs')) {
|
|
330
|
+
const logsDir = path.join(targetDir, 'aioson-logs');
|
|
331
|
+
try {
|
|
332
|
+
const entries = await fs.readdir(logsDir);
|
|
333
|
+
const devlogFiles = entries.filter(f => f.startsWith('devlog-') && f.endsWith('.md'));
|
|
334
|
+
for (const file of devlogFiles) {
|
|
335
|
+
const filePath = path.join(logsDir, file);
|
|
336
|
+
const content = await fs.readFile(filePath, 'utf8');
|
|
337
|
+
const hash = contentHash(content);
|
|
338
|
+
if (!force && !needsBackup(db, `devlog:${file}`, hash)) {
|
|
339
|
+
skipped++;
|
|
340
|
+
continue;
|
|
341
|
+
}
|
|
342
|
+
if (!dryRun) {
|
|
343
|
+
try {
|
|
344
|
+
const remoteKey = `devlogs/${file}`;
|
|
345
|
+
await provider.upload(remoteKey, Buffer.from(content, 'utf8'), 'text/markdown');
|
|
346
|
+
upsertManifest(db, `devlog:${file}`, 'devlog', hash, remoteKey);
|
|
347
|
+
uploaded++;
|
|
348
|
+
} catch (err) {
|
|
349
|
+
errors.push(`devlog:${file}: ${err.message}`);
|
|
350
|
+
}
|
|
351
|
+
} else {
|
|
352
|
+
uploaded++;
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
logger.log(` devlogs: ${devlogFiles.length} files found`);
|
|
356
|
+
} catch {
|
|
357
|
+
// No aioson-logs/ — skip
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
// ── Upload backup index ──
|
|
362
|
+
if (!dryRun && uploaded > 0) {
|
|
363
|
+
const index = {
|
|
364
|
+
schemaVersion: 1,
|
|
365
|
+
provider: config.provider,
|
|
366
|
+
lastBackupAt: nowIso(),
|
|
367
|
+
uploaded,
|
|
368
|
+
skipped,
|
|
369
|
+
errors: errors.length,
|
|
370
|
+
tables
|
|
371
|
+
};
|
|
372
|
+
try {
|
|
373
|
+
await provider.upload('backup-index.json', Buffer.from(JSON.stringify(index, null, 2)), 'application/json');
|
|
374
|
+
} catch {
|
|
375
|
+
// Non-fatal
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
const prefix = dryRun ? '[DRY RUN] ' : '';
|
|
380
|
+
logger.log(`\n${prefix}Backup ${errors.length === 0 ? 'complete' : 'completed with errors'}:`);
|
|
381
|
+
logger.log(` Uploaded: ${uploaded}, Skipped (unchanged): ${skipped}`);
|
|
382
|
+
if (errors.length > 0) {
|
|
383
|
+
logger.log(` Errors: ${errors.length}`);
|
|
384
|
+
for (const e of errors.slice(0, 5)) {
|
|
385
|
+
logger.log(` - ${e}`);
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
return {
|
|
390
|
+
ok: errors.length === 0,
|
|
391
|
+
dbPath,
|
|
392
|
+
uploaded,
|
|
393
|
+
skipped,
|
|
394
|
+
errors,
|
|
395
|
+
dryRun,
|
|
396
|
+
timestamp: nowIso()
|
|
397
|
+
};
|
|
398
|
+
} finally {
|
|
399
|
+
db.close();
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
// ── Restore command ──
|
|
404
|
+
|
|
405
|
+
async function runRuntimeRestore({ args, options = {}, logger, t }) {
|
|
406
|
+
const targetDir = resolveTargetDir(args);
|
|
407
|
+
const dryRun = Boolean(options['dry-run'] || options.dryRun);
|
|
408
|
+
const tables = parseTables(options.tables);
|
|
409
|
+
|
|
410
|
+
const config = await readBackupConfig(targetDir);
|
|
411
|
+
if (!config) {
|
|
412
|
+
logger.error('No backup config found in .aioson/install.json.');
|
|
413
|
+
return { ok: false, error: 'missing_backup_config' };
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
const provider = createProvider(config);
|
|
417
|
+
|
|
418
|
+
// Check backup index exists
|
|
419
|
+
const indexBuffer = await provider.download('backup-index.json');
|
|
420
|
+
if (!indexBuffer) {
|
|
421
|
+
logger.error('No backup-index.json found at the remote. Has a backup been created?');
|
|
422
|
+
return { ok: false, error: 'no_backup_index' };
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
const backupIndex = JSON.parse(indexBuffer.toString());
|
|
426
|
+
logger.log(`Found backup from ${backupIndex.lastBackupAt} (schema v${backupIndex.schemaVersion})`);
|
|
427
|
+
|
|
428
|
+
const { db, dbPath } = await openRuntimeDb(targetDir);
|
|
429
|
+
let restored = 0;
|
|
430
|
+
const errors = [];
|
|
431
|
+
|
|
432
|
+
try {
|
|
433
|
+
const restoreTable = async (prefix, tableName, insertFn) => {
|
|
434
|
+
if (!tables.includes(tableName)) return;
|
|
435
|
+
const items = await provider.list(`${prefix}/`);
|
|
436
|
+
for (const item of items) {
|
|
437
|
+
if (!item.key.endsWith('.json')) continue;
|
|
438
|
+
try {
|
|
439
|
+
const buffer = await provider.download(item.key);
|
|
440
|
+
if (!buffer) continue;
|
|
441
|
+
const data = JSON.parse(buffer.toString());
|
|
442
|
+
if (!dryRun) {
|
|
443
|
+
insertFn(data);
|
|
444
|
+
}
|
|
445
|
+
restored++;
|
|
446
|
+
} catch (err) {
|
|
447
|
+
errors.push(`${item.key}: ${err.message}`);
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
logger.log(` ${tableName}: ${items.length} items`);
|
|
451
|
+
};
|
|
452
|
+
|
|
453
|
+
// Restore tasks
|
|
454
|
+
await restoreTable('tasks', 'tasks', (task) => {
|
|
455
|
+
db.prepare(`
|
|
456
|
+
INSERT OR REPLACE INTO tasks (task_key, squad_slug, session_key, title, goal, status, created_by, created_at, updated_at, finished_at)
|
|
457
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
458
|
+
`).run(task.task_key, task.squad_slug, task.session_key, task.title, task.goal, task.status, task.created_by, task.created_at, task.updated_at, task.finished_at);
|
|
459
|
+
});
|
|
460
|
+
|
|
461
|
+
// Restore runs
|
|
462
|
+
await restoreTable('runs', 'runs', (run) => {
|
|
463
|
+
db.prepare(`
|
|
464
|
+
INSERT OR REPLACE INTO agent_runs (run_key, task_key, agent_name, agent_kind, squad_slug, session_key, source, workflow_id, workflow_stage, parent_run_key, title, status, summary, used_skills_json, output_path, started_at, updated_at, finished_at)
|
|
465
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
466
|
+
`).run(run.run_key, run.task_key, run.agent_name, run.agent_kind, run.squad_slug, run.session_key, run.source, run.workflow_id, run.workflow_stage, run.parent_run_key, run.title, run.status, run.summary, run.used_skills_json, run.output_path, run.started_at, run.updated_at, run.finished_at);
|
|
467
|
+
});
|
|
468
|
+
|
|
469
|
+
// Restore artifacts
|
|
470
|
+
await restoreTable('artifacts', 'artifacts', (art) => {
|
|
471
|
+
db.prepare(`
|
|
472
|
+
INSERT OR REPLACE INTO artifacts (id, task_key, run_key, squad_slug, agent_name, kind, title, file_path, created_at)
|
|
473
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
474
|
+
`).run(art.id, art.task_key, art.run_key, art.squad_slug, art.agent_name, art.kind, art.title, art.file_path, art.created_at);
|
|
475
|
+
});
|
|
476
|
+
|
|
477
|
+
// Restore content items
|
|
478
|
+
await restoreTable('content', 'content_items', (item) => {
|
|
479
|
+
db.prepare(`
|
|
480
|
+
INSERT OR REPLACE INTO content_items (content_key, task_key, run_key, squad_slug, session_key, title, content_type, layout_type, status, summary, blueprint_slug, used_skills_json, payload_json, json_path, html_path, created_by_agent, created_at, updated_at)
|
|
481
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
482
|
+
`).run(item.content_key, item.task_key, item.run_key, item.squad_slug, item.session_key, item.title, item.content_type, item.layout_type, item.status, item.summary, item.blueprint_slug, item.used_skills_json, item.payload_json, item.json_path, item.html_path, item.created_by_agent, item.created_at, item.updated_at);
|
|
483
|
+
});
|
|
484
|
+
|
|
485
|
+
// Restore devlog files
|
|
486
|
+
if (tables.includes('devlogs')) {
|
|
487
|
+
const devlogItems = await provider.list('devlogs/');
|
|
488
|
+
const logsDir = path.join(targetDir, 'aioson-logs');
|
|
489
|
+
await fs.mkdir(logsDir, { recursive: true });
|
|
490
|
+
for (const item of devlogItems) {
|
|
491
|
+
if (!item.key.endsWith('.md')) continue;
|
|
492
|
+
try {
|
|
493
|
+
const buffer = await provider.download(item.key);
|
|
494
|
+
if (!buffer) continue;
|
|
495
|
+
const filename = path.basename(item.key);
|
|
496
|
+
if (!dryRun) {
|
|
497
|
+
await fs.writeFile(path.join(logsDir, filename), buffer);
|
|
498
|
+
}
|
|
499
|
+
restored++;
|
|
500
|
+
} catch (err) {
|
|
501
|
+
errors.push(`devlog:${item.key}: ${err.message}`);
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
logger.log(` devlogs: ${devlogItems.length} files`);
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
const prefix = dryRun ? '[DRY RUN] ' : '';
|
|
508
|
+
logger.log(`\n${prefix}Restore ${errors.length === 0 ? 'complete' : 'completed with errors'}:`);
|
|
509
|
+
logger.log(` Restored: ${restored}`);
|
|
510
|
+
if (errors.length > 0) {
|
|
511
|
+
logger.log(` Errors: ${errors.length}`);
|
|
512
|
+
for (const e of errors.slice(0, 5)) {
|
|
513
|
+
logger.log(` - ${e}`);
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
return {
|
|
518
|
+
ok: errors.length === 0,
|
|
519
|
+
dbPath,
|
|
520
|
+
restored,
|
|
521
|
+
errors,
|
|
522
|
+
dryRun,
|
|
523
|
+
backupIndex
|
|
524
|
+
};
|
|
525
|
+
} finally {
|
|
526
|
+
db.close();
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
module.exports = {
|
|
531
|
+
runRuntimeBackup,
|
|
532
|
+
runRuntimeRestore
|
|
533
|
+
};
|
package/src/commands/cloud.js
CHANGED
|
@@ -35,7 +35,7 @@ function squadImportFilePath(projectDir, slug, versionNumber) {
|
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
function genomeImportFilePath(projectDir, slug, versionNumber) {
|
|
38
|
-
const safeSlug = sanitizeSegment(slug, '
|
|
38
|
+
const safeSlug = sanitizeSegment(slug, 'genome');
|
|
39
39
|
const safeVersion = sanitizeSegment(versionNumber, 'latest');
|
|
40
40
|
return path.join(cloudImportsRoot(projectDir), 'genomes', safeSlug, `${safeVersion}.json`);
|
|
41
41
|
}
|
|
@@ -53,7 +53,7 @@ function historyImportFilePath(projectDir, slug, versionNumber) {
|
|
|
53
53
|
}
|
|
54
54
|
|
|
55
55
|
function genomeHistoryImportFilePath(projectDir, slug, versionNumber) {
|
|
56
|
-
const safeSlug = sanitizeSegment(slug, '
|
|
56
|
+
const safeSlug = sanitizeSegment(slug, 'genome');
|
|
57
57
|
const safeVersion = sanitizeSegment(versionNumber, 'latest');
|
|
58
58
|
return path.join(
|
|
59
59
|
cloudImportsRoot(projectDir),
|
|
@@ -73,7 +73,7 @@ function installedManifestPath(projectDir, slug) {
|
|
|
73
73
|
}
|
|
74
74
|
|
|
75
75
|
function installedGenomeManifestPath(projectDir, slug) {
|
|
76
|
-
return path.join(installedRoot(projectDir), 'genomes', sanitizeSegment(slug, '
|
|
76
|
+
return path.join(installedRoot(projectDir), 'genomes', sanitizeSegment(slug, 'genome'), 'manifest.json');
|
|
77
77
|
}
|
|
78
78
|
|
|
79
79
|
function localSquadPackageDir(projectDir, slug) {
|
|
@@ -113,7 +113,7 @@ function localSquadOutputDir(projectDir, slug) {
|
|
|
113
113
|
}
|
|
114
114
|
|
|
115
115
|
function localSquadLogsDir(projectDir, slug) {
|
|
116
|
-
return path.join(projectDir, '
|
|
116
|
+
return path.join(projectDir, 'aioson-logs', sanitizeSegment(slug, 'squad'));
|
|
117
117
|
}
|
|
118
118
|
|
|
119
119
|
function localSquadMediaDir(projectDir, slug) {
|
|
@@ -161,7 +161,7 @@ function localLegacySquadReadinessPath(projectDir, slug) {
|
|
|
161
161
|
}
|
|
162
162
|
|
|
163
163
|
function localGenomeFilePath(projectDir, slug) {
|
|
164
|
-
return path.join(projectDir, '.aioson', '
|
|
164
|
+
return path.join(projectDir, '.aioson', 'genomes', `${sanitizeSegment(slug, 'genome')}.md`);
|
|
165
165
|
}
|
|
166
166
|
|
|
167
167
|
function findPrimaryHeading(markdown, fallback) {
|
|
@@ -428,7 +428,7 @@ function buildLocalSquadManifest(snapshot, agents) {
|
|
|
428
428
|
),
|
|
429
429
|
rules: {
|
|
430
430
|
outputsDir: `output/${slug}`,
|
|
431
|
-
logsDir: `
|
|
431
|
+
logsDir: `aioson-logs/${slug}`,
|
|
432
432
|
mediaDir: `media/${slug}`,
|
|
433
433
|
reviewPolicy: Array.isArray(source?.rules?.reviewPolicy)
|
|
434
434
|
? source.rules.reviewPolicy
|
|
@@ -532,7 +532,7 @@ function buildSquadTextManifest(snapshot, manifest) {
|
|
|
532
532
|
'## Outputs and review',
|
|
533
533
|
`- Drafts: \`output/${manifest.slug}/\``,
|
|
534
534
|
`- Final HTML: \`output/${manifest.slug}/{session-id}.html\``,
|
|
535
|
-
`- Logs: \`
|
|
535
|
+
`- Logs: \`aioson-logs/${manifest.slug}/\``,
|
|
536
536
|
`- Media: \`media/${manifest.slug}/\``,
|
|
537
537
|
`- Package root: \`.aioson/squads/${manifest.slug}/\``,
|
|
538
538
|
`- Design doc: \`.aioson/squads/${manifest.slug}/docs/design-doc.md\``,
|
|
@@ -586,7 +586,7 @@ function buildSquadMetadata(snapshot, options = {}) {
|
|
|
586
586
|
`Templates: ${packageRoot}/templates/`,
|
|
587
587
|
`Docs: ${packageRoot}/docs/`,
|
|
588
588
|
`Output: output/${slug}/`,
|
|
589
|
-
`Logs:
|
|
589
|
+
`Logs: aioson-logs/${slug}/`,
|
|
590
590
|
`Media: media/${slug}/`,
|
|
591
591
|
`DesignDoc: ${packageRoot}/docs/design-doc.md`,
|
|
592
592
|
`Readiness: ${packageRoot}/docs/readiness.md`,
|
|
@@ -602,7 +602,7 @@ function buildSquadMetadata(snapshot, options = {}) {
|
|
|
602
602
|
? snapshot.appliedGenomes.filter((item) => String(item.scopeType || 'SQUAD').toUpperCase() === 'SQUAD')
|
|
603
603
|
: [];
|
|
604
604
|
for (const genome of shared) {
|
|
605
|
-
lines.push(`- .aioson/
|
|
605
|
+
lines.push(`- .aioson/genomes/${sanitizeSegment(genome.genome.slug, 'genome')}.md`);
|
|
606
606
|
}
|
|
607
607
|
|
|
608
608
|
lines.push('', 'AgentGenomes:');
|
|
@@ -614,7 +614,7 @@ function buildSquadMetadata(snapshot, options = {}) {
|
|
|
614
614
|
|
|
615
615
|
for (const genome of scoped) {
|
|
616
616
|
lines.push(
|
|
617
|
-
`- ${normalizeAgentSlug(genome.agentSlug)}: .aioson/
|
|
617
|
+
`- ${normalizeAgentSlug(genome.agentSlug)}: .aioson/genomes/${sanitizeSegment(genome.genome.slug, 'genome')}.md`
|
|
618
618
|
);
|
|
619
619
|
}
|
|
620
620
|
|
|
@@ -898,7 +898,7 @@ async function materializeImportedSquad(projectDir, payload, sourceUrl, force) {
|
|
|
898
898
|
packageDir: `.aioson/squads/${slug}`,
|
|
899
899
|
agentsDir: `.aioson/squads/${slug}/agents`,
|
|
900
900
|
outputDir: `output/${slug}`,
|
|
901
|
-
logsDir: `
|
|
901
|
+
logsDir: `aioson-logs/${slug}`,
|
|
902
902
|
mediaDir: `media/${slug}`,
|
|
903
903
|
latestSessionPath: `output/${slug}/latest.html`
|
|
904
904
|
});
|
|
@@ -1109,7 +1109,7 @@ function buildInstalledGenomeManifest(snapshot, sourceUrl) {
|
|
|
1109
1109
|
}
|
|
1110
1110
|
|
|
1111
1111
|
async function materializeImportedGenome(projectDir, payload, sourceUrl, force) {
|
|
1112
|
-
const slug = sanitizeSegment(payload.genome.slug, '
|
|
1112
|
+
const slug = sanitizeSegment(payload.genome.slug, 'genome');
|
|
1113
1113
|
const genomePath = localGenomeFilePath(projectDir, slug);
|
|
1114
1114
|
const manifestPath = installedGenomeManifestPath(projectDir, slug);
|
|
1115
1115
|
|
|
@@ -1298,7 +1298,7 @@ async function loadLocalGenomeSnapshot(projectDir, slug, options = {}) {
|
|
|
1298
1298
|
genome: {
|
|
1299
1299
|
id: null,
|
|
1300
1300
|
name: genomeName,
|
|
1301
|
-
slug: sanitizeSegment(slug, '
|
|
1301
|
+
slug: sanitizeSegment(slug, 'genome'),
|
|
1302
1302
|
description: options.description ? String(options.description).trim() : firstParagraph(markdown),
|
|
1303
1303
|
visibility: String(options.visibility || 'PRIVATE').toUpperCase(),
|
|
1304
1304
|
status: 'PUBLISHED',
|
|
@@ -1353,7 +1353,7 @@ async function buildAppliedGenomesFromMetadata(projectDir, metadataContent, opti
|
|
|
1353
1353
|
const genomeAbsPath = path.join(projectDir, normalizeRel(genomeRelPath));
|
|
1354
1354
|
const markdown = await fs.readFile(genomeAbsPath, 'utf8').catch(() => null);
|
|
1355
1355
|
if (!markdown) continue;
|
|
1356
|
-
const slug = sanitizeSegment(path.basename(genomeAbsPath, '.md'), '
|
|
1356
|
+
const slug = sanitizeSegment(path.basename(genomeAbsPath, '.md'), 'genome');
|
|
1357
1357
|
items.push({
|
|
1358
1358
|
scopeType: 'SQUAD',
|
|
1359
1359
|
agentSlug: null,
|
|
@@ -1384,7 +1384,7 @@ async function buildAppliedGenomesFromMetadata(projectDir, metadataContent, opti
|
|
|
1384
1384
|
const genomeAbsPath = path.join(projectDir, normalizeRel(entry.genomePath));
|
|
1385
1385
|
const markdown = await fs.readFile(genomeAbsPath, 'utf8').catch(() => null);
|
|
1386
1386
|
if (!markdown) continue;
|
|
1387
|
-
const slug = sanitizeSegment(path.basename(genomeAbsPath, '.md'), '
|
|
1387
|
+
const slug = sanitizeSegment(path.basename(genomeAbsPath, '.md'), 'genome');
|
|
1388
1388
|
items.push({
|
|
1389
1389
|
scopeType: 'AGENT',
|
|
1390
1390
|
agentSlug: entry.agentSlug,
|
|
@@ -1420,7 +1420,7 @@ async function buildAppliedGenomesFromBindings(projectDir, genomeBindings, optio
|
|
|
1420
1420
|
const items = [];
|
|
1421
1421
|
|
|
1422
1422
|
for (const binding of flattened) {
|
|
1423
|
-
const genomeAbsPath = path.join(projectDir, '.aioson', '
|
|
1423
|
+
const genomeAbsPath = path.join(projectDir, '.aioson', 'genomes', `${binding.slug}.md`);
|
|
1424
1424
|
const markdown = await fs.readFile(genomeAbsPath, 'utf8').catch(() => null);
|
|
1425
1425
|
if (!markdown) continue;
|
|
1426
1426
|
|
|
@@ -1477,7 +1477,7 @@ async function loadLocalSquadSnapshot(projectDir, slug, options = {}) {
|
|
|
1477
1477
|
const packageRootRel = `.aioson/squads/${slug}`;
|
|
1478
1478
|
const agentsDirRel = normalizeRel(extractField(content, 'Agents') || `${packageRootRel}/agents`);
|
|
1479
1479
|
const outputDirRel = normalizeRel(extractField(content, 'Output') || `output/${slug}`);
|
|
1480
|
-
const logsDirRel = normalizeRel(extractField(content, 'Logs') || `
|
|
1480
|
+
const logsDirRel = normalizeRel(extractField(content, 'Logs') || `aioson-logs/${slug}`);
|
|
1481
1481
|
const mediaDirRel = normalizeRel(extractField(content, 'Media') || `media/${slug}`);
|
|
1482
1482
|
const agentsDirAbs = path.join(projectDir, agentsDirRel);
|
|
1483
1483
|
const localManifest = (await loadLocalSquadManifest(projectDir, slug)) || {};
|