@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.
Files changed (118) hide show
  1. package/.claude-plugin/plugin.json +10 -0
  2. package/.codex-plugin/plugin.json +13 -0
  3. package/.skills.json +19 -0
  4. package/AGENTS.md +1344 -0
  5. package/CLAUDE.md +178 -0
  6. package/GEMINI.md +102 -0
  7. package/LICENSE +21 -0
  8. package/README.md +350 -0
  9. package/SKILL.md +132 -0
  10. package/bin/agentic-hooks.sh +79 -0
  11. package/bin/cli.js +1060 -0
  12. package/core/__init__.py +52 -0
  13. package/core/ai_evaluator.py +117 -0
  14. package/core/autopilot_engine.py +368 -0
  15. package/core/clean_code_guard.py +188 -0
  16. package/core/engine_py/__init__.py +29 -0
  17. package/core/engine_py/agent_worker.py +136 -0
  18. package/core/engine_py/decider.py +150 -0
  19. package/core/engine_py/energy.py +45 -0
  20. package/core/engine_py/event_bus.py +63 -0
  21. package/core/engine_py/executor.py +186 -0
  22. package/core/engine_py/models.py +193 -0
  23. package/core/engine_py/queue.py +314 -0
  24. package/core/engine_py/runner.py +116 -0
  25. package/core/engine_py/system_workers.py +70 -0
  26. package/core/engine_py/toon_adapter.py +586 -0
  27. package/core/engine_py/verification_controller.py +208 -0
  28. package/core/engine_py/worker.py +167 -0
  29. package/core/engine_spec/event_schema.json +65 -0
  30. package/core/engine_spec/example_workflow.yaml +73 -0
  31. package/core/engine_spec/workflow_schema.json +127 -0
  32. package/core/hooks/__init__.py +29 -0
  33. package/core/hooks/adapters/__init__.py +25 -0
  34. package/core/hooks/adapters/claude_adapter.py +83 -0
  35. package/core/hooks/adapters/cli_agent_adapter.py +82 -0
  36. package/core/hooks/adapters/codex_adapter.py +78 -0
  37. package/core/hooks/adapters/cursor_adapter.py +73 -0
  38. package/core/hooks/adapters/gemini_adapter.py +93 -0
  39. package/core/hooks/adapters/homebrew_adapter.py +69 -0
  40. package/core/hooks/adapters/mcp_proxy.py +133 -0
  41. package/core/hooks/adapters/shell_adapter.py +65 -0
  42. package/core/hooks/dispatcher.py +118 -0
  43. package/core/hooks/policy_engine.py +375 -0
  44. package/core/hooks/session_end.py +141 -0
  45. package/core/hooks/types.py +147 -0
  46. package/core/integrations/__init__.py +28 -0
  47. package/core/integrations/installer.py +225 -0
  48. package/core/integrations/lifecycle_director.py +175 -0
  49. package/core/integrations/registry.py +105 -0
  50. package/core/multi_agent_system.py +164 -0
  51. package/core/skills_indexer.py +742 -0
  52. package/core/system/__init__.py +25 -0
  53. package/core/system/announcements.py +72 -0
  54. package/core/system/dependencies.py +69 -0
  55. package/core/system/doctor.py +171 -0
  56. package/core/system/health.py +144 -0
  57. package/core/system/installer.py +137 -0
  58. package/core/system/notifications.py +97 -0
  59. package/core/system/refresher.py +110 -0
  60. package/core/system/updater.py +167 -0
  61. package/core/system/version_tracker.py +65 -0
  62. package/docs/architecture_plan.md +7 -0
  63. package/docs/guides/failure-recovery.md +714 -0
  64. package/docs/implementation_summary.md +10 -0
  65. package/docs/protocols/autopilot-execution.md +148 -0
  66. package/docs/protocols/code-change-protocol.md +49 -0
  67. package/docs/protocols/context-preservation-detail.md +114 -0
  68. package/docs/protocols/quality-gates.md +110 -0
  69. package/docs/protocols/ulw-mode.md +60 -0
  70. package/docs/research_findings.md +10 -0
  71. package/docs/solutions/autonomous-autopilot-engine-architecture.md +38 -0
  72. package/install.sh +111 -0
  73. package/marketplace.json +37 -0
  74. package/package.json +81 -0
  75. package/skills/agentic-workflow/SKILL.md +132 -0
  76. package/skills/agentic-workflow/skill-spec.json +100 -0
  77. package/soul.md +445 -0
  78. package/src/engine_ts/decider.ts +186 -0
  79. package/src/engine_ts/event-bus.ts +57 -0
  80. package/src/engine_ts/executor.ts +262 -0
  81. package/src/engine_ts/index.ts +12 -0
  82. package/src/engine_ts/queue.ts +93 -0
  83. package/src/engine_ts/runner.ts +108 -0
  84. package/src/engine_ts/skills-indexer.ts +264 -0
  85. package/src/engine_ts/toon-adapter.ts +91 -0
  86. package/src/engine_ts/types.ts +134 -0
  87. package/src/engine_ts/verification-controller.ts +204 -0
  88. package/src/engine_ts/worker.ts +280 -0
  89. package/src/hooks/adapters/claude-adapter.ts +54 -0
  90. package/src/hooks/adapters/cli-agent-adapter.ts +46 -0
  91. package/src/hooks/adapters/codex-adapter.ts +69 -0
  92. package/src/hooks/adapters/cursor-adapter.ts +60 -0
  93. package/src/hooks/adapters/gemini-adapter.ts +71 -0
  94. package/src/hooks/adapters/homebrew-adapter.ts +36 -0
  95. package/src/hooks/adapters/mcp-proxy.ts +66 -0
  96. package/src/hooks/adapters/shell-adapter.ts +42 -0
  97. package/src/hooks/dispatcher.ts +113 -0
  98. package/src/hooks/index.ts +16 -0
  99. package/src/hooks/policy-engine.ts +376 -0
  100. package/src/hooks/session-end.ts +125 -0
  101. package/src/hooks/types.ts +61 -0
  102. package/src/index.d.ts +34 -0
  103. package/src/index.ts +23 -0
  104. package/src/integrations/index.ts +7 -0
  105. package/src/integrations/installer.ts +208 -0
  106. package/src/integrations/lifecycle-director.ts +139 -0
  107. package/src/integrations/registry.ts +82 -0
  108. package/src/system/announcements.ts +143 -0
  109. package/src/system/dependencies.ts +176 -0
  110. package/src/system/doctor.ts +374 -0
  111. package/src/system/health.ts +270 -0
  112. package/src/system/index.ts +14 -0
  113. package/src/system/installer.ts +262 -0
  114. package/src/system/notifications.ts +180 -0
  115. package/src/system/refresher.ts +207 -0
  116. package/src/system/types.ts +268 -0
  117. package/src/system/updater.ts +219 -0
  118. package/src/system/version-tracker.ts +137 -0
@@ -0,0 +1,143 @@
1
+ /**
2
+ * src/system/announcements.ts — Announcement & Bulletin Engine
3
+ */
4
+
5
+ import fs from 'node:fs';
6
+ import path from 'node:path';
7
+ import type { AnnouncementItem, AnnouncementState, AnnouncementCategory } from './types.ts';
8
+
9
+ export class AnnouncementEngine {
10
+ private projectDir: string;
11
+ private announcementsFile: string;
12
+ private stateFile: string;
13
+
14
+ constructor(projectDir: string = '.') {
15
+ this.projectDir = path.resolve(projectDir);
16
+ this.announcementsFile = path.join(this.projectDir, '.announcements.json');
17
+ this.stateFile = path.join(this.projectDir, '.announcements_seen.json');
18
+ }
19
+
20
+ private getDefaultAnnouncements(): AnnouncementItem[] {
21
+ return [
22
+ {
23
+ id: 'ann_v110_engines',
24
+ title: 'Universal System Engines Suite Online',
25
+ body: 'AgenticWorkflow v1.1.0 now integrates 9 core toolchain engines: Auto-Updater, Auto-Installer, Refresher, Doctor, Health Engine, Dependencies Engine, Notifications, Announcements, and Version Tracker with dual-runtime parity.',
26
+ category: 'FEATURE',
27
+ date: '2026-09-06',
28
+ version: '1.1.0',
29
+ priority: 'high'
30
+ },
31
+ {
32
+ id: 'ann_toon_v41',
33
+ title: 'TOON Protocol v4.1 Released',
34
+ body: 'Token-Oriented Object Notation (v4.1) delivers 30-60% token compression across all multi-agent dialogues and workflow telemetry.',
35
+ category: 'UPDATE',
36
+ date: '2026-09-01',
37
+ version: '1.0.5',
38
+ priority: 'normal'
39
+ },
40
+ {
41
+ id: 'ann_uahf_online',
42
+ title: 'Universal Agentic Hooks Framework (UAHF)',
43
+ body: 'UAHF governs Claude Code, Cursor, Codex, OpenCode, and shell processes with zero-drift safety policies.',
44
+ category: 'FEATURE',
45
+ date: '2026-08-25',
46
+ version: '1.0.0',
47
+ priority: 'normal'
48
+ }
49
+ ];
50
+ }
51
+
52
+ private getState(): AnnouncementState {
53
+ try {
54
+ if (fs.existsSync(this.stateFile)) {
55
+ const raw = JSON.parse(fs.readFileSync(this.stateFile, 'utf-8'));
56
+ const seenIds = Array.isArray(raw.seenIds) ? raw.seenIds : (Array.isArray(raw.seen_ids) ? raw.seen_ids : []);
57
+ return { seenIds, lastChecked: raw.lastChecked || raw.last_checked || new Date().toISOString() };
58
+ }
59
+ } catch {
60
+ // Ignore
61
+ }
62
+ return { seenIds: [], lastChecked: new Date().toISOString() };
63
+ }
64
+
65
+ private saveState(state: AnnouncementState): void {
66
+ try {
67
+ const data = {
68
+ seenIds: state.seenIds,
69
+ seen_ids: state.seenIds,
70
+ lastChecked: state.lastChecked
71
+ };
72
+ fs.writeFileSync(this.stateFile, JSON.stringify(data, null, 2));
73
+ } catch {
74
+ // Ignore
75
+ }
76
+ }
77
+
78
+ public listAll(): Array<AnnouncementItem & { seen: boolean }> {
79
+ let list = this.getDefaultAnnouncements();
80
+ if (fs.existsSync(this.announcementsFile)) {
81
+ try {
82
+ const custom = JSON.parse(fs.readFileSync(this.announcementsFile, 'utf-8'));
83
+ if (Array.isArray(custom)) {
84
+ list = [...custom, ...list];
85
+ }
86
+ } catch {
87
+ // Ignore
88
+ }
89
+ }
90
+
91
+ const state = this.getState();
92
+ return list.map(item => ({
93
+ ...item,
94
+ seen: state.seenIds.includes(item.id)
95
+ }));
96
+ }
97
+
98
+ public getUnread(): AnnouncementItem[] {
99
+ return this.listAll().filter(a => !a.seen);
100
+ }
101
+
102
+ public markAsRead(id: string): void {
103
+ const state = this.getState();
104
+ if (!state.seenIds.includes(id)) {
105
+ state.seenIds.push(id);
106
+ this.saveState(state);
107
+ }
108
+ }
109
+
110
+ public markAllAsRead(): void {
111
+ const all = this.listAll();
112
+ const state: AnnouncementState = {
113
+ seenIds: all.map(a => a.id),
114
+ lastChecked: new Date().toISOString()
115
+ };
116
+ this.saveState(state);
117
+ }
118
+
119
+ public addAnnouncement(item: AnnouncementItem): void {
120
+ let custom: AnnouncementItem[] = [];
121
+ if (fs.existsSync(this.announcementsFile)) {
122
+ try {
123
+ custom = JSON.parse(fs.readFileSync(this.announcementsFile, 'utf-8'));
124
+ } catch {
125
+ // Ignore
126
+ }
127
+ }
128
+ custom.unshift(item);
129
+ fs.writeFileSync(this.announcementsFile, JSON.stringify(custom, null, 2));
130
+ }
131
+
132
+ public renderBroadcastBanner(): string | null {
133
+ const unread = this.getUnread();
134
+ if (unread.length === 0) return null;
135
+
136
+ const top = unread[0];
137
+ const color = '\x1b[35m'; // Magenta
138
+ const reset = '\x1b[0m';
139
+ const bold = '\x1b[1m';
140
+
141
+ return `\n${color}📢 [Announcement]${reset} ${bold}${top.title}${reset} (${top.date})\n ${top.body.substring(0, 100)}${top.body.length > 100 ? '...' : ''}\n Run 'agentic-workflow announcements' to view all.\n`;
142
+ }
143
+ }
@@ -0,0 +1,176 @@
1
+ /**
2
+ * src/system/dependencies.ts — Lib Dependencies & Multi-Ecosystem Auditor Engine
3
+ */
4
+
5
+ import fs from 'node:fs';
6
+ import path from 'node:path';
7
+ import { execSync } from 'node:child_process';
8
+ import type { DependencyItem, DependencyAuditReport } from './types.ts';
9
+
10
+ export class DependenciesEngine {
11
+ private projectDir: string;
12
+
13
+ constructor(projectDir: string = '.') {
14
+ this.projectDir = path.resolve(projectDir);
15
+ }
16
+
17
+ private checkNpmPackage(pkgName: string): { installed: boolean; version?: string } {
18
+ try {
19
+ const pkgJsonPath = path.join(this.projectDir, 'node_modules', pkgName, 'package.json');
20
+ if (fs.existsSync(pkgJsonPath)) {
21
+ const pkg = JSON.parse(fs.readFileSync(pkgJsonPath, 'utf-8'));
22
+ return { installed: true, version: pkg.version };
23
+ }
24
+ } catch {
25
+ // Ignore
26
+ }
27
+ return { installed: false };
28
+ }
29
+
30
+ private checkPythonModule(modName: string): { available: boolean } {
31
+ try {
32
+ execSync(`python3 -c "import ${modName}"`, { cwd: this.projectDir, stdio: 'pipe' });
33
+ return { available: true };
34
+ } catch {
35
+ return { available: false };
36
+ }
37
+ }
38
+
39
+ private checkBinary(cmd: string): { available: boolean; version?: string } {
40
+ try {
41
+ const out = execSync(`${cmd} --version`, { stdio: 'pipe', encoding: 'utf-8' }).trim();
42
+ return { available: true, version: out.split('\n')[0] };
43
+ } catch {
44
+ return { available: false };
45
+ }
46
+ }
47
+
48
+ public audit(): DependencyAuditReport {
49
+ const deps: DependencyItem[] = [];
50
+
51
+ // 1. Bun / Node Packages
52
+ const packageJsonPath = path.join(this.projectDir, 'package.json');
53
+ if (fs.existsSync(packageJsonPath)) {
54
+ try {
55
+ const pkgData = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));
56
+ const declared = { ...pkgData.dependencies, ...pkgData.devDependencies };
57
+
58
+ for (const [name, reqVer] of Object.entries(declared)) {
59
+ const check = this.checkNpmPackage(name);
60
+ deps.push({
61
+ name,
62
+ type: 'bun-npm',
63
+ requiredVersion: reqVer as string,
64
+ installedVersion: check.version,
65
+ status: check.installed ? 'SATISFIED' : 'MISSING',
66
+ location: path.join('node_modules', name)
67
+ });
68
+ }
69
+ } catch {
70
+ // Ignore
71
+ }
72
+ }
73
+
74
+ // 2. Python Modules
75
+ const pyModules = ['json', 'pathlib', 'unittest', 'dataclasses', 'asyncio', 'hashlib'];
76
+ for (const mod of pyModules) {
77
+ const check = this.checkPythonModule(mod);
78
+ deps.push({
79
+ name: `python:${mod}`,
80
+ type: 'python',
81
+ status: check.available ? 'SATISFIED' : 'MISSING',
82
+ description: 'Standard Python 3 dual-engine module'
83
+ });
84
+ }
85
+
86
+ // 3. Supportive Tools Integrations
87
+ const integrationsPath = path.join(this.projectDir, 'integrations.json');
88
+ if (fs.existsSync(integrationsPath)) {
89
+ try {
90
+ const intData = JSON.parse(fs.readFileSync(integrationsPath, 'utf-8'));
91
+ for (const item of intData.integrations || []) {
92
+ deps.push({
93
+ name: `integration:${item.id}`,
94
+ type: 'supportive-tool',
95
+ status: 'SATISFIED',
96
+ description: item.description,
97
+ location: item.repo
98
+ });
99
+ }
100
+ } catch {
101
+ // Ignore
102
+ }
103
+ }
104
+
105
+ // 4. System Toolchain Binaries
106
+ const binaries = ['bun', 'python3', 'git'];
107
+ for (const bin of binaries) {
108
+ const check = this.checkBinary(bin);
109
+ deps.push({
110
+ name: `bin:${bin}`,
111
+ type: 'system-binary',
112
+ installedVersion: check.version,
113
+ status: check.available ? 'SATISFIED' : 'MISSING'
114
+ });
115
+ }
116
+
117
+ const satisfied = deps.filter(d => d.status === 'SATISFIED').length;
118
+ const missing = deps.filter(d => d.status === 'MISSING').length;
119
+ const outdated = deps.filter(d => d.status === 'OUTDATED').length;
120
+ const incompatible = deps.filter(d => d.status === 'INCOMPATIBLE').length;
121
+
122
+ return {
123
+ total: deps.length,
124
+ satisfied,
125
+ missing,
126
+ outdated,
127
+ incompatible,
128
+ dependencies: deps,
129
+ allSatisfied: missing === 0 && incompatible === 0
130
+ };
131
+ }
132
+
133
+ public installMissing(): { success: boolean; message: string } {
134
+ try {
135
+ execSync('bun install', { cwd: this.projectDir, stdio: 'pipe' });
136
+ return { success: true, message: 'Bun dependencies installed successfully.' };
137
+ } catch (err: any) {
138
+ return { success: false, message: `Installation failed: ${err.message}` };
139
+ }
140
+ }
141
+
142
+ public formatTree(): string {
143
+ const audit = this.audit();
144
+ let tree = `agentic-workflow@1.1.0\n`;
145
+
146
+ const byType: Record<string, DependencyItem[]> = {};
147
+ for (const dep of audit.dependencies) {
148
+ byType[dep.type] = byType[dep.type] || [];
149
+ byType[dep.type].push(dep);
150
+ }
151
+
152
+ const typeKeys = Object.keys(byType);
153
+ typeKeys.forEach((type, tIdx) => {
154
+ const isLastType = tIdx === typeKeys.length - 1;
155
+ const typeBranch = isLastType ? '└── ' : '├── ';
156
+ tree += `${typeBranch}${type.toUpperCase()}\n`;
157
+
158
+ const items = byType[type];
159
+ items.forEach((item, iIdx) => {
160
+ const isLastItem = iIdx === items.length - 1;
161
+ const subBranch = (isLastType ? ' ' : '│ ') + (isLastItem ? '└── ' : '├── ');
162
+ const statusIcon = item.status === 'SATISFIED' ? '✓' : '✗';
163
+ const versionStr = item.installedVersion ? ` (${item.installedVersion})` : '';
164
+ tree += `${subBranch}[${statusIcon}] ${item.name}${versionStr}\n`;
165
+ });
166
+ });
167
+
168
+ return tree;
169
+ }
170
+
171
+ public formatToon(audit: DependencyAuditReport): string {
172
+ return `dependencies_audit{total:${audit.total},satisfied:${audit.satisfied},missing:${audit.missing},all_ok:${audit.allSatisfied}}:
173
+ items[${audit.dependencies.length}]{name,type,status,version}:
174
+ ${audit.dependencies.map(d => ` ${d.name},${d.type},${d.status},${d.installedVersion || d.requiredVersion || 'default'}`).join('\n')}`;
175
+ }
176
+ }
@@ -0,0 +1,374 @@
1
+ /**
2
+ * src/system/doctor.ts — Doctor Diagnostic & Automated Remediation 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 { DoctorCheckItem, DoctorReport, FixResult } from './types.ts';
10
+
11
+ export class DoctorEngine {
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 runCmd(cmd: string): { ok: boolean; stdout: string } {
21
+ try {
22
+ const out = execSync(cmd, { cwd: this.projectDir, stdio: 'pipe', encoding: 'utf-8' }).trim();
23
+ return { ok: true, stdout: out };
24
+ } catch {
25
+ return { ok: false, stdout: '' };
26
+ }
27
+ }
28
+
29
+ public diagnose(): DoctorReport {
30
+ const checks: DoctorCheckItem[] = [];
31
+
32
+ // 1. Runtime Checks
33
+ // Bun
34
+ const bunCheck = this.runCmd('bun --version');
35
+ if (bunCheck.ok) {
36
+ checks.push({
37
+ id: 'runtime-bun',
38
+ category: 'runtime',
39
+ title: 'Bun JavaScript/TypeScript Runtime',
40
+ status: 'PASS',
41
+ details: `Bun v${bunCheck.stdout} installed and online.`,
42
+ fixable: false
43
+ });
44
+ } else {
45
+ checks.push({
46
+ id: 'runtime-bun',
47
+ category: 'runtime',
48
+ title: 'Bun JavaScript/TypeScript Runtime',
49
+ status: 'FAIL',
50
+ details: 'Bun runtime is not installed or not in PATH.',
51
+ recommendation: 'Install Bun via: curl -fsSL https://bun.sh/install | bash',
52
+ fixable: false
53
+ });
54
+ }
55
+
56
+ // Node
57
+ const nodeCheck = this.runCmd('node --version');
58
+ if (nodeCheck.ok) {
59
+ checks.push({
60
+ id: 'runtime-node',
61
+ category: 'runtime',
62
+ title: 'Node.js Runtime',
63
+ status: 'PASS',
64
+ details: `Node.js ${nodeCheck.stdout} detected.`,
65
+ fixable: false
66
+ });
67
+ } else {
68
+ checks.push({
69
+ id: 'runtime-node',
70
+ category: 'runtime',
71
+ title: 'Node.js Runtime',
72
+ status: 'WARN',
73
+ details: 'Node.js runtime not found. Bun will be used as primary engine.',
74
+ fixable: false
75
+ });
76
+ }
77
+
78
+ // Python 3
79
+ const pyCheck = this.runCmd('python3 --version');
80
+ if (pyCheck.ok) {
81
+ checks.push({
82
+ id: 'runtime-python',
83
+ category: 'runtime',
84
+ title: 'Python 3 Runtime',
85
+ status: 'PASS',
86
+ details: `${pyCheck.stdout} detected and available for dual engine parity.`,
87
+ fixable: false
88
+ });
89
+ } else {
90
+ checks.push({
91
+ id: 'runtime-python',
92
+ category: 'runtime',
93
+ title: 'Python 3 Runtime',
94
+ status: 'FAIL',
95
+ details: 'Python 3 is required for deterministic verification hooks and SOT validation.',
96
+ recommendation: 'Install Python 3.10+ via brew install python3 or package manager.',
97
+ fixable: false
98
+ });
99
+ }
100
+
101
+ // 2. CLI & PATH Checks
102
+ const cliPath = path.join(this.projectDir, 'bin', 'cli.js');
103
+ if (fs.existsSync(cliPath)) {
104
+ try {
105
+ const stats = fs.statSync(cliPath);
106
+ const isExecutable = !!(stats.mode & 0o111);
107
+ checks.push({
108
+ id: 'cli-permission',
109
+ category: 'cli',
110
+ title: 'CLI Executable Permission (bin/cli.js)',
111
+ status: isExecutable ? 'PASS' : 'WARN',
112
+ details: isExecutable ? 'bin/cli.js has executable bit set.' : 'bin/cli.js lacks execute permission.',
113
+ recommendation: 'Run: chmod +x bin/cli.js',
114
+ fixable: !isExecutable
115
+ });
116
+ } catch {
117
+ // Ignore
118
+ }
119
+ } else {
120
+ checks.push({
121
+ id: 'cli-permission',
122
+ category: 'cli',
123
+ title: 'CLI Executable Permission (bin/cli.js)',
124
+ status: 'FAIL',
125
+ details: 'bin/cli.js not found in project repository.',
126
+ fixable: false
127
+ });
128
+ }
129
+
130
+ const localBin = path.join(this.homeDir, '.local', 'bin', 'agentic-workflow');
131
+ const usrBin = '/usr/local/bin/agentic-workflow';
132
+ const isLinked = fs.existsSync(localBin) || fs.existsSync(usrBin);
133
+ checks.push({
134
+ id: 'cli-symlink',
135
+ category: 'cli',
136
+ title: 'Global CLI Binary Symlink',
137
+ status: isLinked ? 'PASS' : 'WARN',
138
+ details: isLinked ? `Linked at ${fs.existsSync(localBin) ? localBin : usrBin}` : 'CLI binary is not symlinked into user PATH.',
139
+ recommendation: 'Run agentic-workflow install or doctor --fix to link binary.',
140
+ fixable: !isLinked
141
+ });
142
+
143
+ // 3. Git Repository Checks
144
+ const gitDir = path.join(this.projectDir, '.git');
145
+ if (fs.existsSync(gitDir)) {
146
+ const branchCheck = this.runCmd('git rev-parse --abbrev-ref HEAD');
147
+ checks.push({
148
+ id: 'git-repo',
149
+ category: 'git',
150
+ title: 'Git Version Control & Tracking',
151
+ status: 'PASS',
152
+ details: `Git repository active on branch '${branchCheck.stdout || 'main'}'.`,
153
+ fixable: false
154
+ });
155
+ } else {
156
+ checks.push({
157
+ id: 'git-repo',
158
+ category: 'git',
159
+ title: 'Git Version Control & Tracking',
160
+ status: 'WARN',
161
+ details: 'No .git directory found. Auto-updater requires git tracking.',
162
+ recommendation: 'Initialize git repository: git init',
163
+ fixable: false
164
+ });
165
+ }
166
+
167
+ // 4. Dependencies Checks
168
+ const nodeModules = path.join(this.projectDir, 'node_modules');
169
+ const toonModule = path.join(this.projectDir, 'node_modules', '@toon-format', 'toon');
170
+ const hasDeps = fs.existsSync(nodeModules) && fs.existsSync(toonModule);
171
+ checks.push({
172
+ id: 'dependencies-npm',
173
+ category: 'dependencies',
174
+ title: 'Node/Bun Dependencies (@toon-format/toon)',
175
+ status: hasDeps ? 'PASS' : 'WARN',
176
+ details: hasDeps ? 'Dependencies installed and verified.' : 'node_modules missing or @toon-format/toon not installed.',
177
+ recommendation: 'Run bun install to resolve dependencies.',
178
+ fixable: !hasDeps
179
+ });
180
+
181
+ // 5. State & SOT Checks
182
+ const sotPath = path.join(this.projectDir, 'state.yaml');
183
+ if (fs.existsSync(sotPath)) {
184
+ const content = fs.readFileSync(sotPath, 'utf-8');
185
+ const hasCore = content.includes('workflow:') && content.includes('current_step:');
186
+ checks.push({
187
+ id: 'state-sot',
188
+ category: 'state',
189
+ title: 'Single Source of Truth (state.yaml)',
190
+ status: hasCore ? 'PASS' : 'WARN',
191
+ details: hasCore ? 'state.yaml is present with valid workflow structure.' : 'state.yaml is missing core schema fields.',
192
+ recommendation: 'Run agentic-workflow validate or doctor --fix.',
193
+ fixable: !hasCore
194
+ });
195
+ } else {
196
+ checks.push({
197
+ id: 'state-sot',
198
+ category: 'state',
199
+ title: 'Single Source of Truth (state.yaml)',
200
+ status: 'WARN',
201
+ details: 'state.yaml not found. Workflow is in idle state ready for new plan.',
202
+ fixable: false
203
+ });
204
+ }
205
+
206
+ // 6. UAHF Hooks & Ledger Checks
207
+ const hooksDir = path.join(this.projectDir, '.claude', 'hooks', 'scripts');
208
+ const hasHooks = fs.existsSync(path.join(hooksDir, 'context_guard.py')) && fs.existsSync(path.join(hooksDir, 'block_destructive_commands.py'));
209
+ checks.push({
210
+ id: 'hooks-uahf',
211
+ category: 'hooks',
212
+ title: 'Universal Agentic Hooks Framework Scripts',
213
+ status: hasHooks ? 'PASS' : 'FAIL',
214
+ details: hasHooks ? 'UAHF deterministic verification and safety hooks present.' : 'UAHF hook scripts missing.',
215
+ fixable: false
216
+ });
217
+
218
+ const ledgerFile = path.join(this.projectDir, 'ledger.jsonl');
219
+ let ledgerWritable = false;
220
+ try {
221
+ if (!fs.existsSync(ledgerFile)) {
222
+ fs.writeFileSync(ledgerFile, '');
223
+ }
224
+ fs.accessSync(ledgerFile, fs.constants.W_OK);
225
+ ledgerWritable = true;
226
+ } catch {
227
+ ledgerWritable = false;
228
+ }
229
+ checks.push({
230
+ id: 'hooks-ledger',
231
+ category: 'hooks',
232
+ title: 'Audit Ledger (ledger.jsonl)',
233
+ status: ledgerWritable ? 'PASS' : 'WARN',
234
+ details: ledgerWritable ? 'ledger.jsonl is writable.' : 'ledger.jsonl cannot be written.',
235
+ fixable: !ledgerWritable
236
+ });
237
+
238
+ // 7. Skills Mesh Checks
239
+ const skillsJson = path.join(this.projectDir, 'skills-index.json');
240
+ const skillsToon = path.join(this.projectDir, 'skills-index.toon');
241
+ const hasSkillsIndex = fs.existsSync(skillsJson) && fs.existsSync(skillsToon);
242
+ checks.push({
243
+ id: 'skills-mesh',
244
+ category: 'skills',
245
+ title: 'Agentic Skills Mesh Index (JSON & TOON)',
246
+ status: hasSkillsIndex ? 'PASS' : 'WARN',
247
+ details: hasSkillsIndex ? 'Dual skills index synchronized.' : 'skills-index.json or skills-index.toon missing.',
248
+ recommendation: 'Run agentic-workflow skills index or doctor --fix.',
249
+ fixable: !hasSkillsIndex
250
+ });
251
+
252
+ // 8. Supportive Integrations Checks
253
+ const integrationsFile = path.join(this.projectDir, 'integrations.json');
254
+ const hasIntegrations = fs.existsSync(integrationsFile);
255
+ checks.push({
256
+ id: 'integrations-registry',
257
+ category: 'integrations',
258
+ title: 'Supportive Tools Registry (integrations.json)',
259
+ status: hasIntegrations ? 'PASS' : 'WARN',
260
+ details: hasIntegrations ? 'integrations.json present.' : 'integrations.json missing.',
261
+ fixable: !hasIntegrations
262
+ });
263
+
264
+ // 9. Security Checks
265
+ const gitignore = path.join(this.projectDir, '.gitignore');
266
+ const hasGitignore = fs.existsSync(gitignore) && fs.readFileSync(gitignore, 'utf-8').includes('.env');
267
+ checks.push({
268
+ id: 'security-env-guard',
269
+ category: 'security',
270
+ title: 'Environment & Secrets Protection (.gitignore)',
271
+ status: hasGitignore ? 'PASS' : 'WARN',
272
+ details: hasGitignore ? '.gitignore protects .env and secret files.' : '.gitignore lacks explicit .env rule.',
273
+ recommendation: 'Add .env* to .gitignore',
274
+ fixable: !hasGitignore
275
+ });
276
+
277
+ const passed = checks.filter(c => c.status === 'PASS').length;
278
+ const warned = checks.filter(c => c.status === 'WARN').length;
279
+ const failed = checks.filter(c => c.status === 'FAIL').length;
280
+
281
+ return {
282
+ passed,
283
+ warned,
284
+ failed,
285
+ total: checks.length,
286
+ checks,
287
+ overallHealthy: failed === 0,
288
+ timestamp: new Date().toISOString()
289
+ };
290
+ }
291
+
292
+ public fixAll(): FixResult[] {
293
+ const report = this.diagnose();
294
+ const fixableChecks = report.checks.filter(c => c.fixable && c.status !== 'PASS');
295
+ const results: FixResult[] = [];
296
+
297
+ for (const check of fixableChecks) {
298
+ const res = this.fixCheck(check.id);
299
+ results.push(res);
300
+ }
301
+ return results;
302
+ }
303
+
304
+ public fixCheck(checkId: string): FixResult {
305
+ switch (checkId) {
306
+ case 'cli-permission': {
307
+ const cliPath = path.join(this.projectDir, 'bin', 'cli.js');
308
+ try {
309
+ fs.chmodSync(cliPath, 0o755);
310
+ return { checkId, remediated: true, message: 'Granted executable permission (0755) to bin/cli.js.' };
311
+ } catch (e: any) {
312
+ return { checkId, remediated: false, message: `Failed to chmod bin/cli.js: ${e.message}` };
313
+ }
314
+ }
315
+
316
+ case 'cli-symlink': {
317
+ const localBinDir = path.join(this.homeDir, '.local', 'bin');
318
+ if (!fs.existsSync(localBinDir)) {
319
+ fs.mkdirSync(localBinDir, { recursive: true });
320
+ }
321
+ const target = path.join(localBinDir, 'agentic-workflow');
322
+ const src = path.join(this.projectDir, 'bin', 'cli.js');
323
+ try {
324
+ if (fs.existsSync(target)) fs.unlinkSync(target);
325
+ fs.symlinkSync(src, target);
326
+ return { checkId, remediated: true, message: `Symlinked ${target} -> ${src}.` };
327
+ } catch (e: any) {
328
+ return { checkId, remediated: false, message: `Failed to symlink CLI: ${e.message}` };
329
+ }
330
+ }
331
+
332
+ case 'dependencies-npm': {
333
+ try {
334
+ execSync('bun install', { cwd: this.projectDir, stdio: 'pipe' });
335
+ return { checkId, remediated: true, message: 'Successfully ran bun install.' };
336
+ } catch (e: any) {
337
+ return { checkId, remediated: false, message: `bun install failed: ${e.message}` };
338
+ }
339
+ }
340
+
341
+ case 'skills-mesh': {
342
+ try {
343
+ execSync('python3 core/skills_indexer.py index', { cwd: this.projectDir, stdio: 'pipe' });
344
+ return { checkId, remediated: true, message: 'Rebuilt skills-index.json and skills-index.toon.' };
345
+ } catch (e: any) {
346
+ return { checkId, remediated: false, message: `Skills indexing failed: ${e.message}` };
347
+ }
348
+ }
349
+
350
+ case 'security-env-guard': {
351
+ const gitignore = path.join(this.projectDir, '.gitignore');
352
+ try {
353
+ fs.appendFileSync(gitignore, '\n.env\n.env.*\n*.pem\n');
354
+ return { checkId, remediated: true, message: 'Appended .env protection rules to .gitignore.' };
355
+ } catch (e: any) {
356
+ return { checkId, remediated: false, message: `Failed updating .gitignore: ${e.message}` };
357
+ }
358
+ }
359
+
360
+ case 'hooks-ledger': {
361
+ const ledgerFile = path.join(this.projectDir, 'ledger.jsonl');
362
+ try {
363
+ fs.writeFileSync(ledgerFile, '');
364
+ return { checkId, remediated: true, message: 'Initialized ledger.jsonl.' };
365
+ } catch (e: any) {
366
+ return { checkId, remediated: false, message: `Failed creating ledger: ${e.message}` };
367
+ }
368
+ }
369
+
370
+ default:
371
+ return { checkId, remediated: false, message: `No automated fix available for ${checkId}.` };
372
+ }
373
+ }
374
+ }