@markjaquith/agency 3.5.1 → 3.6.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/README.md +167 -18
- package/cli-main.ts +13 -2
- package/docs/opencode-auto-start.md +67 -0
- package/package.json +10 -5
- package/src/act-schema.ts +62 -0
- package/src/cli-parser.ts +13 -3
- package/src/commands/act-actions.ts +734 -0
- package/src/commands/act-prompts.ts +294 -0
- package/src/commands/act.ts +602 -436
- package/src/commands/work.ts +16 -2
- package/src/utils/chooser.ts +7 -0
- package/src/utils/exec.ts +21 -6
- package/src/utils/interactive.tsx +528 -87
- package/src/workbase/AGENTS.md +49 -0
- package/src/workbase/opencode-launch.ts +120 -0
- package/src/workbase/work-target.ts +6 -4
package/src/commands/work.ts
CHANGED
|
@@ -37,6 +37,7 @@ import {
|
|
|
37
37
|
readValidationEvidence,
|
|
38
38
|
} from "../workbase/execution-contract"
|
|
39
39
|
import { ValidationFailedError } from "./validate"
|
|
40
|
+
import { prepareOpenCodeLaunch } from "../workbase/opencode-launch"
|
|
40
41
|
|
|
41
42
|
export interface WorkOptions extends BaseCommandOptions {
|
|
42
43
|
readonly directory?: string
|
|
@@ -386,12 +387,22 @@ export const work = (
|
|
|
386
387
|
...agentEnvironment(agent, variables),
|
|
387
388
|
}
|
|
388
389
|
if (writablePath) environment.AGENCY_WRITABLE_CHECKOUT = writablePath
|
|
390
|
+
const managedOpenCodeAuto =
|
|
391
|
+
options.auto &&
|
|
392
|
+
(agent === "opencode" || agent === "opencode2") &&
|
|
393
|
+
!config.agents?.[agent]
|
|
389
394
|
if (options.printCommand) {
|
|
390
395
|
log(
|
|
391
396
|
JSON.stringify(
|
|
392
397
|
{
|
|
393
398
|
cwd: launchPath,
|
|
394
399
|
argv: resolved.argv,
|
|
400
|
+
...(managedOpenCodeAuto
|
|
401
|
+
? {
|
|
402
|
+
startup:
|
|
403
|
+
"OpenCode V2: submit via API, then attach with --session; V1: use argv",
|
|
404
|
+
}
|
|
405
|
+
: {}),
|
|
395
406
|
environment: printableEnvironment(environment),
|
|
396
407
|
},
|
|
397
408
|
null,
|
|
@@ -449,14 +460,17 @@ export const work = (
|
|
|
449
460
|
)
|
|
450
461
|
}
|
|
451
462
|
}
|
|
463
|
+
const launchArgv = managedOpenCodeAuto
|
|
464
|
+
? yield* prepareOpenCodeLaunch(resolved.argv, launchPath, environment)
|
|
465
|
+
: resolved.argv
|
|
452
466
|
for (const [key, value] of Object.entries(environment)) {
|
|
453
467
|
process.env[key] = value
|
|
454
468
|
}
|
|
455
469
|
verboseLog(
|
|
456
|
-
`Launching command: ${formatCommand(
|
|
470
|
+
`Launching command: ${formatCommand(launchArgv)} (cwd: ${launchPath})`,
|
|
457
471
|
)
|
|
458
472
|
try {
|
|
459
|
-
launch(cli,
|
|
473
|
+
launch(cli, launchArgv, launchPath, environment)
|
|
460
474
|
} finally {
|
|
461
475
|
for (const key of Object.keys(environment)) {
|
|
462
476
|
const previous = previousEnvironment[key]
|
package/src/utils/chooser.ts
CHANGED
|
@@ -6,6 +6,7 @@ export interface Choice<T> {
|
|
|
6
6
|
readonly plainLabel?: string
|
|
7
7
|
readonly depth?: number
|
|
8
8
|
readonly segments?: readonly ChoiceSegment[]
|
|
9
|
+
readonly details?: ChoiceDetails
|
|
9
10
|
readonly value: T
|
|
10
11
|
}
|
|
11
12
|
|
|
@@ -14,6 +15,12 @@ export interface ChoiceSegment {
|
|
|
14
15
|
readonly color?: string
|
|
15
16
|
}
|
|
16
17
|
|
|
18
|
+
export interface ChoiceDetails {
|
|
19
|
+
readonly title: readonly ChoiceSegment[]
|
|
20
|
+
readonly metadata: readonly ChoiceSegment[]
|
|
21
|
+
readonly description: string
|
|
22
|
+
}
|
|
23
|
+
|
|
17
24
|
export type ChooserErrorReason =
|
|
18
25
|
| "invalid-choices"
|
|
19
26
|
| "input-unavailable"
|
package/src/utils/exec.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { dlopen, FFIType, ptr } from "bun:ffi"
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
4
|
+
* PATH-resolving native exec using POSIX execve and an explicit environment.
|
|
5
5
|
* This completely replaces the current process with the specified command.
|
|
6
6
|
*
|
|
7
7
|
* IMPORTANT: This function will never return if successful. The process
|
|
@@ -12,12 +12,18 @@ import { dlopen, FFIType, ptr } from "bun:ffi"
|
|
|
12
12
|
* @throws Error if exec fails (e.g., command not found)
|
|
13
13
|
*/
|
|
14
14
|
export function execvp(file: string, args: string[]): never {
|
|
15
|
-
|
|
15
|
+
const executable = Bun.which(file)
|
|
16
|
+
if (!executable) throw new Error(`Unable to find executable '${file}'`)
|
|
17
|
+
// Bun's process.env mutations are not reflected in libc's environ. Passing
|
|
18
|
+
// envp explicitly preserves launch identity and deletions across replacement.
|
|
19
|
+
const variables = Object.entries(process.env)
|
|
20
|
+
.filter((entry): entry is [string, string] => entry[1] !== undefined)
|
|
21
|
+
.map(([key, value]) => `${key}=${value}`)
|
|
16
22
|
const libcPath =
|
|
17
23
|
process.platform === "darwin" ? "/usr/lib/libSystem.B.dylib" : "libc.so.6"
|
|
18
24
|
const libc = dlopen(libcPath, {
|
|
19
|
-
|
|
20
|
-
args: [FFIType.cstring, FFIType.ptr],
|
|
25
|
+
execve: {
|
|
26
|
+
args: [FFIType.cstring, FFIType.ptr, FFIType.ptr],
|
|
21
27
|
returns: FFIType.int,
|
|
22
28
|
},
|
|
23
29
|
})
|
|
@@ -36,10 +42,19 @@ export function execvp(file: string, args: string[]): never {
|
|
|
36
42
|
}
|
|
37
43
|
// Null-terminate the pointer array
|
|
38
44
|
ptrs[args.length] = 0n
|
|
45
|
+
const environmentStrings = variables.map((value) => Buffer.from(value + "\0"))
|
|
46
|
+
const environmentPointers = new BigUint64Array(environmentStrings.length + 1)
|
|
47
|
+
for (let i = 0; i < environmentStrings.length; i++) {
|
|
48
|
+
environmentPointers[i] = BigInt(ptr(environmentStrings[i]!))
|
|
49
|
+
}
|
|
39
50
|
|
|
40
51
|
// Call execvp - this will replace the current process if successful
|
|
41
|
-
const fileBuffer = Buffer.from(
|
|
42
|
-
const result = libc.symbols.
|
|
52
|
+
const fileBuffer = Buffer.from(executable + "\0")
|
|
53
|
+
const result = libc.symbols.execve(
|
|
54
|
+
ptr(fileBuffer),
|
|
55
|
+
ptr(ptrs),
|
|
56
|
+
ptr(environmentPointers),
|
|
57
|
+
)
|
|
43
58
|
|
|
44
59
|
// If we reach here, exec failed
|
|
45
60
|
throw new Error(
|