@workbench-ai/agent-driver 0.0.44
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/access-contracts.d.ts +10 -0
- package/dist/access-contracts.d.ts.map +1 -0
- package/dist/access-contracts.js +45 -0
- package/dist/behavior-contract.d.ts +26 -0
- package/dist/behavior-contract.d.ts.map +1 -0
- package/dist/behavior-contract.js +200 -0
- package/dist/conformance.d.ts +3 -0
- package/dist/conformance.d.ts.map +1 -0
- package/dist/conformance.js +37 -0
- package/dist/global-skills.d.ts +22 -0
- package/dist/global-skills.d.ts.map +1 -0
- package/dist/global-skills.js +168 -0
- package/dist/index.d.ts +138 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +44 -0
- package/dist/internal-utils.d.ts +8 -0
- package/dist/internal-utils.d.ts.map +1 -0
- package/dist/internal-utils.js +46 -0
- package/dist/json-rpc.d.ts +22 -0
- package/dist/json-rpc.d.ts.map +1 -0
- package/dist/json-rpc.js +1 -0
- package/dist/managed-runtime.d.ts +21 -0
- package/dist/managed-runtime.d.ts.map +1 -0
- package/dist/managed-runtime.js +119 -0
- package/dist/model-config.d.ts +17 -0
- package/dist/model-config.d.ts.map +1 -0
- package/dist/model-config.js +43 -0
- package/dist/normalized-activity.d.ts +75 -0
- package/dist/normalized-activity.d.ts.map +1 -0
- package/dist/normalized-activity.js +89 -0
- package/dist/prepare.d.ts +9 -0
- package/dist/prepare.d.ts.map +1 -0
- package/dist/prepare.js +119 -0
- package/dist/process-env.d.ts +20 -0
- package/dist/process-env.d.ts.map +1 -0
- package/dist/process-env.js +75 -0
- package/dist/session-runtime.d.ts +60 -0
- package/dist/session-runtime.d.ts.map +1 -0
- package/dist/session-runtime.js +240 -0
- package/dist/tool-semantics.d.ts +22 -0
- package/dist/tool-semantics.d.ts.map +1 -0
- package/dist/tool-semantics.js +241 -0
- package/dist/trace-builder.d.ts +88 -0
- package/dist/trace-builder.d.ts.map +1 -0
- package/dist/trace-builder.js +493 -0
- package/dist/trace-replay.d.ts +33 -0
- package/dist/trace-replay.d.ts.map +1 -0
- package/dist/trace-replay.js +4 -0
- package/dist/types.d.ts +156 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +10 -0
- package/package.json +39 -0
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import type { GlobalSkillCatalog, GlobalSkillCatalogEntry, GlobalSkillProviderSupport, GlobalSkillUpdate, ProviderIntegrationCatalog, ProviderIntegrationCatalogEntry, ProviderIntegrationUpdate } from "./types.js";
|
|
3
|
+
export declare const GlobalSkillProviderSupportSchema: z.ZodType<GlobalSkillProviderSupport>;
|
|
4
|
+
export declare const GlobalSkillCatalogEntrySchema: z.ZodType<GlobalSkillCatalogEntry>;
|
|
5
|
+
export declare const GlobalSkillCatalogSchema: z.ZodType<GlobalSkillCatalog>;
|
|
6
|
+
export declare const GlobalSkillUpdateSchema: z.ZodType<GlobalSkillUpdate>;
|
|
7
|
+
export declare const ProviderIntegrationCatalogEntrySchema: z.ZodType<ProviderIntegrationCatalogEntry>;
|
|
8
|
+
export declare const ProviderIntegrationCatalogSchema: z.ZodType<ProviderIntegrationCatalog>;
|
|
9
|
+
export declare const ProviderIntegrationUpdateSchema: z.ZodType<ProviderIntegrationUpdate>;
|
|
10
|
+
//# sourceMappingURL=access-contracts.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"access-contracts.d.ts","sourceRoot":"","sources":["../src/access-contracts.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,KAAK,EACV,kBAAkB,EAClB,uBAAuB,EACvB,0BAA0B,EAC1B,iBAAiB,EACjB,0BAA0B,EAC1B,+BAA+B,EAC/B,yBAAyB,EAC1B,MAAM,YAAY,CAAC;AAEpB,eAAO,MAAM,gCAAgC,EAAE,CAAC,CAAC,OAAO,CAAC,0BAA0B,CAKxE,CAAC;AAEZ,eAAO,MAAM,6BAA6B,EAAE,CAAC,CAAC,OAAO,CAAC,uBAAuB,CAQlE,CAAC;AAEZ,eAAO,MAAM,wBAAwB,EAAE,CAAC,CAAC,OAAO,CAAC,kBAAkB,CAIxD,CAAC;AAEZ,eAAO,MAAM,uBAAuB,EAAE,CAAC,CAAC,OAAO,CAAC,iBAAiB,CAItD,CAAC;AAEZ,eAAO,MAAM,qCAAqC,EAAE,CAAC,CAAC,OAAO,CAAC,+BAA+B,CAMlF,CAAC;AAEZ,eAAO,MAAM,gCAAgC,EAAE,CAAC,CAAC,OAAO,CAAC,0BAA0B,CAMxE,CAAC;AAEZ,eAAO,MAAM,+BAA+B,EAAE,CAAC,CAAC,OAAO,CAAC,yBAAyB,CAItE,CAAC"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export const GlobalSkillProviderSupportSchema = z
|
|
3
|
+
.object({
|
|
4
|
+
providerId: z.string().min(1),
|
|
5
|
+
providerLabel: z.string().min(1),
|
|
6
|
+
})
|
|
7
|
+
.strict();
|
|
8
|
+
export const GlobalSkillCatalogEntrySchema = z
|
|
9
|
+
.object({
|
|
10
|
+
id: z.string().min(1),
|
|
11
|
+
label: z.string().min(1),
|
|
12
|
+
summary: z.string().nullable(),
|
|
13
|
+
enabled: z.boolean(),
|
|
14
|
+
providerSupport: z.array(GlobalSkillProviderSupportSchema).default([]),
|
|
15
|
+
})
|
|
16
|
+
.strict();
|
|
17
|
+
export const GlobalSkillCatalogSchema = z
|
|
18
|
+
.object({
|
|
19
|
+
skills: z.array(GlobalSkillCatalogEntrySchema).default([]),
|
|
20
|
+
})
|
|
21
|
+
.strict();
|
|
22
|
+
export const GlobalSkillUpdateSchema = z
|
|
23
|
+
.object({
|
|
24
|
+
enabled: z.boolean(),
|
|
25
|
+
})
|
|
26
|
+
.strict();
|
|
27
|
+
export const ProviderIntegrationCatalogEntrySchema = z
|
|
28
|
+
.object({
|
|
29
|
+
id: z.string().min(1),
|
|
30
|
+
label: z.string().min(1),
|
|
31
|
+
enabled: z.boolean(),
|
|
32
|
+
})
|
|
33
|
+
.strict();
|
|
34
|
+
export const ProviderIntegrationCatalogSchema = z
|
|
35
|
+
.object({
|
|
36
|
+
providerId: z.string().min(1),
|
|
37
|
+
providerLabel: z.string().min(1),
|
|
38
|
+
integrations: z.array(ProviderIntegrationCatalogEntrySchema).default([]),
|
|
39
|
+
})
|
|
40
|
+
.strict();
|
|
41
|
+
export const ProviderIntegrationUpdateSchema = z
|
|
42
|
+
.object({
|
|
43
|
+
enabledIds: z.array(z.string().min(1)),
|
|
44
|
+
})
|
|
45
|
+
.strict();
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { JsonValue } from "./types.js";
|
|
2
|
+
import type { ActiveHarnessSession, HarnessExecutionPlan, HarnessProvider, HarnessSessionMode } from "./index.js";
|
|
3
|
+
type BehaviorIssueHookResult = Promise<string[] | void> | string[] | void;
|
|
4
|
+
export interface HarnessBehaviorContractArgs {
|
|
5
|
+
provider: HarnessProvider<unknown>;
|
|
6
|
+
repoRoot: string;
|
|
7
|
+
runtimeHome: string;
|
|
8
|
+
executionId: string;
|
|
9
|
+
ownerId: string;
|
|
10
|
+
workspacePath: string;
|
|
11
|
+
stageSessionPath: string;
|
|
12
|
+
prompt: string;
|
|
13
|
+
attemptNumber?: number;
|
|
14
|
+
stageId?: string;
|
|
15
|
+
stageRunIndex?: number;
|
|
16
|
+
ownerStageId?: string;
|
|
17
|
+
sessionMode?: HarnessSessionMode;
|
|
18
|
+
persistedSession?: Record<string, JsonValue> | null;
|
|
19
|
+
plan?: HarnessExecutionPlan;
|
|
20
|
+
exerciseReadiness?: boolean;
|
|
21
|
+
exerciseStartSession?: boolean;
|
|
22
|
+
validateSession?: (session: ActiveHarnessSession<unknown>) => BehaviorIssueHookResult;
|
|
23
|
+
}
|
|
24
|
+
export declare function collectHarnessProviderBehaviorContractIssues(args: HarnessBehaviorContractArgs): Promise<string[]>;
|
|
25
|
+
export {};
|
|
26
|
+
//# sourceMappingURL=behavior-contract.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"behavior-contract.d.ts","sourceRoot":"","sources":["../src/behavior-contract.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAG5C,OAAO,KAAK,EACV,oBAAoB,EAEpB,oBAAoB,EACpB,eAAe,EACf,kBAAkB,EAEnB,MAAM,YAAY,CAAC;AAEpB,KAAK,uBAAuB,GAAG,OAAO,CAAC,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,MAAM,EAAE,GAAG,IAAI,CAAC;AAE1E,MAAM,WAAW,2BAA2B;IAC1C,QAAQ,EAAE,eAAe,CAAC,OAAO,CAAC,CAAC;IACnC,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;IACtB,gBAAgB,EAAE,MAAM,CAAC;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,kBAAkB,CAAC;IACjC,gBAAgB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,IAAI,CAAC;IACpD,IAAI,CAAC,EAAE,oBAAoB,CAAC;IAC5B,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,eAAe,CAAC,EAAE,CAAC,OAAO,EAAE,oBAAoB,CAAC,OAAO,CAAC,KAAK,uBAAuB,CAAC;CACvF;AAYD,wBAAsB,4CAA4C,CAAC,IAAI,EAAE,2BAA2B,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAoCvH"}
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
import { promises as fs } from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { collectHarnessProviderConformanceIssues } from "./conformance.js";
|
|
4
|
+
export async function collectHarnessProviderBehaviorContractIssues(args) {
|
|
5
|
+
const context = createContractContext(args);
|
|
6
|
+
const issues = collectHarnessProviderConformanceIssues(args.provider);
|
|
7
|
+
await Promise.all([args.repoRoot, args.runtimeHome, args.workspacePath, args.stageSessionPath].map(ensureDir));
|
|
8
|
+
await seedDefaultSecretRefEnv(context.plan, args.repoRoot);
|
|
9
|
+
if (args.exerciseReadiness ?? true) {
|
|
10
|
+
await maybeExerciseReadiness(args, context.plan, issues);
|
|
11
|
+
}
|
|
12
|
+
const adapter = createAdapter(args.provider, issues);
|
|
13
|
+
if (!adapter) {
|
|
14
|
+
return issues;
|
|
15
|
+
}
|
|
16
|
+
validateAdapterBasics(args.provider, adapter, context.plan, issues);
|
|
17
|
+
const sessionBaseArgs = createSessionBaseArgs(args, context);
|
|
18
|
+
if (args.exerciseStartSession ?? true) {
|
|
19
|
+
const session = await captureAsyncIssue(issues, "startSession", () => adapter.startSession({ ...sessionBaseArgs, sessionMode: context.sessionMode }));
|
|
20
|
+
if (session) {
|
|
21
|
+
try {
|
|
22
|
+
validateStartedSession(session, args.provider.manifest.id, context, issues);
|
|
23
|
+
await pushHookIssues(issues, args.validateSession?.(session));
|
|
24
|
+
}
|
|
25
|
+
finally {
|
|
26
|
+
await captureAsyncIssue(issues, "closeSession threw after contract startSession check", () => adapter.closeSession(session, context.plan.harness.cancel));
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return issues;
|
|
31
|
+
}
|
|
32
|
+
function createContractContext(args) {
|
|
33
|
+
const stageId = args.stageId ?? "stage";
|
|
34
|
+
return {
|
|
35
|
+
plan: args.plan ?? createDefaultBehaviorPlan(args.provider),
|
|
36
|
+
attemptNumber: args.attemptNumber ?? 1,
|
|
37
|
+
stageId,
|
|
38
|
+
stageRunIndex: args.stageRunIndex ?? 0,
|
|
39
|
+
ownerStageId: args.ownerStageId ?? stageId,
|
|
40
|
+
sessionMode: args.sessionMode ?? "fresh",
|
|
41
|
+
persistedSession: args.persistedSession ?? null,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
function createSessionBaseArgs(args, context) {
|
|
45
|
+
return {
|
|
46
|
+
repoRoot: args.repoRoot,
|
|
47
|
+
runtimeHome: args.runtimeHome,
|
|
48
|
+
plan: context.plan,
|
|
49
|
+
ownerId: args.ownerId,
|
|
50
|
+
executionId: args.executionId,
|
|
51
|
+
attemptNumber: context.attemptNumber,
|
|
52
|
+
stageId: context.stageId,
|
|
53
|
+
stageRunIndex: context.stageRunIndex,
|
|
54
|
+
workspacePath: args.workspacePath,
|
|
55
|
+
ownerStageId: context.ownerStageId,
|
|
56
|
+
sessionMode: context.sessionMode,
|
|
57
|
+
stageSessionPath: args.stageSessionPath,
|
|
58
|
+
persistedSession: context.persistedSession,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
async function maybeExerciseReadiness(args, plan, issues) {
|
|
62
|
+
const checkReadiness = args.provider.checkReadiness;
|
|
63
|
+
if (typeof checkReadiness !== "function") {
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
const readiness = await captureAsyncIssue(issues, "provider.checkReadiness", () => checkReadiness({ repoRoot: args.repoRoot, runtimeHome: args.runtimeHome, plan }));
|
|
67
|
+
if (!readiness) {
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
if (!Array.isArray(readiness.availability_errors)) {
|
|
71
|
+
issues.push("provider.checkReadiness(args) must return { availability_errors: string[] }.");
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
if (readiness.availability_errors.length > 0) {
|
|
75
|
+
issues.push(`provider.checkReadiness returned availability errors: ${readiness.availability_errors.join("; ")}`);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
function createAdapter(provider, issues) {
|
|
79
|
+
try {
|
|
80
|
+
const adapter = provider.create();
|
|
81
|
+
if (!adapter || typeof adapter !== "object") {
|
|
82
|
+
issues.push("provider.create must return a harness adapter object.");
|
|
83
|
+
return null;
|
|
84
|
+
}
|
|
85
|
+
return adapter;
|
|
86
|
+
}
|
|
87
|
+
catch (error) {
|
|
88
|
+
issues.push(`provider.create threw: ${formatError(error)}`);
|
|
89
|
+
return null;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
function validateAdapterBasics(provider, adapter, plan, issues) {
|
|
93
|
+
if (adapter.manifest.id !== provider.manifest.id) {
|
|
94
|
+
issues.push(`adapter.manifest.id (${JSON.stringify(adapter.manifest.id)}) must match provider.manifest.id (${JSON.stringify(provider.manifest.id)}).`);
|
|
95
|
+
}
|
|
96
|
+
let ignoredEntries;
|
|
97
|
+
try {
|
|
98
|
+
ignoredEntries = adapter.getManagedWorkspaceIgnoreEntries(plan);
|
|
99
|
+
}
|
|
100
|
+
catch (error) {
|
|
101
|
+
issues.push(`adapter.getManagedWorkspaceIgnoreEntries threw: ${formatError(error)}`);
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
if (!Array.isArray(ignoredEntries)) {
|
|
105
|
+
issues.push("adapter.getManagedWorkspaceIgnoreEntries(plan) must return an array.");
|
|
106
|
+
}
|
|
107
|
+
else if (ignoredEntries.some((value) => typeof value !== "string")) {
|
|
108
|
+
issues.push("adapter.getManagedWorkspaceIgnoreEntries(plan) must return only strings.");
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
function createDefaultBehaviorPlan(provider) {
|
|
112
|
+
const { defaults, id, supported_workspace_modes: workspaceModes } = provider.manifest;
|
|
113
|
+
const harness = {
|
|
114
|
+
id,
|
|
115
|
+
auth: normalizeHarnessAuth(defaults.auth),
|
|
116
|
+
turn_timeout_ms: defaults.turn_timeout_ms ?? 3_600_000,
|
|
117
|
+
stall_timeout_ms: defaults.stall_timeout_ms ?? 300_000,
|
|
118
|
+
config: normalizeJsonRecord(defaults.config),
|
|
119
|
+
retry: { max_retries: 0, base_delay_ms: 1_000, max_backoff_ms: 5_000 },
|
|
120
|
+
cancel: { graceful_timeout_ms: 2_000, hard_kill_timeout_ms: 1_000 },
|
|
121
|
+
};
|
|
122
|
+
if (defaults.model) {
|
|
123
|
+
harness.model = defaults.model;
|
|
124
|
+
}
|
|
125
|
+
if (defaults.effort) {
|
|
126
|
+
harness.effort = defaults.effort;
|
|
127
|
+
}
|
|
128
|
+
return {
|
|
129
|
+
workspace: { mode: workspaceModes[0] ?? "managed", prune_ttl_seconds: 604_800 },
|
|
130
|
+
harness,
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
async function seedDefaultSecretRefEnv(plan, repoRoot) {
|
|
134
|
+
const auth = plan.harness.auth;
|
|
135
|
+
if (!isJsonRecord(auth) || auth.strategy !== "secret_ref") {
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
const ref = typeof auth.ref === "string" ? auth.ref.trim() : "";
|
|
139
|
+
if (!ref) {
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
const value = `FLOW_TEST_${ref.toUpperCase().replace(/[^A-Z0-9_]+/gu, "_")}`;
|
|
143
|
+
await fs.writeFile(path.join(repoRoot, ".env"), `${ref}=${value}\n`, "utf8");
|
|
144
|
+
}
|
|
145
|
+
function validateStartedSession(session, expectedHarnessId, context, issues) {
|
|
146
|
+
if (!session || typeof session !== "object") {
|
|
147
|
+
issues.push("adapter.startSession(args) must return an ActiveHarnessSession object.");
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
if (session.ownerStageId !== context.ownerStageId) {
|
|
151
|
+
issues.push(`startSession returned ownerStageId ${JSON.stringify(session.ownerStageId)} instead of ${JSON.stringify(context.ownerStageId)}.`);
|
|
152
|
+
}
|
|
153
|
+
if (!session.session || typeof session.session !== "object") {
|
|
154
|
+
issues.push("startSession must return session.session metadata.");
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
for (const [field, actual, expected] of [
|
|
158
|
+
["harness_id", session.session.harness_id, expectedHarnessId],
|
|
159
|
+
["attempt_number", session.session.attempt_number, context.attemptNumber],
|
|
160
|
+
["stage_id", session.session.stage_id, context.stageId],
|
|
161
|
+
["stage_run_index", session.session.stage_run_index, context.stageRunIndex],
|
|
162
|
+
]) {
|
|
163
|
+
if (actual !== expected) {
|
|
164
|
+
issues.push(`startSession returned ${field} ${JSON.stringify(actual)} instead of ${JSON.stringify(expected)}.`);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
if (!session.session.harness_session || typeof session.session.harness_session !== "object") {
|
|
168
|
+
issues.push("startSession must return session.harness_session as an object.");
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
async function pushHookIssues(issues, result) {
|
|
172
|
+
const additionalIssues = await result;
|
|
173
|
+
if (Array.isArray(additionalIssues)) {
|
|
174
|
+
issues.push(...additionalIssues);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
async function captureAsyncIssue(issues, label, action) {
|
|
178
|
+
try {
|
|
179
|
+
return await action();
|
|
180
|
+
}
|
|
181
|
+
catch (error) {
|
|
182
|
+
issues.push(`${label}: ${formatError(error)}`);
|
|
183
|
+
return null;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
function formatError(error) {
|
|
187
|
+
return error instanceof Error ? error.message : String(error);
|
|
188
|
+
}
|
|
189
|
+
function normalizeHarnessAuth(value) {
|
|
190
|
+
return isJsonRecord(value) ? value : {};
|
|
191
|
+
}
|
|
192
|
+
function normalizeJsonRecord(value) {
|
|
193
|
+
return isJsonRecord(value) ? { ...value } : {};
|
|
194
|
+
}
|
|
195
|
+
function isJsonRecord(value) {
|
|
196
|
+
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
197
|
+
}
|
|
198
|
+
async function ensureDir(targetPath) {
|
|
199
|
+
await fs.mkdir(targetPath, { recursive: true });
|
|
200
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"conformance.d.ts","sourceRoot":"","sources":["../src/conformance.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAElD,wBAAgB,uCAAuC,CACrD,QAAQ,EAAE,eAAe,CAAC,OAAO,CAAC,GACjC,MAAM,EAAE,CAoBV"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
export function collectHarnessProviderConformanceIssues(provider) {
|
|
2
|
+
const issues = [];
|
|
3
|
+
const manifest = provider.manifest;
|
|
4
|
+
validateManifest(manifest, issues);
|
|
5
|
+
if (!provider.schemas) {
|
|
6
|
+
issues.push("provider.schemas is required.");
|
|
7
|
+
}
|
|
8
|
+
else {
|
|
9
|
+
if (!provider.schemas.auth) {
|
|
10
|
+
issues.push("provider.schemas.auth is required.");
|
|
11
|
+
}
|
|
12
|
+
if (!provider.schemas.config) {
|
|
13
|
+
issues.push("provider.schemas.config is required.");
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
if (typeof provider.create !== "function") {
|
|
17
|
+
issues.push("provider.create must be a function.");
|
|
18
|
+
}
|
|
19
|
+
return issues;
|
|
20
|
+
}
|
|
21
|
+
function validateManifest(manifest, issues) {
|
|
22
|
+
if (!manifest.id?.trim()) {
|
|
23
|
+
issues.push("manifest.id must be a non-empty string.");
|
|
24
|
+
}
|
|
25
|
+
if (!manifest.display_name?.trim()) {
|
|
26
|
+
issues.push("manifest.display_name must be a non-empty string.");
|
|
27
|
+
}
|
|
28
|
+
if (!manifest.auth_schema) {
|
|
29
|
+
issues.push("manifest.auth_schema is required.");
|
|
30
|
+
}
|
|
31
|
+
if (!manifest.config_schema) {
|
|
32
|
+
issues.push("manifest.config_schema is required.");
|
|
33
|
+
}
|
|
34
|
+
if (!Array.isArray(manifest.supported_workspace_modes) || manifest.supported_workspace_modes.length === 0) {
|
|
35
|
+
issues.push("manifest.supported_workspace_modes must declare at least one mode.");
|
|
36
|
+
}
|
|
37
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { GlobalSkillCatalog, GlobalSkillCatalogEntry, GlobalSkillProviderSupport } from "./types.js";
|
|
2
|
+
export declare function globalSkillsRoot(homeDir: string): string;
|
|
3
|
+
export declare function globalDisabledSkillsRoot(homeDir: string): string;
|
|
4
|
+
export declare function listGlobalSkills(args: {
|
|
5
|
+
homeDir: string;
|
|
6
|
+
providerSupport?: readonly GlobalSkillProviderSupport[];
|
|
7
|
+
}): Promise<GlobalSkillCatalog>;
|
|
8
|
+
export declare function updateGlobalSkill(args: {
|
|
9
|
+
enabled: boolean;
|
|
10
|
+
homeDir: string;
|
|
11
|
+
providerSupport?: readonly GlobalSkillProviderSupport[];
|
|
12
|
+
skillId: string;
|
|
13
|
+
}): Promise<GlobalSkillCatalogEntry>;
|
|
14
|
+
export declare function projectGlobalSkills(args: {
|
|
15
|
+
sourceHomeDir: string;
|
|
16
|
+
targetHomeDir: string;
|
|
17
|
+
}): Promise<void>;
|
|
18
|
+
export declare function syncEnabledGlobalSkillsToTarget(args: {
|
|
19
|
+
sourceHomeDir: string;
|
|
20
|
+
targetRoot: string;
|
|
21
|
+
}): Promise<void>;
|
|
22
|
+
//# sourceMappingURL=global-skills.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"global-skills.d.ts","sourceRoot":"","sources":["../src/global-skills.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACV,kBAAkB,EAClB,uBAAuB,EACvB,0BAA0B,EAC3B,MAAM,YAAY,CAAC;AAOpB,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAExD;AAED,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAEhE;AAED,wBAAsB,gBAAgB,CAAC,IAAI,EAAE;IAC3C,OAAO,EAAE,MAAM,CAAC;IAChB,eAAe,CAAC,EAAE,SAAS,0BAA0B,EAAE,CAAC;CACzD,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAK9B;AAED,wBAAsB,iBAAiB,CAAC,IAAI,EAAE;IAC5C,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,eAAe,CAAC,EAAE,SAAS,0BAA0B,EAAE,CAAC;IACxD,OAAO,EAAE,MAAM,CAAC;CACjB,GAAG,OAAO,CAAC,uBAAuB,CAAC,CAuBnC;AAED,wBAAsB,mBAAmB,CAAC,IAAI,EAAE;IAC9C,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;CACvB,GAAG,OAAO,CAAC,IAAI,CAAC,CAUhB;AAED,wBAAsB,+BAA+B,CAAC,IAAI,EAAE;IAC1D,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;CACpB,GAAG,OAAO,CAAC,IAAI,CAAC,CAgBhB"}
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
import { promises as fs } from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
export function globalSkillsRoot(homeDir) {
|
|
4
|
+
return path.join(homeDir, ".agents", "skills");
|
|
5
|
+
}
|
|
6
|
+
export function globalDisabledSkillsRoot(homeDir) {
|
|
7
|
+
return path.join(homeDir, ".agents", ".disabled-skills");
|
|
8
|
+
}
|
|
9
|
+
export async function listGlobalSkills(args) {
|
|
10
|
+
const skills = await discoverGlobalSkillRecords(args.homeDir);
|
|
11
|
+
return {
|
|
12
|
+
skills: skills.map((skill) => toCatalogEntry(skill, args.providerSupport)),
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
export async function updateGlobalSkill(args) {
|
|
16
|
+
const skills = await discoverGlobalSkillRecords(args.homeDir);
|
|
17
|
+
const skill = skills.find((entry) => entry.id === args.skillId);
|
|
18
|
+
if (!skill) {
|
|
19
|
+
throw new Error(`Unknown global skill id: ${args.skillId}`);
|
|
20
|
+
}
|
|
21
|
+
if (skill.enabled !== args.enabled) {
|
|
22
|
+
const targetRoot = args.enabled
|
|
23
|
+
? globalSkillsRoot(args.homeDir)
|
|
24
|
+
: globalDisabledSkillsRoot(args.homeDir);
|
|
25
|
+
const targetPath = path.join(targetRoot, skill.name);
|
|
26
|
+
await fs.mkdir(targetRoot, { recursive: true });
|
|
27
|
+
await fs.rm(targetPath, { recursive: true, force: true });
|
|
28
|
+
await fs.rename(skill.sourcePath, targetPath);
|
|
29
|
+
}
|
|
30
|
+
const updated = (await discoverGlobalSkillRecords(args.homeDir)).find((entry) => entry.id === args.skillId);
|
|
31
|
+
if (!updated) {
|
|
32
|
+
throw new Error(`Global skill disappeared after update: ${args.skillId}`);
|
|
33
|
+
}
|
|
34
|
+
return toCatalogEntry(updated, args.providerSupport);
|
|
35
|
+
}
|
|
36
|
+
export async function projectGlobalSkills(args) {
|
|
37
|
+
const targetRoot = globalSkillsRoot(args.targetHomeDir);
|
|
38
|
+
await syncEnabledGlobalSkillsToTarget({
|
|
39
|
+
sourceHomeDir: args.sourceHomeDir,
|
|
40
|
+
targetRoot,
|
|
41
|
+
});
|
|
42
|
+
await fs.rm(globalDisabledSkillsRoot(args.targetHomeDir), {
|
|
43
|
+
recursive: true,
|
|
44
|
+
force: true,
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
export async function syncEnabledGlobalSkillsToTarget(args) {
|
|
48
|
+
const skills = await discoverGlobalSkillRecords(args.sourceHomeDir);
|
|
49
|
+
await fs.rm(args.targetRoot, { recursive: true, force: true });
|
|
50
|
+
for (const skill of skills) {
|
|
51
|
+
if (!skill.enabled) {
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
const targetPath = path.join(args.targetRoot, skill.name);
|
|
55
|
+
await fs.mkdir(args.targetRoot, { recursive: true });
|
|
56
|
+
await fs.cp(skill.sourcePath, targetPath, {
|
|
57
|
+
recursive: true,
|
|
58
|
+
dereference: true,
|
|
59
|
+
errorOnExist: false,
|
|
60
|
+
force: true,
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
async function discoverGlobalSkillRecords(homeDir) {
|
|
65
|
+
const records = new Map();
|
|
66
|
+
for (const enabled of [true, false]) {
|
|
67
|
+
const root = enabled ? globalSkillsRoot(homeDir) : globalDisabledSkillsRoot(homeDir);
|
|
68
|
+
for (const entry of await discoverSkillDirectories(root)) {
|
|
69
|
+
if (records.has(entry.name)) {
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
const markdown = await fs.readFile(path.join(entry.path, "SKILL.md"), "utf8");
|
|
73
|
+
records.set(entry.name, {
|
|
74
|
+
id: entry.name,
|
|
75
|
+
label: readSkillLabel(markdown, entry.name),
|
|
76
|
+
summary: readSkillSummary(markdown),
|
|
77
|
+
enabled,
|
|
78
|
+
name: entry.name,
|
|
79
|
+
sourcePath: entry.path,
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return [...records.values()].sort((left, right) => left.label.localeCompare(right.label));
|
|
84
|
+
}
|
|
85
|
+
async function discoverSkillDirectories(root) {
|
|
86
|
+
let entries;
|
|
87
|
+
try {
|
|
88
|
+
entries = await fs.readdir(root, { withFileTypes: true });
|
|
89
|
+
}
|
|
90
|
+
catch (error) {
|
|
91
|
+
if (error.code === "ENOENT") {
|
|
92
|
+
return [];
|
|
93
|
+
}
|
|
94
|
+
throw error;
|
|
95
|
+
}
|
|
96
|
+
const skills = [];
|
|
97
|
+
for (const entry of entries) {
|
|
98
|
+
if (entry.name.startsWith(".")) {
|
|
99
|
+
continue;
|
|
100
|
+
}
|
|
101
|
+
if (!entry.isDirectory() && !entry.isSymbolicLink()) {
|
|
102
|
+
continue;
|
|
103
|
+
}
|
|
104
|
+
const skillDir = path.join(root, entry.name);
|
|
105
|
+
try {
|
|
106
|
+
const stat = await fs.stat(path.join(skillDir, "SKILL.md"));
|
|
107
|
+
if (!stat.isFile()) {
|
|
108
|
+
continue;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
catch (error) {
|
|
112
|
+
if (error.code === "ENOENT") {
|
|
113
|
+
continue;
|
|
114
|
+
}
|
|
115
|
+
throw error;
|
|
116
|
+
}
|
|
117
|
+
skills.push({
|
|
118
|
+
name: entry.name,
|
|
119
|
+
path: skillDir,
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
return skills.sort((left, right) => left.name.localeCompare(right.name));
|
|
123
|
+
}
|
|
124
|
+
function toCatalogEntry(skill, providerSupport) {
|
|
125
|
+
return {
|
|
126
|
+
id: skill.id,
|
|
127
|
+
label: skill.label,
|
|
128
|
+
summary: skill.summary,
|
|
129
|
+
enabled: skill.enabled,
|
|
130
|
+
providerSupport: [...(providerSupport ?? [])],
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
function readSkillLabel(markdown, fallback) {
|
|
134
|
+
for (const line of contentLines(markdown)) {
|
|
135
|
+
const match = line.match(/^#\s+(.+)$/u);
|
|
136
|
+
if (match?.[1]?.trim()) {
|
|
137
|
+
return match[1].trim();
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
return fallback;
|
|
141
|
+
}
|
|
142
|
+
function readSkillSummary(markdown) {
|
|
143
|
+
const paragraph = [];
|
|
144
|
+
let inCodeBlock = false;
|
|
145
|
+
for (const line of contentLines(markdown)) {
|
|
146
|
+
const trimmed = line.trim();
|
|
147
|
+
if (trimmed.startsWith("```")) {
|
|
148
|
+
inCodeBlock = !inCodeBlock;
|
|
149
|
+
continue;
|
|
150
|
+
}
|
|
151
|
+
if (inCodeBlock || trimmed.length === 0 || trimmed.startsWith("#")) {
|
|
152
|
+
if (paragraph.length > 0 && trimmed.length === 0) {
|
|
153
|
+
break;
|
|
154
|
+
}
|
|
155
|
+
continue;
|
|
156
|
+
}
|
|
157
|
+
paragraph.push(trimmed);
|
|
158
|
+
}
|
|
159
|
+
return paragraph.length > 0 ? paragraph.join(" ") : null;
|
|
160
|
+
}
|
|
161
|
+
function contentLines(markdown) {
|
|
162
|
+
const lines = markdown.split(/\r?\n/u);
|
|
163
|
+
if (lines[0]?.trim() !== "---") {
|
|
164
|
+
return lines;
|
|
165
|
+
}
|
|
166
|
+
const closingIndex = lines.findIndex((line, index) => index > 0 && line.trim() === "---");
|
|
167
|
+
return closingIndex >= 0 ? lines.slice(closingIndex + 1) : lines;
|
|
168
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import type { ExecutionTrace, HarnessEvent, HarnessAuth, HarnessSession, JsonValue, WorkflowDocument, WorkflowHarness, WorkspaceMode } from "./types.js";
|
|
3
|
+
export * from "./behavior-contract.js";
|
|
4
|
+
export * from "./access-contracts.js";
|
|
5
|
+
export * from "./conformance.js";
|
|
6
|
+
export * from "./global-skills.js";
|
|
7
|
+
export * from "./internal-utils.js";
|
|
8
|
+
export * from "./json-rpc.js";
|
|
9
|
+
export * from "./managed-runtime.js";
|
|
10
|
+
export * from "./model-config.js";
|
|
11
|
+
export * from "./normalized-activity.js";
|
|
12
|
+
export * from "./prepare.js";
|
|
13
|
+
export * from "./process-env.js";
|
|
14
|
+
export * from "./session-runtime.js";
|
|
15
|
+
export * from "./trace-builder.js";
|
|
16
|
+
export * from "./trace-replay.js";
|
|
17
|
+
export * from "./tool-semantics.js";
|
|
18
|
+
export * from "./types.js";
|
|
19
|
+
export interface HarnessExecutionPlan extends Pick<WorkflowDocument, "workspace"> {
|
|
20
|
+
harness: WorkflowHarness;
|
|
21
|
+
}
|
|
22
|
+
type WorkflowHarnessCancel = HarnessExecutionPlan["harness"]["cancel"];
|
|
23
|
+
export interface HarnessCapabilities {
|
|
24
|
+
supports_resume: boolean;
|
|
25
|
+
supports_interrupt: boolean;
|
|
26
|
+
required_runtime_capabilities: string[];
|
|
27
|
+
}
|
|
28
|
+
export interface HarnessManifest {
|
|
29
|
+
id: string;
|
|
30
|
+
display_name: string;
|
|
31
|
+
auth_schema: JsonValue;
|
|
32
|
+
config_schema: JsonValue;
|
|
33
|
+
defaults: {
|
|
34
|
+
auth?: HarnessAuth;
|
|
35
|
+
model?: string;
|
|
36
|
+
effort?: string;
|
|
37
|
+
turn_timeout_ms?: number;
|
|
38
|
+
stall_timeout_ms?: number;
|
|
39
|
+
config?: Record<string, JsonValue>;
|
|
40
|
+
};
|
|
41
|
+
capabilities: HarnessCapabilities;
|
|
42
|
+
supported_workspace_modes: WorkspaceMode[];
|
|
43
|
+
}
|
|
44
|
+
export interface HarnessValidationSchemas<TAuth extends Record<string, JsonValue> = Record<string, JsonValue>, TConfig extends Record<string, JsonValue> = Record<string, JsonValue>> {
|
|
45
|
+
auth: z.ZodType<TAuth>;
|
|
46
|
+
config: z.ZodType<TConfig>;
|
|
47
|
+
}
|
|
48
|
+
export interface HarnessReadinessContext {
|
|
49
|
+
repoRoot: string;
|
|
50
|
+
runtimeHome: string;
|
|
51
|
+
parentEnv?: NodeJS.ProcessEnv;
|
|
52
|
+
}
|
|
53
|
+
export interface HarnessReadinessCheckArgs extends HarnessReadinessContext {
|
|
54
|
+
plan: HarnessExecutionPlan;
|
|
55
|
+
}
|
|
56
|
+
export interface HarnessReadinessResult {
|
|
57
|
+
availability_errors: string[];
|
|
58
|
+
}
|
|
59
|
+
export interface HarnessTurnLiveBatch {
|
|
60
|
+
harnessEvents: HarnessEvent[];
|
|
61
|
+
traceBundle: {
|
|
62
|
+
spans: ExecutionTrace["spans"];
|
|
63
|
+
events: ExecutionTrace["events"];
|
|
64
|
+
summaries: ExecutionTrace["summaries"];
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
export interface HarnessTurnLivePersistence {
|
|
68
|
+
flushWindowMs?: number;
|
|
69
|
+
onFlush: (batch: HarnessTurnLiveBatch) => Promise<void>;
|
|
70
|
+
}
|
|
71
|
+
export interface HarnessRunResult {
|
|
72
|
+
sessionId: string;
|
|
73
|
+
finalOutput: string;
|
|
74
|
+
trace: ExecutionTrace;
|
|
75
|
+
events: HarnessEvent[];
|
|
76
|
+
}
|
|
77
|
+
export type HarnessSessionMode = "fresh" | "resume";
|
|
78
|
+
export interface StartSessionArgs {
|
|
79
|
+
repoRoot: string;
|
|
80
|
+
runtimeHome: string;
|
|
81
|
+
plan: HarnessExecutionPlan;
|
|
82
|
+
ownerId: string;
|
|
83
|
+
executionId: string;
|
|
84
|
+
attemptNumber: number;
|
|
85
|
+
stageId: string;
|
|
86
|
+
stageRunIndex: number;
|
|
87
|
+
workspacePath: string;
|
|
88
|
+
ownerStageId: string;
|
|
89
|
+
sessionMode: HarnessSessionMode;
|
|
90
|
+
persistedSession: Record<string, JsonValue> | null;
|
|
91
|
+
stageSessionPath: string;
|
|
92
|
+
}
|
|
93
|
+
export interface StartTurnArgs {
|
|
94
|
+
prompt: string;
|
|
95
|
+
eventsFile: string;
|
|
96
|
+
rawEventsFile: string;
|
|
97
|
+
stageSpanId: string;
|
|
98
|
+
plan: HarnessExecutionPlan;
|
|
99
|
+
livePersistence?: HarnessTurnLivePersistence;
|
|
100
|
+
}
|
|
101
|
+
export interface ActiveHarnessSession<TState = unknown> {
|
|
102
|
+
adapter: HarnessAdapter<TState>;
|
|
103
|
+
ownerStageId: string;
|
|
104
|
+
session: HarnessSession;
|
|
105
|
+
state: TState;
|
|
106
|
+
}
|
|
107
|
+
export interface HarnessAdapter<TState = unknown> {
|
|
108
|
+
readonly manifest: HarnessManifest;
|
|
109
|
+
getManagedWorkspaceIgnoreEntries(plan: HarnessExecutionPlan): string[];
|
|
110
|
+
startSession(args: StartSessionArgs): Promise<ActiveHarnessSession<TState>>;
|
|
111
|
+
startTurn(context: ActiveHarnessSession<TState>, args: StartTurnArgs): Promise<HarnessRunResult>;
|
|
112
|
+
interruptTurn(context: ActiveHarnessSession<TState>): Promise<void>;
|
|
113
|
+
closeSession(context: ActiveHarnessSession<TState>, cancelConfig?: WorkflowHarnessCancel): Promise<void>;
|
|
114
|
+
}
|
|
115
|
+
export interface HarnessProvider<TState = unknown, TAuth extends Record<string, JsonValue> = Record<string, JsonValue>, TConfig extends Record<string, JsonValue> = Record<string, JsonValue>> {
|
|
116
|
+
readonly manifest: HarnessManifest;
|
|
117
|
+
readonly schemas: HarnessValidationSchemas<TAuth, TConfig>;
|
|
118
|
+
checkReadiness?(args: HarnessReadinessCheckArgs): Promise<HarnessReadinessResult>;
|
|
119
|
+
create(): HarnessAdapter<TState>;
|
|
120
|
+
}
|
|
121
|
+
export declare function defineHarnessProvider<TState = unknown, TAuth extends Record<string, JsonValue> = Record<string, JsonValue>, TConfig extends Record<string, JsonValue> = Record<string, JsonValue>>(factory: HarnessProvider<TState, TAuth, TConfig>): HarnessProvider<TState, TAuth, TConfig>;
|
|
122
|
+
export declare function createCliHarnessManifest(args: {
|
|
123
|
+
id: string;
|
|
124
|
+
displayName?: string;
|
|
125
|
+
auth: z.ZodTypeAny;
|
|
126
|
+
config: z.ZodTypeAny;
|
|
127
|
+
defaults?: {
|
|
128
|
+
auth?: HarnessAuth;
|
|
129
|
+
model?: string;
|
|
130
|
+
effort?: string;
|
|
131
|
+
turn_timeout_ms?: number;
|
|
132
|
+
stall_timeout_ms?: number;
|
|
133
|
+
config?: Record<string, JsonValue>;
|
|
134
|
+
};
|
|
135
|
+
capabilities: HarnessManifest["capabilities"];
|
|
136
|
+
supportedWorkspaceModes: readonly WorkspaceMode[];
|
|
137
|
+
}): HarnessManifest;
|
|
138
|
+
//# sourceMappingURL=index.d.ts.map
|