@moxxy/plugin-provider-acp 0.48.2 → 0.48.4
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/dist/constants.d.ts +6 -0
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +6 -0
- package/dist/constants.js.map +1 -1
- package/dist/executable.d.ts +4 -1
- package/dist/executable.d.ts.map +1 -1
- package/dist/executable.js +6 -1
- package/dist/executable.js.map +1 -1
- package/dist/login.d.ts.map +1 -1
- package/dist/login.js +51 -11
- package/dist/login.js.map +1 -1
- package/package.json +8 -8
- package/src/constants.ts +6 -0
- package/src/executable.test.ts +28 -1
- package/src/executable.ts +9 -1
- package/src/login-env.test.ts +173 -0
- package/src/login.test.ts +11 -0
- package/src/login.ts +58 -11
package/dist/constants.d.ts
CHANGED
|
@@ -28,4 +28,10 @@ export declare const OPENCODE_DEBUG_CONFIG_ARGS: readonly ["debug", "config"];
|
|
|
28
28
|
export declare const OPENCODE_AUTH_LIST_ARGS: readonly ["auth", "list"];
|
|
29
29
|
export declare const OPENCODE_AUTH_LOGIN_ARGS: readonly ["auth", "login"];
|
|
30
30
|
export declare const OPENCODE_AUTH_LOGOUT_ARGS: readonly ["auth", "logout"];
|
|
31
|
+
/** Prints the URL of OpenCode 2's shared background server when it runs, `stopped` when not; it starts nothing. */
|
|
32
|
+
/** What OpenCode 2 prints when its plugins did not start within the 5 seconds it gives them. */
|
|
33
|
+
export declare const OPENCODE_PLUGINS_TIMEOUT = "did not finish activating";
|
|
34
|
+
export declare const OPENCODE_SERVICE_STATUS_ARGS: readonly ["service", "status"];
|
|
35
|
+
/** Makes an OpenCode 2 command run on a private server that ends with it, not on the shared one. */
|
|
36
|
+
export declare const OPENCODE_STANDALONE_FLAG = "--standalone";
|
|
31
37
|
//# sourceMappingURL=constants.d.ts.map
|
package/dist/constants.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA,sEAAsE;AACtE,eAAO,MAAM,oBAAoB,aAAa,CAAC;AAE/C,0EAA0E;AAC1E,eAAO,MAAM,qBAAqB,aAAa,CAAC;AAEhD,gGAAgG;AAChG,eAAO,MAAM,uBAAuB,wBAAwB,CAAC;AAE7D,mFAAmF;AACnF,eAAO,MAAM,sBAAsB,wBAAwB,CAAC;AAE5D;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,EAAE,aAAa,CAAC,MAAM,CAA4B,CAAC;AAEpF,uGAAuG;AACvG,eAAO,MAAM,gBAAgB,UAAU,CAAC;AAExC,eAAO,MAAM,iBAAiB,kBAAmB,CAAC;AAClD,8HAA8H;AAC9H,eAAO,MAAM,iBAAiB,cAAc,CAAC;AAC7C,eAAO,MAAM,qBAAqB,aAAa,CAAC;AAChD,eAAO,MAAM,4BAA4B,6BAA6B,CAAC;AACvE,eAAO,MAAM,4BAA4B,6BAA6B,CAAC;AACvE,yGAAyG;AACzG,eAAO,MAAM,iCAAiC,+CAA+C,CAAC;AAC9F,eAAO,MAAM,oBAAoB,qBAAsB,CAAC;AACxD,eAAO,MAAM,yBAAyB,6BAA8B,CAAC;AACrE,eAAO,MAAM,0BAA0B,8BAA+B,CAAC;AACvE,eAAO,MAAM,uBAAuB,2BAA4B,CAAC;AACjE,eAAO,MAAM,wBAAwB,4BAA6B,CAAC;AACnE,eAAO,MAAM,yBAAyB,6BAA8B,CAAC"}
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA,sEAAsE;AACtE,eAAO,MAAM,oBAAoB,aAAa,CAAC;AAE/C,0EAA0E;AAC1E,eAAO,MAAM,qBAAqB,aAAa,CAAC;AAEhD,gGAAgG;AAChG,eAAO,MAAM,uBAAuB,wBAAwB,CAAC;AAE7D,mFAAmF;AACnF,eAAO,MAAM,sBAAsB,wBAAwB,CAAC;AAE5D;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,EAAE,aAAa,CAAC,MAAM,CAA4B,CAAC;AAEpF,uGAAuG;AACvG,eAAO,MAAM,gBAAgB,UAAU,CAAC;AAExC,eAAO,MAAM,iBAAiB,kBAAmB,CAAC;AAClD,8HAA8H;AAC9H,eAAO,MAAM,iBAAiB,cAAc,CAAC;AAC7C,eAAO,MAAM,qBAAqB,aAAa,CAAC;AAChD,eAAO,MAAM,4BAA4B,6BAA6B,CAAC;AACvE,eAAO,MAAM,4BAA4B,6BAA6B,CAAC;AACvE,yGAAyG;AACzG,eAAO,MAAM,iCAAiC,+CAA+C,CAAC;AAC9F,eAAO,MAAM,oBAAoB,qBAAsB,CAAC;AACxD,eAAO,MAAM,yBAAyB,6BAA8B,CAAC;AACrE,eAAO,MAAM,0BAA0B,8BAA+B,CAAC;AACvE,eAAO,MAAM,uBAAuB,2BAA4B,CAAC;AACjE,eAAO,MAAM,wBAAwB,4BAA6B,CAAC;AACnE,eAAO,MAAM,yBAAyB,6BAA8B,CAAC;AACrE,mHAAmH;AACnH,gGAAgG;AAChG,eAAO,MAAM,wBAAwB,8BAA8B,CAAC;AACpE,eAAO,MAAM,4BAA4B,gCAAiC,CAAC;AAC3E,oGAAoG;AACpG,eAAO,MAAM,wBAAwB,iBAAiB,CAAC"}
|
package/dist/constants.js
CHANGED
|
@@ -28,4 +28,10 @@ export const OPENCODE_DEBUG_CONFIG_ARGS = ['debug', 'config'];
|
|
|
28
28
|
export const OPENCODE_AUTH_LIST_ARGS = ['auth', 'list'];
|
|
29
29
|
export const OPENCODE_AUTH_LOGIN_ARGS = ['auth', 'login'];
|
|
30
30
|
export const OPENCODE_AUTH_LOGOUT_ARGS = ['auth', 'logout'];
|
|
31
|
+
/** Prints the URL of OpenCode 2's shared background server when it runs, `stopped` when not; it starts nothing. */
|
|
32
|
+
/** What OpenCode 2 prints when its plugins did not start within the 5 seconds it gives them. */
|
|
33
|
+
export const OPENCODE_PLUGINS_TIMEOUT = 'did not finish activating';
|
|
34
|
+
export const OPENCODE_SERVICE_STATUS_ARGS = ['service', 'status'];
|
|
35
|
+
/** Makes an OpenCode 2 command run on a private server that ends with it, not on the shared one. */
|
|
36
|
+
export const OPENCODE_STANDALONE_FLAG = '--standalone';
|
|
31
37
|
//# sourceMappingURL=constants.js.map
|
package/dist/constants.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA,sEAAsE;AACtE,MAAM,CAAC,MAAM,oBAAoB,GAAG,UAAU,CAAC;AAE/C,0EAA0E;AAC1E,MAAM,CAAC,MAAM,qBAAqB,GAAG,UAAU,CAAC;AAEhD,gGAAgG;AAChG,MAAM,CAAC,MAAM,uBAAuB,GAAG,qBAAqB,CAAC;AAE7D,mFAAmF;AACnF,MAAM,CAAC,MAAM,sBAAsB,GAAG,qBAAqB,CAAC;AAE5D;;;;GAIG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAA0B,CAAC,sBAAsB,CAAC,CAAC;AAEpF,uGAAuG;AACvG,MAAM,CAAC,MAAM,gBAAgB,GAAG,OAAO,CAAC;AAExC,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,KAAK,CAAU,CAAC;AAClD,8HAA8H;AAC9H,MAAM,CAAC,MAAM,iBAAiB,GAAG,WAAW,CAAC;AAC7C,MAAM,CAAC,MAAM,qBAAqB,GAAG,UAAU,CAAC;AAChD,MAAM,CAAC,MAAM,4BAA4B,GAAG,0BAA0B,CAAC;AACvE,MAAM,CAAC,MAAM,4BAA4B,GAAG,0BAA0B,CAAC;AACvE,yGAAyG;AACzG,MAAM,CAAC,MAAM,iCAAiC,GAAG,4CAA4C,CAAC;AAC9F,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,QAAQ,CAAU,CAAC;AACxD,MAAM,CAAC,MAAM,yBAAyB,GAAG,CAAC,OAAO,EAAE,OAAO,CAAU,CAAC;AACrE,MAAM,CAAC,MAAM,0BAA0B,GAAG,CAAC,OAAO,EAAE,QAAQ,CAAU,CAAC;AACvE,MAAM,CAAC,MAAM,uBAAuB,GAAG,CAAC,MAAM,EAAE,MAAM,CAAU,CAAC;AACjE,MAAM,CAAC,MAAM,wBAAwB,GAAG,CAAC,MAAM,EAAE,OAAO,CAAU,CAAC;AACnE,MAAM,CAAC,MAAM,yBAAyB,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAU,CAAC"}
|
|
1
|
+
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA,sEAAsE;AACtE,MAAM,CAAC,MAAM,oBAAoB,GAAG,UAAU,CAAC;AAE/C,0EAA0E;AAC1E,MAAM,CAAC,MAAM,qBAAqB,GAAG,UAAU,CAAC;AAEhD,gGAAgG;AAChG,MAAM,CAAC,MAAM,uBAAuB,GAAG,qBAAqB,CAAC;AAE7D,mFAAmF;AACnF,MAAM,CAAC,MAAM,sBAAsB,GAAG,qBAAqB,CAAC;AAE5D;;;;GAIG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAA0B,CAAC,sBAAsB,CAAC,CAAC;AAEpF,uGAAuG;AACvG,MAAM,CAAC,MAAM,gBAAgB,GAAG,OAAO,CAAC;AAExC,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,KAAK,CAAU,CAAC;AAClD,8HAA8H;AAC9H,MAAM,CAAC,MAAM,iBAAiB,GAAG,WAAW,CAAC;AAC7C,MAAM,CAAC,MAAM,qBAAqB,GAAG,UAAU,CAAC;AAChD,MAAM,CAAC,MAAM,4BAA4B,GAAG,0BAA0B,CAAC;AACvE,MAAM,CAAC,MAAM,4BAA4B,GAAG,0BAA0B,CAAC;AACvE,yGAAyG;AACzG,MAAM,CAAC,MAAM,iCAAiC,GAAG,4CAA4C,CAAC;AAC9F,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,QAAQ,CAAU,CAAC;AACxD,MAAM,CAAC,MAAM,yBAAyB,GAAG,CAAC,OAAO,EAAE,OAAO,CAAU,CAAC;AACrE,MAAM,CAAC,MAAM,0BAA0B,GAAG,CAAC,OAAO,EAAE,QAAQ,CAAU,CAAC;AACvE,MAAM,CAAC,MAAM,uBAAuB,GAAG,CAAC,MAAM,EAAE,MAAM,CAAU,CAAC;AACjE,MAAM,CAAC,MAAM,wBAAwB,GAAG,CAAC,MAAM,EAAE,OAAO,CAAU,CAAC;AACnE,MAAM,CAAC,MAAM,yBAAyB,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAU,CAAC;AACrE,mHAAmH;AACnH,gGAAgG;AAChG,MAAM,CAAC,MAAM,wBAAwB,GAAG,2BAA2B,CAAC;AACpE,MAAM,CAAC,MAAM,4BAA4B,GAAG,CAAC,SAAS,EAAE,QAAQ,CAAU,CAAC;AAC3E,oGAAoG;AACpG,MAAM,CAAC,MAAM,wBAAwB,GAAG,cAAc,CAAC"}
|
package/dist/executable.d.ts
CHANGED
|
@@ -14,7 +14,8 @@ export interface OpenCodeTargetOptions extends AgentCliTargetOptions {
|
|
|
14
14
|
export declare function opencodeTarget(command: string, opts?: OpenCodeTargetOptions): ExecutableTarget;
|
|
15
15
|
export interface OpenCodeAcpLaunch {
|
|
16
16
|
readonly args: ReadonlyArray<string>;
|
|
17
|
-
|
|
17
|
+
/** Added to the inherited environment; a variable set to `undefined` is left out. */
|
|
18
|
+
readonly env: Readonly<Record<string, string | undefined>>;
|
|
18
19
|
/** OpenCode's HTTP API, when this OpenCode serves it beside ACP. */
|
|
19
20
|
readonly api?: OpenCodeApi;
|
|
20
21
|
}
|
|
@@ -25,6 +26,8 @@ export interface OpenCodeAcpLaunch {
|
|
|
25
26
|
* 2 is, since `acp` alone starts on both.
|
|
26
27
|
*/
|
|
27
28
|
export declare function opencodeServesApiBesideAcp(version: string | null): boolean;
|
|
29
|
+
/** Whether this OpenCode has a shared background server (OpenCode 2). An unreadable version is taken as not. */
|
|
30
|
+
export declare function opencodeHasSharedServer(version: string | null): boolean;
|
|
28
31
|
/**
|
|
29
32
|
* How `opencode acp` is started. Given a `server`, OpenCode serves its HTTP
|
|
30
33
|
* API on that port behind that password, so Moxxy can read the subagents
|
package/dist/executable.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"executable.d.ts","sourceRoot":"","sources":["../src/executable.ts"],"names":[],"mappings":"AAEA,OAAO,EAAyB,KAAK,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AACjF,OAAO,
|
|
1
|
+
{"version":3,"file":"executable.d.ts","sourceRoot":"","sources":["../src/executable.ts"],"names":[],"mappings":"AAEA,OAAO,EAAyB,KAAK,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AACjF,OAAO,EAQL,KAAK,qBAAqB,EAC3B,MAAM,6BAA6B,CAAC;AAUrC,OAAO,KAAK,EAAiB,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACrE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAErD,MAAM,WAAW,qBAAsB,SAAQ,qBAAqB;IAClE,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,CAAC;CACpD;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,GAAE,qBAA0B,GAAG,gBAAgB,CAIlG;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;IACrC,qFAAqF;IACrF,QAAQ,CAAC,GAAG,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC,CAAC;IAC3D,oEAAoE;IACpE,QAAQ,CAAC,GAAG,CAAC,EAAE,WAAW,CAAC;CAC5B;AAED;;;;;GAKG;AACH,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAE1E;AAED,gHAAgH;AAChH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAEvE;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE;IACtC,QAAQ,CAAC,MAAM,CAAC,EAAE;QAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC;IACvE,yDAAyD;IACzD,QAAQ,CAAC,SAAS,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC,CAAC;IACjE,qEAAqE;IACrE,QAAQ,CAAC,GAAG,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;CACjD,GAAG,iBAAiB,CAoBpB;AAcD,+EAA+E;AAC/E,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,aAAa,CAsC/D"}
|
package/dist/executable.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { randomBytes } from 'node:crypto';
|
|
2
2
|
import { createServer } from 'node:net';
|
|
3
3
|
import { spawnExecutableTarget } from '@moxxy/sdk/server';
|
|
4
|
-
import { OPENCODE_CLI, agentCliTargetAt, compareVersions, findAgentCli, readCliVersion, stopAgentProcess, } from '@moxxy/agent-connection-kit';
|
|
4
|
+
import { OPENCODE_CLI, agentCliTargetAt, compareVersions, findAgentCli, moxxyOwnVariables, readCliVersion, stopAgentProcess, } from '@moxxy/agent-connection-kit';
|
|
5
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
6
|
/**
|
|
7
7
|
* How to start the person's OpenCode without a shell. A Windows npm install
|
|
@@ -24,6 +24,10 @@ export function opencodeTarget(command, opts = {}) {
|
|
|
24
24
|
export function opencodeServesApiBesideAcp(version) {
|
|
25
25
|
return version !== null && compareVersions(version, '2.0.0-0') < 0;
|
|
26
26
|
}
|
|
27
|
+
/** Whether this OpenCode has a shared background server (OpenCode 2). An unreadable version is taken as not. */
|
|
28
|
+
export function opencodeHasSharedServer(version) {
|
|
29
|
+
return version !== null && compareVersions(version, '2.0.0-0') >= 0;
|
|
30
|
+
}
|
|
27
31
|
/**
|
|
28
32
|
* How `opencode acp` is started. Given a `server`, OpenCode serves its HTTP
|
|
29
33
|
* API on that port behind that password, so Moxxy can read the subagents
|
|
@@ -33,6 +37,7 @@ export function opencodeServesApiBesideAcp(version) {
|
|
|
33
37
|
*/
|
|
34
38
|
export function opencodeAcpLaunch(opts) {
|
|
35
39
|
const env = {
|
|
40
|
+
...moxxyOwnVariables(opts.inherited),
|
|
36
41
|
...opts.env,
|
|
37
42
|
[OPENCODE_BACKGROUND_SUBAGENTS_ENV]: opts.inherited[OPENCODE_BACKGROUND_SUBAGENTS_ENV] ?? 'true',
|
|
38
43
|
};
|
package/dist/executable.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"executable.js","sourceRoot":"","sources":["../src/executable.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AACxC,OAAO,EAAE,qBAAqB,EAAyB,MAAM,mBAAmB,CAAC;AACjF,OAAO,EACL,YAAY,EACZ,gBAAgB,EAChB,eAAe,EACf,YAAY,EACZ,cAAc,EACd,gBAAgB,GAEjB,MAAM,6BAA6B,CAAC;AACrC,OAAO,EACL,iBAAiB,EACjB,iBAAiB,EACjB,qBAAqB,EACrB,iCAAiC,EACjC,uBAAuB,EACvB,4BAA4B,EAC5B,4BAA4B,GAC7B,MAAM,gBAAgB,CAAC;AAQxB;;;;;GAKG;AACH,MAAM,UAAU,cAAc,CAAC,OAAe,EAAE,OAA8B,EAAE;IAC9E,MAAM,KAAK,GAAG,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,YAAY,CAAC,YAAY,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;IAChG,IAAI,CAAC,KAAK;QAAE,MAAM,IAAI,KAAK,CAAC,uBAAuB,OAAO,6BAA6B,uBAAuB,GAAG,CAAC,CAAC;IACnH,OAAO,gBAAgB,CAAC,YAAY,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC;AACrD,CAAC;
|
|
1
|
+
{"version":3,"file":"executable.js","sourceRoot":"","sources":["../src/executable.ts"],"names":[],"mappings":"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"}
|
package/dist/login.d.ts.map
CHANGED
|
@@ -1 +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;
|
|
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;AAGxC,OAAO,KAAK,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAehG,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;AAW/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,CAyBrG;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
CHANGED
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
import { MoxxyError } from '@moxxy/sdk';
|
|
2
|
+
import { moxxyOwnVariables, readCliVersion } from '@moxxy/agent-connection-kit';
|
|
2
3
|
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';
|
|
4
|
+
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_PLUGINS_TIMEOUT, OPENCODE_PROVIDER_ID, OPENCODE_SERVICE_STATUS_ARGS, OPENCODE_STANDALONE_FLAG, } from './constants.js';
|
|
5
|
+
import { opencodeHasSharedServer, opencodeTarget } from './executable.js';
|
|
5
6
|
const ANSI = /\u001b\[[0-9;]*m/g;
|
|
7
|
+
/** OpenCode 1: `● OpenAI oauth`. */
|
|
6
8
|
const CREDENTIAL = /^●\s+(.+?)\s+\S+$/;
|
|
9
|
+
/** OpenCode 2: `OpenRouter OpenRouter stored`; `environment` rows are the person's variables, not a sign-in. */
|
|
10
|
+
const STORED_CREDENTIAL = /^(.+?)\s{2,}.*\s{2,}stored$/;
|
|
7
11
|
const MODEL_ID = /^[\w.@-]+\/\S+$/;
|
|
8
12
|
const LOGIN_HINT = 'Run `opencode auth login` in a terminal to sign OpenCode in to a model provider.';
|
|
9
13
|
let runCommandImpl = runCommand;
|
|
@@ -31,13 +35,15 @@ export async function checkOpenCode(executable = resolveOpenCodeExecutable()) {
|
|
|
31
35
|
const detail = result.error?.message ?? (result.stderr.trim() || `exit code ${result.code}`);
|
|
32
36
|
return { state: 'error', executable, message: `Could not run OpenCode: ${detail}` };
|
|
33
37
|
}
|
|
34
|
-
const providers =
|
|
35
|
-
.
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
38
|
+
const providers = [
|
|
39
|
+
...new Set(result.stdout
|
|
40
|
+
.replace(ANSI, '')
|
|
41
|
+
.split('\n')
|
|
42
|
+
.flatMap((line) => {
|
|
43
|
+
const match = CREDENTIAL.exec(line.trim()) ?? STORED_CREDENTIAL.exec(line.trim());
|
|
44
|
+
return match?.[1] ? [match[1]] : [];
|
|
45
|
+
})),
|
|
46
|
+
];
|
|
41
47
|
if (providers.length === 0) {
|
|
42
48
|
return { state: 'signed-in', executable, message: `OpenCode is ready with its free models. ${LOGIN_HINT}` };
|
|
43
49
|
}
|
|
@@ -164,8 +170,42 @@ async function runCommand(executable, args, options = {}) {
|
|
|
164
170
|
const error = Object.assign(err instanceof Error ? err : new Error(String(err)), { code: 'ENOENT' });
|
|
165
171
|
return { code: 1, stdout: '', stderr: '', error };
|
|
166
172
|
}
|
|
167
|
-
|
|
168
|
-
|
|
173
|
+
const asked = await withoutStartingSharedServer(target, args);
|
|
174
|
+
let result = await spawnCommand(target, asked, options);
|
|
175
|
+
// A busy computer: the plugins took longer than OpenCode allows. Ask on the
|
|
176
|
+
// shared server (started without Moxxy's variables, it carries nothing of
|
|
177
|
+
// Moxxy's after it quits). It goes on starting them after an answer times
|
|
178
|
+
// out, so asking it again gets the answer once they are up.
|
|
179
|
+
for (let asks = 0; asks < SHARED_SERVER_ASKS && pluginsTimedOut(result); asks++) {
|
|
180
|
+
result = await spawnCommand(target, args, options);
|
|
181
|
+
}
|
|
182
|
+
return result;
|
|
183
|
+
}
|
|
184
|
+
/** How many times a command is asked of the shared server while its plugins are still starting: each ask waits up to their 5 seconds. */
|
|
185
|
+
const SHARED_SERVER_ASKS = 3;
|
|
186
|
+
/** OpenCode gives its plugins 5 seconds to start; a private server starts them anew each time, and the shared one for each folder it has not served. */
|
|
187
|
+
function pluginsTimedOut(result) {
|
|
188
|
+
return result.code !== 0 && `${result.stderr}${result.stdout}`.includes(OPENCODE_PLUGINS_TIMEOUT);
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* `args`, run so that Moxxy never starts OpenCode 2's shared background
|
|
192
|
+
* server: that server stays after Moxxy quits. When it already runs, the
|
|
193
|
+
* command uses it, as it answers at once and is the person's own; when not,
|
|
194
|
+
* the command runs on a private server that ends with it (`--standalone`,
|
|
195
|
+
* about a second longer). OpenCode 1 has no shared server, and an OpenCode
|
|
196
|
+
* that cannot say whether it runs is asked as it was before.
|
|
197
|
+
*/
|
|
198
|
+
async function withoutStartingSharedServer(target, args) {
|
|
199
|
+
if (!opencodeHasSharedServer(await readCliVersion(target)))
|
|
200
|
+
return args;
|
|
201
|
+
const status = await spawnCommand(target, OPENCODE_SERVICE_STATUS_ARGS);
|
|
202
|
+
if (status.error || status.code !== 0)
|
|
203
|
+
return args;
|
|
204
|
+
return status.stdout.trim() === 'stopped' ? [...args, OPENCODE_STANDALONE_FLAG] : args;
|
|
205
|
+
}
|
|
206
|
+
function spawnCommand(target, args, options = {}) {
|
|
207
|
+
return new Promise((resolve) => {
|
|
208
|
+
const where = { ...(options.cwd ? { cwd: options.cwd } : {}), env: moxxyOwnVariables(process.env) };
|
|
169
209
|
const child = spawnExecutableTarget(target, [...args], options.inherit ? { ...where, stdio: 'inherit' } : { ...where, stdio: ['ignore', 'pipe', 'pipe'], windowsHide: true });
|
|
170
210
|
let stdout = '';
|
|
171
211
|
let stderr = '';
|
package/dist/login.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"login.js","sourceRoot":"","sources":["../src/login.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AACxC,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"login.js","sourceRoot":"","sources":["../src/login.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@moxxy/plugin-provider-acp",
|
|
3
|
-
"version": "0.48.
|
|
3
|
+
"version": "0.48.4",
|
|
4
4
|
"description": "Agent connections over the Agent Client Protocol for moxxy: OpenCode itself does the work through `opencode acp`, on the person's own OpenCode setup, while Moxxy shows it, answers its permission asks, steers plan and goal mode, and lends its own tools over MCP.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"moxxy",
|
|
@@ -58,8 +58,8 @@
|
|
|
58
58
|
}
|
|
59
59
|
},
|
|
60
60
|
"dependencies": {
|
|
61
|
-
"@moxxy/agent-connection-kit": "0.1.
|
|
62
|
-
"@moxxy/sdk": "0.48.
|
|
61
|
+
"@moxxy/agent-connection-kit": "0.1.8",
|
|
62
|
+
"@moxxy/sdk": "0.48.4"
|
|
63
63
|
},
|
|
64
64
|
"devDependencies": {
|
|
65
65
|
"@modelcontextprotocol/sdk": "^1.32.2",
|
|
@@ -67,11 +67,11 @@
|
|
|
67
67
|
"typescript": "^6.0.3",
|
|
68
68
|
"vitest": "^5.0.5",
|
|
69
69
|
"zod": "^4.6.7",
|
|
70
|
-
"@moxxy/
|
|
71
|
-
"@moxxy/mode-
|
|
72
|
-
"@moxxy/
|
|
73
|
-
"@moxxy/
|
|
74
|
-
"@moxxy/
|
|
70
|
+
"@moxxy/mode-default": "0.48.4",
|
|
71
|
+
"@moxxy/mode-goal": "0.48.4",
|
|
72
|
+
"@moxxy/core": "0.48.4",
|
|
73
|
+
"@moxxy/mode-plan": "0.48.4",
|
|
74
|
+
"@moxxy/testing": "0.0.83",
|
|
75
75
|
"@moxxy/tsconfig": "0.0.0",
|
|
76
76
|
"@moxxy/vitest-preset": "0.0.0"
|
|
77
77
|
},
|
package/src/constants.ts
CHANGED
|
@@ -34,3 +34,9 @@ export const OPENCODE_DEBUG_CONFIG_ARGS = ['debug', 'config'] as const;
|
|
|
34
34
|
export const OPENCODE_AUTH_LIST_ARGS = ['auth', 'list'] as const;
|
|
35
35
|
export const OPENCODE_AUTH_LOGIN_ARGS = ['auth', 'login'] as const;
|
|
36
36
|
export const OPENCODE_AUTH_LOGOUT_ARGS = ['auth', 'logout'] as const;
|
|
37
|
+
/** Prints the URL of OpenCode 2's shared background server when it runs, `stopped` when not; it starts nothing. */
|
|
38
|
+
/** What OpenCode 2 prints when its plugins did not start within the 5 seconds it gives them. */
|
|
39
|
+
export const OPENCODE_PLUGINS_TIMEOUT = 'did not finish activating';
|
|
40
|
+
export const OPENCODE_SERVICE_STATUS_ARGS = ['service', 'status'] as const;
|
|
41
|
+
/** Makes an OpenCode 2 command run on a private server that ends with it, not on the shared one. */
|
|
42
|
+
export const OPENCODE_STANDALONE_FLAG = '--standalone';
|
package/src/executable.test.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { spawn } from 'node:child_process';
|
|
1
2
|
import { describe, expect, it } from 'vitest';
|
|
2
3
|
import { opencodeAcpLaunch, opencodeServesApiBesideAcp, opencodeTarget } from './executable.js';
|
|
3
4
|
|
|
@@ -68,7 +69,33 @@ describe('the OpenCode Moxxy starts for a conversation', () => {
|
|
|
68
69
|
expect(launch.env).toMatchObject({ OPENCODE_CONFIG_CONTENT: '{}', OPENCODE_SERVER_PASSWORD: 'p' });
|
|
69
70
|
});
|
|
70
71
|
|
|
71
|
-
it('
|
|
72
|
+
it("leaves Moxxy's own variables out, since OpenCode's shared background server keeps them after Moxxy quits", async () => {
|
|
73
|
+
const added = {
|
|
74
|
+
MOXXY_HOME: '/tmp/moxxy-home',
|
|
75
|
+
MOXXY_BROWSER_BRIDGE_TOKEN: 'bridge-secret',
|
|
76
|
+
MOXXY_RUNNER_SOCKET: '/tmp/serve.sock',
|
|
77
|
+
ELECTRON_RUN_AS_NODE: '1',
|
|
78
|
+
};
|
|
79
|
+
// As in Moxxy: OpenCode inherits this process's whole environment.
|
|
80
|
+
const inherited = { ...process.env, ...added };
|
|
81
|
+
const launch = opencodeAcpLaunch({ inherited });
|
|
82
|
+
|
|
83
|
+
expect(launch.env).toMatchObject({ MOXXY_BROWSER_BRIDGE_TOKEN: undefined, MOXXY_RUNNER_SOCKET: undefined, ELECTRON_RUN_AS_NODE: undefined });
|
|
84
|
+
// What a started process really gets: the variables are gone, PATH and MOXXY_HOME stay.
|
|
85
|
+
const seen = await new Promise<Record<string, string>>((resolve, reject) => {
|
|
86
|
+
const child = spawn(process.execPath, ['-e', 'process.stdout.write(JSON.stringify(process.env))'], { env: { ...inherited, ...launch.env } });
|
|
87
|
+
let out = '';
|
|
88
|
+
child.stdout.on('data', (chunk: Buffer) => (out += chunk.toString('utf8')));
|
|
89
|
+
child.once('error', reject);
|
|
90
|
+
child.once('close', () => resolve(JSON.parse(out) as Record<string, string>));
|
|
91
|
+
});
|
|
92
|
+
expect(seen.PATH).toBe(process.env.PATH);
|
|
93
|
+
expect(seen.MOXXY_HOME).toBe('/tmp/moxxy-home');
|
|
94
|
+
expect(Object.keys(seen).filter((key) => key.startsWith('MOXXY_') && key !== 'MOXXY_HOME')).toEqual([]);
|
|
95
|
+
expect(seen.ELECTRON_RUN_AS_NODE).toBeUndefined();
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
it('starts OpenCode 2 with `acp` alone: it takes no port, so Moxxy has no API to read', () => {
|
|
72
99
|
const launch = opencodeAcpLaunch({ inherited: {} });
|
|
73
100
|
|
|
74
101
|
expect(launch.args).toEqual(['acp']);
|
package/src/executable.ts
CHANGED
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
agentCliTargetAt,
|
|
7
7
|
compareVersions,
|
|
8
8
|
findAgentCli,
|
|
9
|
+
moxxyOwnVariables,
|
|
9
10
|
readCliVersion,
|
|
10
11
|
stopAgentProcess,
|
|
11
12
|
type AgentCliTargetOptions,
|
|
@@ -40,7 +41,8 @@ export function opencodeTarget(command: string, opts: OpenCodeTargetOptions = {}
|
|
|
40
41
|
|
|
41
42
|
export interface OpenCodeAcpLaunch {
|
|
42
43
|
readonly args: ReadonlyArray<string>;
|
|
43
|
-
|
|
44
|
+
/** Added to the inherited environment; a variable set to `undefined` is left out. */
|
|
45
|
+
readonly env: Readonly<Record<string, string | undefined>>;
|
|
44
46
|
/** OpenCode's HTTP API, when this OpenCode serves it beside ACP. */
|
|
45
47
|
readonly api?: OpenCodeApi;
|
|
46
48
|
}
|
|
@@ -55,6 +57,11 @@ export function opencodeServesApiBesideAcp(version: string | null): boolean {
|
|
|
55
57
|
return version !== null && compareVersions(version, '2.0.0-0') < 0;
|
|
56
58
|
}
|
|
57
59
|
|
|
60
|
+
/** Whether this OpenCode has a shared background server (OpenCode 2). An unreadable version is taken as not. */
|
|
61
|
+
export function opencodeHasSharedServer(version: string | null): boolean {
|
|
62
|
+
return version !== null && compareVersions(version, '2.0.0-0') >= 0;
|
|
63
|
+
}
|
|
64
|
+
|
|
58
65
|
/**
|
|
59
66
|
* How `opencode acp` is started. Given a `server`, OpenCode serves its HTTP
|
|
60
67
|
* API on that port behind that password, so Moxxy can read the subagents
|
|
@@ -70,6 +77,7 @@ export function opencodeAcpLaunch(opts: {
|
|
|
70
77
|
readonly env?: Readonly<Record<string, string>>;
|
|
71
78
|
}): OpenCodeAcpLaunch {
|
|
72
79
|
const env = {
|
|
80
|
+
...moxxyOwnVariables(opts.inherited),
|
|
73
81
|
...opts.env,
|
|
74
82
|
[OPENCODE_BACKGROUND_SUBAGENTS_ENV]: opts.inherited[OPENCODE_BACKGROUND_SUBAGENTS_ENV] ?? 'true',
|
|
75
83
|
};
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The OpenCode commands Moxxy runs to check OpenCode (`auth list`, `models`,
|
|
3
|
+
* `debug config`, `debug agent`). On OpenCode 2 each one starts the shared
|
|
4
|
+
* background server when none runs, and that server keeps their environment
|
|
5
|
+
* and stays after Moxxy quits. A stand-in `opencode` (the external boundary)
|
|
6
|
+
* records what it was given.
|
|
7
|
+
*/
|
|
8
|
+
import { chmodSync, mkdtempSync, readFileSync, writeFileSync } from 'node:fs';
|
|
9
|
+
import { tmpdir } from 'node:os';
|
|
10
|
+
import path from 'node:path';
|
|
11
|
+
import { afterEach, describe, expect, it } from 'vitest';
|
|
12
|
+
import { removeDirSync } from '@moxxy/vitest-preset/fs';
|
|
13
|
+
import { checkOpenCode, listOpenCodeModels, readOpenCodeMcpServers, readOpenCodeRules } from './login.js';
|
|
14
|
+
|
|
15
|
+
const roots: string[] = [];
|
|
16
|
+
const saved = { token: process.env.MOXXY_BROWSER_BRIDGE_TOKEN, electron: process.env.ELECTRON_RUN_AS_NODE, home: process.env.MOXXY_HOME };
|
|
17
|
+
afterEach(() => {
|
|
18
|
+
for (const root of roots.splice(0)) removeDirSync(root);
|
|
19
|
+
const restore = (key: string, value: string | undefined) => (value === undefined ? delete process.env[key] : (process.env[key] = value));
|
|
20
|
+
restore('MOXXY_BROWSER_BRIDGE_TOKEN', saved.token);
|
|
21
|
+
restore('ELECTRON_RUN_AS_NODE', saved.electron);
|
|
22
|
+
restore('MOXXY_HOME', saved.home);
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
interface FakeOpenCode {
|
|
26
|
+
readonly file: string;
|
|
27
|
+
/** The arguments of every run, in order. */
|
|
28
|
+
runs(): string[][];
|
|
29
|
+
/** The environment of the last run. */
|
|
30
|
+
env(): Record<string, string>;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* An `opencode` of `version` whose `service status` prints `service` (a URL
|
|
35
|
+
* when its shared server runs), or fails when null. With `standaloneTimesOut`
|
|
36
|
+
* its private server fails as OpenCode's does when its plugins take longer
|
|
37
|
+
* than the 5 seconds it allows them (a busy computer). Its shared server's
|
|
38
|
+
* first `sharedTimeouts` answers time out the same way, as a shared server
|
|
39
|
+
* still starting those plugins does.
|
|
40
|
+
*/
|
|
41
|
+
function fakeOpenCode(version: string, service: string | null, standaloneTimesOut = false, sharedTimeouts = 0): FakeOpenCode {
|
|
42
|
+
const root = mkdtempSync(path.join(tmpdir(), 'moxxy-opencode-cli-'));
|
|
43
|
+
roots.push(root);
|
|
44
|
+
const log = path.join(root, 'runs.ndjson');
|
|
45
|
+
const env = path.join(root, 'env.json');
|
|
46
|
+
const shared = path.join(root, 'shared-runs');
|
|
47
|
+
const file = path.join(root, 'opencode');
|
|
48
|
+
const script = `
|
|
49
|
+
const fs = require('node:fs');
|
|
50
|
+
const args = process.argv.slice(2);
|
|
51
|
+
fs.appendFileSync(${JSON.stringify(log)}, JSON.stringify(args) + '\\n');
|
|
52
|
+
fs.writeFileSync(${JSON.stringify(env)}, JSON.stringify(process.env));
|
|
53
|
+
const said = args.filter((arg) => arg !== '--standalone').join(' ');
|
|
54
|
+
const timedOut = () => { console.error('Location plugins did not finish activating'); process.exit(1); };
|
|
55
|
+
if (${JSON.stringify(standaloneTimesOut)} && args.includes('--standalone')) timedOut();
|
|
56
|
+
if (!args.includes('--standalone') && said !== '--version' && said !== 'service status') {
|
|
57
|
+
fs.appendFileSync(${JSON.stringify(shared)}, 'x');
|
|
58
|
+
if (fs.readFileSync(${JSON.stringify(shared)}, 'utf8').length <= ${sharedTimeouts}) timedOut();
|
|
59
|
+
}
|
|
60
|
+
if (said === '--version') console.log(${JSON.stringify(version)});
|
|
61
|
+
else if (said === 'service status') { const out = ${JSON.stringify(service)}; if (out === null) process.exit(1); console.log(out); }
|
|
62
|
+
else if (said === 'models') console.log('opencode/big-pickle');
|
|
63
|
+
else if (said === 'debug config') console.log('{"mcp":{}}');
|
|
64
|
+
else if (said.startsWith('debug agent')) console.log('{"permission":[]}');
|
|
65
|
+
else console.log('0 credentials');
|
|
66
|
+
`;
|
|
67
|
+
writeFileSync(file, `#!${process.execPath}\n${script}`);
|
|
68
|
+
chmodSync(file, 0o755);
|
|
69
|
+
return {
|
|
70
|
+
file,
|
|
71
|
+
runs: () => readFileSync(log, 'utf8').trim().split('\n').map((line) => JSON.parse(line) as string[]),
|
|
72
|
+
env: () => JSON.parse(readFileSync(env, 'utf8')) as Record<string, string>,
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/** The runs that did the asked-for work, without the version and server checks around them. */
|
|
77
|
+
const work = (fake: FakeOpenCode) => fake.runs().filter((args) => args[0] !== '--version' && args[0] !== 'service');
|
|
78
|
+
|
|
79
|
+
describe.skipIf(process.platform === 'win32')('the OpenCode commands Moxxy runs to check it', () => {
|
|
80
|
+
it("leave Moxxy's own variables out, since the server they may start keeps them", async () => {
|
|
81
|
+
const fake = fakeOpenCode('2.2.5', 'http://127.0.0.1:4096');
|
|
82
|
+
process.env.MOXXY_BROWSER_BRIDGE_TOKEN = 'bridge-secret';
|
|
83
|
+
process.env.ELECTRON_RUN_AS_NODE = '1';
|
|
84
|
+
process.env.MOXXY_HOME = '/tmp/moxxy-home';
|
|
85
|
+
|
|
86
|
+
await checkOpenCode(fake.file);
|
|
87
|
+
|
|
88
|
+
const env = fake.env();
|
|
89
|
+
expect(Object.keys(env).filter((key) => key.startsWith('MOXXY_') && key !== 'MOXXY_HOME')).toEqual([]);
|
|
90
|
+
expect(env.ELECTRON_RUN_AS_NODE).toBeUndefined();
|
|
91
|
+
expect(env.MOXXY_HOME).toBe('/tmp/moxxy-home');
|
|
92
|
+
expect(env.PATH).toBe(process.env.PATH);
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
it("run on OpenCode 2's own private server when its shared one is not running, so nothing of Moxxy's stays after it quits", async () => {
|
|
96
|
+
const fake = fakeOpenCode('2.2.5', 'stopped');
|
|
97
|
+
|
|
98
|
+
await checkOpenCode(fake.file);
|
|
99
|
+
await listOpenCodeModels(fake.file);
|
|
100
|
+
await readOpenCodeMcpServers(fake.file)({ cwd: tmpdir() });
|
|
101
|
+
await readOpenCodeRules(fake.file)({ cwd: tmpdir(), agent: 'build' });
|
|
102
|
+
|
|
103
|
+
expect(work(fake)).toEqual([
|
|
104
|
+
['auth', 'list', '--standalone'],
|
|
105
|
+
['models', '--standalone'],
|
|
106
|
+
['debug', 'config', '--standalone'],
|
|
107
|
+
['debug', 'agent', 'build', '--standalone'],
|
|
108
|
+
]);
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
it('use the shared server when it already runs, since it answers at once and was not started by Moxxy', async () => {
|
|
112
|
+
const fake = fakeOpenCode('2.2.5', 'http://127.0.0.1:4096');
|
|
113
|
+
|
|
114
|
+
await checkOpenCode(fake.file);
|
|
115
|
+
await listOpenCodeModels(fake.file);
|
|
116
|
+
|
|
117
|
+
expect(work(fake)).toEqual([['auth', 'list'], ['models']]);
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
it('ask again through the shared server when the private one did not start in time, so a busy computer still gets an answer', async () => {
|
|
121
|
+
const fake = fakeOpenCode('2.2.5', 'stopped', true);
|
|
122
|
+
|
|
123
|
+
const status = await checkOpenCode(fake.file);
|
|
124
|
+
const models = await listOpenCodeModels(fake.file);
|
|
125
|
+
|
|
126
|
+
expect(status.state).toBe('signed-in');
|
|
127
|
+
expect(models).toEqual(['opencode/big-pickle']);
|
|
128
|
+
expect(work(fake)).toEqual([['auth', 'list', '--standalone'], ['auth', 'list'], ['models', '--standalone'], ['models']]);
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
it('ask the shared server again while it is still starting its plugins, since it goes on starting them after an answer times out', async () => {
|
|
132
|
+
const fake = fakeOpenCode('2.2.6', 'stopped', true, 1);
|
|
133
|
+
|
|
134
|
+
const status = await checkOpenCode(fake.file);
|
|
135
|
+
|
|
136
|
+
expect(status.state).toBe('signed-in');
|
|
137
|
+
expect(work(fake)).toEqual([['auth', 'list', '--standalone'], ['auth', 'list'], ['auth', 'list']]);
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
it('give up after three answers from the shared server, so plugins that never start do not keep Moxxy waiting', async () => {
|
|
141
|
+
const fake = fakeOpenCode('2.2.6', 'stopped', true, 99);
|
|
142
|
+
|
|
143
|
+
const status = await checkOpenCode(fake.file);
|
|
144
|
+
|
|
145
|
+
expect(status).toMatchObject({ state: 'error', message: 'Could not run OpenCode: Location plugins did not finish activating' });
|
|
146
|
+
expect(work(fake)).toEqual([['auth', 'list', '--standalone'], ['auth', 'list'], ['auth', 'list'], ['auth', 'list']]);
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
it('ask a shared server that was already running again too, as it starts plugins anew for a folder it has not served', async () => {
|
|
150
|
+
const fake = fakeOpenCode('2.2.6', 'http://127.0.0.1:4096', false, 1);
|
|
151
|
+
|
|
152
|
+
const status = await checkOpenCode(fake.file);
|
|
153
|
+
|
|
154
|
+
expect(status.state).toBe('signed-in');
|
|
155
|
+
expect(work(fake)).toEqual([['auth', 'list'], ['auth', 'list']]);
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
it('run as they are on OpenCode 1, which has no shared server and no --standalone', async () => {
|
|
159
|
+
const fake = fakeOpenCode('1.19.4', null);
|
|
160
|
+
|
|
161
|
+
await checkOpenCode(fake.file);
|
|
162
|
+
|
|
163
|
+
expect(fake.runs()).toEqual([['--version'], ['auth', 'list']]);
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
it('run as they are when OpenCode cannot say whether its shared server runs', async () => {
|
|
167
|
+
const fake = fakeOpenCode('2.2.5', null);
|
|
168
|
+
|
|
169
|
+
await checkOpenCode(fake.file);
|
|
170
|
+
|
|
171
|
+
expect(work(fake)).toEqual([['auth', 'list']]);
|
|
172
|
+
});
|
|
173
|
+
});
|
package/src/login.test.ts
CHANGED
|
@@ -48,6 +48,17 @@ describe('OpenCode readiness', () => {
|
|
|
48
48
|
});
|
|
49
49
|
});
|
|
50
50
|
|
|
51
|
+
it('reads the table OpenCode 2 prints, naming each provider it stores a credential for once', async () => {
|
|
52
|
+
const table =
|
|
53
|
+
'OpenAI OpenAI 2 stored\n' +
|
|
54
|
+
'OpenAI OAuth stored\n' +
|
|
55
|
+
'OpenRouter OpenRouter stored\n' +
|
|
56
|
+
'Google GEMINI_API_KEY environment\n';
|
|
57
|
+
answer({ 'auth list': ok(table) });
|
|
58
|
+
|
|
59
|
+
expect((await checkOpenCode('opencode')).accountId).toBe('OpenAI, OpenRouter');
|
|
60
|
+
});
|
|
61
|
+
|
|
51
62
|
it('is ready without any sign-in, since its free models need none', async () => {
|
|
52
63
|
answer({ 'auth list': ok(AUTH_LIST_NONE) });
|
|
53
64
|
|
package/src/login.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { AgentSignIn } from '@moxxy/agent-connection-kit';
|
|
2
2
|
import { MoxxyError } from '@moxxy/sdk';
|
|
3
|
-
import {
|
|
3
|
+
import { moxxyOwnVariables, readCliVersion } from '@moxxy/agent-connection-kit';
|
|
4
|
+
import { spawnExecutableTarget, type ExecutableTarget } from '@moxxy/sdk/server';
|
|
4
5
|
import type { ProviderAuthContext, ProviderOAuthResult, ProviderOAuthStatus } from '@moxxy/sdk';
|
|
5
6
|
import {
|
|
6
7
|
OPENCODE_DEBUG_AGENT_ARGS,
|
|
@@ -10,9 +11,12 @@ import {
|
|
|
10
11
|
OPENCODE_AUTH_LOGOUT_ARGS,
|
|
11
12
|
OPENCODE_EXECUTABLE_ENV,
|
|
12
13
|
OPENCODE_MODELS_ARGS,
|
|
14
|
+
OPENCODE_PLUGINS_TIMEOUT,
|
|
13
15
|
OPENCODE_PROVIDER_ID,
|
|
16
|
+
OPENCODE_SERVICE_STATUS_ARGS,
|
|
17
|
+
OPENCODE_STANDALONE_FLAG,
|
|
14
18
|
} from './constants.js';
|
|
15
|
-
import { opencodeTarget } from './executable.js';
|
|
19
|
+
import { opencodeHasSharedServer, opencodeTarget } from './executable.js';
|
|
16
20
|
import type { OpenCodeRule, ReadAgentMcpServers, ReadAgentRules } from './rules.js';
|
|
17
21
|
|
|
18
22
|
export type OpenCodeState = 'signed-in' | 'missing' | 'error';
|
|
@@ -42,7 +46,10 @@ interface CommandOptions {
|
|
|
42
46
|
type CommandRunner = (executable: string, args: readonly string[], options?: CommandOptions) => Promise<OpenCodeCommandResult>;
|
|
43
47
|
|
|
44
48
|
const ANSI = /\u001b\[[0-9;]*m/g;
|
|
49
|
+
/** OpenCode 1: `● OpenAI oauth`. */
|
|
45
50
|
const CREDENTIAL = /^●\s+(.+?)\s+\S+$/;
|
|
51
|
+
/** OpenCode 2: `OpenRouter OpenRouter stored`; `environment` rows are the person's variables, not a sign-in. */
|
|
52
|
+
const STORED_CREDENTIAL = /^(.+?)\s{2,}.*\s{2,}stored$/;
|
|
46
53
|
const MODEL_ID = /^[\w.@-]+\/\S+$/;
|
|
47
54
|
const LOGIN_HINT = 'Run `opencode auth login` in a terminal to sign OpenCode in to a model provider.';
|
|
48
55
|
|
|
@@ -72,13 +79,17 @@ export async function checkOpenCode(executable = resolveOpenCodeExecutable()): P
|
|
|
72
79
|
const detail = result.error?.message ?? (result.stderr.trim() || `exit code ${result.code}`);
|
|
73
80
|
return { state: 'error', executable, message: `Could not run OpenCode: ${detail}` };
|
|
74
81
|
}
|
|
75
|
-
const providers =
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
+
const providers = [
|
|
83
|
+
...new Set(
|
|
84
|
+
result.stdout
|
|
85
|
+
.replace(ANSI, '')
|
|
86
|
+
.split('\n')
|
|
87
|
+
.flatMap((line) => {
|
|
88
|
+
const match = CREDENTIAL.exec(line.trim()) ?? STORED_CREDENTIAL.exec(line.trim());
|
|
89
|
+
return match?.[1] ? [match[1]] : [];
|
|
90
|
+
}),
|
|
91
|
+
),
|
|
92
|
+
];
|
|
82
93
|
if (providers.length === 0) {
|
|
83
94
|
return { state: 'signed-in', executable, message: `OpenCode is ready with its free models. ${LOGIN_HINT}` };
|
|
84
95
|
}
|
|
@@ -207,8 +218,44 @@ async function runCommand(executable: string, args: readonly string[], options:
|
|
|
207
218
|
const error = Object.assign(err instanceof Error ? err : new Error(String(err)), { code: 'ENOENT' }) as NodeJS.ErrnoException;
|
|
208
219
|
return { code: 1, stdout: '', stderr: '', error };
|
|
209
220
|
}
|
|
210
|
-
|
|
211
|
-
|
|
221
|
+
const asked = await withoutStartingSharedServer(target, args);
|
|
222
|
+
let result = await spawnCommand(target, asked, options);
|
|
223
|
+
// A busy computer: the plugins took longer than OpenCode allows. Ask on the
|
|
224
|
+
// shared server (started without Moxxy's variables, it carries nothing of
|
|
225
|
+
// Moxxy's after it quits). It goes on starting them after an answer times
|
|
226
|
+
// out, so asking it again gets the answer once they are up.
|
|
227
|
+
for (let asks = 0; asks < SHARED_SERVER_ASKS && pluginsTimedOut(result); asks++) {
|
|
228
|
+
result = await spawnCommand(target, args, options);
|
|
229
|
+
}
|
|
230
|
+
return result;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/** How many times a command is asked of the shared server while its plugins are still starting: each ask waits up to their 5 seconds. */
|
|
234
|
+
const SHARED_SERVER_ASKS = 3;
|
|
235
|
+
|
|
236
|
+
/** OpenCode gives its plugins 5 seconds to start; a private server starts them anew each time, and the shared one for each folder it has not served. */
|
|
237
|
+
function pluginsTimedOut(result: OpenCodeCommandResult): boolean {
|
|
238
|
+
return result.code !== 0 && `${result.stderr}${result.stdout}`.includes(OPENCODE_PLUGINS_TIMEOUT);
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* `args`, run so that Moxxy never starts OpenCode 2's shared background
|
|
243
|
+
* server: that server stays after Moxxy quits. When it already runs, the
|
|
244
|
+
* command uses it, as it answers at once and is the person's own; when not,
|
|
245
|
+
* the command runs on a private server that ends with it (`--standalone`,
|
|
246
|
+
* about a second longer). OpenCode 1 has no shared server, and an OpenCode
|
|
247
|
+
* that cannot say whether it runs is asked as it was before.
|
|
248
|
+
*/
|
|
249
|
+
async function withoutStartingSharedServer(target: ExecutableTarget, args: readonly string[]): Promise<readonly string[]> {
|
|
250
|
+
if (!opencodeHasSharedServer(await readCliVersion(target))) return args;
|
|
251
|
+
const status = await spawnCommand(target, OPENCODE_SERVICE_STATUS_ARGS);
|
|
252
|
+
if (status.error || status.code !== 0) return args;
|
|
253
|
+
return status.stdout.trim() === 'stopped' ? [...args, OPENCODE_STANDALONE_FLAG] : args;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
function spawnCommand(target: ExecutableTarget, args: readonly string[], options: CommandOptions = {}): Promise<OpenCodeCommandResult> {
|
|
257
|
+
return new Promise((resolve) => {
|
|
258
|
+
const where = { ...(options.cwd ? { cwd: options.cwd } : {}), env: moxxyOwnVariables(process.env) };
|
|
212
259
|
const child = spawnExecutableTarget(target, [...args], options.inherit ? { ...where, stdio: 'inherit' } : { ...where, stdio: ['ignore', 'pipe', 'pipe'], windowsHide: true });
|
|
213
260
|
let stdout = '';
|
|
214
261
|
let stderr = '';
|