@esotech/contextuate 2.0.0 → 2.1.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 (105) hide show
  1. package/README.md +169 -1
  2. package/dist/commands/claude.d.ts +21 -0
  3. package/dist/commands/claude.js +213 -0
  4. package/dist/commands/context.d.ts +1 -0
  5. package/dist/commands/create.d.ts +3 -0
  6. package/dist/commands/index.d.ts +4 -0
  7. package/dist/commands/init.d.ts +7 -0
  8. package/dist/commands/init.js +67 -6
  9. package/dist/commands/install.d.ts +28 -0
  10. package/dist/commands/install.js +116 -11
  11. package/dist/commands/monitor.d.ts +55 -0
  12. package/dist/commands/monitor.js +1007 -0
  13. package/dist/commands/remove.d.ts +3 -0
  14. package/dist/commands/run.d.ts +6 -0
  15. package/dist/index.d.ts +2 -0
  16. package/dist/index.js +113 -1
  17. package/dist/monitor/daemon/circuit-breaker.d.ts +121 -0
  18. package/dist/monitor/daemon/circuit-breaker.js +552 -0
  19. package/dist/monitor/daemon/cli.d.ts +8 -0
  20. package/dist/monitor/daemon/cli.js +82 -0
  21. package/dist/monitor/daemon/index.d.ts +137 -0
  22. package/dist/monitor/daemon/index.js +695 -0
  23. package/dist/monitor/daemon/notifier.d.ts +25 -0
  24. package/dist/monitor/daemon/notifier.js +98 -0
  25. package/dist/monitor/daemon/processor.d.ts +89 -0
  26. package/dist/monitor/daemon/processor.js +455 -0
  27. package/dist/monitor/daemon/state.d.ts +80 -0
  28. package/dist/monitor/daemon/state.js +162 -0
  29. package/dist/monitor/daemon/watcher.d.ts +47 -0
  30. package/dist/monitor/daemon/watcher.js +171 -0
  31. package/dist/monitor/daemon/wrapper-manager.d.ts +106 -0
  32. package/dist/monitor/daemon/wrapper-manager.js +374 -0
  33. package/dist/monitor/hooks/emit-event.js +652 -0
  34. package/dist/monitor/persistence/file-store.d.ts +88 -0
  35. package/dist/monitor/persistence/file-store.js +335 -0
  36. package/dist/monitor/persistence/index.d.ts +7 -0
  37. package/dist/monitor/persistence/index.js +10 -0
  38. package/dist/monitor/server/adapters/redis.d.ts +38 -0
  39. package/dist/monitor/server/adapters/redis.js +213 -0
  40. package/dist/monitor/server/adapters/unix-socket.d.ts +33 -0
  41. package/dist/monitor/server/adapters/unix-socket.js +182 -0
  42. package/dist/monitor/server/broker.d.ts +135 -0
  43. package/dist/monitor/server/broker.js +475 -0
  44. package/dist/monitor/server/cli.d.ts +8 -0
  45. package/dist/monitor/server/cli.js +98 -0
  46. package/dist/monitor/server/fastify.d.ts +16 -0
  47. package/dist/monitor/server/fastify.js +184 -0
  48. package/dist/monitor/server/index.d.ts +36 -0
  49. package/dist/monitor/server/index.js +153 -0
  50. package/dist/monitor/server/websocket.d.ts +80 -0
  51. package/dist/monitor/server/websocket.js +453 -0
  52. package/dist/monitor/ui/assets/index-4IssW9On.js +59 -0
  53. package/dist/monitor/ui/assets/index-vo9hLe5R.css +32 -0
  54. package/dist/monitor/ui/favicon.png +0 -0
  55. package/dist/monitor/ui/index.html +14 -0
  56. package/dist/monitor/ui/logo.png +0 -0
  57. package/dist/monitor/ui/logo.svg +1 -0
  58. package/dist/runtime/driver.d.ts +16 -0
  59. package/dist/runtime/tools.d.ts +10 -0
  60. package/dist/templates/README.md +33 -7
  61. package/dist/templates/agents/aegis.md +4 -0
  62. package/dist/templates/agents/archon.md +13 -22
  63. package/dist/templates/agents/atlas.md +4 -0
  64. package/dist/templates/agents/canvas.md +4 -0
  65. package/dist/templates/agents/chronicle.md +4 -0
  66. package/dist/templates/agents/chronos.md +4 -0
  67. package/dist/templates/agents/cipher.md +4 -0
  68. package/dist/templates/agents/crucible.md +4 -0
  69. package/dist/templates/agents/echo.md +4 -0
  70. package/dist/templates/agents/forge.md +4 -0
  71. package/dist/templates/agents/ledger.md +4 -0
  72. package/dist/templates/agents/meridian.md +4 -0
  73. package/dist/templates/agents/nexus.md +4 -0
  74. package/dist/templates/agents/pythia.md +217 -0
  75. package/dist/templates/agents/scribe.md +4 -0
  76. package/dist/templates/agents/sentinel.md +4 -0
  77. package/dist/templates/agents/{oracle.md → thoth.md} +11 -7
  78. package/dist/templates/agents/unity.md +4 -0
  79. package/dist/templates/agents/vox.md +4 -0
  80. package/dist/templates/agents/weaver.md +4 -0
  81. package/dist/templates/framework-agents/documentation-expert.md +3 -3
  82. package/dist/templates/framework-agents/tools-expert.md +8 -8
  83. package/dist/templates/skills/consult.md +138 -0
  84. package/dist/templates/skills/orchestrate.md +173 -0
  85. package/dist/templates/skills/pythia.md +37 -0
  86. package/dist/templates/standards/agent-roles.md +68 -21
  87. package/dist/templates/standards/coding-standards.md +9 -26
  88. package/dist/templates/templates/context.md +17 -2
  89. package/dist/templates/templates/contextuate.md +21 -28
  90. package/dist/templates/templates/standards/go.md +167 -0
  91. package/dist/templates/templates/standards/java.md +167 -0
  92. package/dist/templates/templates/standards/javascript.md +292 -0
  93. package/dist/templates/templates/standards/php.md +181 -0
  94. package/dist/templates/templates/standards/python.md +175 -0
  95. package/dist/templates/tools/agent-creator.md +252 -0
  96. package/dist/templates/tools/agent-creator.tool.md +2 -2
  97. package/dist/templates/tools/quickref.md +216 -0
  98. package/dist/templates/tools/spawn.md +31 -0
  99. package/dist/templates/tools/standards-detector.md +301 -0
  100. package/dist/templates/version.json +1 -1
  101. package/dist/types/monitor.d.ts +660 -0
  102. package/dist/types/monitor.js +75 -0
  103. package/dist/utils/git.d.ts +9 -0
  104. package/dist/utils/tokens.d.ts +10 -0
  105. package/package.json +18 -5
@@ -0,0 +1,374 @@
1
+ "use strict";
2
+ /**
3
+ * Wrapper Manager
4
+ *
5
+ * Manages Claude wrapper sessions with PTY.
6
+ * Spawns and manages Claude processes, handles input/output streaming,
7
+ * persists session state, and cleans up on exit.
8
+ */
9
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ var desc = Object.getOwnPropertyDescriptor(m, k);
12
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
13
+ desc = { enumerable: true, get: function() { return m[k]; } };
14
+ }
15
+ Object.defineProperty(o, k2, desc);
16
+ }) : (function(o, m, k, k2) {
17
+ if (k2 === undefined) k2 = k;
18
+ o[k2] = m[k];
19
+ }));
20
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
21
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
22
+ }) : function(o, v) {
23
+ o["default"] = v;
24
+ });
25
+ var __importStar = (this && this.__importStar) || (function () {
26
+ var ownKeys = function(o) {
27
+ ownKeys = Object.getOwnPropertyNames || function (o) {
28
+ var ar = [];
29
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
30
+ return ar;
31
+ };
32
+ return ownKeys(o);
33
+ };
34
+ return function (mod) {
35
+ if (mod && mod.__esModule) return mod;
36
+ var result = {};
37
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
38
+ __setModuleDefault(result, mod);
39
+ return result;
40
+ };
41
+ })();
42
+ Object.defineProperty(exports, "__esModule", { value: true });
43
+ exports.WrapperManager = void 0;
44
+ const pty = __importStar(require("node-pty"));
45
+ const fs = __importStar(require("fs-extra"));
46
+ const path = __importStar(require("path"));
47
+ const os = __importStar(require("os"));
48
+ const uuid_1 = require("uuid");
49
+ const child_process_1 = require("child_process");
50
+ class WrapperManager {
51
+ constructor(persistPath, onEvent) {
52
+ this.wrappers = new Map();
53
+ this.persistPath = persistPath;
54
+ this.onEvent = onEvent;
55
+ }
56
+ /**
57
+ * Initialize - load persisted wrappers and clean up dead ones
58
+ */
59
+ async initialize() {
60
+ await fs.ensureDir(path.dirname(this.persistPath));
61
+ await this.loadAndCleanup();
62
+ }
63
+ /**
64
+ * Load persisted wrappers and clean up any that are no longer running
65
+ */
66
+ async loadAndCleanup() {
67
+ try {
68
+ if (await fs.pathExists(this.persistPath)) {
69
+ const data = await fs.readJson(this.persistPath);
70
+ const persistedWrappers = data.wrappers || [];
71
+ // Check each persisted wrapper to see if it's still running
72
+ const stillRunning = [];
73
+ for (const wrapper of persistedWrappers) {
74
+ if (this.isProcessRunning(wrapper.pid)) {
75
+ console.log(`[WrapperManager] Found running wrapper ${wrapper.wrapperId} (PID ${wrapper.pid})`);
76
+ stillRunning.push(wrapper);
77
+ // Note: We can't reconnect to existing PTYs, so these are "orphaned"
78
+ // We'll mark them as ended and clean up
79
+ }
80
+ else {
81
+ console.log(`[WrapperManager] Cleaning up dead wrapper ${wrapper.wrapperId} (PID ${wrapper.pid})`);
82
+ }
83
+ }
84
+ // For now, we just clean up all persisted wrappers since we can't reconnect to PTYs
85
+ // In a more advanced implementation, we could use screen/tmux to maintain sessions
86
+ await this.persist();
87
+ }
88
+ }
89
+ catch (err) {
90
+ console.error('[WrapperManager] Error loading persisted wrappers:', err);
91
+ }
92
+ }
93
+ /**
94
+ * Check if a process is still running
95
+ */
96
+ isProcessRunning(pid) {
97
+ try {
98
+ process.kill(pid, 0);
99
+ return true;
100
+ }
101
+ catch {
102
+ return false;
103
+ }
104
+ }
105
+ /**
106
+ * Spawn a new Claude wrapper session
107
+ */
108
+ async spawn(options = {}) {
109
+ const wrapperId = (0, uuid_1.v4)().slice(0, 8);
110
+ const cwd = options.cwd || process.cwd();
111
+ const args = options.args || [];
112
+ const cols = options.cols || 120;
113
+ const rows = options.rows || 40;
114
+ // Find Claude executable
115
+ const claudePath = this.findClaudeExecutable();
116
+ if (!claudePath) {
117
+ throw new Error('Claude CLI not found. Please install Claude Code.');
118
+ }
119
+ console.log(`[WrapperManager] Spawning Claude wrapper ${wrapperId} at ${cwd}`);
120
+ // Spawn Claude with PTY
121
+ const ptyProcess = pty.spawn(claudePath, args, {
122
+ name: 'xterm-256color',
123
+ cols,
124
+ rows,
125
+ cwd,
126
+ env: {
127
+ ...process.env,
128
+ CONTEXTUATE_WRAPPER_ID: wrapperId,
129
+ },
130
+ });
131
+ const session = {
132
+ wrapperId,
133
+ ptyProcess,
134
+ pid: ptyProcess.pid,
135
+ claudeSessionId: null,
136
+ state: 'starting',
137
+ cwd,
138
+ args,
139
+ startTime: Date.now(),
140
+ cols,
141
+ rows,
142
+ };
143
+ this.wrappers.set(wrapperId, session);
144
+ // Handle PTY output
145
+ let outputBuffer = '';
146
+ ptyProcess.onData((data) => {
147
+ // Stream to UI
148
+ this.onEvent({
149
+ type: 'output',
150
+ wrapperId,
151
+ data,
152
+ });
153
+ // Buffer for pattern detection
154
+ outputBuffer += data;
155
+ if (outputBuffer.length > 1000) {
156
+ outputBuffer = outputBuffer.slice(-500);
157
+ }
158
+ // Heuristic: detect if waiting for input
159
+ if (session.state === 'processing' || session.state === 'starting') {
160
+ if (this.detectInputPrompt(outputBuffer)) {
161
+ session.state = 'waiting_input';
162
+ this.onEvent({
163
+ type: 'state_changed',
164
+ wrapperId,
165
+ state: 'waiting_input',
166
+ });
167
+ outputBuffer = '';
168
+ }
169
+ }
170
+ });
171
+ // Handle PTY exit
172
+ ptyProcess.onExit(({ exitCode }) => {
173
+ console.log(`[WrapperManager] Wrapper ${wrapperId} exited with code ${exitCode}`);
174
+ session.state = 'ended';
175
+ this.onEvent({
176
+ type: 'ended',
177
+ wrapperId,
178
+ exitCode,
179
+ });
180
+ this.wrappers.delete(wrapperId);
181
+ this.persist();
182
+ });
183
+ // Persist and notify
184
+ await this.persist();
185
+ this.onEvent({
186
+ type: 'started',
187
+ wrapperId,
188
+ state: 'starting',
189
+ });
190
+ // Mark as processing after a short delay (Claude is starting up)
191
+ setTimeout(() => {
192
+ if (session.state === 'starting') {
193
+ session.state = 'processing';
194
+ this.onEvent({
195
+ type: 'state_changed',
196
+ wrapperId,
197
+ state: 'processing',
198
+ });
199
+ }
200
+ }, 1000);
201
+ return wrapperId;
202
+ }
203
+ /**
204
+ * Write input to a wrapper's PTY
205
+ */
206
+ writeInput(wrapperId, input) {
207
+ const session = this.wrappers.get(wrapperId);
208
+ if (!session) {
209
+ return false;
210
+ }
211
+ session.ptyProcess.write(input);
212
+ return true;
213
+ }
214
+ /**
215
+ * Resize a wrapper's PTY
216
+ */
217
+ resize(wrapperId, cols, rows) {
218
+ const session = this.wrappers.get(wrapperId);
219
+ if (!session) {
220
+ return false;
221
+ }
222
+ session.ptyProcess.resize(cols, rows);
223
+ session.cols = cols;
224
+ session.rows = rows;
225
+ return true;
226
+ }
227
+ /**
228
+ * Kill a wrapper session
229
+ */
230
+ kill(wrapperId) {
231
+ const session = this.wrappers.get(wrapperId);
232
+ if (!session) {
233
+ return false;
234
+ }
235
+ console.log(`[WrapperManager] Killing wrapper ${wrapperId}`);
236
+ session.ptyProcess.kill();
237
+ return true;
238
+ }
239
+ /**
240
+ * Get all active wrappers
241
+ */
242
+ getAll() {
243
+ return Array.from(this.wrappers.values());
244
+ }
245
+ /**
246
+ * Get a specific wrapper
247
+ */
248
+ get(wrapperId) {
249
+ return this.wrappers.get(wrapperId);
250
+ }
251
+ /**
252
+ * Update wrapper state (e.g., from hook events)
253
+ */
254
+ updateState(wrapperId, state, claudeSessionId) {
255
+ const session = this.wrappers.get(wrapperId);
256
+ if (session) {
257
+ session.state = state;
258
+ if (claudeSessionId) {
259
+ session.claudeSessionId = claudeSessionId;
260
+ }
261
+ this.onEvent({
262
+ type: 'state_changed',
263
+ wrapperId,
264
+ state,
265
+ claudeSessionId,
266
+ });
267
+ }
268
+ }
269
+ /**
270
+ * Shutdown all wrappers
271
+ */
272
+ async shutdown() {
273
+ console.log(`[WrapperManager] Shutting down ${this.wrappers.size} wrappers`);
274
+ for (const [wrapperId, session] of this.wrappers) {
275
+ try {
276
+ session.ptyProcess.kill();
277
+ }
278
+ catch (err) {
279
+ console.error(`[WrapperManager] Error killing wrapper ${wrapperId}:`, err);
280
+ }
281
+ }
282
+ this.wrappers.clear();
283
+ await this.persist();
284
+ }
285
+ /**
286
+ * Persist wrapper state to disk
287
+ */
288
+ async persist() {
289
+ const data = Array.from(this.wrappers.values()).map(w => ({
290
+ wrapperId: w.wrapperId,
291
+ pid: w.pid,
292
+ claudeSessionId: w.claudeSessionId,
293
+ state: w.state,
294
+ cwd: w.cwd,
295
+ args: w.args,
296
+ startTime: w.startTime,
297
+ cols: w.cols,
298
+ rows: w.rows,
299
+ }));
300
+ try {
301
+ await fs.writeJson(this.persistPath, { wrappers: data }, { spaces: 2 });
302
+ }
303
+ catch (err) {
304
+ console.error('[WrapperManager] Error persisting wrappers:', err);
305
+ }
306
+ }
307
+ /**
308
+ * Detect if output indicates Claude is waiting for input
309
+ */
310
+ detectInputPrompt(buffer) {
311
+ // Look for common patterns that indicate Claude is waiting
312
+ const patterns = [
313
+ />\s*$/, // Simple prompt
314
+ /\?\s*$/, // Question prompt
315
+ /:\s*$/, // Colon prompt
316
+ /waiting for.*input/i, // Explicit waiting message
317
+ /enter.*to continue/i, // Continue prompt
318
+ /press.*to/i, // Press key prompt
319
+ ];
320
+ return patterns.some(p => p.test(buffer));
321
+ }
322
+ /**
323
+ * Find the Claude executable
324
+ */
325
+ findClaudeExecutable() {
326
+ const commonPaths = [
327
+ // New Claude Code installation location (Bun-based)
328
+ path.join(os.homedir(), '.local', 'bin', 'claude'),
329
+ // Legacy npm-based installations
330
+ path.join(os.homedir(), '.npm-global', 'bin', 'claude'),
331
+ path.join(os.homedir(), '.nvm', 'versions', 'node', process.version, 'bin', 'claude'),
332
+ '/opt/homebrew/bin/claude',
333
+ '/usr/local/bin/claude',
334
+ '/usr/bin/claude',
335
+ ];
336
+ for (const p of commonPaths) {
337
+ if (fs.existsSync(p)) {
338
+ // Resolve symlinks to get the actual executable path
339
+ try {
340
+ const resolved = fs.realpathSync(p);
341
+ console.log(`[WrapperManager] Found Claude at ${p} -> ${resolved}`);
342
+ return resolved;
343
+ }
344
+ catch {
345
+ return p;
346
+ }
347
+ }
348
+ }
349
+ // Try to find via PATH
350
+ try {
351
+ const result = (0, child_process_1.execSync)('which claude 2>/dev/null || where claude 2>/dev/null', {
352
+ encoding: 'utf-8',
353
+ timeout: 5000,
354
+ }).trim();
355
+ if (result) {
356
+ const foundPath = result.split('\n')[0];
357
+ // Resolve symlinks to get the actual executable path
358
+ try {
359
+ const resolved = fs.realpathSync(foundPath);
360
+ console.log(`[WrapperManager] Found Claude via PATH at ${foundPath} -> ${resolved}`);
361
+ return resolved;
362
+ }
363
+ catch {
364
+ return foundPath;
365
+ }
366
+ }
367
+ }
368
+ catch {
369
+ // Not found via PATH
370
+ }
371
+ return null;
372
+ }
373
+ }
374
+ exports.WrapperManager = WrapperManager;