@mamdouh-aboammar/agentic-workflow 1.2.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/.claude-plugin/plugin.json +10 -0
- package/.codex-plugin/plugin.json +13 -0
- package/.skills.json +19 -0
- package/AGENTS.md +1344 -0
- package/CLAUDE.md +178 -0
- package/GEMINI.md +102 -0
- package/LICENSE +21 -0
- package/README.md +350 -0
- package/SKILL.md +132 -0
- package/bin/agentic-hooks.sh +79 -0
- package/bin/cli.js +1060 -0
- package/core/__init__.py +52 -0
- package/core/ai_evaluator.py +117 -0
- package/core/autopilot_engine.py +368 -0
- package/core/clean_code_guard.py +188 -0
- package/core/engine_py/__init__.py +29 -0
- package/core/engine_py/agent_worker.py +136 -0
- package/core/engine_py/decider.py +150 -0
- package/core/engine_py/energy.py +45 -0
- package/core/engine_py/event_bus.py +63 -0
- package/core/engine_py/executor.py +186 -0
- package/core/engine_py/models.py +193 -0
- package/core/engine_py/queue.py +314 -0
- package/core/engine_py/runner.py +116 -0
- package/core/engine_py/system_workers.py +70 -0
- package/core/engine_py/toon_adapter.py +586 -0
- package/core/engine_py/verification_controller.py +208 -0
- package/core/engine_py/worker.py +167 -0
- package/core/engine_spec/event_schema.json +65 -0
- package/core/engine_spec/example_workflow.yaml +73 -0
- package/core/engine_spec/workflow_schema.json +127 -0
- package/core/hooks/__init__.py +29 -0
- package/core/hooks/adapters/__init__.py +25 -0
- package/core/hooks/adapters/claude_adapter.py +83 -0
- package/core/hooks/adapters/cli_agent_adapter.py +82 -0
- package/core/hooks/adapters/codex_adapter.py +78 -0
- package/core/hooks/adapters/cursor_adapter.py +73 -0
- package/core/hooks/adapters/gemini_adapter.py +93 -0
- package/core/hooks/adapters/homebrew_adapter.py +69 -0
- package/core/hooks/adapters/mcp_proxy.py +133 -0
- package/core/hooks/adapters/shell_adapter.py +65 -0
- package/core/hooks/dispatcher.py +118 -0
- package/core/hooks/policy_engine.py +375 -0
- package/core/hooks/session_end.py +141 -0
- package/core/hooks/types.py +147 -0
- package/core/integrations/__init__.py +28 -0
- package/core/integrations/installer.py +225 -0
- package/core/integrations/lifecycle_director.py +175 -0
- package/core/integrations/registry.py +105 -0
- package/core/multi_agent_system.py +164 -0
- package/core/skills_indexer.py +742 -0
- package/core/system/__init__.py +25 -0
- package/core/system/announcements.py +72 -0
- package/core/system/dependencies.py +69 -0
- package/core/system/doctor.py +171 -0
- package/core/system/health.py +144 -0
- package/core/system/installer.py +137 -0
- package/core/system/notifications.py +97 -0
- package/core/system/refresher.py +110 -0
- package/core/system/updater.py +167 -0
- package/core/system/version_tracker.py +65 -0
- package/docs/architecture_plan.md +7 -0
- package/docs/guides/failure-recovery.md +714 -0
- package/docs/implementation_summary.md +10 -0
- package/docs/protocols/autopilot-execution.md +148 -0
- package/docs/protocols/code-change-protocol.md +49 -0
- package/docs/protocols/context-preservation-detail.md +114 -0
- package/docs/protocols/quality-gates.md +110 -0
- package/docs/protocols/ulw-mode.md +60 -0
- package/docs/research_findings.md +10 -0
- package/docs/solutions/autonomous-autopilot-engine-architecture.md +38 -0
- package/install.sh +111 -0
- package/marketplace.json +37 -0
- package/package.json +81 -0
- package/skills/agentic-workflow/SKILL.md +132 -0
- package/skills/agentic-workflow/skill-spec.json +100 -0
- package/soul.md +445 -0
- package/src/engine_ts/decider.ts +186 -0
- package/src/engine_ts/event-bus.ts +57 -0
- package/src/engine_ts/executor.ts +262 -0
- package/src/engine_ts/index.ts +12 -0
- package/src/engine_ts/queue.ts +93 -0
- package/src/engine_ts/runner.ts +108 -0
- package/src/engine_ts/skills-indexer.ts +264 -0
- package/src/engine_ts/toon-adapter.ts +91 -0
- package/src/engine_ts/types.ts +134 -0
- package/src/engine_ts/verification-controller.ts +204 -0
- package/src/engine_ts/worker.ts +280 -0
- package/src/hooks/adapters/claude-adapter.ts +54 -0
- package/src/hooks/adapters/cli-agent-adapter.ts +46 -0
- package/src/hooks/adapters/codex-adapter.ts +69 -0
- package/src/hooks/adapters/cursor-adapter.ts +60 -0
- package/src/hooks/adapters/gemini-adapter.ts +71 -0
- package/src/hooks/adapters/homebrew-adapter.ts +36 -0
- package/src/hooks/adapters/mcp-proxy.ts +66 -0
- package/src/hooks/adapters/shell-adapter.ts +42 -0
- package/src/hooks/dispatcher.ts +113 -0
- package/src/hooks/index.ts +16 -0
- package/src/hooks/policy-engine.ts +376 -0
- package/src/hooks/session-end.ts +125 -0
- package/src/hooks/types.ts +61 -0
- package/src/index.d.ts +34 -0
- package/src/index.ts +23 -0
- package/src/integrations/index.ts +7 -0
- package/src/integrations/installer.ts +208 -0
- package/src/integrations/lifecycle-director.ts +139 -0
- package/src/integrations/registry.ts +82 -0
- package/src/system/announcements.ts +143 -0
- package/src/system/dependencies.ts +176 -0
- package/src/system/doctor.ts +374 -0
- package/src/system/health.ts +270 -0
- package/src/system/index.ts +14 -0
- package/src/system/installer.ts +262 -0
- package/src/system/notifications.ts +180 -0
- package/src/system/refresher.ts +207 -0
- package/src/system/types.ts +268 -0
- package/src/system/updater.ts +219 -0
- package/src/system/version-tracker.ts +137 -0
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* src/system/notifications.ts — CLI/Terminal Banner & Desktop Notification Engine
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import fs from 'node:fs';
|
|
6
|
+
import path from 'node:path';
|
|
7
|
+
import os from 'node:os';
|
|
8
|
+
import { execSync } from 'node:child_process';
|
|
9
|
+
import type { NotificationPayload, NotificationRecord, NotificationLevel } from './types.ts';
|
|
10
|
+
|
|
11
|
+
export class NotificationEngine {
|
|
12
|
+
private projectDir: string;
|
|
13
|
+
private historyFile: string;
|
|
14
|
+
private recentDispatches: Map<string, number> = new Map();
|
|
15
|
+
|
|
16
|
+
constructor(projectDir: string = '.') {
|
|
17
|
+
this.projectDir = path.resolve(projectDir);
|
|
18
|
+
this.historyFile = path.join(this.projectDir, '.notifications.json');
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
private isHeadless(): boolean {
|
|
22
|
+
return !!(process.env.CI || !process.stdout.isTTY);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
public renderBanner(payload: NotificationPayload): string {
|
|
26
|
+
const level = payload.level || 'INFO';
|
|
27
|
+
const timestamp = new Date(payload.timestamp || Date.now()).toLocaleTimeString();
|
|
28
|
+
const source = payload.source ? ` [${payload.source}]` : '';
|
|
29
|
+
|
|
30
|
+
let color = '\x1b[36m'; // Cyan
|
|
31
|
+
let icon = 'ℹ️';
|
|
32
|
+
switch (level) {
|
|
33
|
+
case 'SUCCESS':
|
|
34
|
+
color = '\x1b[32m'; // Green
|
|
35
|
+
icon = '✅';
|
|
36
|
+
break;
|
|
37
|
+
case 'WARN':
|
|
38
|
+
color = '\x1b[33m'; // Yellow
|
|
39
|
+
icon = '⚠️';
|
|
40
|
+
break;
|
|
41
|
+
case 'ERROR':
|
|
42
|
+
case 'CRITICAL':
|
|
43
|
+
color = '\x1b[31m'; // Red
|
|
44
|
+
icon = '🛑';
|
|
45
|
+
break;
|
|
46
|
+
case 'ANNOUNCEMENT':
|
|
47
|
+
color = '\x1b[35m'; // Magenta
|
|
48
|
+
icon = '📢';
|
|
49
|
+
break;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const reset = '\x1b[0m';
|
|
53
|
+
const bold = '\x1b[1m';
|
|
54
|
+
const titleLine = `${icon} ${bold}${color}${level}${reset}${bold}: ${payload.title}${source} (${timestamp})${reset}`;
|
|
55
|
+
const lines = payload.message.split('\n');
|
|
56
|
+
|
|
57
|
+
const width = Math.min(80, Math.max(60, payload.title.length + 20, ...lines.map(l => l.length + 6)));
|
|
58
|
+
const border = '═'.repeat(width);
|
|
59
|
+
|
|
60
|
+
return `
|
|
61
|
+
${color}╔${border}╗${reset}
|
|
62
|
+
${titleLine}
|
|
63
|
+
${color}╟${border}╢${reset}
|
|
64
|
+
${lines.map(l => ` ${l}`).join('\n')}
|
|
65
|
+
${color}╚${border}╝${reset}
|
|
66
|
+
`;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
public sendDesktop(title: string, message: string, sound: boolean = true): boolean {
|
|
70
|
+
if (this.isHeadless()) return false;
|
|
71
|
+
|
|
72
|
+
const cleanTitle = title.replace(/"/g, '\\"');
|
|
73
|
+
const cleanMsg = message.replace(/"/g, '\\"');
|
|
74
|
+
const platform = os.platform();
|
|
75
|
+
|
|
76
|
+
try {
|
|
77
|
+
if (platform === 'darwin') {
|
|
78
|
+
const soundParam = sound ? 'sound name "Glass"' : '';
|
|
79
|
+
const script = `display notification "${cleanMsg}" with title "${cleanTitle}" ${soundParam}`;
|
|
80
|
+
execSync(`osascript -e '${script}'`, { stdio: 'ignore' });
|
|
81
|
+
return true;
|
|
82
|
+
} else if (platform === 'linux') {
|
|
83
|
+
execSync(`notify-send "${cleanTitle}" "${cleanMsg}"`, { stdio: 'ignore' });
|
|
84
|
+
return true;
|
|
85
|
+
}
|
|
86
|
+
} catch {
|
|
87
|
+
// Ignore desktop notification failures gracefully
|
|
88
|
+
}
|
|
89
|
+
return false;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
public ringBell(): void {
|
|
93
|
+
if (!this.isHeadless()) {
|
|
94
|
+
process.stdout.write('\x07');
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
public send(payload: NotificationPayload): NotificationRecord {
|
|
99
|
+
const key = `${payload.level || 'INFO'}:${payload.title}:${payload.message.substring(0, 30)}`;
|
|
100
|
+
const now = Date.now();
|
|
101
|
+
const lastSent = this.recentDispatches.get(key) || 0;
|
|
102
|
+
|
|
103
|
+
// Rate-limiting deduplication: skip if identical within 3 seconds
|
|
104
|
+
if (now - lastSent < 3000) {
|
|
105
|
+
return {
|
|
106
|
+
id: payload.id || `notif_${now}`,
|
|
107
|
+
...payload,
|
|
108
|
+
timestamp: now,
|
|
109
|
+
read: false
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
this.recentDispatches.set(key, now);
|
|
113
|
+
|
|
114
|
+
const record: NotificationRecord = {
|
|
115
|
+
id: payload.id || `notif_${now}_${Math.random().toString(36).substring(2, 6)}`,
|
|
116
|
+
title: payload.title,
|
|
117
|
+
message: payload.message,
|
|
118
|
+
level: payload.level || 'INFO',
|
|
119
|
+
source: payload.source || 'system',
|
|
120
|
+
timestamp: payload.timestamp || now,
|
|
121
|
+
sound: payload.sound !== false,
|
|
122
|
+
desktop: payload.desktop !== false,
|
|
123
|
+
terminal: payload.terminal !== false,
|
|
124
|
+
actionUrl: payload.actionUrl,
|
|
125
|
+
read: false
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
// 1. Terminal banner
|
|
129
|
+
if (record.terminal) {
|
|
130
|
+
console.log(this.renderBanner(record));
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// 2. Audible bell
|
|
134
|
+
if (record.sound && (record.level === 'CRITICAL' || record.level === 'ERROR')) {
|
|
135
|
+
this.ringBell();
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// 3. Desktop dispatch
|
|
139
|
+
if (record.desktop) {
|
|
140
|
+
this.sendDesktop(record.title, record.message, record.sound);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// 4. Save to history
|
|
144
|
+
this.saveToHistory(record);
|
|
145
|
+
return record;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
public getHistory(): NotificationRecord[] {
|
|
149
|
+
try {
|
|
150
|
+
if (fs.existsSync(this.historyFile)) {
|
|
151
|
+
return JSON.parse(fs.readFileSync(this.historyFile, 'utf-8'));
|
|
152
|
+
}
|
|
153
|
+
} catch {
|
|
154
|
+
// Ignore
|
|
155
|
+
}
|
|
156
|
+
return [];
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
public clearHistory(): void {
|
|
160
|
+
try {
|
|
161
|
+
if (fs.existsSync(this.historyFile)) {
|
|
162
|
+
fs.unlinkSync(this.historyFile);
|
|
163
|
+
}
|
|
164
|
+
} catch {
|
|
165
|
+
// Ignore
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
private saveToHistory(record: NotificationRecord): void {
|
|
170
|
+
try {
|
|
171
|
+
const history = this.getHistory();
|
|
172
|
+
history.unshift(record);
|
|
173
|
+
// Keep at most 50
|
|
174
|
+
const trimmed = history.slice(0, 50);
|
|
175
|
+
fs.writeFileSync(this.historyFile, JSON.stringify(trimmed, null, 2));
|
|
176
|
+
} catch {
|
|
177
|
+
// Ignore write errors
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
}
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* src/system/refresher.ts — Refresher & Cache Invalidation Engine
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import fs from 'node:fs';
|
|
6
|
+
import path from 'node:path';
|
|
7
|
+
import os from 'node:os';
|
|
8
|
+
import { execSync } from 'node:child_process';
|
|
9
|
+
import type { RefreshOptions, RefreshReport } from './types.ts';
|
|
10
|
+
|
|
11
|
+
export class Refresher {
|
|
12
|
+
private projectDir: string;
|
|
13
|
+
private homeDir: string;
|
|
14
|
+
|
|
15
|
+
constructor(projectDir: string = '.') {
|
|
16
|
+
this.projectDir = path.resolve(projectDir);
|
|
17
|
+
this.homeDir = os.homedir();
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
private removeDirRecursive(dirPath: string): { count: number; bytes: number } {
|
|
21
|
+
let count = 0;
|
|
22
|
+
let bytes = 0;
|
|
23
|
+
if (!fs.existsSync(dirPath)) return { count, bytes };
|
|
24
|
+
|
|
25
|
+
try {
|
|
26
|
+
const entries = fs.readdirSync(dirPath, { withFileTypes: true });
|
|
27
|
+
for (const entry of entries) {
|
|
28
|
+
const full = path.join(dirPath, entry.name);
|
|
29
|
+
if (entry.isDirectory()) {
|
|
30
|
+
const res = this.removeDirRecursive(full);
|
|
31
|
+
count += res.count;
|
|
32
|
+
bytes += res.bytes;
|
|
33
|
+
} else {
|
|
34
|
+
try {
|
|
35
|
+
const stat = fs.statSync(full);
|
|
36
|
+
bytes += stat.size;
|
|
37
|
+
fs.unlinkSync(full);
|
|
38
|
+
count++;
|
|
39
|
+
} catch {
|
|
40
|
+
// Ignore
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
fs.rmdirSync(dirPath);
|
|
45
|
+
} catch {
|
|
46
|
+
// Ignore
|
|
47
|
+
}
|
|
48
|
+
return { count, bytes };
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
private clearBytecodeCaches(): { items: string[]; bytes: number } {
|
|
52
|
+
const items: string[] = [];
|
|
53
|
+
let bytes = 0;
|
|
54
|
+
|
|
55
|
+
const findPycache = (dir: string) => {
|
|
56
|
+
if (!fs.existsSync(dir)) return;
|
|
57
|
+
try {
|
|
58
|
+
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
59
|
+
for (const entry of entries) {
|
|
60
|
+
const full = path.join(dir, entry.name);
|
|
61
|
+
if (entry.isDirectory()) {
|
|
62
|
+
if (entry.name === '__pycache__' || entry.name === '.pytest_cache') {
|
|
63
|
+
const res = this.removeDirRecursive(full);
|
|
64
|
+
items.push(path.relative(this.projectDir, full));
|
|
65
|
+
bytes += res.bytes;
|
|
66
|
+
} else if (!entry.name.startsWith('.') && entry.name !== 'node_modules') {
|
|
67
|
+
findPycache(full);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
} catch {
|
|
72
|
+
// Ignore
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
findPycache(this.projectDir);
|
|
77
|
+
return { items, bytes };
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
private cleanStaleLocks(): string[] {
|
|
81
|
+
const cleared: string[] = [];
|
|
82
|
+
const lockFiles = [
|
|
83
|
+
path.join(this.projectDir, '.lock'),
|
|
84
|
+
path.join(this.projectDir, '.git', 'index.lock'),
|
|
85
|
+
path.join(this.projectDir, '.git', 'refs', 'heads', 'main.lock')
|
|
86
|
+
];
|
|
87
|
+
|
|
88
|
+
for (const lf of lockFiles) {
|
|
89
|
+
if (fs.existsSync(lf)) {
|
|
90
|
+
try {
|
|
91
|
+
const stat = fs.statSync(lf);
|
|
92
|
+
// If older than 5 minutes, consider stale
|
|
93
|
+
if (Date.now() - stat.mtimeMs > 5 * 60 * 1000) {
|
|
94
|
+
fs.unlinkSync(lf);
|
|
95
|
+
cleared.push(path.relative(this.projectDir, lf));
|
|
96
|
+
}
|
|
97
|
+
} catch {
|
|
98
|
+
// Ignore
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
return cleared;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
public refresh(options: RefreshOptions = {}): RefreshReport {
|
|
106
|
+
const startTime = Date.now();
|
|
107
|
+
const clearedItems: string[] = [];
|
|
108
|
+
let freedBytes = 0;
|
|
109
|
+
const messages: string[] = [];
|
|
110
|
+
const hostsSynced: string[] = [];
|
|
111
|
+
|
|
112
|
+
// 1. Clear Bytecode
|
|
113
|
+
if (options.clearBytecode !== false) {
|
|
114
|
+
const { items, bytes } = this.clearBytecodeCaches();
|
|
115
|
+
clearedItems.push(...items);
|
|
116
|
+
freedBytes += bytes;
|
|
117
|
+
if (items.length > 0) {
|
|
118
|
+
messages.push(`✓ Cleared ${items.length} Python bytecode cache directory(ies)`);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// 2. Clean Stale Lockfiles
|
|
123
|
+
if (options.cleanLockfiles !== false) {
|
|
124
|
+
const locks = this.cleanStaleLocks();
|
|
125
|
+
clearedItems.push(...locks);
|
|
126
|
+
if (locks.length > 0) {
|
|
127
|
+
messages.push(`✓ Removed ${locks.length} stale lockfile(s)`);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// 3. Reset Risk Scores
|
|
132
|
+
if (options.resetRiskScores) {
|
|
133
|
+
const riskPath = path.join(this.projectDir, 'risk-scores.json');
|
|
134
|
+
if (fs.existsSync(riskPath)) {
|
|
135
|
+
try {
|
|
136
|
+
fs.unlinkSync(riskPath);
|
|
137
|
+
clearedItems.push('risk-scores.json');
|
|
138
|
+
messages.push(`✓ Reset predictive debugging risk scores cache`);
|
|
139
|
+
} catch {
|
|
140
|
+
// Ignore
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// 4. Rebuild Skills Index
|
|
146
|
+
let skillsReindexed = false;
|
|
147
|
+
if (options.rebuildSkillsIndex !== false) {
|
|
148
|
+
try {
|
|
149
|
+
execSync('python3 core/skills_indexer.py index', { cwd: this.projectDir, stdio: 'pipe' });
|
|
150
|
+
skillsReindexed = true;
|
|
151
|
+
messages.push(`✓ Rebuilt skills-index.json and skills-index.toon`);
|
|
152
|
+
} catch (err: any) {
|
|
153
|
+
messages.push(`! Skills re-indexing notice: ${err.message}`);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// 5. Sync Integrations
|
|
158
|
+
let integrationsSynced = false;
|
|
159
|
+
if (options.syncIntegrations !== false) {
|
|
160
|
+
try {
|
|
161
|
+
const script = `from core.integrations import IntegrationInstaller; IntegrationInstaller('${this.projectDir}').provision_all()`;
|
|
162
|
+
execSync(`python3 -c "${script}"`, { cwd: this.projectDir, stdio: 'pipe' });
|
|
163
|
+
integrationsSynced = true;
|
|
164
|
+
messages.push(`✓ Synchronized supportive integrations (Ponytail, TOON, Fable, Caveman)`);
|
|
165
|
+
} catch (err: any) {
|
|
166
|
+
messages.push(`! Integrations sync notice: ${err.message}`);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// 6. Sync Host Skills
|
|
171
|
+
if (options.syncHostSkills) {
|
|
172
|
+
const hostDirs = [
|
|
173
|
+
path.join(this.homeDir, '.claude', 'skills', 'agentic-workflow'),
|
|
174
|
+
path.join(this.homeDir, '.gemini', 'config', 'skills', 'agentic-workflow'),
|
|
175
|
+
path.join(this.homeDir, '.cursor', 'skills', 'agentic-workflow'),
|
|
176
|
+
path.join(this.homeDir, '.agents', 'skills', 'agentic-workflow')
|
|
177
|
+
];
|
|
178
|
+
|
|
179
|
+
for (const hDir of hostDirs) {
|
|
180
|
+
if (fs.existsSync(hDir)) {
|
|
181
|
+
try {
|
|
182
|
+
// Update SKILL.md and marketplace.json
|
|
183
|
+
fs.copyFileSync(path.join(this.projectDir, 'SKILL.md'), path.join(hDir, 'SKILL.md'));
|
|
184
|
+
hostsSynced.push(hDir);
|
|
185
|
+
} catch {
|
|
186
|
+
// Ignore
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
if (hostsSynced.length > 0) {
|
|
191
|
+
messages.push(`✓ Updated skill definitions across ${hostsSynced.length} host environments`);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
const durationMs = Date.now() - startTime;
|
|
196
|
+
return {
|
|
197
|
+
success: true,
|
|
198
|
+
clearedItems,
|
|
199
|
+
freedBytes,
|
|
200
|
+
skillsReindexed,
|
|
201
|
+
integrationsSynced,
|
|
202
|
+
hostsSynced,
|
|
203
|
+
durationMs,
|
|
204
|
+
messages
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
}
|
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* src/system/types.ts — Shared Type Definitions for AgenticWorkflow System Engines
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
// 1. Auto-Updater Types
|
|
6
|
+
export type UpdateStrategy = 'fast-forward' | 'stash-and-pull' | 'force-reset';
|
|
7
|
+
|
|
8
|
+
export interface UpdateCheckResult {
|
|
9
|
+
hasUpdate: boolean;
|
|
10
|
+
currentCommit: string;
|
|
11
|
+
currentVersion: string;
|
|
12
|
+
remoteCommit: string;
|
|
13
|
+
remoteVersion?: string;
|
|
14
|
+
branch: string;
|
|
15
|
+
behindCount: number;
|
|
16
|
+
commits: Array<{ hash: string; message: string; date: string }>;
|
|
17
|
+
channel: 'stable' | 'beta' | 'nightly';
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface UpdateOptions {
|
|
21
|
+
strategy?: UpdateStrategy;
|
|
22
|
+
force?: boolean;
|
|
23
|
+
branch?: string;
|
|
24
|
+
autoReinstall?: boolean;
|
|
25
|
+
autoRefresh?: boolean;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface UpdateResult {
|
|
29
|
+
success: boolean;
|
|
30
|
+
previousCommit: string;
|
|
31
|
+
newCommit: string;
|
|
32
|
+
message: string;
|
|
33
|
+
stashed: boolean;
|
|
34
|
+
reinstalled: boolean;
|
|
35
|
+
refreshed: boolean;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export interface RollbackResult {
|
|
39
|
+
success: boolean;
|
|
40
|
+
rolledBackTo: string;
|
|
41
|
+
message: string;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// 2. Auto-Installer Types
|
|
45
|
+
export type HostPlatform = 'claude' | 'gemini' | 'cursor' | 'codex' | 'agents' | 'cli-symlink' | 'shell-profile';
|
|
46
|
+
|
|
47
|
+
export interface InstallTarget {
|
|
48
|
+
name: string;
|
|
49
|
+
platform: HostPlatform;
|
|
50
|
+
path: string;
|
|
51
|
+
installed: boolean;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export interface InstallOptions {
|
|
55
|
+
targets?: HostPlatform[];
|
|
56
|
+
globalBin?: boolean;
|
|
57
|
+
updateShellRc?: boolean;
|
|
58
|
+
provisionTools?: boolean;
|
|
59
|
+
dryRun?: boolean;
|
|
60
|
+
force?: boolean;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export interface InstallReport {
|
|
64
|
+
success: boolean;
|
|
65
|
+
installedTargets: InstallTarget[];
|
|
66
|
+
skippedTargets: InstallTarget[];
|
|
67
|
+
binLinked: string[];
|
|
68
|
+
shellConfigured: string[];
|
|
69
|
+
systemDeps: Array<{ name: string; available: boolean; version?: string }>;
|
|
70
|
+
messages: string[];
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// 3. Refresher Types
|
|
74
|
+
export interface RefreshOptions {
|
|
75
|
+
clearBytecode?: boolean;
|
|
76
|
+
clearTemp?: boolean;
|
|
77
|
+
rebuildSkillsIndex?: boolean;
|
|
78
|
+
syncIntegrations?: boolean;
|
|
79
|
+
syncHostSkills?: boolean;
|
|
80
|
+
resetRiskScores?: boolean;
|
|
81
|
+
cleanLockfiles?: boolean;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export interface RefreshReport {
|
|
85
|
+
success: boolean;
|
|
86
|
+
clearedItems: string[];
|
|
87
|
+
freedBytes: number;
|
|
88
|
+
skillsReindexed: boolean;
|
|
89
|
+
integrationsSynced: boolean;
|
|
90
|
+
hostsSynced: string[];
|
|
91
|
+
durationMs: number;
|
|
92
|
+
messages: string[];
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// 4. Doctor Types
|
|
96
|
+
export type DoctorSeverity = 'PASS' | 'WARN' | 'FAIL';
|
|
97
|
+
|
|
98
|
+
export interface DoctorCheckItem {
|
|
99
|
+
id: string;
|
|
100
|
+
category: 'runtime' | 'cli' | 'git' | 'dependencies' | 'state' | 'hooks' | 'skills' | 'integrations' | 'security';
|
|
101
|
+
title: string;
|
|
102
|
+
status: DoctorSeverity;
|
|
103
|
+
details: string;
|
|
104
|
+
recommendation?: string;
|
|
105
|
+
fixable: boolean;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export interface DoctorReport {
|
|
109
|
+
passed: number;
|
|
110
|
+
warned: number;
|
|
111
|
+
failed: number;
|
|
112
|
+
total: number;
|
|
113
|
+
checks: DoctorCheckItem[];
|
|
114
|
+
overallHealthy: boolean;
|
|
115
|
+
timestamp: string;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export interface FixResult {
|
|
119
|
+
checkId: string;
|
|
120
|
+
remediated: boolean;
|
|
121
|
+
message: string;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// 5. Health Engine Types
|
|
125
|
+
export type HealthGrade = 'A+' | 'A' | 'B' | 'C' | 'F';
|
|
126
|
+
|
|
127
|
+
export interface SystemVitals {
|
|
128
|
+
platform: string;
|
|
129
|
+
arch: string;
|
|
130
|
+
uptimeSeconds: number;
|
|
131
|
+
memory: {
|
|
132
|
+
totalBytes: number;
|
|
133
|
+
freeBytes: number;
|
|
134
|
+
rssBytes: number;
|
|
135
|
+
usedPercentage: number;
|
|
136
|
+
};
|
|
137
|
+
disk: {
|
|
138
|
+
freeBytes?: number;
|
|
139
|
+
totalBytes?: number;
|
|
140
|
+
};
|
|
141
|
+
nodeVersion: string;
|
|
142
|
+
bunVersion?: string;
|
|
143
|
+
pythonVersion?: string;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
export interface WorkflowVitals {
|
|
147
|
+
hasActiveWorkflow: boolean;
|
|
148
|
+
currentStep?: string;
|
|
149
|
+
circuitBreakerStatus: 'CLOSED' | 'OPEN' | 'HALF_OPEN';
|
|
150
|
+
failureStreak: number;
|
|
151
|
+
retryCount: number;
|
|
152
|
+
traceSpansCount: number;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
export interface HealthScore {
|
|
156
|
+
score: number; // 0 - 100
|
|
157
|
+
grade: HealthGrade;
|
|
158
|
+
breakdown: {
|
|
159
|
+
runtime: number; // max 20
|
|
160
|
+
workflow: number; // max 25
|
|
161
|
+
security: number; // max 20
|
|
162
|
+
dependencies: number;// max 15
|
|
163
|
+
integrity: number; // max 20
|
|
164
|
+
};
|
|
165
|
+
warnings: string[];
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
export interface HealthReport {
|
|
169
|
+
timestamp: string;
|
|
170
|
+
score: HealthScore;
|
|
171
|
+
vitals: SystemVitals;
|
|
172
|
+
workflow: WorkflowVitals;
|
|
173
|
+
services: Record<string, 'HEALTHY' | 'DEGRADED' | 'DOWN'>;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// 6. Dependencies Engine Types
|
|
177
|
+
export type DependencyType = 'bun-npm' | 'python' | 'supportive-tool' | 'system-binary';
|
|
178
|
+
|
|
179
|
+
export interface DependencyItem {
|
|
180
|
+
name: string;
|
|
181
|
+
type: DependencyType;
|
|
182
|
+
requiredVersion?: string;
|
|
183
|
+
installedVersion?: string;
|
|
184
|
+
status: 'SATISFIED' | 'OUTDATED' | 'MISSING' | 'INCOMPATIBLE';
|
|
185
|
+
description?: string;
|
|
186
|
+
location?: string;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
export interface DependencyAuditReport {
|
|
190
|
+
total: number;
|
|
191
|
+
satisfied: number;
|
|
192
|
+
missing: number;
|
|
193
|
+
outdated: number;
|
|
194
|
+
incompatible: number;
|
|
195
|
+
dependencies: DependencyItem[];
|
|
196
|
+
allSatisfied: boolean;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// 7. Notifications Engine Types
|
|
200
|
+
export type NotificationLevel = 'INFO' | 'SUCCESS' | 'WARN' | 'ERROR' | 'CRITICAL' | 'ANNOUNCEMENT';
|
|
201
|
+
|
|
202
|
+
export interface NotificationPayload {
|
|
203
|
+
id?: string;
|
|
204
|
+
title: string;
|
|
205
|
+
message: string;
|
|
206
|
+
level?: NotificationLevel;
|
|
207
|
+
source?: string;
|
|
208
|
+
timestamp?: number;
|
|
209
|
+
sound?: boolean;
|
|
210
|
+
desktop?: boolean;
|
|
211
|
+
terminal?: boolean;
|
|
212
|
+
actionUrl?: string;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
export interface NotificationRecord extends NotificationPayload {
|
|
216
|
+
id: string;
|
|
217
|
+
timestamp: number;
|
|
218
|
+
read: boolean;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// 8. Announcement Engine Types
|
|
222
|
+
export type AnnouncementCategory = 'SECURITY' | 'FEATURE' | 'UPDATE' | 'TIP' | 'MAINTENANCE';
|
|
223
|
+
|
|
224
|
+
export interface AnnouncementItem {
|
|
225
|
+
id: string;
|
|
226
|
+
title: string;
|
|
227
|
+
body: string;
|
|
228
|
+
category: AnnouncementCategory;
|
|
229
|
+
date: string;
|
|
230
|
+
version?: string;
|
|
231
|
+
priority: 'low' | 'normal' | 'high' | 'urgent';
|
|
232
|
+
url?: string;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
export interface AnnouncementState {
|
|
236
|
+
seenIds: string[];
|
|
237
|
+
lastChecked: string;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// 9. Version Tracker Types
|
|
241
|
+
export interface ComponentVersion {
|
|
242
|
+
name: string;
|
|
243
|
+
version: string;
|
|
244
|
+
channel: string;
|
|
245
|
+
path?: string;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
export interface VersionMatrix {
|
|
249
|
+
cliVersion: string;
|
|
250
|
+
tsEngineVersion: string;
|
|
251
|
+
pyEngineVersion: string;
|
|
252
|
+
toonProtocolVersion: string;
|
|
253
|
+
uahfHooksVersion: string;
|
|
254
|
+
gitCommit: string;
|
|
255
|
+
gitBranch: string;
|
|
256
|
+
gitClean: boolean;
|
|
257
|
+
buildDate: string;
|
|
258
|
+
components: ComponentVersion[];
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
export interface MigrationStep {
|
|
262
|
+
fromVersion: string;
|
|
263
|
+
toVersion: string;
|
|
264
|
+
name: string;
|
|
265
|
+
description: string;
|
|
266
|
+
executed: boolean;
|
|
267
|
+
timestamp?: string;
|
|
268
|
+
}
|