@vercel/factory 0.0.20 → 0.0.22
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 +16 -0
- package/dist/build-factory.d.mts +1 -1
- package/dist/build-factory.mjs +2 -1
- package/dist/build-factory.mjs.map +1 -1
- package/dist/client.d.mts +4 -4
- package/dist/client.mjs +1 -0
- package/dist/client.mjs.map +1 -1
- package/dist/eve/task-execution.d.mts +16 -16
- package/dist/github.d.mts +21 -1
- package/dist/github.mjs +25 -1
- package/dist/github.mjs.map +1 -1
- package/dist/intake-contracts.d.mts +2 -2
- package/dist/integrations/github.d.mts +2 -2
- package/dist/integrations/github.mjs +2 -2
- package/dist/repository-scripts.d.mts +221 -0
- package/dist/repository-scripts.mjs +330 -0
- package/dist/repository-scripts.mjs.map +1 -0
- package/dist/schema/task-graph.d.mts +96 -96
- package/dist/schema/transcript.d.mts +4 -4
- package/dist/vercel-github-api.mjs +11 -10
- package/dist/vercel-github-api.mjs.map +1 -1
- package/docs/recipes/repository-scripts.md +64 -0
- package/package.json +8 -4
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
import { RepositoryId, SignalId } from "./schema/id.mjs";
|
|
2
|
+
import { Task } from "./schema/task.mjs";
|
|
3
|
+
import { WorkflowDefinition } from "./workflows.mjs";
|
|
4
|
+
import { MaybePromise, ReplyTo } from "./schema/common.mjs";
|
|
5
|
+
import { RepositorySlug } from "./schema/repository.mjs";
|
|
6
|
+
import { FactoryStores } from "./store/engine.mjs";
|
|
7
|
+
import { DispatchBudget } from "./dispatch.mjs";
|
|
8
|
+
import { ConditionalStateStore } from "./store/state.mjs";
|
|
9
|
+
import { z } from "zod";
|
|
10
|
+
//#region src/repository-scripts.d.ts
|
|
11
|
+
/** Events currently available to repository-defined scripts. */
|
|
12
|
+
declare const repositoryScriptEventNames: readonly ["github.issues.opened"];
|
|
13
|
+
/** Name of an event available to repository-defined scripts. */
|
|
14
|
+
type RepositoryScriptEventName = (typeof repositoryScriptEventNames)[number];
|
|
15
|
+
/** Validates an opened GitHub issue supplied to a repository script. */
|
|
16
|
+
declare const repositoryScriptEventSchema: z.ZodObject<{
|
|
17
|
+
name: z.ZodLiteral<"github.issues.opened">;
|
|
18
|
+
deliveryId: z.ZodString;
|
|
19
|
+
repository: z.ZodType<`${string}/${string}`, string, z.core.$ZodTypeInternals<`${string}/${string}`, string>>;
|
|
20
|
+
issue: z.ZodObject<{
|
|
21
|
+
number: z.ZodNumber;
|
|
22
|
+
title: z.ZodString;
|
|
23
|
+
body: z.ZodNullable<z.ZodString>;
|
|
24
|
+
}, z.core.$strict>;
|
|
25
|
+
}, z.core.$strict>;
|
|
26
|
+
/** Normalized event passed to a repository-defined script. */
|
|
27
|
+
type RepositoryScriptEvent = z.infer<typeof repositoryScriptEventSchema>;
|
|
28
|
+
/** Capabilities a repository-defined script may request explicitly. */
|
|
29
|
+
declare const repositoryScriptPermissions: readonly ["ai:classify", "github:issues:comment", "github:issues:label"];
|
|
30
|
+
/** Capability granted to a repository-defined script. */
|
|
31
|
+
type RepositoryScriptPermission = (typeof repositoryScriptPermissions)[number];
|
|
32
|
+
/** Validates one bounded action returned by a repository-defined script. */
|
|
33
|
+
declare const repositoryScriptActionSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
34
|
+
type: z.ZodLiteral<"github.issue.comment">;
|
|
35
|
+
body: z.ZodString;
|
|
36
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
37
|
+
type: z.ZodLiteral<"github.issue.addLabel">;
|
|
38
|
+
label: z.ZodObject<{
|
|
39
|
+
name: z.ZodString;
|
|
40
|
+
color: z.ZodString;
|
|
41
|
+
description: z.ZodString;
|
|
42
|
+
}, z.core.$strict>;
|
|
43
|
+
}, z.core.$strict>], "type">;
|
|
44
|
+
/** Bounded side effect requested by a repository-defined script. */
|
|
45
|
+
type RepositoryScriptAction = z.infer<typeof repositoryScriptActionSchema>;
|
|
46
|
+
/** Validates a bounded classification request made by a repository script. */
|
|
47
|
+
declare const repositoryScriptClassificationInputSchema: z.ZodObject<{
|
|
48
|
+
instruction: z.ZodString;
|
|
49
|
+
subject: z.ZodString;
|
|
50
|
+
choices: z.ZodReadonly<z.ZodArray<z.ZodString>>;
|
|
51
|
+
}, z.core.$strict>;
|
|
52
|
+
/** Bounded classification request made by a repository script. */
|
|
53
|
+
type RepositoryScriptClassificationInput = z.infer<typeof repositoryScriptClassificationInputSchema>;
|
|
54
|
+
/** Validates a structured classification returned to a repository script. */
|
|
55
|
+
declare const repositoryScriptClassificationSchema: z.ZodObject<{
|
|
56
|
+
choice: z.ZodString;
|
|
57
|
+
reason: z.ZodString;
|
|
58
|
+
}, z.core.$strict>;
|
|
59
|
+
/** Structured classification returned to a repository script. */
|
|
60
|
+
type RepositoryScriptClassification = z.infer<typeof repositoryScriptClassificationSchema>;
|
|
61
|
+
/** Input and scoped helpers available while one repository script computes its action plan. */
|
|
62
|
+
interface RepositoryScriptRunContext {
|
|
63
|
+
/** Normalized event that selected the script. */
|
|
64
|
+
readonly event: RepositoryScriptEvent;
|
|
65
|
+
/** Run one bounded model classification when the script declares `ai:classify`. */
|
|
66
|
+
classify(input: RepositoryScriptClassificationInput): Promise<RepositoryScriptClassification>;
|
|
67
|
+
}
|
|
68
|
+
/** Action plan returned by one repository-defined script. */
|
|
69
|
+
interface RepositoryScriptRunResult {
|
|
70
|
+
/** Ordered, bounded effects Factory should apply to the event's issue. */
|
|
71
|
+
readonly actions: readonly RepositoryScriptAction[];
|
|
72
|
+
}
|
|
73
|
+
/** Repository-owned definition of one exact script version. */
|
|
74
|
+
interface RepositoryScriptDefinition {
|
|
75
|
+
/** Stable script identity used for durable Task deduplication. */
|
|
76
|
+
readonly id: string;
|
|
77
|
+
/** Exact positive version retained while Tasks may still reference it. */
|
|
78
|
+
readonly version: number;
|
|
79
|
+
/** Whether this version receives new matching events. Keep old versions inactive for recovery. */
|
|
80
|
+
readonly active: boolean;
|
|
81
|
+
/** Events that start this script. */
|
|
82
|
+
readonly on: readonly RepositoryScriptEventName[];
|
|
83
|
+
/** Optional repository filter; absent applies to every configured repository. */
|
|
84
|
+
readonly repositories?: readonly RepositorySlug[];
|
|
85
|
+
/** Capabilities this script may use. */
|
|
86
|
+
readonly permissions: readonly RepositoryScriptPermission[];
|
|
87
|
+
/** Compute a bounded action plan. Provider credentials are never passed to this callback. */
|
|
88
|
+
run(context: RepositoryScriptRunContext): MaybePromise<RepositoryScriptRunResult>;
|
|
89
|
+
}
|
|
90
|
+
/** Caller input accepted when defining one repository script. */
|
|
91
|
+
type RepositoryScriptDefinitionInput = Omit<RepositoryScriptDefinition, "active"> & {
|
|
92
|
+
/** Defaults to true; false retains an old version only for Task recovery. */
|
|
93
|
+
readonly active?: boolean;
|
|
94
|
+
};
|
|
95
|
+
/** Validate and freeze one exact repository-script definition. */
|
|
96
|
+
declare function defineRepositoryScript(input: RepositoryScriptDefinitionInput): Readonly<RepositoryScriptDefinition>;
|
|
97
|
+
/** Immutable exact-version registry for repository-defined scripts. */
|
|
98
|
+
interface RepositoryScriptRegistry {
|
|
99
|
+
/** Registered definitions in declaration order. */
|
|
100
|
+
readonly definitions: readonly Readonly<RepositoryScriptDefinition>[];
|
|
101
|
+
/** Select active definitions matching an event and its repository. */
|
|
102
|
+
match(event: RepositoryScriptEvent): readonly Readonly<RepositoryScriptDefinition>[];
|
|
103
|
+
/** Resolve one exact persisted script binding. */
|
|
104
|
+
resolve(binding: {
|
|
105
|
+
readonly id: string;
|
|
106
|
+
readonly version: number;
|
|
107
|
+
}): Readonly<RepositoryScriptDefinition>;
|
|
108
|
+
}
|
|
109
|
+
/** Validate repository scripts and build an exact-version event registry. */
|
|
110
|
+
declare function defineRepositoryScripts(inputs: readonly RepositoryScriptDefinitionInput[]): RepositoryScriptRegistry;
|
|
111
|
+
/** Validates the durable result of a repository-script Task. */
|
|
112
|
+
declare const repositoryScriptResultSchema: z.ZodObject<{
|
|
113
|
+
script: z.ZodObject<{
|
|
114
|
+
id: z.ZodString;
|
|
115
|
+
version: z.ZodNumber;
|
|
116
|
+
}, z.core.$strict>;
|
|
117
|
+
actions: z.ZodReadonly<z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
118
|
+
type: z.ZodLiteral<"github.issue.comment">;
|
|
119
|
+
body: z.ZodString;
|
|
120
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
121
|
+
type: z.ZodLiteral<"github.issue.addLabel">;
|
|
122
|
+
label: z.ZodObject<{
|
|
123
|
+
name: z.ZodString;
|
|
124
|
+
color: z.ZodString;
|
|
125
|
+
description: z.ZodString;
|
|
126
|
+
}, z.core.$strict>;
|
|
127
|
+
}, z.core.$strict>], "type">>>;
|
|
128
|
+
classifications: z.ZodReadonly<z.ZodArray<z.ZodObject<{
|
|
129
|
+
choice: z.ZodString;
|
|
130
|
+
reason: z.ZodString;
|
|
131
|
+
instruction: z.ZodString;
|
|
132
|
+
}, z.core.$strict>>>;
|
|
133
|
+
}, z.core.$strict>;
|
|
134
|
+
/** Durable result of a repository-script Task. */
|
|
135
|
+
type RepositoryScriptResult = z.infer<typeof repositoryScriptResultSchema>;
|
|
136
|
+
/** Exact workflow contract used by repository-script Tasks. */
|
|
137
|
+
declare const repositoryScriptWorkflow: Readonly<WorkflowDefinition<z.ZodObject<{
|
|
138
|
+
script: z.ZodObject<{
|
|
139
|
+
id: z.ZodString;
|
|
140
|
+
version: z.ZodNumber;
|
|
141
|
+
}, z.core.$strict>;
|
|
142
|
+
event: z.ZodObject<{
|
|
143
|
+
name: z.ZodLiteral<"github.issues.opened">;
|
|
144
|
+
deliveryId: z.ZodString;
|
|
145
|
+
repository: z.ZodType<`${string}/${string}`, string, z.core.$ZodTypeInternals<`${string}/${string}`, string>>;
|
|
146
|
+
issue: z.ZodObject<{
|
|
147
|
+
number: z.ZodNumber;
|
|
148
|
+
title: z.ZodString;
|
|
149
|
+
body: z.ZodNullable<z.ZodString>;
|
|
150
|
+
}, z.core.$strict>;
|
|
151
|
+
}, z.core.$strict>;
|
|
152
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
153
|
+
script: z.ZodObject<{
|
|
154
|
+
id: z.ZodString;
|
|
155
|
+
version: z.ZodNumber;
|
|
156
|
+
}, z.core.$strict>;
|
|
157
|
+
actions: z.ZodReadonly<z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
158
|
+
type: z.ZodLiteral<"github.issue.comment">;
|
|
159
|
+
body: z.ZodString;
|
|
160
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
161
|
+
type: z.ZodLiteral<"github.issue.addLabel">;
|
|
162
|
+
label: z.ZodObject<{
|
|
163
|
+
name: z.ZodString;
|
|
164
|
+
color: z.ZodString;
|
|
165
|
+
description: z.ZodString;
|
|
166
|
+
}, z.core.$strict>;
|
|
167
|
+
}, z.core.$strict>], "type">>>;
|
|
168
|
+
classifications: z.ZodReadonly<z.ZodArray<z.ZodObject<{
|
|
169
|
+
choice: z.ZodString;
|
|
170
|
+
reason: z.ZodString;
|
|
171
|
+
instruction: z.ZodString;
|
|
172
|
+
}, z.core.$strict>>>;
|
|
173
|
+
}, z.core.$strict>, "repository-script", 1>>;
|
|
174
|
+
/** Dependencies required to classify one repository-script request. */
|
|
175
|
+
interface RepositoryScriptClassifierContext {
|
|
176
|
+
/** Exact running Task whose usage and authority cover the model call. */
|
|
177
|
+
readonly task: Task;
|
|
178
|
+
/** Validated bounded classification request. */
|
|
179
|
+
readonly input: RepositoryScriptClassificationInput;
|
|
180
|
+
/** Zero-based classification index within the script invocation. */
|
|
181
|
+
readonly index: number;
|
|
182
|
+
}
|
|
183
|
+
/** Dependencies required to apply one repository-script action. */
|
|
184
|
+
interface RepositoryScriptActionContext {
|
|
185
|
+
/** Exact running Task whose authority covers the effect. */
|
|
186
|
+
readonly task: Task;
|
|
187
|
+
/** Normalized event that bounds the target repository and issue. */
|
|
188
|
+
readonly event: RepositoryScriptEvent;
|
|
189
|
+
/** Validated action to apply. */
|
|
190
|
+
readonly action: RepositoryScriptAction;
|
|
191
|
+
/** Stable zero-based action index, suitable for an idempotency marker. */
|
|
192
|
+
readonly index: number;
|
|
193
|
+
}
|
|
194
|
+
/** Store capabilities used by repository-script admission and completion. */
|
|
195
|
+
type RepositoryScriptStores = Pick<FactoryStores, "graphs" | "receipts" | "tasks" | "work">;
|
|
196
|
+
/** Input for admitting and running every script matched by one Signal event. */
|
|
197
|
+
interface RunRepositoryScriptEventOptions {
|
|
198
|
+
readonly stores: RepositoryScriptStores;
|
|
199
|
+
readonly state: Pick<ConditionalStateStore, "read" | "write">;
|
|
200
|
+
readonly registry: RepositoryScriptRegistry;
|
|
201
|
+
readonly repositoryId: RepositoryId;
|
|
202
|
+
readonly signalId: SignalId;
|
|
203
|
+
readonly replyTo: ReplyTo;
|
|
204
|
+
readonly event: RepositoryScriptEvent;
|
|
205
|
+
readonly classify: (context: RepositoryScriptClassifierContext) => Promise<RepositoryScriptClassification>;
|
|
206
|
+
readonly applyAction: (context: RepositoryScriptActionContext) => Promise<void>;
|
|
207
|
+
readonly budget?: DispatchBudget;
|
|
208
|
+
readonly maxAttempts?: number;
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* Admit and execute every repository script selected for one normalized event.
|
|
212
|
+
*
|
|
213
|
+
* The exact selection is persisted per Signal before admission, so retries retain inactive script
|
|
214
|
+
* versions. The Task deduplication key is stable per Signal and script ID. Each script's validated
|
|
215
|
+
* result is persisted before effects, so retries reuse the same plan. Effect adapters must use the
|
|
216
|
+
* supplied Task and action index to reconcile ambiguous writes.
|
|
217
|
+
*/
|
|
218
|
+
declare function runRepositoryScriptEvent(options: RunRepositoryScriptEventOptions): Promise<readonly Task[]>;
|
|
219
|
+
//#endregion
|
|
220
|
+
export { RepositoryScriptAction, RepositoryScriptActionContext, RepositoryScriptClassification, RepositoryScriptClassificationInput, RepositoryScriptClassifierContext, RepositoryScriptDefinition, RepositoryScriptDefinitionInput, RepositoryScriptEvent, RepositoryScriptEventName, RepositoryScriptPermission, RepositoryScriptRegistry, RepositoryScriptResult, RepositoryScriptRunContext, RepositoryScriptRunResult, RepositoryScriptStores, RunRepositoryScriptEventOptions, defineRepositoryScript, defineRepositoryScripts, repositoryScriptActionSchema, repositoryScriptClassificationInputSchema, repositoryScriptClassificationSchema, repositoryScriptEventNames, repositoryScriptEventSchema, repositoryScriptPermissions, repositoryScriptResultSchema, repositoryScriptWorkflow, runRepositoryScriptEvent };
|
|
221
|
+
//# sourceMappingURL=repository-scripts.d.mts.map
|
|
@@ -0,0 +1,330 @@
|
|
|
1
|
+
import { repositorySlugSchema } from "./schema/repository.mjs";
|
|
2
|
+
import { taskWork } from "./schema/work.mjs";
|
|
3
|
+
import { VersionConflictError } from "./store/driver.mjs";
|
|
4
|
+
import { dispatchTask } from "./dispatch.mjs";
|
|
5
|
+
import { defineWorkflow } from "./workflows.mjs";
|
|
6
|
+
import { z } from "zod";
|
|
7
|
+
//#region src/repository-scripts.ts
|
|
8
|
+
const scriptIdSchema = z.string().regex(/^[a-z][a-z0-9-]{0,63}$/u).describe("Stable lowercase repository-script identifier.");
|
|
9
|
+
/** Events currently available to repository-defined scripts. */
|
|
10
|
+
const repositoryScriptEventNames = ["github.issues.opened"];
|
|
11
|
+
/** Validates an opened GitHub issue supplied to a repository script. */
|
|
12
|
+
const repositoryScriptEventSchema = z.strictObject({
|
|
13
|
+
name: z.literal("github.issues.opened"),
|
|
14
|
+
deliveryId: z.string().min(1).max(256),
|
|
15
|
+
repository: repositorySlugSchema,
|
|
16
|
+
issue: z.strictObject({
|
|
17
|
+
number: z.number().int().positive(),
|
|
18
|
+
title: z.string().max(1024),
|
|
19
|
+
body: z.string().max(65536).nullable()
|
|
20
|
+
})
|
|
21
|
+
}).describe("Normalized, bounded event passed to a repository-defined script.");
|
|
22
|
+
/** Capabilities a repository-defined script may request explicitly. */
|
|
23
|
+
const repositoryScriptPermissions = [
|
|
24
|
+
"ai:classify",
|
|
25
|
+
"github:issues:comment",
|
|
26
|
+
"github:issues:label"
|
|
27
|
+
];
|
|
28
|
+
const repositoryScriptPermissionSchema = z.enum(repositoryScriptPermissions);
|
|
29
|
+
/** Validates one bounded action returned by a repository-defined script. */
|
|
30
|
+
const repositoryScriptActionSchema = z.discriminatedUnion("type", [z.strictObject({
|
|
31
|
+
type: z.literal("github.issue.comment"),
|
|
32
|
+
body: z.string().trim().min(1).max(1e4)
|
|
33
|
+
}), z.strictObject({
|
|
34
|
+
type: z.literal("github.issue.addLabel"),
|
|
35
|
+
label: z.strictObject({
|
|
36
|
+
name: z.string().trim().min(1).max(50),
|
|
37
|
+
color: z.string().regex(/^[a-fA-F0-9]{6}$/u),
|
|
38
|
+
description: z.string().max(100)
|
|
39
|
+
})
|
|
40
|
+
})]);
|
|
41
|
+
/** Validates a bounded classification request made by a repository script. */
|
|
42
|
+
const repositoryScriptClassificationInputSchema = z.strictObject({
|
|
43
|
+
instruction: z.string().trim().min(1).max(4e3),
|
|
44
|
+
subject: z.string().trim().min(1).max(16e3),
|
|
45
|
+
choices: z.array(z.string().trim().min(1).max(100)).min(2).max(32).refine((choices) => new Set(choices).size === choices.length, "choices must be unique").readonly()
|
|
46
|
+
}).describe("Instruction, untrusted subject, and allowed results for one classification.");
|
|
47
|
+
/** Validates a structured classification returned to a repository script. */
|
|
48
|
+
const repositoryScriptClassificationSchema = z.strictObject({
|
|
49
|
+
choice: z.string().trim().min(1).max(100),
|
|
50
|
+
reason: z.string().trim().min(1).max(2e3)
|
|
51
|
+
}).describe("Selected allowed choice and a bounded explanation.");
|
|
52
|
+
const repositoryScriptMetadataSchema = z.strictObject({
|
|
53
|
+
id: scriptIdSchema,
|
|
54
|
+
version: z.number().int().positive(),
|
|
55
|
+
active: z.boolean().default(true),
|
|
56
|
+
on: z.array(z.enum(repositoryScriptEventNames)).min(1).readonly(),
|
|
57
|
+
repositories: z.array(repositorySlugSchema).min(1).readonly().optional(),
|
|
58
|
+
permissions: z.array(repositoryScriptPermissionSchema).readonly()
|
|
59
|
+
});
|
|
60
|
+
/** Validate and freeze one exact repository-script definition. */
|
|
61
|
+
function defineRepositoryScript(input) {
|
|
62
|
+
if (typeof input.run !== "function") throw new Error("Repository script run must be a function");
|
|
63
|
+
const { run, ...candidate } = input;
|
|
64
|
+
const metadata = repositoryScriptMetadataSchema.parse(candidate);
|
|
65
|
+
return Object.freeze({
|
|
66
|
+
...metadata,
|
|
67
|
+
run
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
/** Validate repository scripts and build an exact-version event registry. */
|
|
71
|
+
function defineRepositoryScripts(inputs) {
|
|
72
|
+
const definitions = inputs.map(defineRepositoryScript);
|
|
73
|
+
const byBinding = /* @__PURE__ */ new Map();
|
|
74
|
+
const activeIds = /* @__PURE__ */ new Set();
|
|
75
|
+
for (const definition of definitions) {
|
|
76
|
+
const key = `${definition.id}@${definition.version}`;
|
|
77
|
+
if (byBinding.has(key)) throw new Error(`Duplicate repository script ${key}`);
|
|
78
|
+
if (definition.active && activeIds.has(definition.id)) throw new Error(`Repository script ${definition.id} has more than one active version`);
|
|
79
|
+
byBinding.set(key, definition);
|
|
80
|
+
if (definition.active) activeIds.add(definition.id);
|
|
81
|
+
}
|
|
82
|
+
return Object.freeze({
|
|
83
|
+
definitions: Object.freeze(definitions),
|
|
84
|
+
match(event) {
|
|
85
|
+
const parsed = repositoryScriptEventSchema.parse(event);
|
|
86
|
+
return definitions.filter((definition) => definition.active && definition.on.includes(parsed.name) && (definition.repositories === void 0 || definition.repositories.includes(parsed.repository)));
|
|
87
|
+
},
|
|
88
|
+
resolve(binding) {
|
|
89
|
+
const id = scriptIdSchema.parse(binding.id);
|
|
90
|
+
const version = z.number().int().positive().parse(binding.version);
|
|
91
|
+
const definition = byBinding.get(`${id}@${version}`);
|
|
92
|
+
if (definition === void 0) throw new Error(`Unknown repository script ${id}@${version}`);
|
|
93
|
+
return definition;
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
const recordedClassificationSchema = repositoryScriptClassificationSchema.extend({ instruction: repositoryScriptClassificationInputSchema.shape.instruction });
|
|
98
|
+
/** Validates the durable result of a repository-script Task. */
|
|
99
|
+
const repositoryScriptResultSchema = z.strictObject({
|
|
100
|
+
script: z.strictObject({
|
|
101
|
+
id: scriptIdSchema,
|
|
102
|
+
version: z.number().int().positive()
|
|
103
|
+
}),
|
|
104
|
+
actions: z.array(repositoryScriptActionSchema).max(16).readonly(),
|
|
105
|
+
classifications: z.array(recordedClassificationSchema).max(16).readonly()
|
|
106
|
+
});
|
|
107
|
+
/** Exact workflow contract used by repository-script Tasks. */
|
|
108
|
+
const repositoryScriptWorkflow = defineWorkflow({
|
|
109
|
+
id: "repository-script",
|
|
110
|
+
version: 1,
|
|
111
|
+
input: z.strictObject({
|
|
112
|
+
script: z.strictObject({
|
|
113
|
+
id: scriptIdSchema,
|
|
114
|
+
version: z.number().int().positive()
|
|
115
|
+
}),
|
|
116
|
+
event: repositoryScriptEventSchema
|
|
117
|
+
}),
|
|
118
|
+
output: repositoryScriptResultSchema
|
|
119
|
+
});
|
|
120
|
+
const repositoryScriptSelectionSchema = z.strictObject({
|
|
121
|
+
event: repositoryScriptEventSchema,
|
|
122
|
+
scripts: z.array(z.strictObject({
|
|
123
|
+
id: scriptIdSchema,
|
|
124
|
+
version: z.number().int().positive()
|
|
125
|
+
})).readonly()
|
|
126
|
+
});
|
|
127
|
+
function permissionForAction(action) {
|
|
128
|
+
return action.type === "github.issue.comment" ? "github:issues:comment" : "github:issues:label";
|
|
129
|
+
}
|
|
130
|
+
async function computeResult(definition, task, event, classify) {
|
|
131
|
+
const classifications = [];
|
|
132
|
+
const result = await definition.run({
|
|
133
|
+
event,
|
|
134
|
+
async classify(candidate) {
|
|
135
|
+
if (!definition.permissions.includes("ai:classify")) throw new Error(`Repository script ${definition.id} lacks ai:classify`);
|
|
136
|
+
const input = repositoryScriptClassificationInputSchema.parse(candidate);
|
|
137
|
+
const classification = repositoryScriptClassificationSchema.parse(await classify({
|
|
138
|
+
task,
|
|
139
|
+
input,
|
|
140
|
+
index: classifications.length
|
|
141
|
+
}));
|
|
142
|
+
if (!input.choices.includes(classification.choice)) throw new Error(`Repository script classifier returned disallowed choice ${classification.choice}`);
|
|
143
|
+
classifications.push({
|
|
144
|
+
instruction: input.instruction,
|
|
145
|
+
choice: classification.choice,
|
|
146
|
+
reason: classification.reason
|
|
147
|
+
});
|
|
148
|
+
return classification;
|
|
149
|
+
}
|
|
150
|
+
});
|
|
151
|
+
const actions = z.array(repositoryScriptActionSchema).max(16).parse(result.actions);
|
|
152
|
+
for (const action of actions) {
|
|
153
|
+
const permission = permissionForAction(action);
|
|
154
|
+
if (!definition.permissions.includes(permission)) throw new Error(`Repository script ${definition.id} lacks ${permission}`);
|
|
155
|
+
}
|
|
156
|
+
return repositoryScriptResultSchema.parse({
|
|
157
|
+
script: {
|
|
158
|
+
id: definition.id,
|
|
159
|
+
version: definition.version
|
|
160
|
+
},
|
|
161
|
+
actions,
|
|
162
|
+
classifications
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
async function persistedResult(options, definition, task, event) {
|
|
166
|
+
const pathname = `/repository-scripts/results/${task.id}`;
|
|
167
|
+
const existing = await options.state.read({ pathname });
|
|
168
|
+
if (existing !== null) return repositoryScriptResultSchema.parse(JSON.parse(existing.body));
|
|
169
|
+
const computed = await computeResult(definition, task, event, options.classify);
|
|
170
|
+
try {
|
|
171
|
+
await options.state.write({
|
|
172
|
+
pathname,
|
|
173
|
+
body: JSON.stringify(computed),
|
|
174
|
+
overwrite: false
|
|
175
|
+
});
|
|
176
|
+
return computed;
|
|
177
|
+
} catch (error) {
|
|
178
|
+
if (!(error instanceof VersionConflictError)) throw error;
|
|
179
|
+
const winner = await options.state.read({ pathname });
|
|
180
|
+
if (winner === null) throw error;
|
|
181
|
+
return repositoryScriptResultSchema.parse(JSON.parse(winner.body));
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
async function persistedAdmissionInput(options, selected) {
|
|
185
|
+
const pathname = `/repository-scripts/admissions/${options.signalId}/${selected.id}`;
|
|
186
|
+
const existing = await options.state.read({ pathname });
|
|
187
|
+
if (existing !== null) return parseAdmissionInput(existing.body, selected.id);
|
|
188
|
+
const candidate = repositoryScriptWorkflow.input.parse({
|
|
189
|
+
script: {
|
|
190
|
+
id: selected.id,
|
|
191
|
+
version: selected.version
|
|
192
|
+
},
|
|
193
|
+
event: options.event
|
|
194
|
+
});
|
|
195
|
+
try {
|
|
196
|
+
await options.state.write({
|
|
197
|
+
pathname,
|
|
198
|
+
body: JSON.stringify(candidate),
|
|
199
|
+
overwrite: false
|
|
200
|
+
});
|
|
201
|
+
return candidate;
|
|
202
|
+
} catch (error) {
|
|
203
|
+
if (!(error instanceof VersionConflictError)) throw error;
|
|
204
|
+
const winner = await options.state.read({ pathname });
|
|
205
|
+
if (winner === null) throw error;
|
|
206
|
+
return parseAdmissionInput(winner.body, selected.id);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
function parseAdmissionInput(body, expectedScriptId) {
|
|
210
|
+
const input = repositoryScriptWorkflow.input.parse(JSON.parse(body));
|
|
211
|
+
if (input.script.id !== expectedScriptId) throw new Error("Repository script admission ID mismatch");
|
|
212
|
+
return input;
|
|
213
|
+
}
|
|
214
|
+
async function persistedSelection(options, event) {
|
|
215
|
+
const pathname = `/repository-scripts/selections/${options.signalId}`;
|
|
216
|
+
const existing = await options.state.read({ pathname });
|
|
217
|
+
if (existing !== null) return repositoryScriptSelectionSchema.parse(JSON.parse(existing.body));
|
|
218
|
+
const candidate = repositoryScriptSelectionSchema.parse({
|
|
219
|
+
event,
|
|
220
|
+
scripts: options.registry.match(event).map(({ id, version }) => ({
|
|
221
|
+
id,
|
|
222
|
+
version
|
|
223
|
+
}))
|
|
224
|
+
});
|
|
225
|
+
try {
|
|
226
|
+
await options.state.write({
|
|
227
|
+
pathname,
|
|
228
|
+
body: JSON.stringify(candidate),
|
|
229
|
+
overwrite: false
|
|
230
|
+
});
|
|
231
|
+
return candidate;
|
|
232
|
+
} catch (error) {
|
|
233
|
+
if (!(error instanceof VersionConflictError)) throw error;
|
|
234
|
+
const winner = await options.state.read({ pathname });
|
|
235
|
+
if (winner === null) throw error;
|
|
236
|
+
return repositoryScriptSelectionSchema.parse(JSON.parse(winner.body));
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
async function settleTerminal(stores, task) {
|
|
240
|
+
if (task.settledUsd !== void 0) return task;
|
|
241
|
+
return stores.tasks.settle(task.id, {
|
|
242
|
+
cost: { totalUsd: task.usage?.costUsd ?? 0 },
|
|
243
|
+
reason: "repository script execution finished"
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
async function runOne(options, selected) {
|
|
247
|
+
const admissionInput = await persistedAdmissionInput(options, selected);
|
|
248
|
+
let task = await options.stores.tasks.create({
|
|
249
|
+
repositoryIds: [options.repositoryId],
|
|
250
|
+
kind: "repository_script",
|
|
251
|
+
work: taskWork({
|
|
252
|
+
workflow: repositoryScriptWorkflow,
|
|
253
|
+
title: `Run repository script ${selected.id}`,
|
|
254
|
+
input: admissionInput
|
|
255
|
+
}),
|
|
256
|
+
origin: { signalId: options.signalId },
|
|
257
|
+
replyTo: options.replyTo,
|
|
258
|
+
dedupeKey: `repository-script:${options.signalId}:${selected.id}`
|
|
259
|
+
});
|
|
260
|
+
const storedInput = repositoryScriptWorkflow.input.parse(task.work.input);
|
|
261
|
+
const definition = options.registry.resolve(storedInput.script);
|
|
262
|
+
if (task.state === "succeeded" || task.state === "failed" || task.state === "cancelled") return settleTerminal(options.stores, task);
|
|
263
|
+
const maxAttempts = options.maxAttempts ?? 3;
|
|
264
|
+
if (task.state === "stalled" || task.state === "needs_human") throw new Error(`Repository script Task ${task.id} cannot resume from ${task.state}`);
|
|
265
|
+
if (task.state === "queued") {
|
|
266
|
+
try {
|
|
267
|
+
await dispatchTask(options.stores, {
|
|
268
|
+
taskId: task.id,
|
|
269
|
+
workflowOwned: true,
|
|
270
|
+
...options.budget === void 0 ? {} : { budget: options.budget }
|
|
271
|
+
});
|
|
272
|
+
} catch (error) {
|
|
273
|
+
const refused = await options.stores.tasks.get(task.id);
|
|
274
|
+
if (refused?.state === "failed") return settleTerminal(options.stores, refused);
|
|
275
|
+
throw error;
|
|
276
|
+
}
|
|
277
|
+
task = await options.stores.tasks.get(task.id);
|
|
278
|
+
}
|
|
279
|
+
try {
|
|
280
|
+
const result = await persistedResult(options, definition, task, storedInput.event);
|
|
281
|
+
for (const [index, action] of result.actions.entries()) await options.applyAction({
|
|
282
|
+
task,
|
|
283
|
+
event: storedInput.event,
|
|
284
|
+
action,
|
|
285
|
+
index
|
|
286
|
+
});
|
|
287
|
+
const completed = await options.stores.work.completeWorkflow({
|
|
288
|
+
task: {
|
|
289
|
+
taskId: task.id,
|
|
290
|
+
attempt: task.attempt
|
|
291
|
+
},
|
|
292
|
+
workflow: repositoryScriptWorkflow.binding,
|
|
293
|
+
output: result
|
|
294
|
+
});
|
|
295
|
+
return settleTerminal(options.stores, completed);
|
|
296
|
+
} catch (error) {
|
|
297
|
+
const current = await options.stores.tasks.get(task.id);
|
|
298
|
+
if (current?.state !== "running" || current.attempt !== task.attempt) throw error;
|
|
299
|
+
const terminal = current.attempt >= maxAttempts;
|
|
300
|
+
const transitioned = await options.stores.tasks.transition(current.id, terminal ? "failed" : "queued", {
|
|
301
|
+
expectFrom: "running",
|
|
302
|
+
expectAttempt: current.attempt,
|
|
303
|
+
reason: "repository script execution failed"
|
|
304
|
+
});
|
|
305
|
+
if (terminal) return settleTerminal(options.stores, transitioned);
|
|
306
|
+
throw error;
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
/**
|
|
310
|
+
* Admit and execute every repository script selected for one normalized event.
|
|
311
|
+
*
|
|
312
|
+
* The exact selection is persisted per Signal before admission, so retries retain inactive script
|
|
313
|
+
* versions. The Task deduplication key is stable per Signal and script ID. Each script's validated
|
|
314
|
+
* result is persisted before effects, so retries reuse the same plan. Effect adapters must use the
|
|
315
|
+
* supplied Task and action index to reconcile ambiguous writes.
|
|
316
|
+
*/
|
|
317
|
+
async function runRepositoryScriptEvent(options) {
|
|
318
|
+
const selection = await persistedSelection(options, repositoryScriptEventSchema.parse(options.event));
|
|
319
|
+
const selectedOptions = {
|
|
320
|
+
...options,
|
|
321
|
+
event: selection.event
|
|
322
|
+
};
|
|
323
|
+
const tasks = [];
|
|
324
|
+
for (const binding of selection.scripts) tasks.push(await runOne(selectedOptions, options.registry.resolve(binding)));
|
|
325
|
+
return tasks;
|
|
326
|
+
}
|
|
327
|
+
//#endregion
|
|
328
|
+
export { defineRepositoryScript, defineRepositoryScripts, repositoryScriptActionSchema, repositoryScriptClassificationInputSchema, repositoryScriptClassificationSchema, repositoryScriptEventNames, repositoryScriptEventSchema, repositoryScriptPermissions, repositoryScriptResultSchema, repositoryScriptWorkflow, runRepositoryScriptEvent };
|
|
329
|
+
|
|
330
|
+
//# sourceMappingURL=repository-scripts.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"repository-scripts.mjs","names":[],"sources":["../src/repository-scripts.ts"],"sourcesContent":["import { z } from \"zod\";\nimport { dispatchTask, type DispatchBudget } from \"./dispatch\";\nimport type { MaybePromise, ReplyTo } from \"./schema/common\";\nimport type { RepositoryId, SignalId } from \"./schema/id\";\nimport { repositorySlugSchema, type RepositorySlug } from \"./schema/repository\";\nimport type { Task } from \"./schema/task\";\nimport type { ConditionalStateStore } from \"./store/state\";\nimport type { FactoryStores } from \"./store/engine\";\nimport { VersionConflictError } from \"./store/driver\";\nimport { defineWorkflow, taskWork } from \"./workflows\";\n\nconst scriptIdSchema = z\n .string()\n .regex(/^[a-z][a-z0-9-]{0,63}$/u)\n .describe(\"Stable lowercase repository-script identifier.\");\n\n/** Events currently available to repository-defined scripts. */\nexport const repositoryScriptEventNames = [\"github.issues.opened\"] as const;\n\n/** Name of an event available to repository-defined scripts. */\nexport type RepositoryScriptEventName = (typeof repositoryScriptEventNames)[number];\n\n/** Validates an opened GitHub issue supplied to a repository script. */\nexport const repositoryScriptEventSchema = z\n .strictObject({\n name: z.literal(\"github.issues.opened\"),\n deliveryId: z.string().min(1).max(256),\n repository: repositorySlugSchema,\n issue: z.strictObject({\n number: z.number().int().positive(),\n title: z.string().max(1024),\n body: z.string().max(65_536).nullable(),\n }),\n })\n .describe(\"Normalized, bounded event passed to a repository-defined script.\");\n\n/** Normalized event passed to a repository-defined script. */\nexport type RepositoryScriptEvent = z.infer<typeof repositoryScriptEventSchema>;\n\n/** Capabilities a repository-defined script may request explicitly. */\nexport const repositoryScriptPermissions = [\n \"ai:classify\",\n \"github:issues:comment\",\n \"github:issues:label\",\n] as const;\n\n/** Capability granted to a repository-defined script. */\nexport type RepositoryScriptPermission = (typeof repositoryScriptPermissions)[number];\n\nconst repositoryScriptPermissionSchema = z.enum(repositoryScriptPermissions);\n\n/** Validates one bounded action returned by a repository-defined script. */\nexport const repositoryScriptActionSchema = z.discriminatedUnion(\"type\", [\n z.strictObject({\n type: z.literal(\"github.issue.comment\"),\n body: z.string().trim().min(1).max(10_000),\n }),\n z.strictObject({\n type: z.literal(\"github.issue.addLabel\"),\n label: z.strictObject({\n name: z.string().trim().min(1).max(50),\n color: z.string().regex(/^[a-fA-F0-9]{6}$/u),\n description: z.string().max(100),\n }),\n }),\n]);\n\n/** Bounded side effect requested by a repository-defined script. */\nexport type RepositoryScriptAction = z.infer<typeof repositoryScriptActionSchema>;\n\n/** Validates a bounded classification request made by a repository script. */\nexport const repositoryScriptClassificationInputSchema = z\n .strictObject({\n instruction: z.string().trim().min(1).max(4000),\n subject: z.string().trim().min(1).max(16_000),\n choices: z\n .array(z.string().trim().min(1).max(100))\n .min(2)\n .max(32)\n .refine((choices) => new Set(choices).size === choices.length, \"choices must be unique\")\n .readonly(),\n })\n .describe(\"Instruction, untrusted subject, and allowed results for one classification.\");\n\n/** Bounded classification request made by a repository script. */\nexport type RepositoryScriptClassificationInput = z.infer<\n typeof repositoryScriptClassificationInputSchema\n>;\n\n/** Validates a structured classification returned to a repository script. */\nexport const repositoryScriptClassificationSchema = z\n .strictObject({\n choice: z.string().trim().min(1).max(100),\n reason: z.string().trim().min(1).max(2000),\n })\n .describe(\"Selected allowed choice and a bounded explanation.\");\n\n/** Structured classification returned to a repository script. */\nexport type RepositoryScriptClassification = z.infer<typeof repositoryScriptClassificationSchema>;\n\n/** Input and scoped helpers available while one repository script computes its action plan. */\nexport interface RepositoryScriptRunContext {\n /** Normalized event that selected the script. */\n readonly event: RepositoryScriptEvent;\n /** Run one bounded model classification when the script declares `ai:classify`. */\n classify(input: RepositoryScriptClassificationInput): Promise<RepositoryScriptClassification>;\n}\n\n/** Action plan returned by one repository-defined script. */\nexport interface RepositoryScriptRunResult {\n /** Ordered, bounded effects Factory should apply to the event's issue. */\n readonly actions: readonly RepositoryScriptAction[];\n}\n\n/** Repository-owned definition of one exact script version. */\nexport interface RepositoryScriptDefinition {\n /** Stable script identity used for durable Task deduplication. */\n readonly id: string;\n /** Exact positive version retained while Tasks may still reference it. */\n readonly version: number;\n /** Whether this version receives new matching events. Keep old versions inactive for recovery. */\n readonly active: boolean;\n /** Events that start this script. */\n readonly on: readonly RepositoryScriptEventName[];\n /** Optional repository filter; absent applies to every configured repository. */\n readonly repositories?: readonly RepositorySlug[];\n /** Capabilities this script may use. */\n readonly permissions: readonly RepositoryScriptPermission[];\n /** Compute a bounded action plan. Provider credentials are never passed to this callback. */\n run(context: RepositoryScriptRunContext): MaybePromise<RepositoryScriptRunResult>;\n}\n\n/** Caller input accepted when defining one repository script. */\nexport type RepositoryScriptDefinitionInput = Omit<RepositoryScriptDefinition, \"active\"> & {\n /** Defaults to true; false retains an old version only for Task recovery. */\n readonly active?: boolean;\n};\n\nconst repositoryScriptMetadataSchema = z.strictObject({\n id: scriptIdSchema,\n version: z.number().int().positive(),\n active: z.boolean().default(true),\n on: z.array(z.enum(repositoryScriptEventNames)).min(1).readonly(),\n repositories: z.array(repositorySlugSchema).min(1).readonly().optional(),\n permissions: z.array(repositoryScriptPermissionSchema).readonly(),\n});\n\n/** Validate and freeze one exact repository-script definition. */\nexport function defineRepositoryScript(\n input: RepositoryScriptDefinitionInput,\n): Readonly<RepositoryScriptDefinition> {\n if (typeof input.run !== \"function\") throw new Error(\"Repository script run must be a function\");\n const { run, ...candidate } = input;\n const metadata = repositoryScriptMetadataSchema.parse(candidate);\n return Object.freeze({ ...metadata, run });\n}\n\n/** Immutable exact-version registry for repository-defined scripts. */\nexport interface RepositoryScriptRegistry {\n /** Registered definitions in declaration order. */\n readonly definitions: readonly Readonly<RepositoryScriptDefinition>[];\n /** Select active definitions matching an event and its repository. */\n match(event: RepositoryScriptEvent): readonly Readonly<RepositoryScriptDefinition>[];\n /** Resolve one exact persisted script binding. */\n resolve(binding: {\n readonly id: string;\n readonly version: number;\n }): Readonly<RepositoryScriptDefinition>;\n}\n\n/** Validate repository scripts and build an exact-version event registry. */\nexport function defineRepositoryScripts(\n inputs: readonly RepositoryScriptDefinitionInput[],\n): RepositoryScriptRegistry {\n const definitions = inputs.map(defineRepositoryScript);\n const byBinding = new Map<string, Readonly<RepositoryScriptDefinition>>();\n const activeIds = new Set<string>();\n for (const definition of definitions) {\n const key = `${definition.id}@${definition.version}`;\n if (byBinding.has(key)) throw new Error(`Duplicate repository script ${key}`);\n if (definition.active && activeIds.has(definition.id)) {\n throw new Error(`Repository script ${definition.id} has more than one active version`);\n }\n byBinding.set(key, definition);\n if (definition.active) activeIds.add(definition.id);\n }\n return Object.freeze({\n definitions: Object.freeze(definitions),\n match(event: RepositoryScriptEvent) {\n const parsed = repositoryScriptEventSchema.parse(event);\n return definitions.filter(\n (definition) =>\n definition.active &&\n definition.on.includes(parsed.name) &&\n (definition.repositories === undefined ||\n definition.repositories.includes(parsed.repository)),\n );\n },\n resolve(binding: { readonly id: string; readonly version: number }) {\n const id = scriptIdSchema.parse(binding.id);\n const version = z.number().int().positive().parse(binding.version);\n const definition = byBinding.get(`${id}@${version}`);\n if (definition === undefined) {\n throw new Error(`Unknown repository script ${id}@${version}`);\n }\n return definition;\n },\n });\n}\n\nconst recordedClassificationSchema = repositoryScriptClassificationSchema.extend({\n instruction: repositoryScriptClassificationInputSchema.shape.instruction,\n});\n\n/** Validates the durable result of a repository-script Task. */\nexport const repositoryScriptResultSchema = z.strictObject({\n script: z.strictObject({ id: scriptIdSchema, version: z.number().int().positive() }),\n actions: z.array(repositoryScriptActionSchema).max(16).readonly(),\n classifications: z.array(recordedClassificationSchema).max(16).readonly(),\n});\n\n/** Durable result of a repository-script Task. */\nexport type RepositoryScriptResult = z.infer<typeof repositoryScriptResultSchema>;\n\n/** Exact workflow contract used by repository-script Tasks. */\nexport const repositoryScriptWorkflow = defineWorkflow({\n id: \"repository-script\",\n version: 1,\n input: z.strictObject({\n script: z.strictObject({ id: scriptIdSchema, version: z.number().int().positive() }),\n event: repositoryScriptEventSchema,\n }),\n output: repositoryScriptResultSchema,\n});\n\nconst repositoryScriptSelectionSchema = z.strictObject({\n event: repositoryScriptEventSchema,\n scripts: z\n .array(z.strictObject({ id: scriptIdSchema, version: z.number().int().positive() }))\n .readonly(),\n});\n\n/** Dependencies required to classify one repository-script request. */\nexport interface RepositoryScriptClassifierContext {\n /** Exact running Task whose usage and authority cover the model call. */\n readonly task: Task;\n /** Validated bounded classification request. */\n readonly input: RepositoryScriptClassificationInput;\n /** Zero-based classification index within the script invocation. */\n readonly index: number;\n}\n\n/** Dependencies required to apply one repository-script action. */\nexport interface RepositoryScriptActionContext {\n /** Exact running Task whose authority covers the effect. */\n readonly task: Task;\n /** Normalized event that bounds the target repository and issue. */\n readonly event: RepositoryScriptEvent;\n /** Validated action to apply. */\n readonly action: RepositoryScriptAction;\n /** Stable zero-based action index, suitable for an idempotency marker. */\n readonly index: number;\n}\n\n/** Store capabilities used by repository-script admission and completion. */\nexport type RepositoryScriptStores = Pick<FactoryStores, \"graphs\" | \"receipts\" | \"tasks\" | \"work\">;\n\n/** Input for admitting and running every script matched by one Signal event. */\nexport interface RunRepositoryScriptEventOptions {\n readonly stores: RepositoryScriptStores;\n readonly state: Pick<ConditionalStateStore, \"read\" | \"write\">;\n readonly registry: RepositoryScriptRegistry;\n readonly repositoryId: RepositoryId;\n readonly signalId: SignalId;\n readonly replyTo: ReplyTo;\n readonly event: RepositoryScriptEvent;\n readonly classify: (\n context: RepositoryScriptClassifierContext,\n ) => Promise<RepositoryScriptClassification>;\n readonly applyAction: (context: RepositoryScriptActionContext) => Promise<void>;\n readonly budget?: DispatchBudget;\n readonly maxAttempts?: number;\n}\n\nfunction permissionForAction(action: RepositoryScriptAction): RepositoryScriptPermission {\n return action.type === \"github.issue.comment\" ? \"github:issues:comment\" : \"github:issues:label\";\n}\n\nasync function computeResult(\n definition: Readonly<RepositoryScriptDefinition>,\n task: Task,\n event: RepositoryScriptEvent,\n classify: RunRepositoryScriptEventOptions[\"classify\"],\n): Promise<RepositoryScriptResult> {\n const classifications: z.infer<typeof recordedClassificationSchema>[] = [];\n const result = await definition.run({\n event,\n async classify(candidate) {\n if (!definition.permissions.includes(\"ai:classify\")) {\n throw new Error(`Repository script ${definition.id} lacks ai:classify`);\n }\n const input = repositoryScriptClassificationInputSchema.parse(candidate);\n const classification = repositoryScriptClassificationSchema.parse(\n await classify({ task, input, index: classifications.length }),\n );\n if (!input.choices.includes(classification.choice)) {\n throw new Error(\n `Repository script classifier returned disallowed choice ${classification.choice}`,\n );\n }\n classifications.push({\n instruction: input.instruction,\n choice: classification.choice,\n reason: classification.reason,\n });\n return classification;\n },\n });\n const actions = z.array(repositoryScriptActionSchema).max(16).parse(result.actions);\n for (const action of actions) {\n const permission = permissionForAction(action);\n if (!definition.permissions.includes(permission)) {\n throw new Error(`Repository script ${definition.id} lacks ${permission}`);\n }\n }\n return repositoryScriptResultSchema.parse({\n script: { id: definition.id, version: definition.version },\n actions,\n classifications,\n });\n}\n\nasync function persistedResult(\n options: RunRepositoryScriptEventOptions,\n definition: Readonly<RepositoryScriptDefinition>,\n task: Task,\n event: RepositoryScriptEvent,\n): Promise<RepositoryScriptResult> {\n const pathname = `/repository-scripts/results/${task.id}`;\n const existing = await options.state.read({ pathname });\n if (existing !== null) return repositoryScriptResultSchema.parse(JSON.parse(existing.body));\n const computed = await computeResult(definition, task, event, options.classify);\n try {\n await options.state.write({\n pathname,\n body: JSON.stringify(computed),\n overwrite: false,\n });\n return computed;\n } catch (error) {\n if (!(error instanceof VersionConflictError)) throw error;\n const winner = await options.state.read({ pathname });\n if (winner === null) throw error;\n return repositoryScriptResultSchema.parse(JSON.parse(winner.body));\n }\n}\n\nasync function persistedAdmissionInput(\n options: RunRepositoryScriptEventOptions,\n selected: Readonly<RepositoryScriptDefinition>,\n): Promise<z.infer<typeof repositoryScriptWorkflow.input>> {\n const pathname = `/repository-scripts/admissions/${options.signalId}/${selected.id}`;\n const existing = await options.state.read({ pathname });\n if (existing !== null) return parseAdmissionInput(existing.body, selected.id);\n const candidate = repositoryScriptWorkflow.input.parse({\n script: { id: selected.id, version: selected.version },\n event: options.event,\n });\n try {\n await options.state.write({\n pathname,\n body: JSON.stringify(candidate),\n overwrite: false,\n });\n return candidate;\n } catch (error) {\n if (!(error instanceof VersionConflictError)) throw error;\n const winner = await options.state.read({ pathname });\n if (winner === null) throw error;\n return parseAdmissionInput(winner.body, selected.id);\n }\n}\n\nfunction parseAdmissionInput(\n body: string,\n expectedScriptId: string,\n): z.infer<typeof repositoryScriptWorkflow.input> {\n const input = repositoryScriptWorkflow.input.parse(JSON.parse(body));\n if (input.script.id !== expectedScriptId) {\n throw new Error(\"Repository script admission ID mismatch\");\n }\n return input;\n}\n\nasync function persistedSelection(\n options: RunRepositoryScriptEventOptions,\n event: RepositoryScriptEvent,\n): Promise<z.infer<typeof repositoryScriptSelectionSchema>> {\n const pathname = `/repository-scripts/selections/${options.signalId}`;\n const existing = await options.state.read({ pathname });\n if (existing !== null) return repositoryScriptSelectionSchema.parse(JSON.parse(existing.body));\n const candidate = repositoryScriptSelectionSchema.parse({\n event,\n scripts: options.registry.match(event).map(({ id, version }) => ({ id, version })),\n });\n try {\n await options.state.write({\n pathname,\n body: JSON.stringify(candidate),\n overwrite: false,\n });\n return candidate;\n } catch (error) {\n if (!(error instanceof VersionConflictError)) throw error;\n const winner = await options.state.read({ pathname });\n if (winner === null) throw error;\n return repositoryScriptSelectionSchema.parse(JSON.parse(winner.body));\n }\n}\n\nasync function settleTerminal(stores: RepositoryScriptStores, task: Task): Promise<Task> {\n if (task.settledUsd !== undefined) return task;\n return stores.tasks.settle(task.id, {\n cost: { totalUsd: task.usage?.costUsd ?? 0 },\n reason: \"repository script execution finished\",\n });\n}\n\nasync function runOne(\n options: RunRepositoryScriptEventOptions,\n selected: Readonly<RepositoryScriptDefinition>,\n): Promise<Task> {\n const admissionInput = await persistedAdmissionInput(options, selected);\n let task = await options.stores.tasks.create({\n repositoryIds: [options.repositoryId],\n kind: \"repository_script\",\n work: taskWork({\n workflow: repositoryScriptWorkflow,\n title: `Run repository script ${selected.id}`,\n input: admissionInput,\n }),\n origin: { signalId: options.signalId },\n replyTo: options.replyTo,\n dedupeKey: `repository-script:${options.signalId}:${selected.id}`,\n });\n const storedInput = repositoryScriptWorkflow.input.parse(task.work.input);\n const definition = options.registry.resolve(storedInput.script);\n if (task.state === \"succeeded\" || task.state === \"failed\" || task.state === \"cancelled\") {\n return settleTerminal(options.stores, task);\n }\n const maxAttempts = options.maxAttempts ?? 3;\n if (task.state === \"stalled\" || task.state === \"needs_human\") {\n throw new Error(`Repository script Task ${task.id} cannot resume from ${task.state}`);\n }\n if (task.state === \"queued\") {\n try {\n await dispatchTask(options.stores, {\n taskId: task.id,\n workflowOwned: true,\n ...(options.budget === undefined ? {} : { budget: options.budget }),\n });\n } catch (error) {\n const refused = await options.stores.tasks.get(task.id);\n if (refused?.state === \"failed\") return settleTerminal(options.stores, refused);\n throw error;\n }\n task = (await options.stores.tasks.get(task.id))!;\n }\n try {\n const result = await persistedResult(options, definition, task, storedInput.event);\n for (const [index, action] of result.actions.entries()) {\n await options.applyAction({ task, event: storedInput.event, action, index });\n }\n const completed = await options.stores.work.completeWorkflow({\n task: { taskId: task.id, attempt: task.attempt },\n workflow: repositoryScriptWorkflow.binding,\n output: result,\n });\n return settleTerminal(options.stores, completed);\n } catch (error) {\n const current = await options.stores.tasks.get(task.id);\n if (current?.state !== \"running\" || current.attempt !== task.attempt) throw error;\n const terminal = current.attempt >= maxAttempts;\n const transitioned = await options.stores.tasks.transition(\n current.id,\n terminal ? \"failed\" : \"queued\",\n {\n expectFrom: \"running\",\n expectAttempt: current.attempt,\n reason: \"repository script execution failed\",\n },\n );\n if (terminal) return settleTerminal(options.stores, transitioned);\n throw error;\n }\n}\n\n/**\n * Admit and execute every repository script selected for one normalized event.\n *\n * The exact selection is persisted per Signal before admission, so retries retain inactive script\n * versions. The Task deduplication key is stable per Signal and script ID. Each script's validated\n * result is persisted before effects, so retries reuse the same plan. Effect adapters must use the\n * supplied Task and action index to reconcile ambiguous writes.\n */\nexport async function runRepositoryScriptEvent(\n options: RunRepositoryScriptEventOptions,\n): Promise<readonly Task[]> {\n const event = repositoryScriptEventSchema.parse(options.event);\n const selection = await persistedSelection(options, event);\n const selectedOptions = { ...options, event: selection.event };\n const tasks: Task[] = [];\n for (const binding of selection.scripts) {\n tasks.push(await runOne(selectedOptions, options.registry.resolve(binding)));\n }\n return tasks;\n}\n"],"mappings":"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"}
|