autodev-cli 1.4.0 → 1.4.3
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/bin/autodev.js +0 -0
- package/out/agentBackup/archive.d.ts +44 -0
- package/out/agentBackup/archive.js +131 -0
- package/out/agentBackup/archive.js.map +1 -0
- package/out/agentBackup/export.d.ts +18 -0
- package/out/agentBackup/export.js +92 -0
- package/out/agentBackup/export.js.map +1 -0
- package/out/agentBackup/import.d.ts +21 -0
- package/out/agentBackup/import.js +40 -0
- package/out/agentBackup/import.js.map +1 -0
- package/out/agentBackup/index.d.ts +6 -0
- package/out/agentBackup/index.js +11 -0
- package/out/agentBackup/index.js.map +1 -0
- package/out/agentBackup/layout.d.ts +30 -0
- package/out/agentBackup/layout.js +126 -0
- package/out/agentBackup/layout.js.map +1 -0
- package/out/agentBackup/manifest.d.ts +24 -0
- package/out/agentBackup/manifest.js +70 -0
- package/out/agentBackup/manifest.js.map +1 -0
- package/out/agentBackup/opencodeDb.d.ts +20 -0
- package/out/agentBackup/opencodeDb.js +213 -0
- package/out/agentBackup/opencodeDb.js.map +1 -0
- package/out/agentBackup/sessionProviders.d.ts +35 -0
- package/out/agentBackup/sessionProviders.js +263 -0
- package/out/agentBackup/sessionProviders.js.map +1 -0
- package/out/agentBackup/upload.d.ts +9 -0
- package/out/agentBackup/upload.js +121 -0
- package/out/agentBackup/upload.js.map +1 -0
- package/out/cli.d.ts +1 -0
- package/out/cli.js +8 -0
- package/out/cli.js.map +1 -1
- package/out/cliExit.d.ts +34 -0
- package/out/cliExit.js +159 -0
- package/out/cliExit.js.map +1 -0
- package/out/commands/config.d.ts +2 -0
- package/out/commands/config.js +7 -7
- package/out/commands/config.js.map +1 -1
- package/out/commands/connect.d.ts +2 -0
- package/out/commands/connect.js +11 -0
- package/out/commands/connect.js.map +1 -1
- package/out/commands/export.d.ts +2 -0
- package/out/commands/export.js +79 -0
- package/out/commands/export.js.map +1 -0
- package/out/commands/import.d.ts +2 -0
- package/out/commands/import.js +92 -0
- package/out/commands/import.js.map +1 -0
- package/out/commands/init.d.ts +16 -0
- package/out/commands/init.js +9 -5
- package/out/commands/init.js.map +1 -1
- package/out/commands/resume.d.ts +2 -0
- package/out/commands/resume.js +65 -0
- package/out/commands/resume.js.map +1 -0
- package/out/commands/sessions.d.ts +2 -0
- package/out/commands/sessions.js +64 -0
- package/out/commands/sessions.js.map +1 -0
- package/out/commands/start.d.ts +2 -0
- package/out/commands/start.js +40 -7
- package/out/commands/start.js.map +1 -1
- package/out/commands/status.d.ts +2 -0
- package/out/commands/status.js +3 -3
- package/out/commands/status.js.map +1 -1
- package/out/commands/tailOutput.d.ts +12 -0
- package/out/commands/up.d.ts +3 -0
- package/out/configManager.d.ts +42 -0
- package/out/configManager.js +430 -0
- package/out/configManager.js.map +1 -0
- package/out/connect.d.ts +4 -0
- package/out/connect.js +7 -7
- package/out/connect.js.map +1 -1
- package/out/core/adapters.d.ts +34 -0
- package/out/core/adapters.js +84 -0
- package/out/core/adapters.js.map +1 -0
- package/out/core/commandHelpers.d.ts +12 -0
- package/out/core/commandHelpers.js +96 -0
- package/out/core/commandHelpers.js.map +1 -0
- package/out/core/projectMcp.d.ts +25 -0
- package/out/core/projectMcp.js +144 -0
- package/out/core/projectMcp.js.map +1 -0
- package/out/core/provider/BaseProvider.d.ts +14 -0
- package/out/core/provider/BaseProvider.js +25 -0
- package/out/core/provider/BaseProvider.js.map +1 -0
- package/out/core/provider/ProviderRegistry.d.ts +12 -0
- package/out/core/provider/ProviderRegistry.js +40 -0
- package/out/core/provider/ProviderRegistry.js.map +1 -0
- package/out/core/provider/contract.d.ts +62 -0
- package/out/core/provider/contract.js +9 -0
- package/out/core/provider/contract.js.map +1 -0
- package/out/core/provider/implementations.d.ts +54 -0
- package/out/core/provider/implementations.js +147 -0
- package/out/core/provider/implementations.js.map +1 -0
- package/out/core/settingsLoader.d.ts +221 -0
- package/out/core/settingsLoader.js +176 -0
- package/out/core/settingsLoader.js.map +1 -0
- package/out/discordGateway.d.ts +26 -0
- package/out/discordGateway.js +230 -0
- package/out/discordGateway.js.map +1 -0
- package/out/discordPoller.d.ts +28 -0
- package/out/discordPoller.js +247 -0
- package/out/discordPoller.js.map +1 -0
- package/out/dispatcher.d.ts +12 -0
- package/out/dispatcher.js +214 -0
- package/out/dispatcher.js.map +1 -0
- package/out/emailPoller.d.ts +42 -0
- package/out/emailPoller.js +221 -0
- package/out/emailPoller.js.map +1 -0
- package/out/git/gitService.d.ts +36 -0
- package/out/git/gitService.js +165 -0
- package/out/git/gitService.js.map +1 -0
- package/out/hookEventNormalizer.d.ts +39 -0
- package/out/hookEventNormalizer.js +397 -0
- package/out/hookEventNormalizer.js.map +1 -0
- package/out/hooksManager.d.ts +25 -0
- package/out/hooksManager.js +471 -0
- package/out/hooksManager.js.map +1 -0
- package/out/launchIde.d.ts +14 -0
- package/out/logger.d.ts +12 -0
- package/out/mcpEmailTest.d.ts +29 -0
- package/out/mcpEmailTest.js +245 -0
- package/out/mcpEmailTest.js.map +1 -0
- package/out/mcpInstallCheck.d.ts +23 -0
- package/out/mcpInstallCheck.js +219 -0
- package/out/mcpInstallCheck.js.map +1 -0
- package/out/mcpManager.d.ts +35 -0
- package/out/mcpManager.js +371 -0
- package/out/mcpManager.js.map +1 -0
- package/out/messageBuilder.d.ts +54 -0
- package/out/messageBuilder.js +373 -0
- package/out/messageBuilder.js.map +1 -0
- package/out/openCodeHooksManager.d.ts +23 -0
- package/out/openCodeHooksManager.js +511 -0
- package/out/openCodeHooksManager.js.map +1 -0
- package/out/periodicActions.d.ts +63 -0
- package/out/periodicActions.js +237 -0
- package/out/periodicActions.js.map +1 -0
- package/out/profileBuilder.d.ts +29 -0
- package/out/profileBuilder.js +366 -0
- package/out/profileBuilder.js.map +1 -0
- package/out/prompt.d.ts +12 -0
- package/out/prompt.js +18 -0
- package/out/prompt.js.map +1 -0
- package/out/protocolSections.d.ts +26 -0
- package/out/protocolSections.js +209 -0
- package/out/protocolSections.js.map +1 -0
- package/out/providers/claudeCliProvider.d.ts +71 -0
- package/out/providers/claudeCliProvider.js +425 -0
- package/out/providers/claudeCliProvider.js.map +1 -0
- package/out/providers/claudeTuiProvider.d.ts +23 -0
- package/out/providers/claudeTuiProvider.js +296 -0
- package/out/providers/claudeTuiProvider.js.map +1 -0
- package/out/providers/copilotCliProvider.d.ts +16 -0
- package/out/providers/copilotCliProvider.js +44 -0
- package/out/providers/copilotCliProvider.js.map +1 -0
- package/out/providers/copilotSdkProvider.d.ts +12 -0
- package/out/providers/copilotSdkProvider.js +445 -0
- package/out/providers/copilotSdkProvider.js.map +1 -0
- package/out/providers/grokTuiProvider.d.ts +14 -0
- package/out/providers/grokTuiProvider.js +271 -0
- package/out/providers/grokTuiProvider.js.map +1 -0
- package/out/providers/opencodeCliProvider.d.ts +29 -0
- package/out/providers/opencodeCliProvider.js +199 -0
- package/out/providers/opencodeCliProvider.js.map +1 -0
- package/out/providers/opencodeSdkProvider.d.ts +22 -0
- package/out/providers/opencodeSdkProvider.js +557 -0
- package/out/providers/opencodeSdkProvider.js.map +1 -0
- package/out/providers.d.ts +9 -0
- package/out/providers.js +44 -0
- package/out/providers.js.map +1 -0
- package/out/rateLimit.d.ts +18 -0
- package/out/rateLimit.js +90 -0
- package/out/rateLimit.js.map +1 -0
- package/out/rdp/auth.d.ts +55 -0
- package/out/rdp/auth.js +197 -0
- package/out/rdp/auth.js.map +1 -0
- package/out/rdp/bridge.d.ts +86 -0
- package/out/rdp/bridge.js +1398 -0
- package/out/rdp/bridge.js.map +1 -0
- package/out/rdp/constants.d.ts +86 -0
- package/out/rdp/constants.js +182 -0
- package/out/rdp/constants.js.map +1 -0
- package/out/rdp/index.d.ts +7 -0
- package/out/rdp/index.js +14 -0
- package/out/rdp/index.js.map +1 -0
- package/out/rdp/session.d.ts +30 -0
- package/out/rdp/session.js +196 -0
- package/out/rdp/session.js.map +1 -0
- package/out/rdp/types.d.ts +27 -0
- package/out/rdp/types.js +6 -0
- package/out/rdp/types.js.map +1 -0
- package/out/sdk/index.d.ts +22 -0
- package/out/sdk/index.js +81 -0
- package/out/sdk/index.js.map +1 -0
- package/out/sessionState.d.ts +54 -0
- package/out/sessionState.js +284 -0
- package/out/sessionState.js.map +1 -0
- package/out/sessions.d.ts +11 -0
- package/out/sessions.js +32 -0
- package/out/sessions.js.map +1 -0
- package/out/taskLoop.d.ts +152 -0
- package/out/taskLoop.js +2505 -0
- package/out/taskLoop.js.map +1 -0
- package/out/todo.d.ts +42 -0
- package/out/todo.js +311 -0
- package/out/todo.js.map +1 -0
- package/out/todoWriteManager.d.ts +26 -0
- package/out/todoWriteManager.js +44 -0
- package/out/todoWriteManager.js.map +1 -0
- package/out/vnc/auth.d.ts +52 -0
- package/out/vnc/auth.js +181 -0
- package/out/vnc/auth.js.map +1 -0
- package/out/vnc/bridge.d.ts +40 -0
- package/out/vnc/bridge.js +540 -0
- package/out/vnc/bridge.js.map +1 -0
- package/out/vnc/constants.d.ts +8 -0
- package/out/vnc/constants.js +34 -0
- package/out/vnc/constants.js.map +1 -0
- package/out/vnc/des.d.ts +6 -0
- package/out/vnc/des.js +93 -0
- package/out/vnc/des.js.map +1 -0
- package/out/vnc/index.d.ts +7 -0
- package/out/vnc/index.js +13 -0
- package/out/vnc/index.js.map +1 -0
- package/out/vnc/session.d.ts +18 -0
- package/out/vnc/session.js +193 -0
- package/out/vnc/session.js.map +1 -0
- package/out/vnc/types.d.ts +16 -0
- package/out/vnc/types.js +6 -0
- package/out/vnc/types.js.map +1 -0
- package/out/webSocketPoller.d.ts +95 -0
- package/out/webSocketPoller.js +986 -0
- package/out/webSocketPoller.js.map +1 -0
- package/out/webhook.d.ts +37 -0
- package/out/webhook.js +265 -0
- package/out/webhook.js.map +1 -0
- package/out/webhookPoller.d.ts +40 -0
- package/out/webhookPoller.js +378 -0
- package/out/webhookPoller.js.map +1 -0
- package/package.json +54 -41
|
@@ -0,0 +1,511 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.isOpenCodeHooksInstalled = isOpenCodeHooksInstalled;
|
|
37
|
+
exports.installOpenCodeHooks = installOpenCodeHooks;
|
|
38
|
+
exports.isOpenCodeCliActive = isOpenCodeCliActive;
|
|
39
|
+
exports.openCodeExitedCleanly = openCodeExitedCleanly;
|
|
40
|
+
exports.getOpenCodeSessionIdFromHooks = getOpenCodeSessionIdFromHooks;
|
|
41
|
+
exports.uninstallOpenCodeHooks = uninstallOpenCodeHooks;
|
|
42
|
+
const fs = __importStar(require("fs"));
|
|
43
|
+
const path = __importStar(require("path"));
|
|
44
|
+
// ---------------------------------------------------------------------------
|
|
45
|
+
// OpenCode hooks manager — installs/removes an OpenCode plugin that appends
|
|
46
|
+
// hook events to <workspaceRoot>/.autodev/hooks-events.jsonl in the same
|
|
47
|
+
// format as the Claude Code hooks, so the task loop can stream them to
|
|
48
|
+
// Pixel Office.
|
|
49
|
+
//
|
|
50
|
+
// The plugin is placed at <workspaceRoot>/.opencode/plugins/autodev-hooks.ts
|
|
51
|
+
// OpenCode discovers plugins in that directory automatically.
|
|
52
|
+
// ---------------------------------------------------------------------------
|
|
53
|
+
const PLUGIN_FILENAME = 'autodev-hooks.ts';
|
|
54
|
+
const PLUGIN_MARKER = '// __autodev_opencode_hooks__';
|
|
55
|
+
function pluginDir(workspaceRoot) {
|
|
56
|
+
return path.join(workspaceRoot, '.opencode', 'plugins');
|
|
57
|
+
}
|
|
58
|
+
function pluginPath(workspaceRoot) {
|
|
59
|
+
return path.join(pluginDir(workspaceRoot), PLUGIN_FILENAME);
|
|
60
|
+
}
|
|
61
|
+
// ---------------------------------------------------------------------------
|
|
62
|
+
// Plugin content — TypeScript executed by OpenCode/Bun at runtime.
|
|
63
|
+
// The JSONL path is baked in at install time (workspace-scoped, forward
|
|
64
|
+
// slashes only so Bun/Windows path handling doesn't break the string).
|
|
65
|
+
// ---------------------------------------------------------------------------
|
|
66
|
+
function buildPluginContent(workspaceRoot) {
|
|
67
|
+
// Bake in the workspace-scoped JSONL dir with forward slashes so the
|
|
68
|
+
// plugin always writes to the right place regardless of the process cwd.
|
|
69
|
+
const autodevDir = JSON.stringify(path.join(workspaceRoot, '.autodev').replace(/\\/g, '/'));
|
|
70
|
+
return `${PLUGIN_MARKER}
|
|
71
|
+
// AutoDev hooks plugin for OpenCode — auto-generated, do not edit.
|
|
72
|
+
// Streams tool/session events to Pixel Office via <workspaceRoot>/.autodev/
|
|
73
|
+
import { appendFileSync, mkdirSync, existsSync } from 'fs';
|
|
74
|
+
import { join } from 'path';
|
|
75
|
+
|
|
76
|
+
// Dir is baked in at install time (workspace-scoped, always forward slashes)
|
|
77
|
+
const AUTODEV_DIR: string = ${autodevDir};
|
|
78
|
+
// Global file for session-ID discovery; per-session files for state tracking
|
|
79
|
+
const GLOBAL_JSONL = join(AUTODEV_DIR, 'hooks-events.jsonl');
|
|
80
|
+
|
|
81
|
+
function sessionJsonlPath(sessionId: string | null): string | null {
|
|
82
|
+
if (!sessionId) { return null; }
|
|
83
|
+
// Replace chars that are unsafe in filenames but keep the ID readable
|
|
84
|
+
const safe = sessionId.replace(/[^a-zA-Z0-9_-]/g, '_');
|
|
85
|
+
return join(AUTODEV_DIR, \`hooks-events-\${safe}.jsonl\`);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// High-frequency / large-payload events we intentionally skip in the generic catch-all
|
|
89
|
+
// (tool events have dedicated hooks; these are too noisy or already handled explicitly)
|
|
90
|
+
const SKIP_EVENTS = new Set([
|
|
91
|
+
'message.part.delta',
|
|
92
|
+
'message.part.removed',
|
|
93
|
+
'message.part.updated', // replaced by session.next.text.ended (simpler, same data)
|
|
94
|
+
'message.updated', // role-tracking no longer needed
|
|
95
|
+
'message.removed',
|
|
96
|
+
'session.diff',
|
|
97
|
+
// Explicit named hooks — don't double-log
|
|
98
|
+
'tool.execute.before',
|
|
99
|
+
'tool.execute.after',
|
|
100
|
+
'permission.asked',
|
|
101
|
+
'permission.replied',
|
|
102
|
+
'tui.prompt.append',
|
|
103
|
+
'tui.command.execute',
|
|
104
|
+
'tui.toast.show',
|
|
105
|
+
'command.executed',
|
|
106
|
+
'file.edited',
|
|
107
|
+
// session.next.* lifecycle markers with no payload — skip the noisy ones
|
|
108
|
+
'session.next.step.started',
|
|
109
|
+
'session.next.reasoning.started',
|
|
110
|
+
'session.next.text.started',
|
|
111
|
+
'session.next.tool.input.started',
|
|
112
|
+
'session.next.tool.input.ended',
|
|
113
|
+
'session.next.tool.called',
|
|
114
|
+
'session.next.tool.success',
|
|
115
|
+
// session.next.tool.failed is NOT skipped — captures error message for failed tool calls
|
|
116
|
+
]);
|
|
117
|
+
|
|
118
|
+
const SESSION_MAP: Record<string, string> = {
|
|
119
|
+
'session.created': 'SessionStart',
|
|
120
|
+
'session.idle': 'Stop',
|
|
121
|
+
'session.error': 'StopFailure',
|
|
122
|
+
'session.deleted': 'SessionEnd',
|
|
123
|
+
'session.compacted': 'PostCompact',
|
|
124
|
+
'session.updated': 'SessionStatus',
|
|
125
|
+
'session.status': 'SessionStatus',
|
|
126
|
+
'message.removed': 'MessageRemoved',
|
|
127
|
+
'todo.updated': 'TaskCreated',
|
|
128
|
+
'command.executed': 'CommandExecuted',
|
|
129
|
+
'file.edited': 'FileEdited',
|
|
130
|
+
'file.watcher.updated': 'FileWatcherUpdated',
|
|
131
|
+
'permission.asked': 'PermissionAsked',
|
|
132
|
+
'permission.replied': 'PermissionReplied',
|
|
133
|
+
'server.connected': 'ServerConnected',
|
|
134
|
+
'lsp.updated': 'LspUpdated',
|
|
135
|
+
'installation.updated': 'InstallationUpdated',
|
|
136
|
+
'tui.prompt.append': 'TuiPromptAppend',
|
|
137
|
+
'tui.command.execute':'TuiCommandExecute',
|
|
138
|
+
'tui.toast.show': 'TuiToastShow',
|
|
139
|
+
// session.next.* meaningful events
|
|
140
|
+
'session.next.prompted': 'UserMessage',
|
|
141
|
+
'session.next.step.ended': 'StepEnded',
|
|
142
|
+
'session.next.model.switched': 'ModelSwitched',
|
|
143
|
+
'session.next.agent.switched': 'AgentSwitched',
|
|
144
|
+
'session.next.reasoning.ended':'Reasoning',
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
function appendEvent(ev: Record<string, unknown>): void {
|
|
148
|
+
try {
|
|
149
|
+
if (!existsSync(AUTODEV_DIR)) { mkdirSync(AUTODEV_DIR, { recursive: true }); }
|
|
150
|
+
ev['timestamp'] = new Date().toISOString();
|
|
151
|
+
const line = JSON.stringify(ev) + '\\n';
|
|
152
|
+
// Always write to global file (used for session-ID discovery)
|
|
153
|
+
appendFileSync(GLOBAL_JSONL, line, 'utf8');
|
|
154
|
+
// Also write to per-session file when we know the session ID
|
|
155
|
+
const sid = typeof ev['session_id'] === 'string' ? ev['session_id'] as string : null;
|
|
156
|
+
const perFile = sessionJsonlPath(sid);
|
|
157
|
+
if (perFile) { appendFileSync(perFile, line, 'utf8'); }
|
|
158
|
+
} catch { }
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// Helper to extract session ID from various event shapes
|
|
162
|
+
function extractSessionId(input: any): string | null {
|
|
163
|
+
return input?.sessionID ?? input?.session_id ?? input?.properties?.sessionID ?? null;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// Accumulated assistant text per session.
|
|
167
|
+
// session.next.text.ended fires once per step with the complete generated text.
|
|
168
|
+
// Multi-step sessions accumulate across steps and flush as AgentMessage on session.idle.
|
|
169
|
+
const sessionText = new Map<string, string>();
|
|
170
|
+
|
|
171
|
+
export const AutodevHooksPlugin = async () => ({
|
|
172
|
+
// -------------------------------------------------------------------------
|
|
173
|
+
// Tool lifecycle — explicit named hooks (these do NOT fire via generic 'event')
|
|
174
|
+
// -------------------------------------------------------------------------
|
|
175
|
+
'tool.execute.before': async (input: any, output?: any) => {
|
|
176
|
+
appendEvent({
|
|
177
|
+
hook_event_name: 'PreToolUse',
|
|
178
|
+
provider: 'opencode',
|
|
179
|
+
tool_name: input?.tool ?? 'unknown',
|
|
180
|
+
tool_input: output?.args ?? input?.args ?? null,
|
|
181
|
+
session_id: extractSessionId(input),
|
|
182
|
+
});
|
|
183
|
+
},
|
|
184
|
+
|
|
185
|
+
'tool.execute.after': async (input: any, output?: any) => {
|
|
186
|
+
const rawOut = output?.output ?? output?.result ?? output?.text;
|
|
187
|
+
const outText = typeof rawOut === 'string' ? rawOut.slice(0, 400) : null;
|
|
188
|
+
appendEvent({
|
|
189
|
+
hook_event_name: 'PostToolUse',
|
|
190
|
+
provider: 'opencode',
|
|
191
|
+
tool_name: input?.tool ?? 'unknown',
|
|
192
|
+
tool_input: input?.args ?? null,
|
|
193
|
+
tool_output: outText != null ? { title: output?.title ?? null, text: outText } : null,
|
|
194
|
+
session_id: extractSessionId(input),
|
|
195
|
+
});
|
|
196
|
+
},
|
|
197
|
+
|
|
198
|
+
// -------------------------------------------------------------------------
|
|
199
|
+
// Permission hooks — explicit so we always capture even if generic 'event'
|
|
200
|
+
// doesn't fire for them. Critical for detecting blocked/waiting states.
|
|
201
|
+
// -------------------------------------------------------------------------
|
|
202
|
+
'permission.asked': async (input: any, output?: any) => {
|
|
203
|
+
appendEvent({
|
|
204
|
+
hook_event_name: 'PermissionAsked',
|
|
205
|
+
provider: 'opencode',
|
|
206
|
+
session_id: extractSessionId(input),
|
|
207
|
+
tool_name: input?.tool ?? null,
|
|
208
|
+
tool_input: input?.args ?? null,
|
|
209
|
+
message: input?.message ?? input?.description ?? null,
|
|
210
|
+
});
|
|
211
|
+
},
|
|
212
|
+
|
|
213
|
+
'permission.replied': async (input: any, output?: any) => {
|
|
214
|
+
appendEvent({
|
|
215
|
+
hook_event_name: 'PermissionReplied',
|
|
216
|
+
provider: 'opencode',
|
|
217
|
+
session_id: extractSessionId(input),
|
|
218
|
+
tool_name: input?.tool ?? null,
|
|
219
|
+
granted: input?.granted ?? output?.granted ?? null,
|
|
220
|
+
});
|
|
221
|
+
},
|
|
222
|
+
|
|
223
|
+
// -------------------------------------------------------------------------
|
|
224
|
+
// TUI events — explicit named hooks
|
|
225
|
+
// -------------------------------------------------------------------------
|
|
226
|
+
'tui.prompt.append': async (input: any) => {
|
|
227
|
+
appendEvent({
|
|
228
|
+
hook_event_name: 'TuiPromptAppend',
|
|
229
|
+
provider: 'opencode',
|
|
230
|
+
session_id: extractSessionId(input),
|
|
231
|
+
message: input?.text ?? null,
|
|
232
|
+
});
|
|
233
|
+
},
|
|
234
|
+
|
|
235
|
+
'tui.command.execute': async (input: any) => {
|
|
236
|
+
appendEvent({
|
|
237
|
+
hook_event_name: 'TuiCommandExecute',
|
|
238
|
+
provider: 'opencode',
|
|
239
|
+
session_id: extractSessionId(input),
|
|
240
|
+
message: input?.command ?? input?.name ?? null,
|
|
241
|
+
});
|
|
242
|
+
},
|
|
243
|
+
|
|
244
|
+
'tui.toast.show': async (input: any) => {
|
|
245
|
+
appendEvent({
|
|
246
|
+
hook_event_name: 'TuiToastShow',
|
|
247
|
+
provider: 'opencode',
|
|
248
|
+
session_id: extractSessionId(input),
|
|
249
|
+
message: input?.message ?? input?.text ?? null,
|
|
250
|
+
});
|
|
251
|
+
},
|
|
252
|
+
|
|
253
|
+
// -------------------------------------------------------------------------
|
|
254
|
+
// Command + file events — explicit named hooks
|
|
255
|
+
// -------------------------------------------------------------------------
|
|
256
|
+
'command.executed': async (input: any) => {
|
|
257
|
+
appendEvent({
|
|
258
|
+
hook_event_name: 'CommandExecuted',
|
|
259
|
+
provider: 'opencode',
|
|
260
|
+
session_id: extractSessionId(input),
|
|
261
|
+
message: input?.command ?? input?.name ?? null,
|
|
262
|
+
});
|
|
263
|
+
},
|
|
264
|
+
|
|
265
|
+
'file.edited': async (input: any) => {
|
|
266
|
+
appendEvent({
|
|
267
|
+
hook_event_name: 'FileEdited',
|
|
268
|
+
provider: 'opencode',
|
|
269
|
+
session_id: extractSessionId(input),
|
|
270
|
+
message: input?.file ?? input?.path ?? null,
|
|
271
|
+
});
|
|
272
|
+
},
|
|
273
|
+
|
|
274
|
+
// -------------------------------------------------------------------------
|
|
275
|
+
// Generic catch-all for remaining events (session/message/todo/lsp/server…)
|
|
276
|
+
// SKIP_EVENTS excludes high-noise events and events already handled above.
|
|
277
|
+
// message.part.updated (type:'text') is handled here to accumulate the AI's
|
|
278
|
+
// response text; it's flushed as a single AgentMessage on session.idle.
|
|
279
|
+
// -------------------------------------------------------------------------
|
|
280
|
+
'event': async (ctx: any) => {
|
|
281
|
+
const evt = ctx?.event ?? ctx ?? {};
|
|
282
|
+
const t: string = evt?.type ?? '';
|
|
283
|
+
|
|
284
|
+
if (!t || SKIP_EVENTS.has(t)) { return; }
|
|
285
|
+
|
|
286
|
+
const props = evt?.properties ?? {};
|
|
287
|
+
const sessionId = props?.sessionID ?? props?.id ?? null;
|
|
288
|
+
const errMsg = props?.error?.message ?? null;
|
|
289
|
+
|
|
290
|
+
// --- session.next.text.ended: accumulate assistant response text per session ---
|
|
291
|
+
// Fires once per step with the complete generated text. Flushed on session.idle.
|
|
292
|
+
if (t === 'session.next.text.ended') {
|
|
293
|
+
const text = props?.text ?? null;
|
|
294
|
+
if (sessionId && typeof text === 'string' && text.trim()) {
|
|
295
|
+
const prev = sessionText.get(sessionId) ?? '';
|
|
296
|
+
sessionText.set(sessionId, prev ? prev + '\\n\\n' + text : text);
|
|
297
|
+
}
|
|
298
|
+
return; // never emit directly — flushed as AgentMessage on session.idle
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
// --- session.next.prompted: the user's prompt text sent to the model ---
|
|
302
|
+
if (t === 'session.next.prompted') {
|
|
303
|
+
const promptText = props?.prompt?.text ?? null;
|
|
304
|
+
appendEvent({
|
|
305
|
+
hook_event_name: 'UserMessage',
|
|
306
|
+
provider: 'opencode',
|
|
307
|
+
session_id: sessionId,
|
|
308
|
+
message: typeof promptText === 'string' ? promptText.slice(0, 2000) : null,
|
|
309
|
+
});
|
|
310
|
+
return;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
// --- session.idle: flush accumulated assistant text as AgentMessage ---
|
|
314
|
+
if (t === 'session.idle' && sessionId && sessionText.has(sessionId)) {
|
|
315
|
+
const text = sessionText.get(sessionId)!;
|
|
316
|
+
sessionText.delete(sessionId);
|
|
317
|
+
if (text.trim()) {
|
|
318
|
+
appendEvent({
|
|
319
|
+
hook_event_name: 'AgentMessage',
|
|
320
|
+
provider: 'opencode',
|
|
321
|
+
session_id: sessionId,
|
|
322
|
+
message: text.slice(0, 3000),
|
|
323
|
+
});
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
// --- session.next.step.ended: token usage + cost ---
|
|
328
|
+
if (t === 'session.next.step.ended') {
|
|
329
|
+
const tokens = props?.tokens ?? null;
|
|
330
|
+
const cost = props?.cost ?? null;
|
|
331
|
+
appendEvent({
|
|
332
|
+
hook_event_name: 'StepEnded',
|
|
333
|
+
provider: 'opencode',
|
|
334
|
+
session_id: sessionId,
|
|
335
|
+
message: props?.finish ?? null,
|
|
336
|
+
tokens: tokens,
|
|
337
|
+
cost: cost,
|
|
338
|
+
});
|
|
339
|
+
return;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
// Generic catch-all — extract message from known session.next.* fields
|
|
343
|
+
const agentName = props?.agent ?? null;
|
|
344
|
+
const modelId = props?.model?.id ?? props?.model?.modelID ?? null;
|
|
345
|
+
const reasonText = props?.text ?? null; // session.next.reasoning.ended
|
|
346
|
+
const promptText = props?.prompt?.text ?? null; // fallback
|
|
347
|
+
const message = errMsg
|
|
348
|
+
?? reasonText
|
|
349
|
+
?? promptText
|
|
350
|
+
?? (agentName && modelId ? \`\${agentName} (\${modelId})\`
|
|
351
|
+
: agentName ? agentName
|
|
352
|
+
: modelId ? modelId
|
|
353
|
+
: null);
|
|
354
|
+
|
|
355
|
+
appendEvent({
|
|
356
|
+
hook_event_name: SESSION_MAP[t] ?? t,
|
|
357
|
+
provider: 'opencode',
|
|
358
|
+
session_id: sessionId,
|
|
359
|
+
message: message,
|
|
360
|
+
});
|
|
361
|
+
},
|
|
362
|
+
});
|
|
363
|
+
`;
|
|
364
|
+
}
|
|
365
|
+
// ---------------------------------------------------------------------------
|
|
366
|
+
// Public API
|
|
367
|
+
// ---------------------------------------------------------------------------
|
|
368
|
+
function isOpenCodeHooksInstalled(workspaceRoot) {
|
|
369
|
+
try {
|
|
370
|
+
const content = fs.readFileSync(pluginPath(workspaceRoot), 'utf8');
|
|
371
|
+
// Check both the marker AND that the dir is workspace-scoped (not a stale install).
|
|
372
|
+
const expectedDir = path.join(workspaceRoot, '.autodev').replace(/\\/g, '/');
|
|
373
|
+
return content.includes(PLUGIN_MARKER) && content.includes(expectedDir);
|
|
374
|
+
}
|
|
375
|
+
catch {
|
|
376
|
+
return false;
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
function installOpenCodeHooks(workspaceRoot) {
|
|
380
|
+
const dir = pluginDir(workspaceRoot);
|
|
381
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
382
|
+
fs.writeFileSync(pluginPath(workspaceRoot), buildPluginContent(workspaceRoot), 'utf8');
|
|
383
|
+
}
|
|
384
|
+
/**
|
|
385
|
+
* Return true if an opencode process is actively writing to the hooks JSONL.
|
|
386
|
+
* Prefers the per-session file when sessionId is known; falls back to the global file.
|
|
387
|
+
*/
|
|
388
|
+
function isOpenCodeCliActive(workspaceRoot, windowMs = 90_000, sessionId) {
|
|
389
|
+
const safeId = sessionId ? sessionId.replace(/[^a-zA-Z0-9_-]/g, '_') : undefined;
|
|
390
|
+
const perFile = safeId ? path.join(workspaceRoot, '.autodev', `hooks-events-${safeId}.jsonl`) : undefined;
|
|
391
|
+
const jsonlFile = (perFile && fs.existsSync(perFile))
|
|
392
|
+
? perFile
|
|
393
|
+
: path.join(workspaceRoot, '.autodev', 'hooks-events.jsonl');
|
|
394
|
+
try {
|
|
395
|
+
const stat = fs.statSync(jsonlFile);
|
|
396
|
+
if (Date.now() - stat.mtimeMs > windowMs) {
|
|
397
|
+
return false;
|
|
398
|
+
} // stale file
|
|
399
|
+
const lines = fs.readFileSync(jsonlFile, 'utf8').split('\n').filter(Boolean);
|
|
400
|
+
for (let i = lines.length - 1; i >= 0; i--) {
|
|
401
|
+
try {
|
|
402
|
+
const ev = JSON.parse(lines[i]);
|
|
403
|
+
if (ev.provider !== 'opencode') {
|
|
404
|
+
continue;
|
|
405
|
+
}
|
|
406
|
+
// If reading global file, filter to the requested session
|
|
407
|
+
if (!perFile && sessionId && ev.session_id && ev.session_id !== sessionId) {
|
|
408
|
+
continue;
|
|
409
|
+
}
|
|
410
|
+
const name = ev.hook_event_name ?? '';
|
|
411
|
+
if (name === 'Stop' || name === 'StopFailure' || name === 'SessionEnd' || name === 'server.instance.disposed') {
|
|
412
|
+
return false;
|
|
413
|
+
}
|
|
414
|
+
return true;
|
|
415
|
+
}
|
|
416
|
+
catch {
|
|
417
|
+
continue;
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
return false;
|
|
421
|
+
}
|
|
422
|
+
catch {
|
|
423
|
+
return false;
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
/**
|
|
427
|
+
* Return true if the most recent opencode session exited cleanly (Stop event present).
|
|
428
|
+
* Prefers the per-session file when sessionId is known.
|
|
429
|
+
*/
|
|
430
|
+
function openCodeExitedCleanly(workspaceRoot, sessionId) {
|
|
431
|
+
const safeId = sessionId ? sessionId.replace(/[^a-zA-Z0-9_-]/g, '_') : undefined;
|
|
432
|
+
const perFile = safeId ? path.join(workspaceRoot, '.autodev', `hooks-events-${safeId}.jsonl`) : undefined;
|
|
433
|
+
const jsonlFile = (perFile && fs.existsSync(perFile))
|
|
434
|
+
? perFile
|
|
435
|
+
: path.join(workspaceRoot, '.autodev', 'hooks-events.jsonl');
|
|
436
|
+
try {
|
|
437
|
+
const lines = fs.readFileSync(jsonlFile, 'utf8').split('\n').filter(Boolean);
|
|
438
|
+
for (let i = lines.length - 1; i >= 0; i--) {
|
|
439
|
+
try {
|
|
440
|
+
const ev = JSON.parse(lines[i]);
|
|
441
|
+
if (ev.provider !== 'opencode') {
|
|
442
|
+
continue;
|
|
443
|
+
}
|
|
444
|
+
if (!perFile && sessionId && ev.session_id && ev.session_id !== sessionId) {
|
|
445
|
+
continue;
|
|
446
|
+
}
|
|
447
|
+
const name = ev.hook_event_name ?? '';
|
|
448
|
+
if (name === 'Stop' || name === 'StopFailure' || name === 'SessionEnd' || name === 'server.instance.disposed') {
|
|
449
|
+
return true;
|
|
450
|
+
}
|
|
451
|
+
return false;
|
|
452
|
+
}
|
|
453
|
+
catch {
|
|
454
|
+
continue;
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
catch { /* file absent */ }
|
|
459
|
+
return false;
|
|
460
|
+
}
|
|
461
|
+
/**
|
|
462
|
+
* Read the workspace-scoped hooks-events.jsonl and return the session ID from
|
|
463
|
+
* the most recent OpenCode session event.
|
|
464
|
+
* Returns undefined if the file is absent or no session event has been seen yet.
|
|
465
|
+
*
|
|
466
|
+
* @param notBefore Only consider events with a timestamp >= this ISO string or
|
|
467
|
+
* epoch-ms number. Pass the task-start time to avoid picking
|
|
468
|
+
* up stale/foreign sessions from before this dispatch.
|
|
469
|
+
*/
|
|
470
|
+
function getOpenCodeSessionIdFromHooks(workspaceRoot, notBefore) {
|
|
471
|
+
const jsonlFile = path.join(workspaceRoot, '.autodev', 'hooks-events.jsonl');
|
|
472
|
+
const cutoff = notBefore
|
|
473
|
+
? (typeof notBefore === 'number' ? new Date(notBefore).toISOString() : notBefore)
|
|
474
|
+
: undefined;
|
|
475
|
+
try {
|
|
476
|
+
const lines = fs.readFileSync(jsonlFile, 'utf8').split('\n').filter(Boolean);
|
|
477
|
+
// Walk backwards — most recent event first
|
|
478
|
+
for (let i = lines.length - 1; i >= 0; i--) {
|
|
479
|
+
try {
|
|
480
|
+
const ev = JSON.parse(lines[i]);
|
|
481
|
+
if (ev.provider !== 'opencode') {
|
|
482
|
+
continue;
|
|
483
|
+
}
|
|
484
|
+
if (cutoff && ev.timestamp && ev.timestamp < cutoff) {
|
|
485
|
+
break;
|
|
486
|
+
} // events are chronological
|
|
487
|
+
const sid = ev.session_id ?? undefined;
|
|
488
|
+
if (sid) {
|
|
489
|
+
return sid;
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
catch { /* malformed line */ }
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
catch { /* file absent */ }
|
|
496
|
+
return undefined;
|
|
497
|
+
}
|
|
498
|
+
function uninstallOpenCodeHooks(workspaceRoot) {
|
|
499
|
+
const p = pluginPath(workspaceRoot);
|
|
500
|
+
if (!fs.existsSync(p)) {
|
|
501
|
+
return;
|
|
502
|
+
}
|
|
503
|
+
try {
|
|
504
|
+
const content = fs.readFileSync(p, 'utf8');
|
|
505
|
+
if (content.includes(PLUGIN_MARKER)) {
|
|
506
|
+
fs.unlinkSync(p);
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
catch { /* ignore */ }
|
|
510
|
+
}
|
|
511
|
+
//# sourceMappingURL=openCodeHooksManager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openCodeHooksManager.js","sourceRoot":"","sources":["../src/openCodeHooksManager.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { AutodevSettings } from './core/settingsLoader';
|
|
2
|
+
export interface PeriodicActionDef {
|
|
3
|
+
/** Unique stable ID. Used as HTML element id prefix and counter key. */
|
|
4
|
+
id: string;
|
|
5
|
+
/** Sidebar label shown to the user. */
|
|
6
|
+
label: string;
|
|
7
|
+
/** Key in AutodevSettings that holds the interval (0 = disabled). */
|
|
8
|
+
settingKey: keyof AutodevSettings;
|
|
9
|
+
/** Log icon (emoji) used in the extension host log. */
|
|
10
|
+
icon: string;
|
|
11
|
+
/**
|
|
12
|
+
* How the action is executed when due:
|
|
13
|
+
* - 'prompt' — send `prompt` text to the AI via sendToAi (default)
|
|
14
|
+
* - 'compact' — run provider-specific /compact tool (no AI prompt sent)
|
|
15
|
+
* - 'pruneTodo' — move completed [x] tasks from TODO.md into DONE.md
|
|
16
|
+
*/
|
|
17
|
+
type?: 'prompt' | 'compact' | 'pruneTodo';
|
|
18
|
+
/** Prompt text sent to the agent (only used when type === 'prompt'). */
|
|
19
|
+
prompt: string;
|
|
20
|
+
}
|
|
21
|
+
export declare const PERIODIC_ACTIONS: PeriodicActionDef[];
|
|
22
|
+
interface ActionState {
|
|
23
|
+
/** Tasks completed since this action was last triggered (or since loop start). */
|
|
24
|
+
counter: number;
|
|
25
|
+
/** Loop iteration number when this action was last triggered (0 = never). */
|
|
26
|
+
lastTriggeredAt: number;
|
|
27
|
+
/** Wall-clock ISO string when last triggered. */
|
|
28
|
+
lastTriggeredTime: string | null;
|
|
29
|
+
}
|
|
30
|
+
export declare class PeriodicActionManager {
|
|
31
|
+
private readonly _state;
|
|
32
|
+
private _ensureState;
|
|
33
|
+
/** Reset all counters (call at loop start). */
|
|
34
|
+
reset(): void;
|
|
35
|
+
/**
|
|
36
|
+
* Reset all counters and persist the cleared state to .autodev/loop-state.json.
|
|
37
|
+
* Call at loop start.
|
|
38
|
+
*/
|
|
39
|
+
resetAndPersist(workspaceRoot?: string): void;
|
|
40
|
+
/**
|
|
41
|
+
* Increment all action counters by 1.
|
|
42
|
+
* @param iteration Current loop iteration number (used for debug state).
|
|
43
|
+
* @param workspaceRoot If provided, persists loop-state.json to .autodev/.
|
|
44
|
+
*/
|
|
45
|
+
increment(iteration: number, workspaceRoot?: string): void;
|
|
46
|
+
/** Returns the actions whose counter has reached or exceeded the configured interval. */
|
|
47
|
+
getDue(settings: AutodevSettings): PeriodicActionDef[];
|
|
48
|
+
/**
|
|
49
|
+
* Reset the counter for a specific action after it has been handled.
|
|
50
|
+
* Records the iteration + timestamp it was triggered at.
|
|
51
|
+
*/
|
|
52
|
+
markHandled(id: string, iteration: number, workspaceRoot?: string): void;
|
|
53
|
+
/** Returns the current counter value for an action (for debug / display). */
|
|
54
|
+
getCount(id: string): number;
|
|
55
|
+
/** Snapshot of all action states — used for debug persistence. */
|
|
56
|
+
snapshot(): Record<string, ActionState>;
|
|
57
|
+
/**
|
|
58
|
+
* Write .autodev/loop-state.json with current iteration + per-action counters.
|
|
59
|
+
* Safe — silently ignores write errors.
|
|
60
|
+
*/
|
|
61
|
+
private _persist;
|
|
62
|
+
}
|
|
63
|
+
export {};
|