@adityaaria/agent-os 1.0.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.
Files changed (129) hide show
  1. package/AGENTS.md +41 -0
  2. package/AGENT_OS_BOOTSTRAP.md +29 -0
  3. package/ENTRYPOINT.md +118 -0
  4. package/LICENSE +21 -0
  5. package/README.md +230 -0
  6. package/adapters/antigravity/README.md +9 -0
  7. package/adapters/antigravity/plugin.json +13 -0
  8. package/adapters/claude/CLAUDE.md +16 -0
  9. package/adapters/claude/README.md +10 -0
  10. package/adapters/codex/README.md +20 -0
  11. package/adapters/cursor/README.md +9 -0
  12. package/adapters/cursor/agent-os.rules.md +18 -0
  13. package/bin/agent-os.mjs +98 -0
  14. package/core/AUTO_PROJECT_DETECTOR.md +99 -0
  15. package/core/COMPLIANCE_GATE.md +19 -0
  16. package/core/FRAMEWORK_AUDITOR.md +35 -0
  17. package/core/KNOWLEDGE_REGENERATOR.md +30 -0
  18. package/core/KNOWLEDGE_VALIDATOR.md +29 -0
  19. package/core/PROJECT_CONTEXT_STANDARD.md +19 -0
  20. package/core/QUALITY_GATES.md +42 -0
  21. package/core/REPORTING_STANDARD.md +47 -0
  22. package/core/SKILL_ORCHESTRATOR.md +63 -0
  23. package/core/TASK_ROUTER.md +33 -0
  24. package/core/TRACEABILITY_STANDARD.md +40 -0
  25. package/package.json +28 -0
  26. package/scripts/install.mjs +690 -0
  27. package/scripts/lib/cli-utils.mjs +148 -0
  28. package/scripts/lib/run-utils.mjs +185 -0
  29. package/scripts/lib/telegram-audit-log.mjs +50 -0
  30. package/scripts/lib/telegram-bot-utils.mjs +413 -0
  31. package/scripts/lib/telegram-utils.mjs +127 -0
  32. package/scripts/orchestrate.mjs +230 -0
  33. package/scripts/quality-static.mjs +19 -0
  34. package/scripts/report-export.mjs +86 -0
  35. package/scripts/report-notify.mjs +169 -0
  36. package/scripts/run-execution.mjs +83 -0
  37. package/scripts/run-list.mjs +44 -0
  38. package/scripts/run-status.mjs +38 -0
  39. package/scripts/run-step.mjs +173 -0
  40. package/scripts/setup-wizard.mjs +116 -0
  41. package/scripts/sync-runtime.mjs +87 -0
  42. package/scripts/telegram-bot.mjs +88 -0
  43. package/scripts/telegram-check.mjs +94 -0
  44. package/scripts/telegram-poll.mjs +176 -0
  45. package/scripts/validate-framework.mjs +290 -0
  46. package/skills/api-contract-audit/SKILL.md +26 -0
  47. package/skills/api-contract-audit/checklist.md +16 -0
  48. package/skills/api-contract-audit/examples.md +3 -0
  49. package/skills/api-contract-audit/report-template.md +39 -0
  50. package/skills/api-contract-audit/workflow.md +15 -0
  51. package/skills/audit/SKILL.md +28 -0
  52. package/skills/audit/checklist.md +18 -0
  53. package/skills/audit/examples.md +26 -0
  54. package/skills/audit/report-template.md +39 -0
  55. package/skills/audit/workflow.md +15 -0
  56. package/skills/bug-fix/SKILL.md +25 -0
  57. package/skills/bug-fix/checklist.md +18 -0
  58. package/skills/bug-fix/examples.md +26 -0
  59. package/skills/bug-fix/report-template.md +39 -0
  60. package/skills/bug-fix/workflow.md +10 -0
  61. package/skills/database-impact-analysis/SKILL.md +27 -0
  62. package/skills/database-impact-analysis/checklist.md +16 -0
  63. package/skills/database-impact-analysis/examples.md +3 -0
  64. package/skills/database-impact-analysis/report-template.md +39 -0
  65. package/skills/database-impact-analysis/workflow.md +14 -0
  66. package/skills/enhancement/SKILL.md +27 -0
  67. package/skills/enhancement/checklist.md +19 -0
  68. package/skills/enhancement/examples.md +26 -0
  69. package/skills/enhancement/report-template.md +39 -0
  70. package/skills/enhancement/workflow.md +10 -0
  71. package/skills/enterprise-certification/SKILL.md +19 -0
  72. package/skills/enterprise-certification/checklist.md +17 -0
  73. package/skills/enterprise-certification/report-template.md +39 -0
  74. package/skills/enterprise-certification/workflow.md +14 -0
  75. package/skills/knowledge-evolution/SKILL.md +23 -0
  76. package/skills/knowledge-evolution/checklist.md +17 -0
  77. package/skills/knowledge-evolution/report-template.md +39 -0
  78. package/skills/knowledge-evolution/workflow.md +14 -0
  79. package/skills/new-page/SKILL.md +26 -0
  80. package/skills/new-page/checklist.md +21 -0
  81. package/skills/new-page/examples.md +26 -0
  82. package/skills/new-page/report-template.md +39 -0
  83. package/skills/new-page/workflow.md +10 -0
  84. package/skills/project-onboarding/SKILL.md +27 -0
  85. package/skills/project-onboarding/checklist.md +18 -0
  86. package/skills/project-onboarding/examples.md +26 -0
  87. package/skills/project-onboarding/report-template.md +39 -0
  88. package/skills/project-onboarding/workflow.md +9 -0
  89. package/skills/release-readiness/SKILL.md +27 -0
  90. package/skills/release-readiness/checklist.md +16 -0
  91. package/skills/release-readiness/examples.md +3 -0
  92. package/skills/release-readiness/report-template.md +39 -0
  93. package/skills/release-readiness/workflow.md +14 -0
  94. package/skills/repository-health/SKILL.md +26 -0
  95. package/skills/repository-health/checklist.md +20 -0
  96. package/skills/repository-health/report-template.md +39 -0
  97. package/skills/repository-health/workflow.md +14 -0
  98. package/skills/selenium-e2e/SKILL.md +83 -0
  99. package/skills/selenium-e2e/checklist.md +29 -0
  100. package/skills/selenium-e2e/examples.md +26 -0
  101. package/skills/selenium-e2e/report-template.md +39 -0
  102. package/skills/selenium-e2e/workflow.md +9 -0
  103. package/skills/self-audit/SKILL.md +19 -0
  104. package/skills/self-audit/checklist.md +14 -0
  105. package/skills/self-audit/report-template.md +39 -0
  106. package/skills/self-audit/workflow.md +11 -0
  107. package/skills/traceability-analysis/SKILL.md +25 -0
  108. package/skills/traceability-analysis/checklist.md +17 -0
  109. package/skills/traceability-analysis/examples.md +3 -0
  110. package/skills/traceability-analysis/report-template.md +39 -0
  111. package/skills/traceability-analysis/workflow.md +17 -0
  112. package/templates/API_RULES.md +20 -0
  113. package/templates/ARCHITECTURE.md +20 -0
  114. package/templates/BUSINESS_FLOW.md +20 -0
  115. package/templates/COMMANDS.md +20 -0
  116. package/templates/DATABASE_RULES.md +20 -0
  117. package/templates/DEPENDENCY_MAP.md +20 -0
  118. package/templates/DEPLOYMENT_RULES.md +20 -0
  119. package/templates/DOMAIN_MODEL.md +20 -0
  120. package/templates/FE_BE_TRACEABILITY.md +20 -0
  121. package/templates/KNOWN_LIMITATIONS.md +20 -0
  122. package/templates/MODULE_CATALOG.md +20 -0
  123. package/templates/PROJECT_PROFILE.md +20 -0
  124. package/templates/RISK_REGISTER.md +20 -0
  125. package/templates/SECURITY_RULES.md +20 -0
  126. package/templates/TECHNICAL_DEBT.md +20 -0
  127. package/templates/TECH_STACK.md +20 -0
  128. package/templates/TESTING_RULES.md +47 -0
  129. package/templates/UI_UX_RULES.md +20 -0
@@ -0,0 +1,230 @@
1
+ #!/usr/bin/env node
2
+ import fs from 'node:fs';
3
+ import path from 'node:path';
4
+ import { fileURLToPath } from 'node:url';
5
+ import { renderReport } from './lib/run-utils.mjs';
6
+ import { wantsHelp, showHelp } from './lib/cli-utils.mjs';
7
+
8
+ if (wantsHelp(process.argv)) {
9
+ showHelp({
10
+ command: 'orchestrate',
11
+ description: 'Create deterministic execution plans from prompts',
12
+ usage: [
13
+ 'agent-os orchestrate "<TRIGGER>: <description>"',
14
+ 'agent-os orchestrate --run-root <dir> "<TRIGGER>: <description>"'
15
+ ],
16
+ required: [
17
+ { flag: '<prompt>', desc: 'Trigger prompt (e.g., "BUG: Fix login", "ENHANCEMENT: Add CSV export")' }
18
+ ],
19
+ options: [
20
+ { flag: '--root <dir>', desc: 'Agent OS source root', default: '(auto-detected)' },
21
+ { flag: '--chain <skills>', desc: 'Explicit skill chain (comma-separated)' },
22
+ { flag: '--write-report <file>', desc: 'Write master report stub to file' },
23
+ { flag: '--run-root <dir>', desc: 'Create run directory under this root' },
24
+ { flag: '--run-id <id>', desc: 'Explicit run ID' }
25
+ ],
26
+ examples: [
27
+ 'agent-os orchestrate "BUG: Fix the login redirect"',
28
+ 'agent-os orchestrate --run-root .agent-os/runs "ENHANCEMENT: Add CSV export"',
29
+ 'agent-os orchestrate --write-report reports/master.md "AUDIT: Review auth module"'
30
+ ]
31
+ });
32
+ }
33
+
34
+ const __filename = fileURLToPath(import.meta.url);
35
+ const defaultRepoRoot = path.resolve(path.dirname(__filename), '..');
36
+ const args = process.argv.slice(2);
37
+
38
+ function takeOption(name) {
39
+ const index = args.indexOf(name);
40
+ if (index === -1) return null;
41
+ const value = args[index + 1] ?? null;
42
+ args.splice(index, 2);
43
+ return value;
44
+ }
45
+
46
+ const root = path.resolve(process.cwd(), takeOption('--root') ?? defaultRepoRoot);
47
+ const explicitChain = takeOption('--chain');
48
+ const reportOutputPath = takeOption('--write-report');
49
+ const runRoot = takeOption('--run-root');
50
+ const requestedRunId = takeOption('--run-id');
51
+ const prompt = args.join(' ').trim();
52
+
53
+ const reportSections = [
54
+ 'Executive Summary',
55
+ 'Scope',
56
+ 'Knowledge Confidence',
57
+ 'Knowledge Classification',
58
+ 'Traceability Matrix',
59
+ 'Evidence',
60
+ 'Root Cause',
61
+ 'Impact',
62
+ 'Recommendation',
63
+ 'Quality Gate',
64
+ 'Enterprise Readiness',
65
+ 'Final Decision'
66
+ ];
67
+
68
+ const triggerMap = [
69
+ { trigger: 'ANALYZE PROJECT', skill: 'project-onboarding', pattern: /^ANALYZE PROJECT:/i, traceability: false },
70
+ { trigger: 'AUDIT FRAMEWORK', skill: 'self-audit', pattern: /^AUDIT FRAMEWORK$/i, traceability: false },
71
+ { trigger: 'BUG', skill: 'bug-fix', pattern: /^BUG:/i },
72
+ { trigger: 'ENHANCEMENT', skill: 'enhancement', pattern: /^ENHANCEMENT:/i },
73
+ { trigger: 'NEW PAGE', skill: 'new-page', pattern: /^NEW PAGE:/i },
74
+ { trigger: 'AUDIT', skill: 'audit', pattern: /^AUDIT:/i },
75
+ { trigger: 'TEST', skill: 'selenium-e2e', pattern: /^TEST:/i }
76
+ ];
77
+
78
+ function detectPrimarySkill(input) {
79
+ const matched = triggerMap.find((item) => item.pattern.test(input));
80
+ if (!matched) {
81
+ return { trigger: 'UNKNOWN', skill: null, traceability: true };
82
+ }
83
+ if (matched.trigger === 'AUDIT' && /\b(agent os|framework)\b/i.test(input)) {
84
+ return { trigger: 'AUDIT', skill: 'self-audit', traceability: false };
85
+ }
86
+ return {
87
+ trigger: matched.trigger,
88
+ skill: matched.skill,
89
+ traceability: matched.traceability !== false
90
+ };
91
+ }
92
+
93
+ function detectDependentSkills(input) {
94
+ const normalized = input.toLowerCase();
95
+ const dependents = [];
96
+
97
+ if (/\baudit\b|\breview\b|\binspect\b/.test(normalized)) {
98
+ dependents.push('audit');
99
+ }
100
+
101
+ if (/\be2e\b|\bselenium\b|\btest\b|\btests\b/.test(normalized)) {
102
+ dependents.push('selenium-e2e');
103
+ }
104
+
105
+ return dependents;
106
+ }
107
+
108
+ function unique(items) {
109
+ return [...new Set(items)];
110
+ }
111
+
112
+ function skillExists(skill) {
113
+ return {
114
+ source: fs.existsSync(path.join(root, 'skills', skill, 'SKILL.md')),
115
+ runtime: fs.existsSync(path.join(root, '.agent-os', 'skills', skill, 'SKILL.md'))
116
+ };
117
+ }
118
+
119
+ function validatePlan(trigger, skillChain) {
120
+ const errors = [];
121
+ const warnings = [];
122
+
123
+ if (trigger === 'UNKNOWN') {
124
+ errors.push('Unsupported task trigger. Expected ANALYZE PROJECT, AUDIT FRAMEWORK, BUG, ENHANCEMENT, NEW PAGE, AUDIT, or TEST.');
125
+ }
126
+
127
+ for (const skill of skillChain) {
128
+ const exists = skillExists(skill);
129
+ if (!exists.source) errors.push(`Missing source skill: ${skill}`);
130
+ if (!exists.runtime) errors.push(`Missing runtime skill: ${skill}`);
131
+ }
132
+
133
+ const traceabilityIndex = skillChain.indexOf('traceability-analysis');
134
+ for (const skill of ['bug-fix', 'enhancement', 'new-page', 'audit', 'selenium-e2e']) {
135
+ const index = skillChain.indexOf(skill);
136
+ if (index !== -1 && (traceabilityIndex === -1 || traceabilityIndex > index)) {
137
+ errors.push(`traceability-analysis must run before ${skill}`);
138
+ }
139
+ }
140
+
141
+ return {
142
+ status: errors.length === 0 ? 'PASS' : 'FAIL',
143
+ errors,
144
+ warnings
145
+ };
146
+ }
147
+
148
+ function buildPlan(input) {
149
+ const primary = detectPrimarySkill(input);
150
+ const skillChain = explicitChain
151
+ ? explicitChain.split(',').map((skill) => skill.trim()).filter(Boolean)
152
+ : unique([
153
+ primary.traceability ? 'traceability-analysis' : null,
154
+ primary.skill,
155
+ ...(primary.traceability ? detectDependentSkills(input) : [])
156
+ ].filter(Boolean));
157
+ const validation = validatePlan(primary.trigger, skillChain);
158
+
159
+ return {
160
+ mode: 'sequential',
161
+ trigger: primary.trigger,
162
+ prompt: input,
163
+ skillChain,
164
+ validation,
165
+ executionPlan: skillChain.map((skill, index) => ({
166
+ step: index + 1,
167
+ skill,
168
+ status: 'pending',
169
+ dependsOn: index === 0 ? [] : [skillChain[index - 1]]
170
+ })),
171
+ masterReport: {
172
+ format: 'Agent OS Master Execution Report',
173
+ sections: reportSections
174
+ }
175
+ };
176
+ }
177
+
178
+ function timestampRunId() {
179
+ return new Date().toISOString().replace(/[:.]/g, '-');
180
+ }
181
+
182
+ function writeReport(outputPath, plan) {
183
+ const absolutePath = path.resolve(process.cwd(), outputPath);
184
+ fs.mkdirSync(path.dirname(absolutePath), { recursive: true });
185
+ fs.writeFileSync(absolutePath, renderReport(plan));
186
+ }
187
+
188
+ function createRun(baseDir, runId, plan) {
189
+ const id = runId || timestampRunId();
190
+ const runDir = path.resolve(process.cwd(), baseDir, id);
191
+ const runPlan = {
192
+ ...plan,
193
+ run: {
194
+ id,
195
+ directory: runDir,
196
+ status: 'created'
197
+ }
198
+ };
199
+
200
+ fs.mkdirSync(runDir, { recursive: true });
201
+ fs.writeFileSync(path.join(runDir, 'plan.json'), JSON.stringify(runPlan, null, 2) + '\n');
202
+ fs.writeFileSync(path.join(runDir, 'steps.json'), JSON.stringify(runPlan.executionPlan, null, 2) + '\n');
203
+ fs.writeFileSync(path.join(runDir, 'master-report.md'), renderReport(runPlan));
204
+ return runPlan;
205
+ }
206
+
207
+ if (!prompt) {
208
+ console.error('✗ ERROR [orchestrate]: No task prompt provided.');
209
+ console.error(' → Suggestion: agent-os orchestrate "BUG: describe the issue here"');
210
+ process.exit(1);
211
+ }
212
+
213
+ const plan = buildPlan(prompt);
214
+
215
+ // Inject entrypoint status from pre-flight check
216
+ if (process.env.AGENT_OS_ENTRYPOINT_MISSING === 'true') {
217
+ plan.entrypoint_missing = true;
218
+ } else if (process.env.AGENT_OS_ENTRYPOINT_PATH) {
219
+ plan.entrypoint_path = process.env.AGENT_OS_ENTRYPOINT_PATH;
220
+ }
221
+
222
+ let outputPlan = plan;
223
+ if (reportOutputPath && plan.validation.status === 'PASS') {
224
+ writeReport(reportOutputPath, plan);
225
+ }
226
+ if (runRoot && plan.validation.status === 'PASS') {
227
+ outputPlan = createRun(runRoot, requestedRunId, plan);
228
+ }
229
+ console.log(JSON.stringify(outputPlan, null, 2));
230
+ process.exit(outputPlan.validation.status === 'PASS' ? 0 : 1);
@@ -0,0 +1,19 @@
1
+ #!/usr/bin/env node
2
+ import { spawnSync } from 'node:child_process';
3
+
4
+ function run(command, args) {
5
+ const result = spawnSync(command, args, {
6
+ encoding: 'utf8',
7
+ stdio: ['ignore', 'pipe', 'pipe']
8
+ });
9
+
10
+ if (result.status !== 0) {
11
+ if (result.stdout) process.stdout.write(result.stdout);
12
+ if (result.stderr) process.stderr.write(result.stderr);
13
+ process.exit(result.status ?? 1);
14
+ }
15
+ }
16
+
17
+ run('git', ['diff', '--check']);
18
+
19
+ console.log('Static quality checks passed.');
@@ -0,0 +1,86 @@
1
+ #!/usr/bin/env node
2
+ import fs from 'node:fs';
3
+ import path from 'node:path';
4
+ import { assertEnabledChannel, collectRun, collectRuns, loadReportChannel, renderRunSummariesCsv } from './lib/run-utils.mjs';
5
+ import { createCli, fail, failAll, showHelp, wantsHelp } from './lib/cli-utils.mjs';
6
+
7
+ const { takeOption } = createCli(process.argv.slice(2));
8
+
9
+ if (wantsHelp(process.argv)) {
10
+ showHelp({
11
+ command: 'report-export',
12
+ description: 'Export run reports as JSON or CSV',
13
+ usage: [
14
+ 'agent-os report-export --run-dir <dir> --output <file> [options]',
15
+ 'agent-os report-export --run-root <dir> --output <file> [options]'
16
+ ],
17
+ required: [
18
+ { flag: '--run-dir <dir> | --run-root <dir>', desc: 'Single run directory or runs root' },
19
+ { flag: '--output <file>', desc: 'Output file path' }
20
+ ],
21
+ options: [
22
+ { flag: '--format <json|csv>', desc: 'Output format', default: 'json' },
23
+ { flag: '--channel-config <file>', desc: 'Channel config file (reads format/output from channel)' },
24
+ { flag: '--channel <name>', desc: 'Channel name' }
25
+ ],
26
+ examples: [
27
+ 'agent-os report-export --run-root .agent-os/runs --output reports/runs.json',
28
+ 'agent-os report-export --run-dir .agent-os/runs/my-run --output report.csv --format csv',
29
+ 'agent-os report-export --run-root .agent-os/runs --channel-config .agent-os/project/report-channels.json --channel spreadsheet'
30
+ ]
31
+ });
32
+ }
33
+
34
+ const runDir = takeOption('--run-dir');
35
+ const runRoot = takeOption('--run-root');
36
+ const channelConfig = takeOption('--channel-config');
37
+ const channelName = takeOption('--channel');
38
+ let format = takeOption('--format') ?? null;
39
+ let output = takeOption('--output');
40
+
41
+ const errors = [];
42
+ if (!runDir && !runRoot) errors.push('Missing --run-dir <dir> or --run-root <dir>.');
43
+ if (runDir && runRoot) errors.push('Use either --run-dir or --run-root, not both.');
44
+ if (channelName && !channelConfig) errors.push('Missing --channel-config <file> when using --channel.');
45
+ failAll(errors, 'agent-os report-export --run-root .agent-os/runs --output reports/runs.json', 'report-export');
46
+
47
+ let outputBaseDir = process.cwd();
48
+ if (channelConfig) {
49
+ if (channelName) {
50
+ try {
51
+ const channelContext = loadReportChannel(channelConfig, channelName);
52
+ assertEnabledChannel(channelContext);
53
+ outputBaseDir = channelContext.outputBaseDir;
54
+ format = format ?? channelContext.channel.format;
55
+ output = output ?? channelContext.channel.output;
56
+ } catch (err) {
57
+ fail(err.message);
58
+ }
59
+ }
60
+ }
61
+
62
+ format = format ?? 'json';
63
+
64
+ if (!['json', 'csv'].includes(format)) {
65
+ fail(`Unsupported format: ${format}. Expected json or csv.`);
66
+ }
67
+
68
+ if (!output) {
69
+ fail('Missing required --output <file>.');
70
+ }
71
+
72
+ let payload;
73
+ try {
74
+ payload = runDir ? collectRun(runDir) : collectRuns(runRoot);
75
+ } catch (err) {
76
+ fail(err.message);
77
+ }
78
+ const body = format === 'csv'
79
+ ? renderRunSummariesCsv(payload)
80
+ : `${JSON.stringify(payload, null, 2)}\n`;
81
+ const outputPath = path.resolve(outputBaseDir, output);
82
+
83
+ fs.mkdirSync(path.dirname(outputPath), { recursive: true });
84
+ fs.writeFileSync(outputPath, body);
85
+ if (channelName) console.log(`Channel: ${channelName}`);
86
+ console.log(`Exported report: ${outputPath}`);
@@ -0,0 +1,169 @@
1
+ #!/usr/bin/env node
2
+ import fs from 'node:fs';
3
+ import path from 'node:path';
4
+ import { assertEnabledChannel, collectRun, collectRuns, loadReportChannel } from './lib/run-utils.mjs';
5
+ import { escapeTelegramMarkdown } from './lib/telegram-utils.mjs';
6
+ import { createCli, fail, failAll, resolveDefault, showHelp, wantsHelp } from './lib/cli-utils.mjs';
7
+
8
+ const { hasFlag, takeOption } = createCli(process.argv.slice(2));
9
+
10
+ if (wantsHelp(process.argv)) {
11
+ showHelp({
12
+ command: 'report-notify',
13
+ description: 'Send run notifications via configured channels',
14
+ usage: [
15
+ 'agent-os report-notify --run-dir <dir> --dry-run [options]',
16
+ 'agent-os report-notify --run-root <dir> --send [options]'
17
+ ],
18
+ required: [
19
+ { flag: '--run-dir <dir> | --run-root <dir>', desc: 'Single run directory or runs root' },
20
+ { flag: '--send | --dry-run', desc: 'Send notification or write payload to file' }
21
+ ],
22
+ options: [
23
+ { flag: '--channel-config <file>', desc: 'Channel config file', default: '.agent-os/project/report-channels.json' },
24
+ { flag: '--channel <name>', desc: 'Channel name', default: 'telegram' },
25
+ { flag: '--output <file>', desc: 'Override output path' }
26
+ ],
27
+ examples: [
28
+ 'agent-os report-notify --run-root .agent-os/runs --dry-run',
29
+ 'agent-os report-notify --run-dir .agent-os/runs/my-run --send'
30
+ ]
31
+ });
32
+ }
33
+
34
+ function renderTelegramText(runs, event) {
35
+ const rows = Array.isArray(runs) ? runs : [runs];
36
+ const lines = [];
37
+ if (event) {
38
+ lines.push(`🚨 *Agent OS Lifecycle Alert: ${event.toUpperCase()}*`);
39
+ } else {
40
+ lines.push('*Agent OS Run Report*');
41
+ }
42
+ for (const run of rows) {
43
+ lines.push(`\n📅 *Run ID*: \`${escapeTelegramMarkdown(run.runId)}\``);
44
+ lines.push(`📊 *Status*: *${run.status.toUpperCase()}* (${run.counts.passed}/${run.total} passed, ${run.counts.failed} failed, ${run.counts.blocked} blocked)`);
45
+ if (run.plan) {
46
+ lines.push(`🎯 *Trigger*: ${escapeTelegramMarkdown(run.plan.trigger)}`);
47
+ lines.push(`📝 *Prompt*: _${escapeTelegramMarkdown(run.plan.prompt)}_`);
48
+ }
49
+ if (run.steps && run.steps.length > 0) {
50
+ lines.push('\n*Execution Steps:*');
51
+ run.steps.forEach(step => {
52
+ const icon = step.status === 'passed' ? '✅' : step.status === 'failed' ? '❌' : step.status === 'running' ? '⏳' : step.status === 'blocked' ? '🚧' : '⏳';
53
+ lines.push(`${icon} Step ${step.step}: \`${escapeTelegramMarkdown(step.skill)}\` (${step.status})`);
54
+ });
55
+ }
56
+ if (run.reportDetails && run.reportDetails.evidence && run.reportDetails.evidence !== 'N/A. Reason: Skills were not executed by this stub.') {
57
+ lines.push(`\n🔎 *Test Evidence:*`);
58
+ lines.push(`${run.reportDetails.evidence}`);
59
+ }
60
+ }
61
+ return lines.join('\n');
62
+ }
63
+
64
+ const runDir = takeOption('--run-dir');
65
+ const runRoot = takeOption('--run-root');
66
+ const channelConfig = takeOption('--channel-config') ?? resolveDefault(null, '.agent-os/project/report-channels.json');
67
+ const channelName = takeOption('--channel') ?? 'telegram';
68
+ const outputOverride = takeOption('--output');
69
+ const event = takeOption('--event');
70
+ const dryRun = hasFlag('--dry-run');
71
+ const send = hasFlag('--send');
72
+
73
+ const errors = [];
74
+ if ((dryRun && send) || (!dryRun && !send)) errors.push('Use either --dry-run or --send (exactly one required).');
75
+ if (!runDir && !runRoot) errors.push('Missing --run-dir <dir> or --run-root <dir>.');
76
+ if (runDir && runRoot) errors.push('Use either --run-dir or --run-root, not both.');
77
+ if (!channelConfig) errors.push('Missing --channel-config <file> (no default found at .agent-os/project/report-channels.json).');
78
+ failAll(errors, 'agent-os report-notify --run-root .agent-os/runs --channel telegram --dry-run', 'report-notify');
79
+
80
+ let channelContext;
81
+ try {
82
+ channelContext = loadReportChannel(channelConfig, channelName);
83
+ assertEnabledChannel(channelContext);
84
+ } catch (err) {
85
+ fail(err.message);
86
+ }
87
+
88
+ const channel = channelContext.channel;
89
+ if (channel.type !== 'telegram') {
90
+ fail(`Report channel is not a telegram channel: ${channelName}`);
91
+ }
92
+
93
+ let runs;
94
+ try {
95
+ runs = runDir ? collectRun(runDir) : collectRuns(runRoot);
96
+ } catch (err) {
97
+ fail(err.message);
98
+ }
99
+ const rows = Array.isArray(runs) ? runs : [runs];
100
+ const botTokenEnv = channel.botTokenEnv ?? 'AGENT_OS_TELEGRAM_BOT_TOKEN';
101
+ const chatIdEnv = channel.chatIdEnv ?? 'AGENT_OS_TELEGRAM_CHAT_ID';
102
+ const chatId = process.env[chatIdEnv] ?? null;
103
+ const message = {
104
+ parse_mode: 'Markdown',
105
+ text: renderTelegramText(rows, event)
106
+ };
107
+
108
+ if (send) {
109
+ const botToken = process.env[botTokenEnv];
110
+ if (!botToken) {
111
+ fail(`Missing required environment variable: ${botTokenEnv}`);
112
+ }
113
+ if (!chatId) {
114
+ fail(`Missing required environment variable: ${chatIdEnv}`);
115
+ }
116
+
117
+ const apiBaseUrl = channel.apiBaseUrl ?? 'https://api.telegram.org';
118
+ const telegramRequest = {
119
+ method: 'POST',
120
+ url: `${apiBaseUrl}/bot${botToken}/sendMessage`,
121
+ body: {
122
+ chat_id: chatId,
123
+ ...message
124
+ }
125
+ };
126
+
127
+ if (channel.mockRequestFile) {
128
+ const mockRequestPath = path.resolve(channelContext.outputBaseDir, channel.mockRequestFile);
129
+ fs.mkdirSync(path.dirname(mockRequestPath), { recursive: true });
130
+ fs.writeFileSync(mockRequestPath, `${JSON.stringify(telegramRequest, null, 2)}\n`);
131
+ console.log(`Channel: ${channelName}`);
132
+ console.log(`Sent notification: ${channelName}`);
133
+ process.exit(0);
134
+ }
135
+
136
+ const response = await fetch(telegramRequest.url, {
137
+ method: telegramRequest.method,
138
+ headers: { 'content-type': 'application/json' },
139
+ body: JSON.stringify(telegramRequest.body)
140
+ });
141
+
142
+ if (!response.ok) {
143
+ const responseText = await response.text();
144
+ fail(`Telegram send failed (${response.status}): ${responseText}`);
145
+ }
146
+
147
+ console.log(`Channel: ${channelName}`);
148
+ console.log(`Sent notification: ${channelName}`);
149
+ process.exit(0);
150
+ }
151
+
152
+ const payload = {
153
+ channel: channelName,
154
+ event: event,
155
+ mode: 'dry-run',
156
+ transport: 'telegram',
157
+ botTokenEnv,
158
+ chatIdEnv,
159
+ chatId,
160
+ message,
161
+ runs: rows
162
+ };
163
+
164
+ const outputPath = path.resolve(channelContext.outputBaseDir, outputOverride ?? channel.output ?? 'reports/telegram-payload.json');
165
+
166
+ fs.mkdirSync(path.dirname(outputPath), { recursive: true });
167
+ fs.writeFileSync(outputPath, `${JSON.stringify(payload, null, 2)}\n`);
168
+ console.log(`Channel: ${channelName}`);
169
+ console.log(`Dry-run notification payload: ${outputPath}`);
@@ -0,0 +1,83 @@
1
+ #!/usr/bin/env node
2
+ import fs from 'node:fs';
3
+ import path from 'node:path';
4
+ import { renderReport } from './lib/run-utils.mjs';
5
+ import { createCli, fail, showHelp, wantsHelp } from './lib/cli-utils.mjs';
6
+
7
+ const { takeOption } = createCli(process.argv.slice(2));
8
+
9
+ if (wantsHelp(process.argv)) {
10
+ showHelp({
11
+ command: 'run-execution',
12
+ description: 'Execute a reviewed run directory',
13
+ usage: ['agent-os run-execution --run-dir <dir>'],
14
+ required: [{ flag: '--run-dir <dir>', desc: 'Path to the run directory' }],
15
+ examples: ['agent-os run-execution --run-dir .agent-os/runs/my-run']
16
+ });
17
+ }
18
+
19
+ const runDir = takeOption('--run-dir');
20
+ if (!runDir) {
21
+ fail('Missing --run-dir <dir>. Run \'agent-os run-execution --help\' for usage.');
22
+ }
23
+
24
+ const absoluteRunDir = path.resolve(process.cwd(), runDir);
25
+ const planPath = path.join(absoluteRunDir, 'plan.json');
26
+ const stepsPath = path.join(absoluteRunDir, 'steps.json');
27
+ const reportPath = path.join(absoluteRunDir, 'master-report.md');
28
+
29
+ if (!fs.existsSync(planPath) || !fs.existsSync(stepsPath)) {
30
+ fail(`Run directory is missing plan.json or steps.json: ${absoluteRunDir}`);
31
+ }
32
+
33
+ const plan = JSON.parse(fs.readFileSync(planPath, 'utf8'));
34
+ const steps = JSON.parse(fs.readFileSync(stepsPath, 'utf8'));
35
+
36
+ if (plan.validation?.status !== 'PASS') {
37
+ fail(`Cannot execute invalid plan: ${plan.validation?.status ?? 'unknown'}`);
38
+ }
39
+
40
+ const evidence = [];
41
+ for (const step of steps) {
42
+ if (step.status === 'failed' || step.status === 'blocked') {
43
+ fail(`Cannot execute step ${step.step} with status ${step.status}`);
44
+ }
45
+ if (step.status === 'passed') {
46
+ evidence.push(`Deterministic executor skipped already-passed step ${step.step}: ${step.skill}`);
47
+ continue;
48
+ }
49
+
50
+ const incompleteDependencies = step.dependsOn.filter((dependencySkill) => {
51
+ const dependencyStep = steps.find((candidate) => candidate.skill === dependencySkill);
52
+ return !dependencyStep || dependencyStep.status !== 'passed';
53
+ });
54
+ if (incompleteDependencies.length > 0) {
55
+ fail(`Dependencies must pass before step ${step.step} can execute: ${incompleteDependencies.join(', ')}`);
56
+ }
57
+
58
+ step.status = 'running';
59
+ step.status = 'passed';
60
+ evidence.push(`Deterministic executor passed step ${step.step}: ${step.skill}`);
61
+ }
62
+
63
+ plan.executionPlan = plan.executionPlan.map((step) => (
64
+ steps.find((updatedStep) => updatedStep.step === step.step) ?? step
65
+ ));
66
+ plan.executionEvidence = [
67
+ ...(plan.executionEvidence ?? []),
68
+ ...evidence
69
+ ];
70
+ plan.run = {
71
+ ...(plan.run ?? {}),
72
+ status: steps.every((step) => step.status === 'passed') ? 'complete' : 'running'
73
+ };
74
+
75
+ fs.writeFileSync(stepsPath, JSON.stringify(steps, null, 2) + '\n');
76
+ fs.writeFileSync(planPath, JSON.stringify(plan, null, 2) + '\n');
77
+ fs.writeFileSync(reportPath, renderReport(plan));
78
+
79
+ console.log(JSON.stringify({
80
+ runDir: absoluteRunDir,
81
+ status: plan.run.status,
82
+ steps: steps.length
83
+ }, null, 2));
@@ -0,0 +1,44 @@
1
+ #!/usr/bin/env node
2
+ import { collectRuns, renderRunSummariesCsv } from './lib/run-utils.mjs';
3
+ import { createCli, fail, resolveDefault, showHelp, wantsHelp } from './lib/cli-utils.mjs';
4
+
5
+ const { takeOption } = createCli(process.argv.slice(2));
6
+
7
+ if (wantsHelp(process.argv)) {
8
+ showHelp({
9
+ command: 'run-list',
10
+ description: 'List all known runs',
11
+ usage: ['agent-os run-list [options]'],
12
+ options: [
13
+ { flag: '--run-root <dir>', desc: 'Run directory root', default: '.agent-os/runs' },
14
+ { flag: '--format <json|csv>', desc: 'Output format', default: 'json' }
15
+ ],
16
+ examples: [
17
+ 'agent-os run-list',
18
+ 'agent-os run-list --format csv'
19
+ ]
20
+ });
21
+ }
22
+
23
+ const runRoot = takeOption('--run-root') ?? resolveDefault(null, '.agent-os/runs');
24
+ const format = takeOption('--format') ?? 'json';
25
+ if (!runRoot) {
26
+ fail('Missing --run-root <dir> (no default found at .agent-os/runs). Run \'agent-os run-list --help\' for usage.');
27
+ }
28
+
29
+ if (!['json', 'csv'].includes(format)) {
30
+ fail(`Unsupported format: ${format}. Expected json or csv.`);
31
+ }
32
+
33
+ let runs;
34
+ try {
35
+ runs = collectRuns(runRoot);
36
+ } catch (err) {
37
+ fail(err.message);
38
+ }
39
+
40
+ if (format === 'csv') {
41
+ process.stdout.write(renderRunSummariesCsv(runs));
42
+ } else {
43
+ console.log(JSON.stringify(runs, null, 2));
44
+ }
@@ -0,0 +1,38 @@
1
+ #!/usr/bin/env node
2
+ import { collectRun, renderRunSummariesCsv } from './lib/run-utils.mjs';
3
+ import { createCli, fail, showHelp, wantsHelp } from './lib/cli-utils.mjs';
4
+
5
+ const { takeOption } = createCli(process.argv.slice(2));
6
+
7
+ if (wantsHelp(process.argv)) {
8
+ showHelp({
9
+ command: 'run-status',
10
+ description: 'Show status of a specific run',
11
+ usage: ['agent-os run-status --run-dir <dir> [options]'],
12
+ required: [{ flag: '--run-dir <dir>', desc: 'Path to the run directory' }],
13
+ options: [{ flag: '--format <json|csv>', desc: 'Output format', default: 'json' }],
14
+ examples: ['agent-os run-status --run-dir .agent-os/runs/my-run']
15
+ });
16
+ }
17
+
18
+ const runDir = takeOption('--run-dir');
19
+ const format = takeOption('--format') ?? 'json';
20
+ if (!runDir) {
21
+ fail('Missing --run-dir <dir>. Run \'agent-os run-status --help\' for usage.');
22
+ }
23
+
24
+ if (!['json', 'csv'].includes(format)) {
25
+ fail(`Unsupported format: ${format}. Expected json or csv.`);
26
+ }
27
+
28
+ let summary;
29
+ try {
30
+ summary = collectRun(runDir);
31
+ } catch (err) {
32
+ fail(err.message);
33
+ }
34
+ if (format === 'csv') {
35
+ process.stdout.write(renderRunSummariesCsv(summary));
36
+ } else {
37
+ console.log(JSON.stringify(summary, null, 2));
38
+ }