@meego-harness/opencode-worker 0.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.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/cli.ts"],"sourcesContent":["import type { OpenCodeWorkerSetupInput } from './types'\nimport { spawn, spawnSync } from 'node:child_process'\nimport process from 'node:process'\nimport { OpenCodeWorkerBridge } from './bridge'\nimport {\n createClackPrompter,\n getOpenCodeWorkerDoctorReport,\n listOpenCodeWorkerConfigs,\n loadOpenCodeWorkerConfig,\n resolveOpenCodeWorkerStateFile,\n runOpenCodeWorkerSetup,\n setOpenCodeWorkerEnabled,\n uninstallOpenCodeWorker,\n} from './config'\nimport {\n assertOpenCodeCliAvailable,\n assertOpenCodeCliRuntimeContract,\n OpenCodeCliTaskExecutor,\n} from './runtime'\n\nconst TMUX_OPTION = '--tmux'\nconst TMUX_CHILD_OPTION = '--tmux-worker'\nconst OPENCODE_SHELL_OPTION = '--opencode-shell'\nconst TMUX_SESSION_PREFIX = 'meego-opencode-worker-'\n\nconst consoleLogger = {\n error(message: string) {\n console.error(message)\n },\n info(message: string) {\n console.log(message)\n },\n warn(message: string) {\n console.warn(message)\n },\n}\n\nexport async function runOpenCodeWorkerCli(argv = process.argv.slice(2)) {\n const [command, ...rest] = argv\n\n if (command === 'setup') {\n const setupResult = await runOpenCodeWorkerSetup(\n {\n logger: consoleLogger,\n },\n createClackPrompter(),\n readOpenCodeWorkerSetupInput(rest),\n )\n if (rest.includes('--json')) {\n consoleLogger.info(JSON.stringify(setupResult))\n }\n return\n }\n\n if (command === 'list') {\n const workers = listOpenCodeWorkerConfigs()\n if (rest.includes('--json')) {\n consoleLogger.info(JSON.stringify(workers))\n return\n }\n\n if (workers.length === 0) {\n consoleLogger.warn('No configured OpenCode workers found')\n return\n }\n\n for (const worker of workers) {\n consoleLogger.info(`${worker.workerId} ${worker.enabled ? 'enabled' : 'disabled'} ${worker.serverUrl}`)\n }\n return\n }\n\n if (command === 'doctor') {\n const report = getOpenCodeWorkerDoctorReport(\n {},\n {\n assertOpenCodeCliRuntimeContract,\n },\n )\n if (rest.includes('--json')) {\n consoleLogger.info(JSON.stringify(report))\n return\n }\n\n if (report.workers.length === 0) {\n consoleLogger.warn('No configured OpenCode workers found')\n return\n }\n\n for (const worker of report.workers) {\n consoleLogger.info(`${worker.workerId} config=${worker.configStatus} runtime=${worker.runtimeStatus}`)\n for (const error of worker.errors) {\n consoleLogger.warn(error)\n }\n }\n return\n }\n\n if (command === 'start') {\n const workerId = parseWorkerId(rest, 'start')\n const useTmux = rest.includes(TMUX_OPTION)\n const isTmuxChild = rest.includes(TMUX_CHILD_OPTION)\n const config = loadOpenCodeWorkerConfig(workerId)\n const useOpenCodeShell = rest.includes(OPENCODE_SHELL_OPTION) || config.openCodeShell === true\n if (!config.enabled) {\n throw new Error(\n `OpenCode worker ${workerId} is disabled. Run meego-opencode-worker enable --worker ${workerId} first.`,\n )\n }\n assertOpenCodeCliAvailable('opencode', spawnSync, { useShell: useOpenCodeShell })\n\n if (useTmux && !isTmuxChild) {\n const startedInTmux = startOpenCodeWorkerInTmux(workerId, rest)\n\n if (startedInTmux) {\n consoleLogger.info(`OpenCode worker ${workerId} started in tmux`)\n return\n }\n consoleLogger.warn('tmux is not available, starting in foreground')\n }\n\n const bridge = new OpenCodeWorkerBridge(\n {\n ...config,\n stateFile: resolveOpenCodeWorkerStateFile(workerId),\n },\n {\n executor: new OpenCodeCliTaskExecutor({ useShell: useOpenCodeShell }),\n logger: consoleLogger,\n },\n )\n\n await bridge.start()\n consoleLogger.info(`OpenCode worker ${workerId} is connected`)\n await waitForShutdownSignal()\n await bridge.stop()\n return\n }\n\n if (command === 'enable') {\n const workerId = parseWorkerId(rest, 'enable')\n setOpenCodeWorkerEnabled(workerId, true)\n consoleLogger.info(`Enabled OpenCode worker ${workerId}`)\n return\n }\n\n if (command === 'disable') {\n const workerId = parseWorkerId(rest, 'disable')\n setOpenCodeWorkerEnabled(workerId, false)\n consoleLogger.info(`Disabled OpenCode worker ${workerId}`)\n return\n }\n\n if (command === 'uninstall' || command === 'remove') {\n const workerId = parseWorkerId(rest, 'uninstall')\n const result = uninstallOpenCodeWorker(workerId)\n consoleLogger.info(`Removed OpenCode worker ${workerId}`)\n consoleLogger.info(`- config: ${result.removedConfig ? 'deleted' : 'missing'} ${result.configFile}`)\n consoleLogger.info(`- state: ${result.removedState ? 'deleted' : 'missing'} ${result.stateFile}`)\n if (result.credentialFile) {\n consoleLogger.info(\n `- credential: ${result.removedCredential ? 'deleted' : 'missing'} ${result.credentialFile}`,\n )\n }\n return\n }\n\n if (command === 'stop') {\n const workerId = parseWorkerId(rest, 'stop')\n const stopped = stopOpenCodeWorkerInTmux(workerId)\n if (stopped) {\n consoleLogger.info(`Stopped tmux session for OpenCode worker ${workerId}`)\n }\n else {\n consoleLogger.warn(`No running tmux session found for OpenCode worker ${workerId}`)\n }\n return\n }\n\n if (command === 'stop-all') {\n const stopped = stopAllOpenCodeWorkerSessionsInTmux()\n if (stopped > 0) {\n consoleLogger.info(`Stopped ${stopped} OpenCode worker tmux session(s)`)\n }\n else {\n consoleLogger.warn('No running OpenCode worker tmux session found')\n }\n return\n }\n\n printUsage()\n}\n\nfunction startOpenCodeWorkerInTmux(workerId: string, argv: string[]) {\n const canStartWithTmux = isTmuxAvailable()\n\n if (!canStartWithTmux) {\n return false\n }\n\n if (!process.argv[1]) {\n return false\n }\n\n const sessionName = toTmuxSessionName(workerId)\n const args = sanitizeTmuxArgs(argv).concat(TMUX_CHILD_OPTION)\n\n try {\n spawn('tmux', ['new-session', '-d', '-s', sessionName, process.execPath, process.argv[1], 'start', ...args], {\n stdio: 'ignore',\n })\n return true\n }\n catch {\n return false\n }\n}\n\nfunction isTmuxAvailable() {\n try {\n const result = spawnSync('tmux', ['-V'], {\n stdio: 'ignore',\n })\n return !result.error && result.status === 0\n }\n catch {\n return false\n }\n}\n\nfunction stopOpenCodeWorkerInTmux(workerId: string) {\n if (!isTmuxAvailable()) {\n return false\n }\n\n const sessionName = toTmuxSessionName(workerId)\n return stopSessionByName(sessionName)\n}\n\nfunction stopAllOpenCodeWorkerSessionsInTmux() {\n if (!isTmuxAvailable()) {\n return 0\n }\n\n const sessionNames = getActiveOpenCodeWorkerSessions()\n let stopped = 0\n for (const sessionName of sessionNames) {\n if (stopSessionByName(sessionName)) {\n stopped += 1\n }\n }\n return stopped\n}\n\nfunction stopSessionByName(sessionName: string) {\n try {\n const result = spawnSync('tmux', ['kill-session', '-t', sessionName], {\n stdio: 'ignore',\n })\n return !result.error && result.status === 0\n }\n catch {\n return false\n }\n}\n\nfunction getActiveOpenCodeWorkerSessions() {\n try {\n const result = spawnSync('tmux', ['list-sessions', '-F', '#S'], {\n encoding: 'utf8',\n })\n if (result.error || result.status !== 0 || typeof result.stdout !== 'string') {\n return []\n }\n\n return result.stdout\n .split('\\n')\n .map(line => line.trim())\n .filter(line => line.startsWith(TMUX_SESSION_PREFIX))\n }\n catch {\n return []\n }\n}\n\nfunction parseWorkerId(argv: string[], commandName: 'start' | 'enable' | 'disable' | 'uninstall' | 'stop') {\n const workerIndex = argv.findIndex(value => value === '--worker')\n const workerId = workerIndex >= 0 ? argv[workerIndex + 1] : undefined\n\n if (!workerId) {\n throw new Error(`${commandName} requires --worker <workerId>`)\n }\n\n return workerId\n}\n\nfunction sanitizeTmuxArgs(argv: string[]) {\n return argv.filter(value => value !== TMUX_OPTION && value !== TMUX_CHILD_OPTION)\n}\n\nfunction toTmuxSessionName(workerId: string) {\n const safeWorkerId = workerId.replace(/[^\\w.-]/g, '-')\n return `${TMUX_SESSION_PREFIX}${safeWorkerId}`\n}\n\nfunction printUsage() {\n console.log([\n 'Usage:',\n ' meego-opencode-worker setup',\n ' meego-opencode-worker list',\n ' meego-opencode-worker doctor',\n ' meego-opencode-worker start --worker <workerId> [--tmux] [--opencode-shell]',\n ' meego-opencode-worker enable --worker <workerId>',\n ' meego-opencode-worker disable --worker <workerId>',\n ' meego-opencode-worker stop --worker <workerId>',\n ' meego-opencode-worker stop-all',\n ' meego-opencode-worker uninstall --worker <workerId>',\n ].join('\\n'))\n}\n\nfunction readOpenCodeWorkerSetupInput(argv: string[]) {\n const serverUrl = readOptionValue(argv, '--server-url')\n const email = readOptionValue(argv, '--email')\n const workerId = readOptionValue(argv, '--worker')\n const capabilitySummary = readOptionValue(argv, '--capability-summary')\n const defaultWorkspace = readOptionValue(argv, '--workspace')\n const artifactStagingRoot = readOptionValue(argv, '--artifact-staging-root')\n const permissionPreset = readOptionValue(argv, '--permission-preset')\n const modelSelection = readOptionValue(argv, '--model')\n const variantDefault = readOptionValue(argv, '--variant')\n const agentDefault = readOptionValue(argv, '--agent')\n const openCodeShell = argv.includes(OPENCODE_SHELL_OPTION)\n const repoMappings = readRepoMappings(argv)\n\n if (\n !serverUrl\n && !email\n && !workerId\n && !capabilitySummary\n && !defaultWorkspace\n && artifactStagingRoot === undefined\n && !permissionPreset\n && !modelSelection\n && !variantDefault\n && !agentDefault\n && !openCodeShell\n && Object.keys(repoMappings).length === 0\n ) {\n return undefined\n }\n\n return {\n ...(serverUrl ? { serverUrl } : {}),\n ...(email ? { email } : {}),\n ...(workerId ? { workerId } : {}),\n ...(capabilitySummary ? { capabilitySummary } : {}),\n ...(defaultWorkspace ? { defaultWorkspace } : {}),\n ...(artifactStagingRoot !== undefined ? { artifactStagingRoot } : {}),\n ...(permissionPreset ? { permissionPreset: permissionPreset as OpenCodeWorkerSetupInput['permissionPreset'] } : {}),\n ...(modelSelection ? { modelSelection: modelSelection as OpenCodeWorkerSetupInput['modelSelection'] } : {}),\n ...(variantDefault ? { variantDefault: variantDefault as OpenCodeWorkerSetupInput['variantDefault'] } : {}),\n ...(agentDefault ? { agentDefault: agentDefault as OpenCodeWorkerSetupInput['agentDefault'] } : {}),\n ...(openCodeShell ? { openCodeShell } : {}),\n repoMappings,\n } satisfies OpenCodeWorkerSetupInput\n}\n\nfunction readOptionValue(argv: string[], optionName: string) {\n const index = argv.findIndex(value => value === optionName)\n if (index < 0) {\n return undefined\n }\n return argv[index + 1]\n}\n\nfunction readRepoMappings(argv: string[]) {\n const repoMappings: Record<string, string> = {}\n for (let index = 0; index < argv.length; index += 1) {\n if (argv[index] !== '--repo-mapping') {\n continue\n }\n\n const pair = argv[index + 1]\n if (!pair) {\n throw new Error('--repo-mapping requires <repo>=<cwd>')\n }\n\n const separatorIndex = pair.indexOf('=')\n if (separatorIndex <= 0 || separatorIndex === pair.length - 1) {\n throw new Error('--repo-mapping must use <repo>=<cwd>')\n }\n\n const repo = pair.slice(0, separatorIndex).trim()\n const cwd = pair.slice(separatorIndex + 1).trim()\n repoMappings[repo] = cwd\n }\n\n return repoMappings\n}\n\nasync function waitForShutdownSignal() {\n return await new Promise<void>((resolve) => {\n const handler = () => {\n process.off('SIGINT', handler)\n process.off('SIGTERM', handler)\n resolve()\n }\n process.on('SIGINT', handler)\n process.on('SIGTERM', handler)\n })\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,205 @@
1
+ import { WorkerClientSDK, Part } from '@meego-harness/worker-sdk';
2
+ import { SpawnOptions, ChildProcess, spawnSync } from 'node:child_process';
3
+
4
+ type PermissionPreset = 'safe' | 'default' | 'full-access';
5
+ type OpenCodeModelSelection = string;
6
+ type OpenCodeVariantSelection = string;
7
+ type OpenCodeAgentSelection = string;
8
+ interface OpenCodeWorkerConfig {
9
+ serverUrl: string;
10
+ email: string;
11
+ workerId: string;
12
+ capabilitySummary: string;
13
+ defaultWorkspace: string;
14
+ artifactStagingRoot?: string;
15
+ repoMappings: Record<string, string>;
16
+ enabled: boolean;
17
+ permissionPreset: PermissionPreset;
18
+ modelSelection: OpenCodeModelSelection;
19
+ variantDefault: OpenCodeVariantSelection;
20
+ agentDefault: OpenCodeAgentSelection;
21
+ openCodeShell?: boolean;
22
+ }
23
+ interface OpenCodeWorkerSetupResult extends OpenCodeWorkerConfig {
24
+ }
25
+ interface OpenCodeWorkerSetupInput extends Partial<Omit<OpenCodeWorkerConfig, 'enabled'>> {
26
+ enabled?: boolean;
27
+ }
28
+ interface OpenCodeWorkerContextBinding {
29
+ contextId: string;
30
+ repo?: string;
31
+ cwd: string;
32
+ sessionId?: string;
33
+ variant?: Exclude<OpenCodeVariantSelection, 'use-opencode-default'>;
34
+ agent?: Exclude<OpenCodeAgentSelection, 'use-opencode-default'>;
35
+ planMode: boolean;
36
+ }
37
+ interface OpenCodeWorkerState {
38
+ contexts: OpenCodeWorkerContextBinding[];
39
+ }
40
+ interface OpenCodeWorkerBridgeConfig extends OpenCodeWorkerConfig {
41
+ stateFile?: string;
42
+ reconnectBaseDelayMs?: number;
43
+ reconnectMaxDelayMs?: number;
44
+ }
45
+ interface OpenCodeWorkerBridgeLogger {
46
+ info: (message: string) => void;
47
+ warn: (message: string) => void;
48
+ error: (message: string) => void;
49
+ }
50
+ interface OpenCodeCliTaskExecutionRequest {
51
+ taskId: string;
52
+ contextId: string;
53
+ cwd: string;
54
+ prompt: string;
55
+ sessionId?: string;
56
+ model?: Exclude<OpenCodeModelSelection, 'use-opencode-default'>;
57
+ variant?: Exclude<OpenCodeVariantSelection, 'use-opencode-default'>;
58
+ agent?: Exclude<OpenCodeAgentSelection, 'use-opencode-default'>;
59
+ permissionPreset: PermissionPreset;
60
+ abortSignal: AbortSignal;
61
+ }
62
+ interface OpenCodeCliTaskExecutionResult {
63
+ text: string;
64
+ sessionId: string;
65
+ }
66
+ interface OpenCodeTaskExecutor {
67
+ runTurn: (request: OpenCodeCliTaskExecutionRequest) => Promise<OpenCodeCliTaskExecutionResult>;
68
+ }
69
+ interface OpenCodeWorkerBridgeDependencies {
70
+ executor: OpenCodeTaskExecutor;
71
+ logger: OpenCodeWorkerBridgeLogger;
72
+ client?: WorkerClientSDK;
73
+ }
74
+ interface OpenCodeWorkerPrompter {
75
+ text: (params: {
76
+ message: string;
77
+ placeholder?: string;
78
+ initialValue?: string;
79
+ validate?: (value: string) => string | undefined;
80
+ }) => Promise<string>;
81
+ select: (params: {
82
+ message: string;
83
+ options: Array<{
84
+ value: string;
85
+ label: string;
86
+ }>;
87
+ initialValue?: string;
88
+ }) => Promise<string>;
89
+ confirm: (params: {
90
+ message: string;
91
+ initialValue?: boolean;
92
+ }) => Promise<boolean>;
93
+ }
94
+ interface RunOpenCodeWorkerSetupDependencies {
95
+ homeDir?: string;
96
+ logger: OpenCodeWorkerBridgeLogger;
97
+ }
98
+ interface OpenCodeWorkerListItem extends OpenCodeWorkerConfig {
99
+ configFile: string;
100
+ stateFile: string;
101
+ }
102
+ interface OpenCodeWorkerDoctorWorkerReport extends OpenCodeWorkerListItem {
103
+ configStatus: 'ok' | 'error';
104
+ runtimeStatus: 'ok' | 'error';
105
+ errors: string[];
106
+ }
107
+ interface OpenCodeWorkerDoctorReport {
108
+ workers: OpenCodeWorkerDoctorWorkerReport[];
109
+ }
110
+ interface ResolveStoragePathsOptions {
111
+ homeDir?: string;
112
+ }
113
+ interface OpenCodeCliTaskExecutorConfig {
114
+ openCodeBin?: string;
115
+ useShell?: boolean;
116
+ shell?: string;
117
+ spawn?: (command: string, args: string[], options: SpawnOptions) => ChildProcess;
118
+ }
119
+
120
+ declare class OpenCodeWorkerBridge {
121
+ private readonly config;
122
+ private readonly executor;
123
+ private readonly logger;
124
+ private readonly client;
125
+ private readonly activeTasks;
126
+ private readonly pendingCanceledTaskIds;
127
+ private readonly bindings;
128
+ private readonly contextQueues;
129
+ private readonly stateFile;
130
+ constructor(config: OpenCodeWorkerBridgeConfig, dependencies: OpenCodeWorkerBridgeDependencies);
131
+ start(): Promise<this>;
132
+ stop(): Promise<void>;
133
+ private handleTaskMessage;
134
+ private processTaskMessage;
135
+ private trySendTaskStatusUpdate;
136
+ private handleTaskCancel;
137
+ private supersedeActiveTaskExecution;
138
+ private runExecutorTurn;
139
+ private createBinding;
140
+ private hydrateBindingFromMetadata;
141
+ private resolveCwd;
142
+ private ensureDirectory;
143
+ private ensureWorkspaceSubdirectory;
144
+ private persistState;
145
+ private isTaskCanceled;
146
+ private resolveStructuredProjectNodeResult;
147
+ private registerStructuredArtifacts;
148
+ }
149
+
150
+ declare function resolveOpenCodeWorkerStorageDir(options?: ResolveStoragePathsOptions): string;
151
+ declare function resolveOpenCodeWorkerConfigFile(workerId: string, options?: ResolveStoragePathsOptions): string;
152
+ declare function resolveOpenCodeWorkerStateFile(workerId: string, options?: ResolveStoragePathsOptions): string;
153
+ declare function loadOpenCodeWorkerConfig(workerId: string, options?: ResolveStoragePathsOptions): OpenCodeWorkerConfig;
154
+ declare function writeOpenCodeWorkerConfig(config: OpenCodeWorkerConfig, options?: ResolveStoragePathsOptions): void;
155
+ declare function loadOpenCodeWorkerState(stateFile: string): OpenCodeWorkerState;
156
+ declare function writeOpenCodeWorkerState(stateFile: string, state: OpenCodeWorkerState): void;
157
+ declare function runOpenCodeWorkerSetup(dependencies: RunOpenCodeWorkerSetupDependencies, prompter: OpenCodeWorkerPrompter, input?: OpenCodeWorkerSetupInput): Promise<OpenCodeWorkerSetupResult>;
158
+ declare function listOpenCodeWorkerConfigs(options?: ResolveStoragePathsOptions): OpenCodeWorkerListItem[];
159
+ declare function getOpenCodeWorkerDoctorReport(options?: ResolveStoragePathsOptions, dependencies?: {
160
+ assertOpenCodeCliRuntimeContract?: (openCodeBin?: string, options?: {
161
+ useShell?: boolean;
162
+ }) => void;
163
+ }): OpenCodeWorkerDoctorReport;
164
+ declare function setOpenCodeWorkerEnabled(workerId: string, enabled: boolean, options?: ResolveStoragePathsOptions): void;
165
+ declare function uninstallOpenCodeWorker(workerId: string, options?: ResolveStoragePathsOptions): {
166
+ configFile: string;
167
+ stateFile: string;
168
+ credentialFile: string | undefined;
169
+ removedConfig: boolean;
170
+ removedState: boolean;
171
+ removedCredential: boolean;
172
+ };
173
+ declare function createClackPrompter(): OpenCodeWorkerPrompter;
174
+
175
+ declare const OPENCODE_WORKER_ROLE = "coder";
176
+ declare const OPENCODE_WORKER_WORKING_TEXT = "OpenCode CLI is working";
177
+ declare const OPENCODE_WORKER_CONFIG_DIR = ".meego-harness/opencode-worker";
178
+
179
+ declare function stringifyTaskMessageParts(parts: Part[]): string;
180
+
181
+ interface OpenCodeShellOptions {
182
+ useShell?: boolean;
183
+ shell?: string;
184
+ }
185
+ declare class OpenCodeCliTaskExecutor {
186
+ private readonly openCodeBin;
187
+ private readonly useShell;
188
+ private readonly shell;
189
+ private readonly spawnChild;
190
+ constructor(config?: OpenCodeCliTaskExecutorConfig);
191
+ runTurn(request: OpenCodeCliTaskExecutionRequest): Promise<OpenCodeCliTaskExecutionResult>;
192
+ }
193
+ declare function assertOpenCodeCliAvailable(openCodeBin?: string, run?: typeof spawnSync, options?: OpenCodeShellOptions): void;
194
+ declare function assertOpenCodeCliRuntimeContract(openCodeBin?: string, dependencies?: {
195
+ run?: typeof spawnSync;
196
+ createTempDir?: () => string;
197
+ useShell?: boolean;
198
+ shell?: string;
199
+ }): void;
200
+ declare function buildOpenCodeArgs(request: OpenCodeCliTaskExecutionRequest): string[];
201
+ declare function shouldSkipPermissionsForPreset(preset: PermissionPreset): preset is "full-access";
202
+ declare function createAbortError(): Error;
203
+ declare function isAbortError(error: unknown): boolean;
204
+
205
+ export { OPENCODE_WORKER_CONFIG_DIR, OPENCODE_WORKER_ROLE, OPENCODE_WORKER_WORKING_TEXT, type OpenCodeAgentSelection, type OpenCodeCliTaskExecutionRequest, type OpenCodeCliTaskExecutionResult, OpenCodeCliTaskExecutor, type OpenCodeCliTaskExecutorConfig, type OpenCodeModelSelection, type OpenCodeTaskExecutor, type OpenCodeVariantSelection, OpenCodeWorkerBridge, type OpenCodeWorkerBridgeConfig, type OpenCodeWorkerBridgeDependencies, type OpenCodeWorkerBridgeLogger, type OpenCodeWorkerConfig, type OpenCodeWorkerContextBinding, type OpenCodeWorkerDoctorReport, type OpenCodeWorkerDoctorWorkerReport, type OpenCodeWorkerListItem, type OpenCodeWorkerPrompter, type OpenCodeWorkerSetupInput, type OpenCodeWorkerSetupResult, type OpenCodeWorkerState, type PermissionPreset, type ResolveStoragePathsOptions, type RunOpenCodeWorkerSetupDependencies, assertOpenCodeCliAvailable, assertOpenCodeCliRuntimeContract, buildOpenCodeArgs, createAbortError, createClackPrompter, getOpenCodeWorkerDoctorReport, isAbortError, listOpenCodeWorkerConfigs, loadOpenCodeWorkerConfig, loadOpenCodeWorkerState, resolveOpenCodeWorkerConfigFile, resolveOpenCodeWorkerStateFile, resolveOpenCodeWorkerStorageDir, runOpenCodeWorkerSetup, setOpenCodeWorkerEnabled, shouldSkipPermissionsForPreset, stringifyTaskMessageParts, uninstallOpenCodeWorker, writeOpenCodeWorkerConfig, writeOpenCodeWorkerState };
package/dist/index.js ADDED
@@ -0,0 +1,55 @@
1
+ import {
2
+ OPENCODE_WORKER_CONFIG_DIR,
3
+ OPENCODE_WORKER_ROLE,
4
+ OPENCODE_WORKER_WORKING_TEXT,
5
+ OpenCodeCliTaskExecutor,
6
+ OpenCodeWorkerBridge,
7
+ assertOpenCodeCliAvailable,
8
+ assertOpenCodeCliRuntimeContract,
9
+ buildOpenCodeArgs,
10
+ createAbortError,
11
+ createClackPrompter,
12
+ getOpenCodeWorkerDoctorReport,
13
+ isAbortError,
14
+ listOpenCodeWorkerConfigs,
15
+ loadOpenCodeWorkerConfig,
16
+ loadOpenCodeWorkerState,
17
+ resolveOpenCodeWorkerConfigFile,
18
+ resolveOpenCodeWorkerStateFile,
19
+ resolveOpenCodeWorkerStorageDir,
20
+ runOpenCodeWorkerSetup,
21
+ setOpenCodeWorkerEnabled,
22
+ shouldSkipPermissionsForPreset,
23
+ stringifyTaskMessageParts,
24
+ uninstallOpenCodeWorker,
25
+ writeOpenCodeWorkerConfig,
26
+ writeOpenCodeWorkerState
27
+ } from "./chunk-4MUQ7X6C.js";
28
+ export {
29
+ OPENCODE_WORKER_CONFIG_DIR,
30
+ OPENCODE_WORKER_ROLE,
31
+ OPENCODE_WORKER_WORKING_TEXT,
32
+ OpenCodeCliTaskExecutor,
33
+ OpenCodeWorkerBridge,
34
+ assertOpenCodeCliAvailable,
35
+ assertOpenCodeCliRuntimeContract,
36
+ buildOpenCodeArgs,
37
+ createAbortError,
38
+ createClackPrompter,
39
+ getOpenCodeWorkerDoctorReport,
40
+ isAbortError,
41
+ listOpenCodeWorkerConfigs,
42
+ loadOpenCodeWorkerConfig,
43
+ loadOpenCodeWorkerState,
44
+ resolveOpenCodeWorkerConfigFile,
45
+ resolveOpenCodeWorkerStateFile,
46
+ resolveOpenCodeWorkerStorageDir,
47
+ runOpenCodeWorkerSetup,
48
+ setOpenCodeWorkerEnabled,
49
+ shouldSkipPermissionsForPreset,
50
+ stringifyTaskMessageParts,
51
+ uninstallOpenCodeWorker,
52
+ writeOpenCodeWorkerConfig,
53
+ writeOpenCodeWorkerState
54
+ };
55
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
package/package.json ADDED
@@ -0,0 +1,127 @@
1
+ {
2
+ "name": "@meego-harness/opencode-worker",
3
+ "type": "module",
4
+ "version": "0.1.0",
5
+ "description": "Standalone OpenCode worker bridge for meego-harness WorkerServerSDK",
6
+ "license": "MIT",
7
+ "keywords": [
8
+ "meego-harness-worker"
9
+ ],
10
+ "meegoHarnessWorker": {
11
+ "schemaVersion": 1,
12
+ "id": "opencode-worker",
13
+ "displayName": "OpenCode Worker",
14
+ "description": "Standalone OpenCode CLI worker bridge for meego-harness WorkerServerSDK",
15
+ "installStrategy": "private-package",
16
+ "runtimeKind": "foreground-process",
17
+ "capabilities": [
18
+ "setup",
19
+ "list",
20
+ "doctor",
21
+ "start",
22
+ "stop",
23
+ "uninstall"
24
+ ],
25
+ "prerequisites": [
26
+ {
27
+ "type": "command",
28
+ "command": "opencode",
29
+ "reason": "OpenCode CLI must be installed before the worker can run"
30
+ }
31
+ ],
32
+ "actions": {
33
+ "setup": {
34
+ "runner": "package-bin",
35
+ "executable": "meego-opencode-worker",
36
+ "args": [
37
+ "setup",
38
+ "--json"
39
+ ]
40
+ },
41
+ "list": {
42
+ "runner": "package-bin",
43
+ "executable": "meego-opencode-worker",
44
+ "args": [
45
+ "list",
46
+ "--json"
47
+ ]
48
+ },
49
+ "doctor": {
50
+ "runner": "package-bin",
51
+ "executable": "meego-opencode-worker",
52
+ "args": [
53
+ "doctor",
54
+ "--json"
55
+ ]
56
+ },
57
+ "start": {
58
+ "runner": "package-bin",
59
+ "executable": "meego-opencode-worker",
60
+ "args": [
61
+ "start",
62
+ "--worker",
63
+ "{{workerId}}"
64
+ ]
65
+ },
66
+ "stop": {
67
+ "runner": "package-bin",
68
+ "executable": "meego-opencode-worker",
69
+ "args": [
70
+ "stop",
71
+ "--worker",
72
+ "{{workerId}}"
73
+ ]
74
+ },
75
+ "uninstall": {
76
+ "runner": "package-bin",
77
+ "executable": "meego-opencode-worker",
78
+ "args": [
79
+ "uninstall",
80
+ "--worker",
81
+ "{{workerId}}"
82
+ ]
83
+ }
84
+ }
85
+ },
86
+ "exports": {
87
+ ".": {
88
+ "types": "./dist/index.d.ts",
89
+ "default": "./dist/index.js"
90
+ }
91
+ },
92
+ "main": "./dist/index.js",
93
+ "types": "./dist/index.d.ts",
94
+ "bin": {
95
+ "meego-opencode-worker": "./bin/meego-opencode-worker.mjs"
96
+ },
97
+ "files": [
98
+ "README.md",
99
+ "bin",
100
+ "dist"
101
+ ],
102
+ "dependencies": {
103
+ "@clack/prompts": "^1.2.0",
104
+ "zod": "^4.3.6",
105
+ "@meego-harness/manager-contract": "^0.3.0",
106
+ "@meego-harness/prompt-registry": "^0.3.3",
107
+ "@meego-harness/worker-sdk": "^0.3.1"
108
+ },
109
+ "devDependencies": {
110
+ "@types/node": "^20.19.39",
111
+ "@vitest/coverage-v8": "^4.1.4",
112
+ "tsup": "^8.5.1",
113
+ "typescript": "^5.9.3",
114
+ "vite": "^7.1.12",
115
+ "vitest": "^4.1.4"
116
+ },
117
+ "publishConfig": {
118
+ "access": "public"
119
+ },
120
+ "scripts": {
121
+ "build": "tsup",
122
+ "dev": "tsup --watch",
123
+ "test": "vitest run",
124
+ "test:watch": "vitest",
125
+ "typecheck": "tsc --noEmit --incremental --tsBuildInfoFile tsconfig.tsbuildinfo"
126
+ }
127
+ }