@moxxy/plugin-provider-acp 0.0.0-stage → 0.45.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.
- package/LICENSE +21 -0
- package/dist/acp-session.d.ts +201 -0
- package/dist/acp-session.d.ts.map +1 -0
- package/dist/acp-session.js +812 -0
- package/dist/acp-session.js.map +1 -0
- package/dist/agent-provider.d.ts +71 -0
- package/dist/agent-provider.d.ts.map +1 -0
- package/dist/agent-provider.js +203 -0
- package/dist/agent-provider.js.map +1 -0
- package/dist/agents.d.ts +23 -0
- package/dist/agents.d.ts.map +1 -0
- package/dist/agents.js +21 -0
- package/dist/agents.js.map +1 -0
- package/dist/constants.d.ts +31 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +31 -0
- package/dist/constants.js.map +1 -0
- package/dist/executable.d.ts +47 -0
- package/dist/executable.d.ts.map +1 -0
- package/dist/executable.js +106 -0
- package/dist/executable.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +69 -0
- package/dist/index.js.map +1 -0
- package/dist/login.d.ts +48 -0
- package/dist/login.d.ts.map +1 -0
- package/dist/login.js +180 -0
- package/dist/login.js.map +1 -0
- package/dist/opencode-api.d.ts +32 -0
- package/dist/opencode-api.d.ts.map +1 -0
- package/dist/opencode-api.js +86 -0
- package/dist/opencode-api.js.map +1 -0
- package/dist/opencode-helpers.d.ts +49 -0
- package/dist/opencode-helpers.d.ts.map +1 -0
- package/dist/opencode-helpers.js +175 -0
- package/dist/opencode-helpers.js.map +1 -0
- package/dist/protocol.d.ts +143 -0
- package/dist/protocol.d.ts.map +1 -0
- package/dist/protocol.js +7 -0
- package/dist/protocol.js.map +1 -0
- package/dist/rules.d.ts +47 -0
- package/dist/rules.d.ts.map +1 -0
- package/dist/rules.js +84 -0
- package/dist/rules.js.map +1 -0
- package/dist/translate.d.ts +50 -0
- package/dist/translate.d.ts.map +1 -0
- package/dist/translate.js +290 -0
- package/dist/translate.js.map +1 -0
- package/package.json +81 -3
- package/src/acp-session.ts +892 -0
- package/src/agent-cli.test.ts +76 -0
- package/src/agent-provider.test.ts +1137 -0
- package/src/agent-provider.ts +234 -0
- package/src/agents.ts +37 -0
- package/src/constants.ts +36 -0
- package/src/event-coverage.test.ts +65 -0
- package/src/executable.test.ts +89 -0
- package/src/executable.ts +143 -0
- package/src/fake-opencode.testkit.ts +755 -0
- package/src/fixtures/acp-session-updates.json +19 -0
- package/src/index.test.ts +69 -0
- package/src/index.ts +83 -0
- package/src/login.test.ts +155 -0
- package/src/login.ts +222 -0
- package/src/opencode-api.ts +105 -0
- package/src/opencode-helpers.test.ts +76 -0
- package/src/opencode-helpers.ts +195 -0
- package/src/protocol.ts +104 -0
- package/src/rules.test.ts +107 -0
- package/src/rules.ts +102 -0
- package/src/translate.test.ts +253 -0
- package/src/translate.ts +318 -0
- package/README.md +0 -3
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { randomBytes } from 'node:crypto';
|
|
2
|
+
import { createServer } from 'node:net';
|
|
3
|
+
import { spawnExecutableTarget } from '@moxxy/sdk/server';
|
|
4
|
+
import { OPENCODE_CLI, agentCliTargetAt, compareVersions, findAgentCli, readCliVersion, stopAgentProcess, } from '@moxxy/agent-connection-kit';
|
|
5
|
+
import { OPENCODE_ACP_ARGS, OPENCODE_API_HOST, OPENCODE_API_USERNAME, OPENCODE_BACKGROUND_SUBAGENTS_ENV, OPENCODE_EXECUTABLE_ENV, OPENCODE_SERVER_PASSWORD_ENV, OPENCODE_SERVER_USERNAME_ENV, } from './constants.js';
|
|
6
|
+
/**
|
|
7
|
+
* How to start the person's OpenCode without a shell. A Windows npm install
|
|
8
|
+
* puts an `opencode.cmd` shim on PATH, which only a shell can run; the
|
|
9
|
+
* `opencode.exe` it points at is started directly instead. The other
|
|
10
|
+
* installers (scoop, choco, the install script) put `opencode.exe` on PATH.
|
|
11
|
+
*/
|
|
12
|
+
export function opencodeTarget(command, opts = {}) {
|
|
13
|
+
const found = (opts.find ?? ((name) => findAgentCli(OPENCODE_CLI, { command: name })))(command);
|
|
14
|
+
if (!found)
|
|
15
|
+
throw new Error(`OpenCode not found: ${command}. Install OpenCode or set ${OPENCODE_EXECUTABLE_ENV}.`);
|
|
16
|
+
return agentCliTargetAt(OPENCODE_CLI, found, opts);
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Whether `opencode acp` serves OpenCode's HTTP API beside ACP. OpenCode 1
|
|
20
|
+
* does, on `--port` / `--hostname`; OpenCode 2 runs a private server with no
|
|
21
|
+
* port and refuses those flags. An unreadable version is started as OpenCode
|
|
22
|
+
* 2 is, since `acp` alone starts on both.
|
|
23
|
+
*/
|
|
24
|
+
export function opencodeServesApiBesideAcp(version) {
|
|
25
|
+
return version !== null && compareVersions(version, '2.0.0-0') < 0;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* How `opencode acp` is started. Given a `server`, OpenCode serves its HTTP
|
|
29
|
+
* API on that port behind that password, so Moxxy can read the subagents
|
|
30
|
+
* OpenCode runs in the background, which ACP does not report, and nothing
|
|
31
|
+
* else on the computer can use the API. Background subagents are switched on
|
|
32
|
+
* unless the person switched them off.
|
|
33
|
+
*/
|
|
34
|
+
export function opencodeAcpLaunch(opts) {
|
|
35
|
+
const env = {
|
|
36
|
+
...opts.env,
|
|
37
|
+
[OPENCODE_BACKGROUND_SUBAGENTS_ENV]: opts.inherited[OPENCODE_BACKGROUND_SUBAGENTS_ENV] ?? 'true',
|
|
38
|
+
};
|
|
39
|
+
const { server } = opts;
|
|
40
|
+
if (!server)
|
|
41
|
+
return { args: [...OPENCODE_ACP_ARGS], env };
|
|
42
|
+
return {
|
|
43
|
+
args: [...OPENCODE_ACP_ARGS, '--port', String(server.port), '--hostname', OPENCODE_API_HOST],
|
|
44
|
+
env: {
|
|
45
|
+
...env,
|
|
46
|
+
[OPENCODE_SERVER_USERNAME_ENV]: OPENCODE_API_USERNAME,
|
|
47
|
+
[OPENCODE_SERVER_PASSWORD_ENV]: server.password,
|
|
48
|
+
},
|
|
49
|
+
api: {
|
|
50
|
+
url: `http://${OPENCODE_API_HOST}:${server.port}`,
|
|
51
|
+
authorization: `Basic ${Buffer.from(`${OPENCODE_API_USERNAME}:${server.password}`).toString('base64')}`,
|
|
52
|
+
},
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
/** A port free on the loopback right now, for OpenCode to serve its API on. */
|
|
56
|
+
function freePort() {
|
|
57
|
+
return new Promise((resolve, reject) => {
|
|
58
|
+
const server = createServer();
|
|
59
|
+
server.once('error', reject);
|
|
60
|
+
server.listen(0, OPENCODE_API_HOST, () => {
|
|
61
|
+
const address = server.address();
|
|
62
|
+
server.close(() => (typeof address === 'object' && address ? resolve(address.port) : reject(new Error('No free port for OpenCode.'))));
|
|
63
|
+
});
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
/** Starts `opencode acp` in the conversation folder, speaking ACP on stdio. */
|
|
67
|
+
export function spawnOpenCodeAcp(command) {
|
|
68
|
+
return async ({ cwd, env }) => {
|
|
69
|
+
const target = opencodeTarget(command);
|
|
70
|
+
const server = opencodeServesApiBesideAcp(await readCliVersion(target))
|
|
71
|
+
? { port: await freePort(), password: randomBytes(24).toString('base64url') }
|
|
72
|
+
: undefined;
|
|
73
|
+
const launch = opencodeAcpLaunch({ inherited: process.env, ...(server ? { server } : {}), ...(env ? { env } : {}) });
|
|
74
|
+
return new Promise((resolve, reject) => {
|
|
75
|
+
const child = spawnExecutableTarget(target, launch.args, {
|
|
76
|
+
cwd,
|
|
77
|
+
env: launch.env,
|
|
78
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
79
|
+
windowsHide: true,
|
|
80
|
+
});
|
|
81
|
+
const { stdin, stdout, stderr } = child;
|
|
82
|
+
if (!stdin || !stdout || !stderr) {
|
|
83
|
+
stopAgentProcess(child);
|
|
84
|
+
reject(new Error('OpenCode started without its stdio.'));
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
child.once('error', reject);
|
|
88
|
+
child.once('spawn', () => {
|
|
89
|
+
child.off('error', reject);
|
|
90
|
+
// A failed write after OpenCode exits is reported by the closed stdout.
|
|
91
|
+
stdin.on('error', () => undefined);
|
|
92
|
+
resolve({
|
|
93
|
+
readable: stdout,
|
|
94
|
+
writable: stdin,
|
|
95
|
+
stderr,
|
|
96
|
+
...(launch.api ? { api: launch.api } : {}),
|
|
97
|
+
close: () => {
|
|
98
|
+
stdin.end();
|
|
99
|
+
stopAgentProcess(child);
|
|
100
|
+
},
|
|
101
|
+
});
|
|
102
|
+
});
|
|
103
|
+
});
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
//# sourceMappingURL=executable.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"executable.js","sourceRoot":"","sources":["../src/executable.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export declare const opencodeProviderDef: import("@moxxy/sdk").ProviderDef;
|
|
2
|
+
export declare const acpAgentPlugin: import("@moxxy/sdk").Plugin;
|
|
3
|
+
export default acpAgentPlugin;
|
|
4
|
+
export { OPENCODE_PROVIDER_ID, OPENCODE_SERVICE_NAME, OPENCODE_EXECUTABLE_ENV, OPENCODE_DEFAULT_MODEL, OPENCODE_FREE_MODELS } from './constants.js';
|
|
5
|
+
export { OPENCODE_AGENT, type AcpAgentSpec } from './agents.js';
|
|
6
|
+
export { AcpAgentProvider, acpModel, acpSessions, createAcpAgentClient, type AcpAgentProviderConfig } from './agent-provider.js';
|
|
7
|
+
export type { AcpConnection, StartAcpAgent } from './acp-session.js';
|
|
8
|
+
export { opencodeTarget, spawnOpenCodeAcp } from './executable.js';
|
|
9
|
+
export { __setOpenCodeCommandRunner, checkOpenCode, listOpenCodeModels, opencodeLogin, opencodeLogout, opencodeStatus, resolveOpenCodeExecutable, type OpenCodeState, type OpenCodeStatus, } from './login.js';
|
|
10
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAQA,eAAO,MAAM,mBAAmB,kCA6B9B,CAAC;AAEH,eAAO,MAAM,cAAc,6BAQzB,CAAC;AAEH,eAAe,cAAc,CAAC;AAkB9B,OAAO,EAAE,oBAAoB,EAAE,qBAAqB,EAAE,uBAAuB,EAAE,sBAAsB,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AACpJ,OAAO,EAAE,cAAc,EAAE,KAAK,YAAY,EAAE,MAAM,aAAa,CAAC;AAChE,OAAO,EAAE,gBAAgB,EAAE,QAAQ,EAAE,WAAW,EAAE,oBAAoB,EAAE,KAAK,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AACjI,YAAY,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACrE,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACnE,OAAO,EACL,0BAA0B,EAC1B,aAAa,EACb,kBAAkB,EAClB,aAAa,EACb,cAAc,EACd,cAAc,EACd,yBAAyB,EACzB,KAAK,aAAa,EAClB,KAAK,cAAc,GACpB,MAAM,YAAY,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { defineProvider, definePlugin } from '@moxxy/sdk';
|
|
2
|
+
import { OPENCODE_CLI, checkAgentCli } from '@moxxy/agent-connection-kit';
|
|
3
|
+
import { OPENCODE_FREE_MODELS, OPENCODE_PROVIDER_ID, OPENCODE_SERVICE_NAME } from './constants.js';
|
|
4
|
+
import { OPENCODE_AGENT } from './agents.js';
|
|
5
|
+
import { acpModel, acpSessions, createAcpAgentClient } from './agent-provider.js';
|
|
6
|
+
import { authError, checkOpenCode, listOpenCodeModels, opencodeLogin, opencodeLogout, opencodeStatus, openCodeSignIn, readOpenCodeRules, resolveOpenCodeExecutable } from './login.js';
|
|
7
|
+
import { openCodeOwnAutoApprove } from './rules.js';
|
|
8
|
+
export const opencodeProviderDef = defineProvider({
|
|
9
|
+
name: OPENCODE_PROVIDER_ID,
|
|
10
|
+
agentName: OPENCODE_AGENT.label,
|
|
11
|
+
models: OPENCODE_FREE_MODELS.map(acpModel),
|
|
12
|
+
agentCli: {
|
|
13
|
+
check: (opts) => {
|
|
14
|
+
const command = resolveOpenCodeExecutable();
|
|
15
|
+
return checkAgentCli(OPENCODE_CLI, { command, refresh: opts?.refresh === true }, { signIn: () => openCodeSignIn(command) });
|
|
16
|
+
},
|
|
17
|
+
models: async () => (await listOpenCodeModels(resolveOpenCodeExecutable())).map(acpModel),
|
|
18
|
+
},
|
|
19
|
+
ownAutoApprove: ({ cwd }) => openCodeOwnAutoApprove(cwd, readOpenCodeRules(resolveOpenCodeExecutable())),
|
|
20
|
+
createClient: (config) => createAcpAgentClient(providerConfigFrom(config)),
|
|
21
|
+
async resolveCredentials({ providerConfig, host }) {
|
|
22
|
+
const config = { ...providerConfig, cwd: host.cwd };
|
|
23
|
+
const executable = resolveOpenCodeExecutable(config);
|
|
24
|
+
const status = await checkOpenCode(executable);
|
|
25
|
+
if (status.state !== 'signed-in')
|
|
26
|
+
throw authError(status);
|
|
27
|
+
// The picker offers exactly what the person's OpenCode can run.
|
|
28
|
+
return { ...config, executable, models: await listOpenCodeModels(executable) };
|
|
29
|
+
},
|
|
30
|
+
// No validateKey: readiness is reported by the installed OpenCode.
|
|
31
|
+
auth: {
|
|
32
|
+
kind: 'oauth',
|
|
33
|
+
serviceName: OPENCODE_SERVICE_NAME,
|
|
34
|
+
login: opencodeLogin,
|
|
35
|
+
logout: opencodeLogout,
|
|
36
|
+
status: opencodeStatus,
|
|
37
|
+
},
|
|
38
|
+
});
|
|
39
|
+
export const acpAgentPlugin = definePlugin({
|
|
40
|
+
name: '@moxxy/plugin-provider-acp',
|
|
41
|
+
version: '0.0.0',
|
|
42
|
+
providers: [opencodeProviderDef],
|
|
43
|
+
hooks: {
|
|
44
|
+
// The conversation's agent ends with it; its session stays saved by the agent, to load.
|
|
45
|
+
onShutdown: (ctx) => acpSessions().close(String(ctx.sessionId)),
|
|
46
|
+
},
|
|
47
|
+
});
|
|
48
|
+
export default acpAgentPlugin;
|
|
49
|
+
function providerConfigFrom(config) {
|
|
50
|
+
const text = (key) => (typeof config[key] === 'string' && config[key] !== '' ? config[key] : undefined);
|
|
51
|
+
const executable = text('executable');
|
|
52
|
+
const model = text('model');
|
|
53
|
+
const defaultModel = text('defaultModel');
|
|
54
|
+
const cwd = text('cwd');
|
|
55
|
+
const models = Array.isArray(config.models) ? config.models.filter((id) => typeof id === 'string' && id !== '') : [];
|
|
56
|
+
return {
|
|
57
|
+
...(executable ? { executable } : {}),
|
|
58
|
+
...(model ? { model } : {}),
|
|
59
|
+
...(defaultModel ? { defaultModel } : {}),
|
|
60
|
+
...(cwd ? { cwd } : {}),
|
|
61
|
+
...(models.length > 0 ? { models } : {}),
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
export { OPENCODE_PROVIDER_ID, OPENCODE_SERVICE_NAME, OPENCODE_EXECUTABLE_ENV, OPENCODE_DEFAULT_MODEL, OPENCODE_FREE_MODELS } from './constants.js';
|
|
65
|
+
export { OPENCODE_AGENT } from './agents.js';
|
|
66
|
+
export { AcpAgentProvider, acpModel, acpSessions, createAcpAgentClient } from './agent-provider.js';
|
|
67
|
+
export { opencodeTarget, spawnOpenCodeAcp } from './executable.js';
|
|
68
|
+
export { __setOpenCodeCommandRunner, checkOpenCode, listOpenCodeModels, opencodeLogin, opencodeLogout, opencodeStatus, resolveOpenCodeExecutable, } from './login.js';
|
|
69
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/login.d.ts
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import type { AgentSignIn } from '@moxxy/agent-connection-kit';
|
|
2
|
+
import { MoxxyError } from '@moxxy/sdk';
|
|
3
|
+
import type { ProviderAuthContext, ProviderOAuthResult, ProviderOAuthStatus } from '@moxxy/sdk';
|
|
4
|
+
import type { ReadAgentMcpServers, ReadAgentRules } from './rules.js';
|
|
5
|
+
export type OpenCodeState = 'signed-in' | 'missing' | 'error';
|
|
6
|
+
export interface OpenCodeStatus {
|
|
7
|
+
readonly state: OpenCodeState;
|
|
8
|
+
readonly executable: string;
|
|
9
|
+
/** The model providers OpenCode is signed in to (`OpenAI, Anthropic`). */
|
|
10
|
+
readonly accountId?: string;
|
|
11
|
+
readonly message: string;
|
|
12
|
+
}
|
|
13
|
+
export interface OpenCodeCommandResult {
|
|
14
|
+
readonly code: number;
|
|
15
|
+
readonly stdout: string;
|
|
16
|
+
readonly stderr: string;
|
|
17
|
+
readonly error?: NodeJS.ErrnoException;
|
|
18
|
+
}
|
|
19
|
+
interface CommandOptions {
|
|
20
|
+
/** Hand OpenCode the terminal (its interactive provider picker). */
|
|
21
|
+
readonly inherit?: boolean;
|
|
22
|
+
/** Where OpenCode runs, so the project's own config applies. */
|
|
23
|
+
readonly cwd?: string;
|
|
24
|
+
}
|
|
25
|
+
type CommandRunner = (executable: string, args: readonly string[], options?: CommandOptions) => Promise<OpenCodeCommandResult>;
|
|
26
|
+
/** Test seam. */
|
|
27
|
+
export declare function __setOpenCodeCommandRunner(runner: CommandRunner): void;
|
|
28
|
+
export declare function resolveOpenCodeExecutable(config?: Readonly<Record<string, unknown>>): string;
|
|
29
|
+
/**
|
|
30
|
+
* Whether the person's OpenCode can work, read from `opencode auth list`.
|
|
31
|
+
* Installed is enough: OpenCode's free models need no sign-in, and the
|
|
32
|
+
* providers it is signed in to are named. Moxxy never touches its tokens.
|
|
33
|
+
*/
|
|
34
|
+
export declare function checkOpenCode(executable?: string): Promise<OpenCodeStatus>;
|
|
35
|
+
/** Who OpenCode is signed in to, for the connection's row; its free models need no sign-in. */
|
|
36
|
+
export declare function openCodeSignIn(executable?: string): Promise<AgentSignIn>;
|
|
37
|
+
/** The models the person's OpenCode offers (`opencode models`); none when it cannot say. */
|
|
38
|
+
export declare function listOpenCodeModels(executable?: string): Promise<string[]>;
|
|
39
|
+
/** The rules of one of the person's OpenCode agents (`opencode debug agent <name>`), read where the conversation runs. */
|
|
40
|
+
export declare function readOpenCodeRules(executable?: string): ReadAgentRules;
|
|
41
|
+
/** The person's own MCP servers that are on, from the config OpenCode resolves in `cwd` (`opencode debug config`). */
|
|
42
|
+
export declare function readOpenCodeMcpServers(executable?: string): ReadAgentMcpServers;
|
|
43
|
+
export declare function opencodeLogin(ctx: ProviderAuthContext): Promise<ProviderOAuthResult>;
|
|
44
|
+
export declare function opencodeLogout(ctx: ProviderAuthContext): Promise<boolean>;
|
|
45
|
+
export declare function opencodeStatus(ctx: ProviderAuthContext): Promise<ProviderOAuthStatus | null>;
|
|
46
|
+
export declare function authError(status: OpenCodeStatus): MoxxyError;
|
|
47
|
+
export {};
|
|
48
|
+
//# sourceMappingURL=login.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"login.d.ts","sourceRoot":"","sources":["../src/login.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,6BAA6B,CAAC;AAC/D,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAExC,OAAO,KAAK,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAYhG,OAAO,KAAK,EAAgB,mBAAmB,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEpF,MAAM,MAAM,aAAa,GAAG,WAAW,GAAG,SAAS,GAAG,OAAO,CAAC;AAE9D,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAC;IAC9B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,0EAA0E;IAC1E,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC,cAAc,CAAC;CACxC;AAED,UAAU,cAAc;IACtB,oEAAoE;IACpE,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC;IAC3B,gEAAgE;IAChE,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,KAAK,aAAa,GAAG,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,MAAM,EAAE,EAAE,OAAO,CAAC,EAAE,cAAc,KAAK,OAAO,CAAC,qBAAqB,CAAC,CAAC;AAQ/H,iBAAiB;AACjB,wBAAgB,0BAA0B,CAAC,MAAM,EAAE,aAAa,GAAG,IAAI,CAEtE;AAED,wBAAgB,yBAAyB,CAAC,MAAM,GAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAM,GAAG,MAAM,CAIhG;AAED;;;;GAIG;AACH,wBAAsB,aAAa,CAAC,UAAU,SAA8B,GAAG,OAAO,CAAC,cAAc,CAAC,CAqBrG;AAED,+FAA+F;AAC/F,wBAAsB,cAAc,CAAC,UAAU,SAA8B,GAAG,OAAO,CAAC,WAAW,CAAC,CAGnG;AAED,4FAA4F;AAC5F,wBAAsB,kBAAkB,CAAC,UAAU,SAA8B,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAQpG;AAED,0HAA0H;AAC1H,wBAAgB,iBAAiB,CAAC,UAAU,SAA8B,GAAG,cAAc,CAW1F;AAED,sHAAsH;AACtH,wBAAgB,sBAAsB,CAAC,UAAU,SAA8B,GAAG,mBAAmB,CAWpG;AAUD,wBAAsB,aAAa,CAAC,GAAG,EAAE,mBAAmB,GAAG,OAAO,CAAC,mBAAmB,CAAC,CA0B1F;AAED,wBAAsB,cAAc,CAAC,GAAG,EAAE,mBAAmB,GAAG,OAAO,CAAC,OAAO,CAAC,CAiB/E;AAED,wBAAsB,cAAc,CAAC,GAAG,EAAE,mBAAmB,GAAG,OAAO,CAAC,mBAAmB,GAAG,IAAI,CAAC,CAGlG;AAED,wBAAgB,SAAS,CAAC,MAAM,EAAE,cAAc,GAAG,UAAU,CAM5D"}
|
package/dist/login.js
ADDED
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
import { MoxxyError } from '@moxxy/sdk';
|
|
2
|
+
import { spawnExecutableTarget } from '@moxxy/sdk/server';
|
|
3
|
+
import { OPENCODE_DEBUG_AGENT_ARGS, OPENCODE_DEBUG_CONFIG_ARGS, OPENCODE_AUTH_LIST_ARGS, OPENCODE_AUTH_LOGIN_ARGS, OPENCODE_AUTH_LOGOUT_ARGS, OPENCODE_EXECUTABLE_ENV, OPENCODE_MODELS_ARGS, OPENCODE_PROVIDER_ID, } from './constants.js';
|
|
4
|
+
import { opencodeTarget } from './executable.js';
|
|
5
|
+
const ANSI = /\u001b\[[0-9;]*m/g;
|
|
6
|
+
const CREDENTIAL = /^●\s+(.+?)\s+\S+$/;
|
|
7
|
+
const MODEL_ID = /^[\w.@-]+\/\S+$/;
|
|
8
|
+
const LOGIN_HINT = 'Run `opencode auth login` in a terminal to sign OpenCode in to a model provider.';
|
|
9
|
+
let runCommandImpl = runCommand;
|
|
10
|
+
/** Test seam. */
|
|
11
|
+
export function __setOpenCodeCommandRunner(runner) {
|
|
12
|
+
runCommandImpl = runner;
|
|
13
|
+
}
|
|
14
|
+
export function resolveOpenCodeExecutable(config = {}) {
|
|
15
|
+
const configured = config.executable;
|
|
16
|
+
if (typeof configured === 'string' && configured.trim())
|
|
17
|
+
return configured;
|
|
18
|
+
return process.env[OPENCODE_EXECUTABLE_ENV]?.trim() || 'opencode';
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Whether the person's OpenCode can work, read from `opencode auth list`.
|
|
22
|
+
* Installed is enough: OpenCode's free models need no sign-in, and the
|
|
23
|
+
* providers it is signed in to are named. Moxxy never touches its tokens.
|
|
24
|
+
*/
|
|
25
|
+
export async function checkOpenCode(executable = resolveOpenCodeExecutable()) {
|
|
26
|
+
const result = await runCommandImpl(executable, OPENCODE_AUTH_LIST_ARGS);
|
|
27
|
+
if (result.error?.code === 'ENOENT') {
|
|
28
|
+
return { state: 'missing', executable, message: `OpenCode not found: ${executable}. Install OpenCode or set ${OPENCODE_EXECUTABLE_ENV}.` };
|
|
29
|
+
}
|
|
30
|
+
if (result.error || result.code !== 0) {
|
|
31
|
+
const detail = result.error?.message ?? (result.stderr.trim() || `exit code ${result.code}`);
|
|
32
|
+
return { state: 'error', executable, message: `Could not run OpenCode: ${detail}` };
|
|
33
|
+
}
|
|
34
|
+
const providers = result.stdout
|
|
35
|
+
.replace(ANSI, '')
|
|
36
|
+
.split('\n')
|
|
37
|
+
.flatMap((line) => {
|
|
38
|
+
const match = CREDENTIAL.exec(line.trim());
|
|
39
|
+
return match?.[1] ? [match[1]] : [];
|
|
40
|
+
});
|
|
41
|
+
if (providers.length === 0) {
|
|
42
|
+
return { state: 'signed-in', executable, message: `OpenCode is ready with its free models. ${LOGIN_HINT}` };
|
|
43
|
+
}
|
|
44
|
+
const accountId = providers.join(', ');
|
|
45
|
+
return { state: 'signed-in', executable, accountId, message: `OpenCode is ready, signed in to ${accountId}.` };
|
|
46
|
+
}
|
|
47
|
+
/** Who OpenCode is signed in to, for the connection's row; its free models need no sign-in. */
|
|
48
|
+
export async function openCodeSignIn(executable = resolveOpenCodeExecutable()) {
|
|
49
|
+
const status = await checkOpenCode(executable);
|
|
50
|
+
return { signedIn: status.state === 'signed-in', ...(status.accountId ? { account: status.accountId } : {}) };
|
|
51
|
+
}
|
|
52
|
+
/** The models the person's OpenCode offers (`opencode models`); none when it cannot say. */
|
|
53
|
+
export async function listOpenCodeModels(executable = resolveOpenCodeExecutable()) {
|
|
54
|
+
const result = await runCommandImpl(executable, OPENCODE_MODELS_ARGS);
|
|
55
|
+
if (result.error || result.code !== 0)
|
|
56
|
+
return [];
|
|
57
|
+
return result.stdout
|
|
58
|
+
.replace(ANSI, '')
|
|
59
|
+
.split('\n')
|
|
60
|
+
.map((line) => line.trim())
|
|
61
|
+
.filter((line) => MODEL_ID.test(line));
|
|
62
|
+
}
|
|
63
|
+
/** The rules of one of the person's OpenCode agents (`opencode debug agent <name>`), read where the conversation runs. */
|
|
64
|
+
export function readOpenCodeRules(executable = resolveOpenCodeExecutable()) {
|
|
65
|
+
return async ({ cwd, agent }) => {
|
|
66
|
+
const result = await runCommandImpl(executable, [...OPENCODE_DEBUG_AGENT_ARGS, agent], { cwd });
|
|
67
|
+
if (result.error || result.code !== 0)
|
|
68
|
+
return undefined;
|
|
69
|
+
try {
|
|
70
|
+
const { permission } = JSON.parse(result.stdout);
|
|
71
|
+
return Array.isArray(permission) ? permission.filter(isRule) : undefined;
|
|
72
|
+
}
|
|
73
|
+
catch {
|
|
74
|
+
return undefined;
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
/** The person's own MCP servers that are on, from the config OpenCode resolves in `cwd` (`opencode debug config`). */
|
|
79
|
+
export function readOpenCodeMcpServers(executable = resolveOpenCodeExecutable()) {
|
|
80
|
+
return async ({ cwd }) => {
|
|
81
|
+
const result = await runCommandImpl(executable, [...OPENCODE_DEBUG_CONFIG_ARGS], { cwd });
|
|
82
|
+
if (result.error || result.code !== 0)
|
|
83
|
+
return undefined;
|
|
84
|
+
try {
|
|
85
|
+
const { mcp } = JSON.parse(result.stdout);
|
|
86
|
+
return Object.entries(mcp ?? {}).flatMap(([name, server]) => (server?.enabled === false ? [] : [name]));
|
|
87
|
+
}
|
|
88
|
+
catch {
|
|
89
|
+
return undefined;
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
function isRule(value) {
|
|
94
|
+
const rule = value;
|
|
95
|
+
return (typeof rule === 'object' && rule !== null && typeof rule.permission === 'string' && typeof rule.pattern === 'string'
|
|
96
|
+
&& (rule.action === 'allow' || rule.action === 'ask' || rule.action === 'deny'));
|
|
97
|
+
}
|
|
98
|
+
export async function opencodeLogin(ctx) {
|
|
99
|
+
const executable = resolveOpenCodeExecutable(ctx.providerConfig);
|
|
100
|
+
const before = await checkOpenCode(executable);
|
|
101
|
+
if (before.state !== 'signed-in')
|
|
102
|
+
throw authError(before);
|
|
103
|
+
// OpenCode asks which provider and how in its own terminal picker; a window cannot answer it.
|
|
104
|
+
if (ctx.noOpen) {
|
|
105
|
+
throw new MoxxyError({
|
|
106
|
+
code: 'AUTH_NO_CREDENTIALS',
|
|
107
|
+
message: 'OpenCode signs in to model providers in a terminal.',
|
|
108
|
+
hint: LOGIN_HINT,
|
|
109
|
+
context: { provider: OPENCODE_PROVIDER_ID },
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
const login = await runCommandImpl(executable, OPENCODE_AUTH_LOGIN_ARGS, { inherit: true });
|
|
113
|
+
if (login.error)
|
|
114
|
+
throw authError({ state: login.error.code === 'ENOENT' ? 'missing' : 'error', executable, message: login.error.message });
|
|
115
|
+
if (login.code !== 0) {
|
|
116
|
+
throw new MoxxyError({
|
|
117
|
+
code: 'AUTH_DENIED',
|
|
118
|
+
message: `OpenCode login failed with exit code ${login.code}.`,
|
|
119
|
+
hint: 'Run `opencode auth login` directly for more detail, then retry.',
|
|
120
|
+
context: { provider: OPENCODE_PROVIDER_ID },
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
const after = await checkOpenCode(executable);
|
|
124
|
+
if (after.state !== 'signed-in')
|
|
125
|
+
throw authError(after);
|
|
126
|
+
return { accountId: after.accountId ?? null };
|
|
127
|
+
}
|
|
128
|
+
export async function opencodeLogout(ctx) {
|
|
129
|
+
const executable = resolveOpenCodeExecutable(ctx.providerConfig);
|
|
130
|
+
const before = await checkOpenCode(executable);
|
|
131
|
+
if (before.state !== 'signed-in' || before.accountId === undefined)
|
|
132
|
+
return false;
|
|
133
|
+
if (ctx.noOpen) {
|
|
134
|
+
throw new MoxxyError({
|
|
135
|
+
code: 'AUTH_INVALID',
|
|
136
|
+
message: 'OpenCode signs out of model providers in a terminal.',
|
|
137
|
+
hint: 'Run `opencode auth logout` in a terminal.',
|
|
138
|
+
context: { provider: OPENCODE_PROVIDER_ID },
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
const result = await runCommandImpl(executable, OPENCODE_AUTH_LOGOUT_ARGS, { inherit: true });
|
|
142
|
+
if (result.error || result.code !== 0) {
|
|
143
|
+
throw new MoxxyError({ code: 'AUTH_INVALID', message: `OpenCode logout failed${result.stderr ? `: ${result.stderr}` : '.'}` });
|
|
144
|
+
}
|
|
145
|
+
return true;
|
|
146
|
+
}
|
|
147
|
+
export async function opencodeStatus(ctx) {
|
|
148
|
+
const status = await checkOpenCode(resolveOpenCodeExecutable(ctx.providerConfig));
|
|
149
|
+
return { accountId: status.accountId ?? null, authState: status.state, message: status.message };
|
|
150
|
+
}
|
|
151
|
+
export function authError(status) {
|
|
152
|
+
return new MoxxyError({
|
|
153
|
+
code: 'AUTH_INVALID',
|
|
154
|
+
message: status.message,
|
|
155
|
+
context: { provider: OPENCODE_PROVIDER_ID, executable: status.executable, state: status.state },
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
async function runCommand(executable, args, options = {}) {
|
|
159
|
+
let target;
|
|
160
|
+
try {
|
|
161
|
+
target = opencodeTarget(executable);
|
|
162
|
+
}
|
|
163
|
+
catch (err) {
|
|
164
|
+
const error = Object.assign(err instanceof Error ? err : new Error(String(err)), { code: 'ENOENT' });
|
|
165
|
+
return { code: 1, stdout: '', stderr: '', error };
|
|
166
|
+
}
|
|
167
|
+
return await new Promise((resolve) => {
|
|
168
|
+
const where = options.cwd ? { cwd: options.cwd } : {};
|
|
169
|
+
const child = spawnExecutableTarget(target, [...args], options.inherit ? { ...where, stdio: 'inherit' } : { ...where, stdio: ['ignore', 'pipe', 'pipe'], windowsHide: true });
|
|
170
|
+
let stdout = '';
|
|
171
|
+
let stderr = '';
|
|
172
|
+
child.stdout?.setEncoding('utf8');
|
|
173
|
+
child.stderr?.setEncoding('utf8');
|
|
174
|
+
child.stdout?.on('data', (chunk) => (stdout += chunk));
|
|
175
|
+
child.stderr?.on('data', (chunk) => (stderr += chunk));
|
|
176
|
+
child.once('error', (error) => resolve({ code: 1, stdout, stderr, error }));
|
|
177
|
+
child.once('close', (code) => resolve({ code: code ?? 1, stdout, stderr }));
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
//# sourceMappingURL=login.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"login.js","sourceRoot":"","sources":["../src/login.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OpenCode's own HTTP API, which `opencode acp` serves beside ACP. ACP does
|
|
3
|
+
* not report what a subagent does nor when a subagent working in the
|
|
4
|
+
* background ends, and has no way to stop one; this API has both: its event
|
|
5
|
+
* stream (`GET /event`) and `POST /session/{id}/abort`.
|
|
6
|
+
*/
|
|
7
|
+
/** Where the API of one running `opencode acp` is, and the credentials Moxxy started it with. */
|
|
8
|
+
export interface OpenCodeApi {
|
|
9
|
+
readonly url: string;
|
|
10
|
+
/** The `Authorization` header value. */
|
|
11
|
+
readonly authorization: string;
|
|
12
|
+
}
|
|
13
|
+
/** One event of OpenCode's stream (`session.status`, `message.part.updated`, …). */
|
|
14
|
+
export interface OpenCodeEvent {
|
|
15
|
+
readonly type: string;
|
|
16
|
+
readonly properties: Record<string, unknown>;
|
|
17
|
+
}
|
|
18
|
+
export interface OpenCodeEventWatch {
|
|
19
|
+
close(): void;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Read OpenCode's event stream for the project `directory` until closed,
|
|
23
|
+
* connecting again whenever it ends (OpenCode serves the API a moment after it
|
|
24
|
+
* starts). `onConnected` is told each time the stream is up.
|
|
25
|
+
*/
|
|
26
|
+
export declare function watchOpenCodeEvents(api: OpenCodeApi, directory: string, onEvent: (event: OpenCodeEvent) => void, opts?: {
|
|
27
|
+
readonly onConnected?: () => void;
|
|
28
|
+
readonly onDisconnected?: () => void;
|
|
29
|
+
}): OpenCodeEventWatch;
|
|
30
|
+
/** Stop what an OpenCode session runs (a subagent's session too). False when OpenCode could not be asked or refused. */
|
|
31
|
+
export declare function abortOpenCodeSession(api: OpenCodeApi, directory: string, sessionId: string): Promise<boolean>;
|
|
32
|
+
//# sourceMappingURL=opencode-api.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"opencode-api.d.ts","sourceRoot":"","sources":["../src/opencode-api.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,iGAAiG;AACjG,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,wCAAwC;IACxC,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;CAChC;AAED,oFAAoF;AACpF,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC9C;AAED,MAAM,WAAW,kBAAkB;IACjC,KAAK,IAAI,IAAI,CAAC;CACf;AAKD;;;;GAIG;AACH,wBAAgB,mBAAmB,CACjC,GAAG,EAAE,WAAW,EAChB,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,EACvC,IAAI,GAAE;IAAE,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,IAAI,CAAC;IAAC,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,IAAI,CAAA;CAAO,GACrF,kBAAkB,CAsBpB;AAED,wHAAwH;AACxH,wBAAsB,oBAAoB,CAAC,GAAG,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAUnH"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OpenCode's own HTTP API, which `opencode acp` serves beside ACP. ACP does
|
|
3
|
+
* not report what a subagent does nor when a subagent working in the
|
|
4
|
+
* background ends, and has no way to stop one; this API has both: its event
|
|
5
|
+
* stream (`GET /event`) and `POST /session/{id}/abort`.
|
|
6
|
+
*/
|
|
7
|
+
/** How long to wait before connecting again after the stream failed or ended. */
|
|
8
|
+
const RECONNECT_MS = 250;
|
|
9
|
+
/**
|
|
10
|
+
* Read OpenCode's event stream for the project `directory` until closed,
|
|
11
|
+
* connecting again whenever it ends (OpenCode serves the API a moment after it
|
|
12
|
+
* starts). `onConnected` is told each time the stream is up.
|
|
13
|
+
*/
|
|
14
|
+
export function watchOpenCodeEvents(api, directory, onEvent, opts = {}) {
|
|
15
|
+
const stop = new AbortController();
|
|
16
|
+
void (async () => {
|
|
17
|
+
while (!stop.signal.aborted) {
|
|
18
|
+
try {
|
|
19
|
+
const response = await fetch(`${api.url}/event?directory=${encodeURIComponent(directory)}`, {
|
|
20
|
+
headers: { Authorization: api.authorization, Accept: 'text/event-stream' },
|
|
21
|
+
signal: stop.signal,
|
|
22
|
+
});
|
|
23
|
+
if (response.ok && response.body) {
|
|
24
|
+
opts.onConnected?.();
|
|
25
|
+
await readEvents(response.body, onEvent);
|
|
26
|
+
opts.onDisconnected?.();
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
// Not up yet, or gone: try again below while the watch is open.
|
|
31
|
+
}
|
|
32
|
+
if (stop.signal.aborted)
|
|
33
|
+
return;
|
|
34
|
+
await new Promise((resolve) => setTimeout(resolve, RECONNECT_MS));
|
|
35
|
+
}
|
|
36
|
+
})();
|
|
37
|
+
return { close: () => stop.abort() };
|
|
38
|
+
}
|
|
39
|
+
/** Stop what an OpenCode session runs (a subagent's session too). False when OpenCode could not be asked or refused. */
|
|
40
|
+
export async function abortOpenCodeSession(api, directory, sessionId) {
|
|
41
|
+
try {
|
|
42
|
+
const response = await fetch(`${api.url}/session/${encodeURIComponent(sessionId)}/abort?directory=${encodeURIComponent(directory)}`, {
|
|
43
|
+
method: 'POST',
|
|
44
|
+
headers: { Authorization: api.authorization },
|
|
45
|
+
});
|
|
46
|
+
return response.ok && (await response.json().catch(() => false)) === true;
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
/** Server-sent events: each event's `data:` lines are one JSON object. */
|
|
53
|
+
async function readEvents(body, onEvent) {
|
|
54
|
+
const decoder = new TextDecoder();
|
|
55
|
+
let buffer = '';
|
|
56
|
+
for await (const chunk of body) {
|
|
57
|
+
buffer += decoder.decode(chunk, { stream: true }).replace(/\r\n/g, '\n');
|
|
58
|
+
for (let end = buffer.indexOf('\n\n'); end >= 0; end = buffer.indexOf('\n\n')) {
|
|
59
|
+
const block = buffer.slice(0, end);
|
|
60
|
+
buffer = buffer.slice(end + 2);
|
|
61
|
+
const data = block
|
|
62
|
+
.split('\n')
|
|
63
|
+
.filter((line) => line.startsWith('data:'))
|
|
64
|
+
.map((line) => line.slice(5).trimStart())
|
|
65
|
+
.join('\n');
|
|
66
|
+
const event = parseEvent(data);
|
|
67
|
+
if (event)
|
|
68
|
+
onEvent(event);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
function parseEvent(data) {
|
|
73
|
+
if (!data)
|
|
74
|
+
return undefined;
|
|
75
|
+
try {
|
|
76
|
+
const value = JSON.parse(data);
|
|
77
|
+
if (typeof value.type !== 'string')
|
|
78
|
+
return undefined;
|
|
79
|
+
const properties = typeof value.properties === 'object' && value.properties !== null ? value.properties : {};
|
|
80
|
+
return { type: value.type, properties };
|
|
81
|
+
}
|
|
82
|
+
catch {
|
|
83
|
+
return undefined;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
//# sourceMappingURL=opencode-api.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"opencode-api.js","sourceRoot":"","sources":["../src/opencode-api.ts"],"names":[],"mappings":"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"}
|