@ai-sdk/harness-opencode 1.0.10 → 1.0.12
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/CHANGELOG.md +17 -0
- package/dist/bridge/host-tool-mcp.mjs +1 -3
- package/dist/bridge/host-tool-mcp.mjs.map +1 -1
- package/dist/bridge/index.mjs +227 -19
- package/dist/bridge/index.mjs.map +1 -1
- package/dist/index.js +20 -78
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/src/bridge/host-tool-mcp.ts +0 -2
- package/src/bridge/index.ts +170 -27
- package/src/bridge/tool-relay-auth.ts +151 -0
- package/src/opencode-harness.ts +19 -85
package/src/opencode-harness.ts
CHANGED
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
type HarnessV1,
|
|
10
10
|
type HarnessV1Bootstrap,
|
|
11
11
|
type HarnessV1BuiltinTool,
|
|
12
|
+
type HarnessV1BuiltinToolFiltering,
|
|
12
13
|
type HarnessV1ContinueTurnState,
|
|
13
14
|
type HarnessV1DebugConfig,
|
|
14
15
|
type HarnessV1NetworkSandboxSession,
|
|
@@ -23,8 +24,11 @@ import {
|
|
|
23
24
|
import {
|
|
24
25
|
classifyDiskLog,
|
|
25
26
|
markBridgeStarting,
|
|
27
|
+
resolveSandboxHomeDir,
|
|
26
28
|
SandboxChannel,
|
|
29
|
+
shellQuote,
|
|
27
30
|
waitForBridgeReady,
|
|
31
|
+
writeSkills as writeHarnessSkills,
|
|
28
32
|
} from '@ai-sdk/harness/utils';
|
|
29
33
|
import {
|
|
30
34
|
tool,
|
|
@@ -295,6 +299,7 @@ export function createOpenCode(
|
|
|
295
299
|
sandboxId,
|
|
296
300
|
debug: startOpts.observability?.debug,
|
|
297
301
|
permissionMode: startOpts.permissionMode,
|
|
302
|
+
builtinToolFiltering: startOpts.builtinToolFiltering,
|
|
298
303
|
});
|
|
299
304
|
} catch {}
|
|
300
305
|
}
|
|
@@ -326,7 +331,7 @@ export function createOpenCode(
|
|
|
326
331
|
const xdgStateHome = `${sandboxHomeDir}/.local/state`;
|
|
327
332
|
const skillSetup =
|
|
328
333
|
startOpts.skills && startOpts.skills.length > 0
|
|
329
|
-
? await
|
|
334
|
+
? await writeOpenCodeSkills({
|
|
330
335
|
sandbox: session,
|
|
331
336
|
skills: startOpts.skills,
|
|
332
337
|
homeDir: sandboxHomeDir,
|
|
@@ -421,6 +426,7 @@ export function createOpenCode(
|
|
|
421
426
|
sandboxId,
|
|
422
427
|
debug: startOpts.observability?.debug,
|
|
423
428
|
permissionMode: startOpts.permissionMode,
|
|
429
|
+
builtinToolFiltering: startOpts.builtinToolFiltering,
|
|
424
430
|
});
|
|
425
431
|
},
|
|
426
432
|
};
|
|
@@ -458,7 +464,7 @@ async function readBridgeAsset(name: string): Promise<string> {
|
|
|
458
464
|
throw lastErr ?? new Error(`bridge asset not found: ${name}`);
|
|
459
465
|
}
|
|
460
466
|
|
|
461
|
-
async function
|
|
467
|
+
async function writeOpenCodeSkills({
|
|
462
468
|
sandbox,
|
|
463
469
|
skills,
|
|
464
470
|
homeDir,
|
|
@@ -469,96 +475,21 @@ async function writeSkills({
|
|
|
469
475
|
homeDir: string;
|
|
470
476
|
abortSignal?: AbortSignal;
|
|
471
477
|
}): Promise<WriteSkillsResult> {
|
|
472
|
-
for (const skill of skills) {
|
|
473
|
-
safeOpenCodeSkillName(skill.name);
|
|
474
|
-
for (const file of skill.files ?? []) {
|
|
475
|
-
safeOpenCodeSkillFilePath({ skillName: skill.name, filePath: file.path });
|
|
476
|
-
}
|
|
477
|
-
}
|
|
478
|
-
|
|
479
478
|
const skillsDir = path.posix.join(homeDir, '.agents', 'skills');
|
|
480
|
-
await
|
|
481
|
-
|
|
479
|
+
await writeHarnessSkills({
|
|
480
|
+
sandbox,
|
|
481
|
+
rootDir: skillsDir,
|
|
482
|
+
skills,
|
|
482
483
|
abortSignal,
|
|
484
|
+
invalidSkillNameMessage: ({ name }) =>
|
|
485
|
+
`Invalid OpenCode skill name: ${name}`,
|
|
486
|
+
invalidSkillFilePathMessage: ({ skillName, filePath }) =>
|
|
487
|
+
`Invalid OpenCode skill file path for ${skillName}: ${filePath}`,
|
|
483
488
|
});
|
|
484
489
|
|
|
485
|
-
for (const skill of skills) {
|
|
486
|
-
const name = safeOpenCodeSkillName(skill.name);
|
|
487
|
-
const skillDir = path.posix.join(skillsDir, name);
|
|
488
|
-
const content = `---\nname: ${skill.name}\ndescription: ${skill.description}\n---\n\n${skill.content}`;
|
|
489
|
-
await sandbox.writeTextFile({
|
|
490
|
-
path: path.posix.join(skillDir, 'SKILL.md'),
|
|
491
|
-
content,
|
|
492
|
-
abortSignal,
|
|
493
|
-
});
|
|
494
|
-
|
|
495
|
-
for (const file of skill.files ?? []) {
|
|
496
|
-
const filePath = safeOpenCodeSkillFilePath({
|
|
497
|
-
skillName: skill.name,
|
|
498
|
-
filePath: file.path,
|
|
499
|
-
});
|
|
500
|
-
await sandbox.writeTextFile({
|
|
501
|
-
path: path.posix.join(skillDir, filePath),
|
|
502
|
-
content: file.content,
|
|
503
|
-
abortSignal,
|
|
504
|
-
});
|
|
505
|
-
}
|
|
506
|
-
}
|
|
507
|
-
|
|
508
490
|
return { skillsDir };
|
|
509
491
|
}
|
|
510
492
|
|
|
511
|
-
async function resolveSandboxHomeDir({
|
|
512
|
-
sandbox,
|
|
513
|
-
abortSignal,
|
|
514
|
-
}: {
|
|
515
|
-
sandbox: Experimental_SandboxSession;
|
|
516
|
-
abortSignal?: AbortSignal;
|
|
517
|
-
}): Promise<string> {
|
|
518
|
-
const result = await sandbox.run({
|
|
519
|
-
command: 'printf "%s" "$HOME"',
|
|
520
|
-
abortSignal,
|
|
521
|
-
});
|
|
522
|
-
const homeDir = result.stdout.trim();
|
|
523
|
-
if (result.exitCode !== 0 || !homeDir || !path.posix.isAbsolute(homeDir)) {
|
|
524
|
-
throw new Error(
|
|
525
|
-
`Unable to resolve sandbox HOME directory: ${result.stderr || result.stdout}`,
|
|
526
|
-
);
|
|
527
|
-
}
|
|
528
|
-
return homeDir;
|
|
529
|
-
}
|
|
530
|
-
|
|
531
|
-
function safeOpenCodeSkillName(name: string): string {
|
|
532
|
-
if (!/^[A-Za-z0-9._-]+$/.test(name) || name === '.' || name === '..') {
|
|
533
|
-
throw new Error(`Invalid OpenCode skill name: ${name}`);
|
|
534
|
-
}
|
|
535
|
-
return name;
|
|
536
|
-
}
|
|
537
|
-
|
|
538
|
-
function safeOpenCodeSkillFilePath({
|
|
539
|
-
skillName,
|
|
540
|
-
filePath,
|
|
541
|
-
}: {
|
|
542
|
-
skillName: string;
|
|
543
|
-
filePath: string;
|
|
544
|
-
}): string {
|
|
545
|
-
const normalized = path.posix.normalize(filePath);
|
|
546
|
-
if (
|
|
547
|
-
normalized === '.' ||
|
|
548
|
-
normalized.startsWith('../') ||
|
|
549
|
-
path.posix.isAbsolute(normalized)
|
|
550
|
-
) {
|
|
551
|
-
throw new Error(
|
|
552
|
-
`Invalid OpenCode skill file path for ${skillName}: ${filePath}`,
|
|
553
|
-
);
|
|
554
|
-
}
|
|
555
|
-
return normalized;
|
|
556
|
-
}
|
|
557
|
-
|
|
558
|
-
function shellQuote(value: string): string {
|
|
559
|
-
return `'${value.replace(/'/g, `'\\''`)}'`;
|
|
560
|
-
}
|
|
561
|
-
|
|
562
493
|
async function forwardBridgeStderr(
|
|
563
494
|
stream: ReadableStream<Uint8Array>,
|
|
564
495
|
): Promise<void> {
|
|
@@ -619,6 +550,7 @@ function createSession({
|
|
|
619
550
|
sandboxId,
|
|
620
551
|
debug,
|
|
621
552
|
permissionMode,
|
|
553
|
+
builtinToolFiltering,
|
|
622
554
|
}: {
|
|
623
555
|
sessionId: string;
|
|
624
556
|
channel: OpenCodeChannel;
|
|
@@ -635,6 +567,7 @@ function createSession({
|
|
|
635
567
|
sandboxId: string;
|
|
636
568
|
debug: HarnessV1DebugConfig | undefined;
|
|
637
569
|
permissionMode: HarnessV1PermissionMode | undefined;
|
|
570
|
+
builtinToolFiltering: HarnessV1BuiltinToolFiltering | undefined;
|
|
638
571
|
}): HarnessV1Session {
|
|
639
572
|
let stopped = false;
|
|
640
573
|
let stopPromise: Promise<void> | undefined;
|
|
@@ -786,6 +719,7 @@ function createSession({
|
|
|
786
719
|
provider,
|
|
787
720
|
...(reasoningVariant ? { variant: reasoningVariant } : {}),
|
|
788
721
|
...(permissionMode ? { permissionMode } : {}),
|
|
722
|
+
...(builtinToolFiltering ? { builtinToolFiltering } : {}),
|
|
789
723
|
...(pendingResumeSessionId
|
|
790
724
|
? { resumeSessionId: pendingResumeSessionId }
|
|
791
725
|
: latestOpenCodeSessionId
|