@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.
- package/AGENTS.md +41 -0
- package/AGENT_OS_BOOTSTRAP.md +29 -0
- package/ENTRYPOINT.md +118 -0
- package/LICENSE +21 -0
- package/README.md +230 -0
- package/adapters/antigravity/README.md +9 -0
- package/adapters/antigravity/plugin.json +13 -0
- package/adapters/claude/CLAUDE.md +16 -0
- package/adapters/claude/README.md +10 -0
- package/adapters/codex/README.md +20 -0
- package/adapters/cursor/README.md +9 -0
- package/adapters/cursor/agent-os.rules.md +18 -0
- package/bin/agent-os.mjs +98 -0
- package/core/AUTO_PROJECT_DETECTOR.md +99 -0
- package/core/COMPLIANCE_GATE.md +19 -0
- package/core/FRAMEWORK_AUDITOR.md +35 -0
- package/core/KNOWLEDGE_REGENERATOR.md +30 -0
- package/core/KNOWLEDGE_VALIDATOR.md +29 -0
- package/core/PROJECT_CONTEXT_STANDARD.md +19 -0
- package/core/QUALITY_GATES.md +42 -0
- package/core/REPORTING_STANDARD.md +47 -0
- package/core/SKILL_ORCHESTRATOR.md +63 -0
- package/core/TASK_ROUTER.md +33 -0
- package/core/TRACEABILITY_STANDARD.md +40 -0
- package/package.json +28 -0
- package/scripts/install.mjs +690 -0
- package/scripts/lib/cli-utils.mjs +148 -0
- package/scripts/lib/run-utils.mjs +185 -0
- package/scripts/lib/telegram-audit-log.mjs +50 -0
- package/scripts/lib/telegram-bot-utils.mjs +413 -0
- package/scripts/lib/telegram-utils.mjs +127 -0
- package/scripts/orchestrate.mjs +230 -0
- package/scripts/quality-static.mjs +19 -0
- package/scripts/report-export.mjs +86 -0
- package/scripts/report-notify.mjs +169 -0
- package/scripts/run-execution.mjs +83 -0
- package/scripts/run-list.mjs +44 -0
- package/scripts/run-status.mjs +38 -0
- package/scripts/run-step.mjs +173 -0
- package/scripts/setup-wizard.mjs +116 -0
- package/scripts/sync-runtime.mjs +87 -0
- package/scripts/telegram-bot.mjs +88 -0
- package/scripts/telegram-check.mjs +94 -0
- package/scripts/telegram-poll.mjs +176 -0
- package/scripts/validate-framework.mjs +290 -0
- package/skills/api-contract-audit/SKILL.md +26 -0
- package/skills/api-contract-audit/checklist.md +16 -0
- package/skills/api-contract-audit/examples.md +3 -0
- package/skills/api-contract-audit/report-template.md +39 -0
- package/skills/api-contract-audit/workflow.md +15 -0
- package/skills/audit/SKILL.md +28 -0
- package/skills/audit/checklist.md +18 -0
- package/skills/audit/examples.md +26 -0
- package/skills/audit/report-template.md +39 -0
- package/skills/audit/workflow.md +15 -0
- package/skills/bug-fix/SKILL.md +25 -0
- package/skills/bug-fix/checklist.md +18 -0
- package/skills/bug-fix/examples.md +26 -0
- package/skills/bug-fix/report-template.md +39 -0
- package/skills/bug-fix/workflow.md +10 -0
- package/skills/database-impact-analysis/SKILL.md +27 -0
- package/skills/database-impact-analysis/checklist.md +16 -0
- package/skills/database-impact-analysis/examples.md +3 -0
- package/skills/database-impact-analysis/report-template.md +39 -0
- package/skills/database-impact-analysis/workflow.md +14 -0
- package/skills/enhancement/SKILL.md +27 -0
- package/skills/enhancement/checklist.md +19 -0
- package/skills/enhancement/examples.md +26 -0
- package/skills/enhancement/report-template.md +39 -0
- package/skills/enhancement/workflow.md +10 -0
- package/skills/enterprise-certification/SKILL.md +19 -0
- package/skills/enterprise-certification/checklist.md +17 -0
- package/skills/enterprise-certification/report-template.md +39 -0
- package/skills/enterprise-certification/workflow.md +14 -0
- package/skills/knowledge-evolution/SKILL.md +23 -0
- package/skills/knowledge-evolution/checklist.md +17 -0
- package/skills/knowledge-evolution/report-template.md +39 -0
- package/skills/knowledge-evolution/workflow.md +14 -0
- package/skills/new-page/SKILL.md +26 -0
- package/skills/new-page/checklist.md +21 -0
- package/skills/new-page/examples.md +26 -0
- package/skills/new-page/report-template.md +39 -0
- package/skills/new-page/workflow.md +10 -0
- package/skills/project-onboarding/SKILL.md +27 -0
- package/skills/project-onboarding/checklist.md +18 -0
- package/skills/project-onboarding/examples.md +26 -0
- package/skills/project-onboarding/report-template.md +39 -0
- package/skills/project-onboarding/workflow.md +9 -0
- package/skills/release-readiness/SKILL.md +27 -0
- package/skills/release-readiness/checklist.md +16 -0
- package/skills/release-readiness/examples.md +3 -0
- package/skills/release-readiness/report-template.md +39 -0
- package/skills/release-readiness/workflow.md +14 -0
- package/skills/repository-health/SKILL.md +26 -0
- package/skills/repository-health/checklist.md +20 -0
- package/skills/repository-health/report-template.md +39 -0
- package/skills/repository-health/workflow.md +14 -0
- package/skills/selenium-e2e/SKILL.md +83 -0
- package/skills/selenium-e2e/checklist.md +29 -0
- package/skills/selenium-e2e/examples.md +26 -0
- package/skills/selenium-e2e/report-template.md +39 -0
- package/skills/selenium-e2e/workflow.md +9 -0
- package/skills/self-audit/SKILL.md +19 -0
- package/skills/self-audit/checklist.md +14 -0
- package/skills/self-audit/report-template.md +39 -0
- package/skills/self-audit/workflow.md +11 -0
- package/skills/traceability-analysis/SKILL.md +25 -0
- package/skills/traceability-analysis/checklist.md +17 -0
- package/skills/traceability-analysis/examples.md +3 -0
- package/skills/traceability-analysis/report-template.md +39 -0
- package/skills/traceability-analysis/workflow.md +17 -0
- package/templates/API_RULES.md +20 -0
- package/templates/ARCHITECTURE.md +20 -0
- package/templates/BUSINESS_FLOW.md +20 -0
- package/templates/COMMANDS.md +20 -0
- package/templates/DATABASE_RULES.md +20 -0
- package/templates/DEPENDENCY_MAP.md +20 -0
- package/templates/DEPLOYMENT_RULES.md +20 -0
- package/templates/DOMAIN_MODEL.md +20 -0
- package/templates/FE_BE_TRACEABILITY.md +20 -0
- package/templates/KNOWN_LIMITATIONS.md +20 -0
- package/templates/MODULE_CATALOG.md +20 -0
- package/templates/PROJECT_PROFILE.md +20 -0
- package/templates/RISK_REGISTER.md +20 -0
- package/templates/SECURITY_RULES.md +20 -0
- package/templates/TECHNICAL_DEBT.md +20 -0
- package/templates/TECH_STACK.md +20 -0
- package/templates/TESTING_RULES.md +47 -0
- package/templates/UI_UX_RULES.md +20 -0
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Creates a CLI argument parser from process.argv.
|
|
6
|
+
* @param {string[]} argv - process.argv.slice(2)
|
|
7
|
+
*/
|
|
8
|
+
export function createCli(argv) {
|
|
9
|
+
const args = [...argv];
|
|
10
|
+
|
|
11
|
+
function hasFlag(name) {
|
|
12
|
+
return args.includes(name);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function takeOption(name) {
|
|
16
|
+
const index = args.indexOf(name);
|
|
17
|
+
if (index === -1) return null;
|
|
18
|
+
const value = args[index + 1] ?? null;
|
|
19
|
+
args.splice(index, 2);
|
|
20
|
+
return value;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
return { hasFlag, takeOption, args };
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Returns true if the user passed --help or -h.
|
|
28
|
+
* @param {string[]} argv
|
|
29
|
+
*/
|
|
30
|
+
export function wantsHelp(argv) {
|
|
31
|
+
return argv.includes('--help') || argv.includes('-h');
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Renders a formatted help text block and exits cleanly.
|
|
36
|
+
* @param {object} config
|
|
37
|
+
* @param {string} config.command - The subcommand name
|
|
38
|
+
* @param {string} config.description - One-line description
|
|
39
|
+
* @param {string[]} config.usage - Usage lines (one per variant)
|
|
40
|
+
* @param {Array<{flag: string, desc: string, default?: string}>} [config.required] - Required flags
|
|
41
|
+
* @param {Array<{flag: string, desc: string, default?: string}>} [config.options] - Optional flags
|
|
42
|
+
* @param {string[]} [config.examples] - Example command lines
|
|
43
|
+
*/
|
|
44
|
+
export function showHelp(config) {
|
|
45
|
+
const lines = [];
|
|
46
|
+
lines.push(`agent-os ${config.command} — ${config.description}`);
|
|
47
|
+
lines.push('');
|
|
48
|
+
|
|
49
|
+
lines.push('Usage:');
|
|
50
|
+
for (const usage of config.usage) {
|
|
51
|
+
lines.push(` ${usage}`);
|
|
52
|
+
}
|
|
53
|
+
lines.push('');
|
|
54
|
+
|
|
55
|
+
if (config.required?.length) {
|
|
56
|
+
lines.push('Required:');
|
|
57
|
+
const maxLen = Math.max(...config.required.map((o) => o.flag.length));
|
|
58
|
+
for (const opt of config.required) {
|
|
59
|
+
lines.push(` ${opt.flag.padEnd(maxLen + 2)} ${opt.desc}`);
|
|
60
|
+
}
|
|
61
|
+
lines.push('');
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if (config.options?.length) {
|
|
65
|
+
lines.push('Options:');
|
|
66
|
+
const maxLen = Math.max(...config.options.map((o) => o.flag.length));
|
|
67
|
+
for (const opt of config.options) {
|
|
68
|
+
const defaultStr = opt.default ? ` [default: ${opt.default}]` : '';
|
|
69
|
+
lines.push(` ${opt.flag.padEnd(maxLen + 2)} ${opt.desc}${defaultStr}`);
|
|
70
|
+
}
|
|
71
|
+
lines.push('');
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
if (config.examples?.length) {
|
|
75
|
+
lines.push('Examples:');
|
|
76
|
+
for (const example of config.examples) {
|
|
77
|
+
lines.push(` ${example}`);
|
|
78
|
+
}
|
|
79
|
+
lines.push('');
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
console.log(lines.join('\n'));
|
|
83
|
+
process.exit(0);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Collects multiple validation errors, then displays them all at once with
|
|
88
|
+
* a usage example, and exits with code 1.
|
|
89
|
+
* @param {string[]} errors - List of error messages
|
|
90
|
+
* @param {string} [example] - Example command to show
|
|
91
|
+
* @param {string} [command] - Command name for --help hint
|
|
92
|
+
*/
|
|
93
|
+
export function failAll(errors, example, command) {
|
|
94
|
+
if (errors.length === 0) return;
|
|
95
|
+
|
|
96
|
+
console.error(`\n✗ ERROR: ${errors.length} issue${errors.length > 1 ? 's' : ''} found:\n`);
|
|
97
|
+
for (const error of errors) {
|
|
98
|
+
console.error(` • ${error}`);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
if (example) {
|
|
102
|
+
console.error(`\nExample:`);
|
|
103
|
+
console.error(` ${example}`);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (command) {
|
|
107
|
+
console.error(`\nRun 'agent-os ${command} --help' for full usage.`);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
console.error('');
|
|
111
|
+
process.exit(1);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Simple single-error fail (for runtime errors after validation).
|
|
116
|
+
* @param {string} message
|
|
117
|
+
*/
|
|
118
|
+
export function fail(message) {
|
|
119
|
+
console.error(message);
|
|
120
|
+
process.exit(1);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Resolves a CLI flag value with a smart default.
|
|
125
|
+
* If the value is already set (from CLI), returns it.
|
|
126
|
+
* Otherwise checks if the default file/directory exists and returns it.
|
|
127
|
+
* @param {string|null} value - The CLI-provided value
|
|
128
|
+
* @param {string} defaultPath - The default path to try
|
|
129
|
+
* @returns {string|null}
|
|
130
|
+
*/
|
|
131
|
+
export function resolveDefault(value, defaultPath) {
|
|
132
|
+
if (value) return value;
|
|
133
|
+
const resolved = path.resolve(process.cwd(), defaultPath);
|
|
134
|
+
if (fs.existsSync(resolved)) return resolved;
|
|
135
|
+
return null;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Resolves a default that does not require the file to exist yet
|
|
140
|
+
* (e.g., state files that will be created on first run).
|
|
141
|
+
* @param {string|null} value
|
|
142
|
+
* @param {string} defaultPath
|
|
143
|
+
* @returns {string|null}
|
|
144
|
+
*/
|
|
145
|
+
export function resolveDefaultPath(value, defaultPath) {
|
|
146
|
+
if (value) return value;
|
|
147
|
+
return defaultPath;
|
|
148
|
+
}
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
|
|
4
|
+
export const runStatuses = ['pending', 'running', 'passed', 'failed', 'blocked'];
|
|
5
|
+
|
|
6
|
+
export function buildStatusCounts(steps) {
|
|
7
|
+
const counts = Object.fromEntries(runStatuses.map((status) => [status, 0]));
|
|
8
|
+
for (const step of steps) {
|
|
9
|
+
if (counts[step.status] === undefined) counts[step.status] = 0;
|
|
10
|
+
counts[step.status]++;
|
|
11
|
+
}
|
|
12
|
+
return counts;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function deriveRunStatus(steps) {
|
|
16
|
+
const counts = buildStatusCounts(steps);
|
|
17
|
+
if (counts.failed > 0 || counts.blocked > 0) return 'failed';
|
|
18
|
+
if (counts.running > 0) return 'running';
|
|
19
|
+
if (steps.length > 0 && counts.passed === steps.length) return 'complete';
|
|
20
|
+
return 'pending';
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function extractSection(content, sectionName) {
|
|
24
|
+
const regex = new RegExp(`^# ${sectionName}\\n([\\s\\S]*?)(?:\\n# |$)`, 'm');
|
|
25
|
+
const match = content.match(regex);
|
|
26
|
+
return match ? match[1].trim() : null;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function summarizeRun(runDir) {
|
|
30
|
+
const planPath = path.join(runDir, 'plan.json');
|
|
31
|
+
const stepsPath = path.join(runDir, 'steps.json');
|
|
32
|
+
if (!fs.existsSync(planPath) || !fs.existsSync(stepsPath)) return null;
|
|
33
|
+
|
|
34
|
+
const plan = JSON.parse(fs.readFileSync(planPath, 'utf8'));
|
|
35
|
+
const steps = JSON.parse(fs.readFileSync(stepsPath, 'utf8'));
|
|
36
|
+
|
|
37
|
+
const reportPath = path.join(runDir, 'master-report.md');
|
|
38
|
+
let reportDetails = null;
|
|
39
|
+
if (fs.existsSync(reportPath)) {
|
|
40
|
+
const content = fs.readFileSync(reportPath, 'utf8');
|
|
41
|
+
reportDetails = {
|
|
42
|
+
evidence: extractSection(content, 'Evidence')
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return {
|
|
47
|
+
runDir,
|
|
48
|
+
runId: plan.run?.id ?? path.basename(runDir),
|
|
49
|
+
status: deriveRunStatus(steps),
|
|
50
|
+
total: steps.length,
|
|
51
|
+
counts: buildStatusCounts(steps),
|
|
52
|
+
plan,
|
|
53
|
+
steps,
|
|
54
|
+
reportDetails
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export function collectRuns(runRoot) {
|
|
59
|
+
const absoluteRunRoot = path.resolve(process.cwd(), runRoot);
|
|
60
|
+
if (!fs.existsSync(absoluteRunRoot)) {
|
|
61
|
+
throw new Error(`Run root not found: ${absoluteRunRoot}`);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return fs.readdirSync(absoluteRunRoot, { withFileTypes: true })
|
|
65
|
+
.filter((entry) => entry.isDirectory())
|
|
66
|
+
.map((entry) => summarizeRun(path.join(absoluteRunRoot, entry.name)))
|
|
67
|
+
.filter(Boolean)
|
|
68
|
+
.sort((a, b) => a.runId.localeCompare(b.runId));
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export function collectRun(runDir) {
|
|
72
|
+
const absoluteRunDir = path.resolve(process.cwd(), runDir);
|
|
73
|
+
const summary = summarizeRun(absoluteRunDir);
|
|
74
|
+
if (!summary) {
|
|
75
|
+
throw new Error(`Run directory is missing plan.json or steps.json: ${absoluteRunDir}`);
|
|
76
|
+
}
|
|
77
|
+
return summary;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export function loadReportChannel(channelConfig, channelName) {
|
|
81
|
+
const absoluteConfigPath = path.resolve(process.cwd(), channelConfig);
|
|
82
|
+
if (!fs.existsSync(absoluteConfigPath)) {
|
|
83
|
+
throw new Error(`Channel config not found: ${absoluteConfigPath}`);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const config = JSON.parse(fs.readFileSync(absoluteConfigPath, 'utf8'));
|
|
87
|
+
const channel = config.channels?.[channelName];
|
|
88
|
+
if (!channel) {
|
|
89
|
+
throw new Error(`Report channel not found: ${channelName}`);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return {
|
|
93
|
+
name: channelName,
|
|
94
|
+
configPath: absoluteConfigPath,
|
|
95
|
+
outputBaseDir: path.dirname(absoluteConfigPath),
|
|
96
|
+
channel
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export function assertEnabledChannel(channelContext) {
|
|
101
|
+
if (channelContext.channel.enabled === false) {
|
|
102
|
+
throw new Error(`Report channel is disabled: ${channelContext.name}`);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function escapeCsvValue(value) {
|
|
107
|
+
const text = String(value ?? '');
|
|
108
|
+
if (!/[",\n\r]/.test(text)) return text;
|
|
109
|
+
return `"${text.replaceAll('"', '""')}"`;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export function renderRunSummariesCsv(summaries) {
|
|
113
|
+
const rows = Array.isArray(summaries) ? summaries : [summaries];
|
|
114
|
+
const headers = ['runId', 'status', 'total', 'pending', 'running', 'passed', 'failed', 'blocked', 'runDir'];
|
|
115
|
+
const lines = [headers.join(',')];
|
|
116
|
+
|
|
117
|
+
for (const summary of rows) {
|
|
118
|
+
lines.push([
|
|
119
|
+
summary.runId,
|
|
120
|
+
summary.status,
|
|
121
|
+
summary.total,
|
|
122
|
+
summary.counts.pending ?? 0,
|
|
123
|
+
summary.counts.running ?? 0,
|
|
124
|
+
summary.counts.passed ?? 0,
|
|
125
|
+
summary.counts.failed ?? 0,
|
|
126
|
+
summary.counts.blocked ?? 0,
|
|
127
|
+
summary.runDir
|
|
128
|
+
].map(escapeCsvValue).join(','));
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
return `${lines.join('\n')}\n`;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
export function renderReport(plan) {
|
|
135
|
+
const sectionBody = {
|
|
136
|
+
'Executive Summary': [
|
|
137
|
+
`Trigger: ${plan.trigger}`,
|
|
138
|
+
`Prompt: ${plan.prompt}`,
|
|
139
|
+
`Validation Status: ${plan.validation.status}`
|
|
140
|
+
],
|
|
141
|
+
Scope: [
|
|
142
|
+
`Mode: ${plan.mode}`,
|
|
143
|
+
`Skill Chain: ${plan.skillChain.join(' -> ')}`
|
|
144
|
+
],
|
|
145
|
+
'Knowledge Confidence': [
|
|
146
|
+
'Score: N/A. Reason: Execution stub does not inspect project knowledge.'
|
|
147
|
+
],
|
|
148
|
+
'Knowledge Classification': [
|
|
149
|
+
'Classification: N/A. Reason: Execution stub only renders a validated plan.'
|
|
150
|
+
],
|
|
151
|
+
'Traceability Matrix': [
|
|
152
|
+
'| Step | Skill | Depends On | Status |',
|
|
153
|
+
'| ---- | ----- | ---------- | ------ |',
|
|
154
|
+
...plan.executionPlan.map((step) => (
|
|
155
|
+
`| ${step.step} | ${step.skill} | ${step.dependsOn.join(', ') || 'N/A. Reason: First step.'} | ${step.status} |`
|
|
156
|
+
))
|
|
157
|
+
],
|
|
158
|
+
Evidence: plan.executionEvidence?.length > 0
|
|
159
|
+
? plan.executionEvidence
|
|
160
|
+
: ['N/A. Reason: Skills were not executed by this stub.'],
|
|
161
|
+
'Root Cause': [
|
|
162
|
+
'N/A. Reason: Root cause is produced by the executing skill.'
|
|
163
|
+
],
|
|
164
|
+
Impact: [
|
|
165
|
+
'N/A. Reason: Impact is produced by the executing skill.'
|
|
166
|
+
],
|
|
167
|
+
Recommendation: [
|
|
168
|
+
'Quick Win: Review this validated execution plan before running skills.',
|
|
169
|
+
'Long Term Improvement: Replace this stub with gated skill execution.'
|
|
170
|
+
],
|
|
171
|
+
'Quality Gate': [
|
|
172
|
+
`Plan Validation: ${plan.validation.status}`
|
|
173
|
+
],
|
|
174
|
+
'Enterprise Readiness': [
|
|
175
|
+
'N/A. Reason: Enterprise readiness is assessed after execution evidence exists.'
|
|
176
|
+
],
|
|
177
|
+
'Final Decision': [
|
|
178
|
+
plan.validation.status === 'PASS' ? 'CONDITIONAL PASS' : 'FAIL'
|
|
179
|
+
]
|
|
180
|
+
};
|
|
181
|
+
|
|
182
|
+
return plan.masterReport.sections
|
|
183
|
+
.map((section) => `# ${section}\n${sectionBody[section].join('\n')}`)
|
|
184
|
+
.join('\n\n') + '\n';
|
|
185
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Appends an audit entry to the telegram audit log JSONL file.
|
|
6
|
+
*
|
|
7
|
+
* @param {Object} options
|
|
8
|
+
* @param {string} options.runRoot - The absolute path to the .agent-os/runs or equivalent root directory
|
|
9
|
+
* @param {Object} options.entry - The audit log entry to append
|
|
10
|
+
*/
|
|
11
|
+
export function appendAuditEntry({ runRoot, entry }) {
|
|
12
|
+
if (!runRoot) return;
|
|
13
|
+
|
|
14
|
+
const logPath = path.join(runRoot, '..', 'project', 'reports', 'telegram-audit-log.jsonl');
|
|
15
|
+
|
|
16
|
+
// Ensure directory exists
|
|
17
|
+
fs.mkdirSync(path.dirname(logPath), { recursive: true });
|
|
18
|
+
|
|
19
|
+
// Prepare entry with timestamp if not provided
|
|
20
|
+
const logEntry = {
|
|
21
|
+
timestamp: new Date().toISOString(),
|
|
22
|
+
...entry
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
// Append as JSONL
|
|
26
|
+
fs.appendFileSync(logPath, `${JSON.stringify(logEntry)}\n`, 'utf8');
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Reads and parses the telegram audit log.
|
|
31
|
+
*
|
|
32
|
+
* @param {Object} options
|
|
33
|
+
* @param {string} options.runRoot - The absolute path to the .agent-os/runs or equivalent root directory
|
|
34
|
+
* @returns {Array<Object>} The parsed audit log entries
|
|
35
|
+
*/
|
|
36
|
+
export function readAuditLog({ runRoot }) {
|
|
37
|
+
if (!runRoot) return [];
|
|
38
|
+
|
|
39
|
+
const logPath = path.join(runRoot, '..', 'project', 'reports', 'telegram-audit-log.jsonl');
|
|
40
|
+
if (!fs.existsSync(logPath)) {
|
|
41
|
+
return [];
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const content = fs.readFileSync(logPath, 'utf8');
|
|
45
|
+
return content
|
|
46
|
+
.split('\n')
|
|
47
|
+
.map(line => line.trim())
|
|
48
|
+
.filter(Boolean)
|
|
49
|
+
.map(line => JSON.parse(line));
|
|
50
|
+
}
|