@cpretzinger/boss-claude 1.0.0 → 1.0.2

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 (87) hide show
  1. package/README.md +304 -1
  2. package/bin/boss-claude.js +1138 -0
  3. package/bin/commands/mode.js +250 -0
  4. package/bin/onyx-guard.js +259 -0
  5. package/bin/onyx-guard.sh +251 -0
  6. package/bin/prompts.js +284 -0
  7. package/bin/rollback.js +85 -0
  8. package/bin/setup-wizard.js +492 -0
  9. package/config/.env.example +17 -0
  10. package/lib/README.md +83 -0
  11. package/lib/agent-logger.js +61 -0
  12. package/lib/agents/memory-engineers/github-memory-engineer.js +251 -0
  13. package/lib/agents/memory-engineers/postgres-memory-engineer.js +633 -0
  14. package/lib/agents/memory-engineers/qdrant-memory-engineer.js +358 -0
  15. package/lib/agents/memory-engineers/redis-memory-engineer.js +383 -0
  16. package/lib/agents/memory-supervisor.js +526 -0
  17. package/lib/agents/registry.js +135 -0
  18. package/lib/auto-monitor.js +131 -0
  19. package/lib/checkpoint-hook.js +112 -0
  20. package/lib/checkpoint.js +319 -0
  21. package/lib/commentator.js +213 -0
  22. package/lib/context-scribe.js +120 -0
  23. package/lib/delegation-strategies.js +326 -0
  24. package/lib/hierarchy-validator.js +643 -0
  25. package/lib/index.js +15 -0
  26. package/lib/init-with-mode.js +261 -0
  27. package/lib/init.js +44 -6
  28. package/lib/memory-result-aggregator.js +252 -0
  29. package/lib/memory.js +35 -7
  30. package/lib/mode-enforcer.js +473 -0
  31. package/lib/onyx-banner.js +169 -0
  32. package/lib/onyx-identity.js +214 -0
  33. package/lib/onyx-monitor.js +381 -0
  34. package/lib/onyx-reminder.js +188 -0
  35. package/lib/onyx-tool-interceptor.js +341 -0
  36. package/lib/onyx-wrapper.js +315 -0
  37. package/lib/orchestrator-gate.js +334 -0
  38. package/lib/output-formatter.js +296 -0
  39. package/lib/postgres.js +1 -1
  40. package/lib/prompt-injector.js +220 -0
  41. package/lib/prompts.js +532 -0
  42. package/lib/session.js +153 -6
  43. package/lib/setup/README.md +187 -0
  44. package/lib/setup/env-manager.js +785 -0
  45. package/lib/setup/error-recovery.js +630 -0
  46. package/lib/setup/explain-scopes.js +385 -0
  47. package/lib/setup/github-instructions.js +333 -0
  48. package/lib/setup/github-repo.js +254 -0
  49. package/lib/setup/import-credentials.js +498 -0
  50. package/lib/setup/index.js +62 -0
  51. package/lib/setup/init-postgres.js +785 -0
  52. package/lib/setup/init-redis.js +456 -0
  53. package/lib/setup/integration-test.js +652 -0
  54. package/lib/setup/progress.js +357 -0
  55. package/lib/setup/rollback.js +670 -0
  56. package/lib/setup/rollback.test.js +452 -0
  57. package/lib/setup/setup-with-rollback.example.js +351 -0
  58. package/lib/setup/summary.js +400 -0
  59. package/lib/setup/test-github-setup.js +10 -0
  60. package/lib/setup/test-postgres-init.js +98 -0
  61. package/lib/setup/verify-setup.js +102 -0
  62. package/lib/task-agent-worker.js +235 -0
  63. package/lib/token-monitor.js +466 -0
  64. package/lib/tool-wrapper-integration.js +369 -0
  65. package/lib/tool-wrapper.js +387 -0
  66. package/lib/validators/README.md +497 -0
  67. package/lib/validators/config.js +583 -0
  68. package/lib/validators/config.test.js +175 -0
  69. package/lib/validators/github.js +310 -0
  70. package/lib/validators/github.test.js +61 -0
  71. package/lib/validators/index.js +15 -0
  72. package/lib/validators/postgres.js +525 -0
  73. package/package.json +98 -13
  74. package/scripts/benchmark-memory.js +433 -0
  75. package/scripts/check-secrets.sh +12 -0
  76. package/scripts/fetch-todos.mjs +148 -0
  77. package/scripts/graceful-shutdown.sh +156 -0
  78. package/scripts/install-onyx-hooks.js +373 -0
  79. package/scripts/install.js +119 -18
  80. package/scripts/redis-monitor.js +284 -0
  81. package/scripts/redis-setup.js +412 -0
  82. package/scripts/test-memory-retrieval.js +201 -0
  83. package/scripts/validate-exports.js +68 -0
  84. package/scripts/validate-package.js +120 -0
  85. package/scripts/verify-onyx-deployment.js +309 -0
  86. package/scripts/verify-redis-deployment.js +354 -0
  87. package/scripts/verify-redis-init.js +219 -0
@@ -0,0 +1,315 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * ONYX WRAPPER - Claude Code Integration
4
+ *
5
+ * Drop-in replacement for direct tool calls that enforces ONYX delegation rules.
6
+ * This wrapper intercepts ALL tool calls and applies pre-hook validation.
7
+ *
8
+ * USAGE:
9
+ * import { onyxWrapper } from '@cpretzinger/boss-claude/lib/onyx-wrapper.js';
10
+ *
11
+ * // Wrap tool execution
12
+ * const result = await onyxWrapper.executeTool('Read', { file_path: '/path/to/file.js' });
13
+ *
14
+ * INTEGRATION:
15
+ * Replace direct tool calls in ONYX agent with onyxWrapper.executeTool()
16
+ */
17
+
18
+ import chalk from 'chalk';
19
+ import onyxInterceptor from './onyx-tool-interceptor.js';
20
+
21
+ /**
22
+ * ONYX Wrapper Class
23
+ * Wraps tool execution and enforces delegation rules
24
+ */
25
+ export class OnyxWrapper {
26
+ constructor() {
27
+ this.interceptor = onyxInterceptor;
28
+ this.executionLog = [];
29
+ }
30
+
31
+ /**
32
+ * Execute tool with pre-hook validation
33
+ *
34
+ * @param {string} toolName - Name of the tool (Read, Write, Edit, etc.)
35
+ * @param {Object} toolParams - Tool parameters
36
+ * @param {Object} options - Execution options
37
+ * @returns {Promise<Object>} Tool execution result
38
+ */
39
+ async executeTool(toolName, toolParams = {}, options = {}) {
40
+ const startTime = Date.now();
41
+
42
+ // PRE-HOOK: Intercept before execution
43
+ const interceptionResult = await this.interceptor.interceptToolCall(toolName, toolParams);
44
+
45
+ // Log execution attempt
46
+ this._logExecution(toolName, toolParams, interceptionResult, startTime);
47
+
48
+ if (!interceptionResult.allowed) {
49
+ // Tool blocked - handle delegation or rejection
50
+ return this._handleBlockedTool(toolName, toolParams, interceptionResult, options);
51
+ }
52
+
53
+ if (interceptionResult.override) {
54
+ console.log(chalk.yellow('\n⚠️ ONYX delegation override - proceeding with caution'));
55
+ }
56
+
57
+ // Tool allowed - execute if executor provided
58
+ if (options.executor && typeof options.executor === 'function') {
59
+ try {
60
+ const result = await options.executor(toolName, toolParams);
61
+ return {
62
+ success: true,
63
+ tool: toolName,
64
+ result,
65
+ override: interceptionResult.override || false,
66
+ executionTime: Date.now() - startTime
67
+ };
68
+ } catch (error) {
69
+ return {
70
+ success: false,
71
+ tool: toolName,
72
+ error: error.message,
73
+ executionTime: Date.now() - startTime
74
+ };
75
+ }
76
+ }
77
+
78
+ // No executor - return allowed status
79
+ return {
80
+ success: true,
81
+ allowed: true,
82
+ tool: toolName,
83
+ params: toolParams,
84
+ override: interceptionResult.override || false,
85
+ message: 'Tool allowed - no executor provided (dry run)',
86
+ executionTime: Date.now() - startTime
87
+ };
88
+ }
89
+
90
+ /**
91
+ * Handle blocked tool - auto-delegate or reject
92
+ */
93
+ async _handleBlockedTool(toolName, toolParams, interceptionResult, options) {
94
+ if (interceptionResult.delegateTo === 'Task') {
95
+ // Auto-delegate to Task tool
96
+ console.log(chalk.cyan('\n📤 Auto-delegating to Task tool...'));
97
+ console.log(chalk.dim(interceptionResult.delegationMessage));
98
+
99
+ if (options.taskExecutor && typeof options.taskExecutor === 'function') {
100
+ // Execute via Task tool
101
+ try {
102
+ const taskResult = await options.taskExecutor({
103
+ description: interceptionResult.delegationMessage,
104
+ context: {
105
+ originalTool: toolName,
106
+ originalParams: toolParams,
107
+ delegatedBy: 'ONYX',
108
+ delegationReason: interceptionResult.reason
109
+ }
110
+ });
111
+
112
+ return {
113
+ success: true,
114
+ delegated: true,
115
+ delegateTo: 'Task',
116
+ tool: toolName,
117
+ originalParams: toolParams,
118
+ delegationMessage: interceptionResult.delegationMessage,
119
+ taskResult
120
+ };
121
+ } catch (error) {
122
+ return {
123
+ success: false,
124
+ delegated: true,
125
+ delegateTo: 'Task',
126
+ tool: toolName,
127
+ error: error.message
128
+ };
129
+ }
130
+ }
131
+
132
+ // No task executor - return delegation info
133
+ return {
134
+ success: false,
135
+ delegated: true,
136
+ delegateTo: 'Task',
137
+ tool: toolName,
138
+ originalParams: toolParams,
139
+ delegationMessage: interceptionResult.delegationMessage,
140
+ message: 'Delegation required - no task executor provided'
141
+ };
142
+ }
143
+
144
+ if (interceptionResult.rejected) {
145
+ // Tool rejected entirely
146
+ console.log(chalk.red('\n❌ Tool call rejected by ONYX interceptor'));
147
+
148
+ return {
149
+ success: false,
150
+ blocked: true,
151
+ rejected: true,
152
+ tool: toolName,
153
+ reason: interceptionResult.reason
154
+ };
155
+ }
156
+
157
+ // Generic block
158
+ return {
159
+ success: false,
160
+ blocked: true,
161
+ tool: toolName,
162
+ reason: interceptionResult.reason
163
+ };
164
+ }
165
+
166
+ /**
167
+ * Log tool execution attempt
168
+ */
169
+ _logExecution(toolName, toolParams, interceptionResult, startTime) {
170
+ const logEntry = {
171
+ timestamp: new Date().toISOString(),
172
+ tool: toolName,
173
+ params: toolParams,
174
+ allowed: interceptionResult.allowed,
175
+ blocked: interceptionResult.blocked || false,
176
+ delegated: interceptionResult.delegateTo ? true : false,
177
+ override: interceptionResult.override || false,
178
+ startTime
179
+ };
180
+
181
+ this.executionLog.push(logEntry);
182
+
183
+ // Keep only last 100 entries
184
+ if (this.executionLog.length > 100) {
185
+ this.executionLog.shift();
186
+ }
187
+ }
188
+
189
+ /**
190
+ * Get execution log
191
+ */
192
+ getExecutionLog(limit = 20) {
193
+ return this.executionLog.slice(-limit);
194
+ }
195
+
196
+ /**
197
+ * Print execution summary
198
+ */
199
+ printExecutionSummary() {
200
+ console.log(chalk.blue('\n📊 ONYX TOOL EXECUTION SUMMARY'));
201
+ console.log(chalk.dim('═'.repeat(80)));
202
+
203
+ const stats = this._calculateStats();
204
+
205
+ console.log(chalk.white(`Total Calls: ${chalk.magenta(stats.total)}`));
206
+ console.log(chalk.white(`Allowed: ${chalk.green(stats.allowed)}`));
207
+ console.log(chalk.white(`Blocked: ${chalk.red(stats.blocked)}`));
208
+ console.log(chalk.white(`Delegated: ${chalk.cyan(stats.delegated)}`));
209
+ console.log(chalk.white(`Overrides: ${chalk.yellow(stats.overrides)}`));
210
+
211
+ console.log(chalk.dim('\n─'.repeat(80)));
212
+
213
+ if (stats.topTools.length > 0) {
214
+ console.log(chalk.white('\nTop Tools Used:'));
215
+ stats.topTools.forEach((item, i) => {
216
+ console.log(chalk.dim(` ${i + 1}. ${item.tool} (${item.count} calls)`));
217
+ });
218
+ }
219
+
220
+ console.log(chalk.dim('═'.repeat(80)));
221
+ }
222
+
223
+ /**
224
+ * Calculate execution statistics
225
+ */
226
+ _calculateStats() {
227
+ const stats = {
228
+ total: this.executionLog.length,
229
+ allowed: 0,
230
+ blocked: 0,
231
+ delegated: 0,
232
+ overrides: 0,
233
+ toolCounts: {}
234
+ };
235
+
236
+ this.executionLog.forEach(log => {
237
+ if (log.allowed) stats.allowed++;
238
+ if (log.blocked) stats.blocked++;
239
+ if (log.delegated) stats.delegated++;
240
+ if (log.override) stats.overrides++;
241
+
242
+ stats.toolCounts[log.tool] = (stats.toolCounts[log.tool] || 0) + 1;
243
+ });
244
+
245
+ // Sort tools by usage
246
+ stats.topTools = Object.entries(stats.toolCounts)
247
+ .map(([tool, count]) => ({ tool, count }))
248
+ .sort((a, b) => b.count - a.count)
249
+ .slice(0, 5);
250
+
251
+ return stats;
252
+ }
253
+
254
+ /**
255
+ * Clear execution log
256
+ */
257
+ clearLog() {
258
+ this.executionLog = [];
259
+ console.log(chalk.green('\n✅ Execution log cleared'));
260
+ }
261
+ }
262
+
263
+ // Singleton instance
264
+ const onyxWrapper = new OnyxWrapper();
265
+
266
+ export default onyxWrapper;
267
+
268
+ /**
269
+ * INTEGRATION EXAMPLES:
270
+ *
271
+ * 1. Basic usage - dry run (no executor):
272
+ *
273
+ * import onyxWrapper from '@cpretzinger/boss-claude/lib/onyx-wrapper.js';
274
+ *
275
+ * const result = await onyxWrapper.executeTool('Read', {
276
+ * file_path: '/path/to/file.js'
277
+ * });
278
+ *
279
+ * if (result.success && result.allowed) {
280
+ * console.log('Tool allowed');
281
+ * } else if (result.delegated) {
282
+ * console.log('Delegated to:', result.delegateTo);
283
+ * }
284
+ *
285
+ * 2. With executor function:
286
+ *
287
+ * const result = await onyxWrapper.executeTool('Read', {
288
+ * file_path: '/path/to/file.js'
289
+ * }, {
290
+ * executor: async (tool, params) => {
291
+ * // Your actual tool execution logic
292
+ * return await actualReadTool(params);
293
+ * }
294
+ * });
295
+ *
296
+ * 3. With Task delegation executor:
297
+ *
298
+ * const result = await onyxWrapper.executeTool('Grep', {
299
+ * pattern: 'function',
300
+ * path: '/src'
301
+ * }, {
302
+ * taskExecutor: async (taskParams) => {
303
+ * // Execute via Task tool
304
+ * return await taskTool.execute(taskParams);
305
+ * }
306
+ * });
307
+ *
308
+ * 4. Print execution summary:
309
+ *
310
+ * onyxWrapper.printExecutionSummary();
311
+ *
312
+ * 5. Get interceptor report:
313
+ *
314
+ * onyxWrapper.interceptor.printReport();
315
+ */
@@ -0,0 +1,334 @@
1
+ /**
2
+ * ORCHESTRATOR GATE - Pre-Action Hook System
3
+ *
4
+ * Purpose: Enforce mode checks BEFORE every significant action
5
+ * Pattern: Decorator pattern wrapping critical operations
6
+ *
7
+ * Architecture:
8
+ * 1. Intercepts all major operations (delegate, execute, review)
9
+ * 2. Validates mode + capabilities + token budget
10
+ * 3. Logs all actions (allowed or blocked)
11
+ * 4. Provides clear error messages when blocked
12
+ */
13
+
14
+ import { getEnforcer, MODES, MODE_CAPABILITIES } from './mode-enforcer.js';
15
+ import { loadIdentity } from './identity.js';
16
+
17
+ // ==========================================
18
+ // ORCHESTRATOR GATE CLASS
19
+ // ==========================================
20
+ export class OrchestratorGate {
21
+ constructor() {
22
+ this.enforcer = getEnforcer();
23
+ }
24
+
25
+ /**
26
+ * BEFORE DELEGATE - Check if delegation is allowed
27
+ *
28
+ * @param {string} targetAgent - Agent to delegate to
29
+ * @param {object} task - Task description
30
+ * @param {number} estimatedTokens - Estimated cost
31
+ */
32
+ async beforeDelegate(targetAgent, task, estimatedTokens = 0) {
33
+ console.log(`\n[ORCHESTRATOR GATE] Checking delegation permission...`);
34
+ console.log(`Target agent: ${targetAgent}`);
35
+ console.log(`Task: ${task.description || 'N/A'}`);
36
+ console.log(`Estimated tokens: ${estimatedTokens}`);
37
+
38
+ // 1. Check if current mode allows delegation
39
+ await this.enforcer.checkCapability(
40
+ 'canDelegate',
41
+ `Delegating to ${targetAgent}: ${task.description || 'task'}`
42
+ );
43
+
44
+ // 2. Check token budget if applicable
45
+ if (estimatedTokens > 0) {
46
+ await this.enforcer.enforceTokenBudget(
47
+ estimatedTokens,
48
+ `Delegation to ${targetAgent}`
49
+ );
50
+ }
51
+
52
+ // 3. Verify orchestrator mode is active
53
+ const currentMode = await this.enforcer.getCurrentMode();
54
+ if (currentMode !== MODES.ORCHESTRATOR) {
55
+ throw new Error(
56
+ `[GATE BLOCKED] Delegation requires orchestrator mode.\n` +
57
+ `Current mode: ${currentMode}\n` +
58
+ `Switch with: boss-claude mode orchestrator`
59
+ );
60
+ }
61
+
62
+ console.log(`[ORCHESTRATOR GATE] ✅ Delegation approved`);
63
+ return true;
64
+ }
65
+
66
+ /**
67
+ * BEFORE EXECUTE - Check if direct execution is allowed
68
+ *
69
+ * @param {object} action - Action to execute
70
+ * @param {number} estimatedTokens - Estimated cost
71
+ */
72
+ async beforeExecute(action, estimatedTokens = 0) {
73
+ console.log(`\n[ORCHESTRATOR GATE] Checking execution permission...`);
74
+ console.log(`Action: ${action.description || 'N/A'}`);
75
+ console.log(`Estimated tokens: ${estimatedTokens}`);
76
+
77
+ // 1. Check if current mode allows execution
78
+ await this.enforcer.checkCapability(
79
+ 'canExecute',
80
+ `Executing: ${action.description || 'action'}`
81
+ );
82
+
83
+ // 2. Check token budget
84
+ if (estimatedTokens > 0) {
85
+ await this.enforcer.enforceTokenBudget(
86
+ estimatedTokens,
87
+ `Direct execution: ${action.description || 'action'}`
88
+ );
89
+ }
90
+
91
+ console.log(`[ORCHESTRATOR GATE] ✅ Execution approved`);
92
+ return true;
93
+ }
94
+
95
+ /**
96
+ * BEFORE REVIEW - Check if code review is allowed
97
+ *
98
+ * @param {string} workerAgent - Agent whose code is being reviewed
99
+ * @param {object} code - Code to review
100
+ */
101
+ async beforeReview(workerAgent, code) {
102
+ console.log(`\n[ORCHESTRATOR GATE] Checking review permission...`);
103
+ console.log(`Worker agent: ${workerAgent}`);
104
+
105
+ // 1. Check if current mode allows review
106
+ await this.enforcer.checkCapability(
107
+ 'canReview',
108
+ `Reviewing code from ${workerAgent}`
109
+ );
110
+
111
+ // 2. Verify orchestrator or review mode is active
112
+ const currentMode = await this.enforcer.getCurrentMode();
113
+ if (currentMode !== MODES.ORCHESTRATOR && currentMode !== MODES.REVIEW) {
114
+ throw new Error(
115
+ `[GATE BLOCKED] Code review requires orchestrator or review mode.\n` +
116
+ `Current mode: ${currentMode}\n` +
117
+ `Switch with: boss-claude mode orchestrator`
118
+ );
119
+ }
120
+
121
+ console.log(`[ORCHESTRATOR GATE] ✅ Review approved`);
122
+ return true;
123
+ }
124
+
125
+ /**
126
+ * BEFORE LEARN - Check if learning/memory write is allowed
127
+ *
128
+ * @param {string} learningType - Type of learning (success|failure|pattern)
129
+ * @param {object} data - Learning data
130
+ */
131
+ async beforeLearn(learningType, data) {
132
+ console.log(`\n[ORCHESTRATOR GATE] Checking learning permission...`);
133
+ console.log(`Learning type: ${learningType}`);
134
+
135
+ // 1. Check if current mode allows learning
136
+ await this.enforcer.checkCapability(
137
+ 'canLearn',
138
+ `Recording learning: ${learningType}`
139
+ );
140
+
141
+ console.log(`[ORCHESTRATOR GATE] ✅ Learning approved`);
142
+ return true;
143
+ }
144
+
145
+ /**
146
+ * BEFORE CONFIG CHANGE - Check if global config modification is allowed
147
+ *
148
+ * @param {string} configKey - Config key being modified
149
+ * @param {any} newValue - New value
150
+ */
151
+ async beforeConfigChange(configKey, newValue) {
152
+ console.log(`\n[ORCHESTRATOR GATE] Checking config change permission...`);
153
+ console.log(`Config key: ${configKey}`);
154
+
155
+ // 1. Check if current mode allows global config changes
156
+ await this.enforcer.checkCapability(
157
+ 'canModifyGlobalConfig',
158
+ `Modifying global config: ${configKey}`
159
+ );
160
+
161
+ // 2. Verify orchestrator mode is active
162
+ const currentMode = await this.enforcer.getCurrentMode();
163
+ if (currentMode !== MODES.ORCHESTRATOR) {
164
+ throw new Error(
165
+ `[GATE BLOCKED] Global config changes require orchestrator mode.\n` +
166
+ `Current mode: ${currentMode}\n` +
167
+ `Config key: ${configKey}\n` +
168
+ `Switch with: boss-claude mode orchestrator`
169
+ );
170
+ }
171
+
172
+ console.log(`[ORCHESTRATOR GATE] ✅ Config change approved`);
173
+ return true;
174
+ }
175
+
176
+ /**
177
+ * GET GATE STATUS - Current mode and capabilities
178
+ */
179
+ async getStatus() {
180
+ const currentMode = await this.enforcer.getCurrentMode();
181
+ const metadata = await this.enforcer.getModeMetadata();
182
+ const capabilities = MODE_CAPABILITIES[currentMode];
183
+ const agentIdentity = await this.enforcer.getAgentIdentity();
184
+ const bossIdentity = await loadIdentity();
185
+
186
+ return {
187
+ mode: currentMode,
188
+ metadata,
189
+ capabilities,
190
+ agent: agentIdentity,
191
+ boss: {
192
+ level: bossIdentity.level,
193
+ xp: bossIdentity.xp,
194
+ token_bank: bossIdentity.token_bank
195
+ },
196
+ restrictions: {
197
+ canDelegate: capabilities.canDelegate,
198
+ canReview: capabilities.canReview,
199
+ canExecute: capabilities.canExecute,
200
+ canLearn: capabilities.canLearn,
201
+ canModifyGlobalConfig: capabilities.canModifyGlobalConfig,
202
+ maxTokenBudget: capabilities.maxTokenBudget
203
+ }
204
+ };
205
+ }
206
+
207
+ /**
208
+ * PRINT STATUS - Human-readable gate status
209
+ */
210
+ async printStatus() {
211
+ const status = await this.getStatus();
212
+
213
+ console.log(`\n╔══════════════════════════════════════════════════════════╗`);
214
+ console.log(`║ ORCHESTRATOR GATE STATUS ║`);
215
+ console.log(`╚══════════════════════════════════════════════════════════╝`);
216
+ console.log(`\nMode: ${status.mode.toUpperCase()}`);
217
+ console.log(`Set by: ${status.metadata?.setBy || 'N/A'}`);
218
+ console.log(`Set at: ${status.metadata?.setAt || 'N/A'}`);
219
+ console.log(`Reason: ${status.metadata?.reason || 'N/A'}`);
220
+
221
+ if (status.agent) {
222
+ console.log(`\nAgent: ${status.agent.agent}`);
223
+ console.log(`Domain: ${status.agent.domain || 'N/A'}`);
224
+ }
225
+
226
+ console.log(`\nBoss Identity:`);
227
+ console.log(` Level: ${status.boss.level}`);
228
+ console.log(` XP: ${status.boss.xp}`);
229
+ console.log(` Token Bank: ${status.boss.token_bank}`);
230
+
231
+ console.log(`\nCapabilities:`);
232
+ console.log(` Delegate: ${status.restrictions.canDelegate ? '✅' : '❌'}`);
233
+ console.log(` Review: ${status.restrictions.canReview ? '✅' : '❌'}`);
234
+ console.log(` Execute: ${status.restrictions.canExecute ? '✅' : '❌'}`);
235
+ console.log(` Learn: ${status.restrictions.canLearn ? '✅' : '❌'}`);
236
+ console.log(` Modify Config: ${status.restrictions.canModifyGlobalConfig ? '✅' : '❌'}`);
237
+ console.log(` Max Token Budget: ${status.restrictions.maxTokenBudget.toLocaleString()}`);
238
+
239
+ console.log(`\n`);
240
+ }
241
+ }
242
+
243
+ // ==========================================
244
+ // SINGLETON INSTANCE
245
+ // ==========================================
246
+ let gateInstance = null;
247
+
248
+ export function getGate() {
249
+ if (!gateInstance) {
250
+ gateInstance = new OrchestratorGate();
251
+ }
252
+ return gateInstance;
253
+ }
254
+
255
+ // ==========================================
256
+ // CONVENIENCE WRAPPER FUNCTIONS
257
+ // ==========================================
258
+
259
+ /**
260
+ * Initialize orchestrator mode - Call at session start
261
+ */
262
+ export async function initOrchestratorMode(sessionId = null) {
263
+ const enforcer = getEnforcer();
264
+
265
+ await enforcer.setMode(MODES.ORCHESTRATOR, {
266
+ agent: 'boss-claude',
267
+ reason: 'session-start',
268
+ sessionId
269
+ });
270
+
271
+ await enforcer.setAgentIdentity('boss-claude', 'orchestrator');
272
+
273
+ console.log(`\n[ORCHESTRATOR MODE] Initialized`);
274
+ console.log(`Session ID: ${sessionId || 'N/A'}`);
275
+ console.log(`Mode: ${MODES.ORCHESTRATOR}`);
276
+
277
+ return true;
278
+ }
279
+
280
+ /**
281
+ * Switch to specialist mode
282
+ */
283
+ export async function switchToSpecialist(agentName, domain) {
284
+ const enforcer = getEnforcer();
285
+
286
+ await enforcer.setMode(MODES.SPECIALIST, {
287
+ agent: agentName,
288
+ reason: 'specialist-delegation',
289
+ domain
290
+ });
291
+
292
+ await enforcer.setAgentIdentity(agentName, domain);
293
+
294
+ console.log(`\n[MODE SWITCH] Switched to specialist mode`);
295
+ console.log(`Agent: ${agentName}`);
296
+ console.log(`Domain: ${domain}`);
297
+
298
+ return true;
299
+ }
300
+
301
+ /**
302
+ * Return to orchestrator mode
303
+ */
304
+ export async function returnToOrchestrator() {
305
+ const enforcer = getEnforcer();
306
+
307
+ await enforcer.setMode(MODES.ORCHESTRATOR, {
308
+ agent: 'boss-claude',
309
+ reason: 'specialist-task-complete'
310
+ });
311
+
312
+ await enforcer.setAgentIdentity('boss-claude', 'orchestrator');
313
+
314
+ console.log(`\n[MODE SWITCH] Returned to orchestrator mode`);
315
+
316
+ return true;
317
+ }
318
+
319
+ /**
320
+ * Emergency reset to safe default
321
+ */
322
+ export async function emergencyReset() {
323
+ const enforcer = getEnforcer();
324
+ await enforcer.resetMode();
325
+ console.log(`\n[EMERGENCY RESET] Mode reset to WORKER (safe default)`);
326
+ }
327
+
328
+ // ==========================================
329
+ // EXPORTS
330
+ // ==========================================
331
+ export {
332
+ MODES,
333
+ MODE_CAPABILITIES
334
+ };