@interf/compiler 0.9.3 → 0.9.5
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 +93 -0
- package/README.md +2 -1
- package/agent-skills/interf-actions/SKILL.md +17 -11
- package/agent-skills/interf-actions/references/cli.md +8 -22
- package/dist/cli/commands/action-input-cli.d.ts +25 -0
- package/dist/cli/commands/action-input-cli.js +73 -0
- package/dist/cli/commands/compile.d.ts +3 -8
- package/dist/cli/commands/compile.js +13 -41
- package/dist/cli/commands/create-method-wizard.d.ts +0 -12
- package/dist/cli/commands/create-method-wizard.js +95 -126
- package/dist/cli/commands/create.d.ts +0 -2
- package/dist/cli/commands/create.js +16 -22
- package/dist/cli/commands/doctor.js +1 -1
- package/dist/cli/commands/executor-flow.js +1 -1
- package/dist/cli/commands/init.d.ts +16 -1
- package/dist/cli/commands/init.js +40 -53
- package/dist/cli/commands/list.js +1 -1
- package/dist/cli/commands/preparation-action.d.ts +8 -0
- package/dist/cli/commands/preparation-action.js +29 -0
- package/dist/cli/commands/preparation-picker.d.ts +5 -0
- package/dist/cli/commands/preparation-picker.js +36 -0
- package/dist/cli/commands/preparation-selection.js +2 -2
- package/dist/cli/commands/reset.js +15 -4
- package/dist/cli/commands/service-action-flow.d.ts +9 -0
- package/dist/cli/commands/service-action-flow.js +19 -0
- package/dist/cli/commands/source-config-wizard.d.ts +0 -1
- package/dist/cli/commands/source-config-wizard.js +43 -53
- package/dist/cli/commands/status.js +7 -123
- package/dist/cli/commands/test.d.ts +1 -2
- package/dist/cli/commands/test.js +40 -203
- package/dist/cli/commands/web.js +8 -262
- package/dist/compiler-ui/404.html +1 -1
- package/dist/compiler-ui/__next.__PAGE__.txt +2 -2
- package/dist/compiler-ui/__next._full.txt +3 -3
- package/dist/compiler-ui/__next._head.txt +1 -1
- package/dist/compiler-ui/__next._index.txt +2 -2
- package/dist/compiler-ui/__next._tree.txt +2 -2
- package/dist/compiler-ui/_next/static/chunks/177mvn4rse235.js +89 -0
- package/dist/compiler-ui/_next/static/chunks/18a8f2jkv3z.c.css +3 -0
- package/dist/compiler-ui/_not-found/__next._full.txt +2 -2
- package/dist/compiler-ui/_not-found/__next._head.txt +1 -1
- package/dist/compiler-ui/_not-found/__next._index.txt +2 -2
- package/dist/compiler-ui/_not-found/__next._not-found.__PAGE__.txt +1 -1
- package/dist/compiler-ui/_not-found/__next._not-found.txt +1 -1
- package/dist/compiler-ui/_not-found/__next._tree.txt +2 -2
- package/dist/compiler-ui/_not-found.html +1 -1
- package/dist/compiler-ui/_not-found.txt +2 -2
- package/dist/compiler-ui/index.html +1 -1
- package/dist/compiler-ui/index.txt +3 -3
- package/dist/index.d.ts +0 -23
- package/dist/index.js +0 -16
- package/dist/packages/agents/lib/shells.js +2 -2
- package/dist/packages/compiler/lib/schema.d.ts +1 -1
- package/dist/packages/compiler/lib/schema.js +1 -1
- package/dist/packages/contracts/lib/schema.d.ts +0 -1
- package/dist/packages/contracts/lib/schema.js +0 -1
- package/dist/packages/execution/lib/schema.d.ts +0 -7
- package/dist/packages/execution/lib/schema.js +0 -1
- package/dist/packages/local-service/action-definitions.d.ts +246 -0
- package/dist/packages/local-service/action-definitions.js +1148 -0
- package/dist/packages/local-service/action-planner.d.ts +9 -0
- package/dist/packages/local-service/action-planner.js +134 -0
- package/dist/packages/local-service/action-values.d.ts +1 -22
- package/dist/packages/local-service/action-values.js +1 -30
- package/dist/packages/local-service/client.d.ts +48 -17
- package/dist/packages/local-service/client.js +95 -52
- package/dist/packages/local-service/index.d.ts +8 -5
- package/dist/packages/local-service/index.js +5 -3
- package/dist/packages/local-service/lib/schema.d.ts +302 -292
- package/dist/packages/local-service/lib/schema.js +115 -39
- package/dist/packages/local-service/native-run-handlers.d.ts +23 -0
- package/dist/{cli/commands/compile-controller.js → packages/local-service/native-run-handlers.js} +203 -19
- package/dist/{cli/commands/check-draft.d.ts → packages/local-service/readiness-check-draft.d.ts} +2 -2
- package/dist/packages/local-service/routes.d.ts +6 -1
- package/dist/packages/local-service/routes.js +7 -2
- package/dist/packages/local-service/run-observability.js +15 -17
- package/dist/packages/local-service/runtime.d.ts +10 -7
- package/dist/packages/local-service/runtime.js +430 -286
- package/dist/packages/local-service/server.js +94 -44
- package/dist/packages/method-package/method-review-paths.d.ts +1 -1
- package/dist/packages/method-package/method-review-paths.js +5 -5
- package/dist/packages/project-model/index.d.ts +1 -0
- package/dist/packages/project-model/index.js +1 -0
- package/dist/packages/project-model/preparation-entries.d.ts +11 -0
- package/dist/packages/project-model/preparation-entries.js +49 -0
- package/dist/packages/project-model/source-config.d.ts +1 -0
- package/dist/packages/project-model/source-config.js +12 -1
- package/dist/packages/testing/lib/schema.d.ts +2 -3
- package/dist/packages/testing/lib/schema.js +2 -3
- package/dist/packages/testing/readiness-check-run.d.ts +3 -3
- package/dist/packages/testing/readiness-check-run.js +12 -17
- package/package.json +5 -24
- package/dist/cli/commands/compile-controller.d.ts +0 -17
- package/dist/cli/commands/compiled-flow.d.ts +0 -25
- package/dist/cli/commands/compiled-flow.js +0 -112
- package/dist/cli/commands/test-flow.d.ts +0 -58
- package/dist/cli/commands/test-flow.js +0 -231
- package/dist/compiler-ui/_next/static/chunks/0c9mu7yldxyyg.css +0 -3
- package/dist/compiler-ui/_next/static/chunks/15mks7ry_cupt.js +0 -118
- /package/dist/compiler-ui/_next/static/{pIZnDsV3Je6hdC3cOsGdK → 84FaeF3EzBF9kKTMjSEVN}/_buildManifest.js +0 -0
- /package/dist/compiler-ui/_next/static/{pIZnDsV3Je6hdC3cOsGdK → 84FaeF3EzBF9kKTMjSEVN}/_clientMiddlewareManifest.js +0 -0
- /package/dist/compiler-ui/_next/static/{pIZnDsV3Je6hdC3cOsGdK → 84FaeF3EzBF9kKTMjSEVN}/_ssgManifest.js +0 -0
- /package/dist/{cli/commands/check-draft.js → packages/local-service/readiness-check-draft.js} +0 -0
|
@@ -0,0 +1,1148 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export const ActionValueIdPattern = /^[a-z0-9][a-z0-9-]{0,79}$/;
|
|
3
|
+
export const ActionValueIdSchema = z.string().trim().regex(ActionValueIdPattern, "Use lowercase letters, numbers, and dashes.");
|
|
4
|
+
export const OptionalActionValueIdSchema = z.string().trim().refine((value) => value === "" || ActionValueIdPattern.test(value), "Use lowercase letters, numbers, and dashes.");
|
|
5
|
+
export const SourceReadinessCheckActionValueSchema = z.object({
|
|
6
|
+
question: z.string().trim().min(1),
|
|
7
|
+
answer: z.string().trim().optional(),
|
|
8
|
+
}).strict();
|
|
9
|
+
export const PreparationSetupActionValuesSchema = z.object({
|
|
10
|
+
name: ActionValueIdSchema,
|
|
11
|
+
path: z.string().trim().min(1, "Source Folder is required."),
|
|
12
|
+
about: z.string().trim().min(1, "Agent work is required."),
|
|
13
|
+
method: OptionalActionValueIdSchema.optional(),
|
|
14
|
+
checks: z.array(SourceReadinessCheckActionValueSchema).optional(),
|
|
15
|
+
max_attempts: z.number().int().min(1).max(5).optional(),
|
|
16
|
+
max_loops: z.number().int().min(1).max(3).optional(),
|
|
17
|
+
readiness_notes: z.string().trim().optional(),
|
|
18
|
+
prepare_after_setup: z.boolean().optional(),
|
|
19
|
+
setup_mode: z.enum(["create", "select-method"]).optional(),
|
|
20
|
+
}).strict();
|
|
21
|
+
export const MethodAuthoringActionValuesSchema = z.object({
|
|
22
|
+
method_id: ActionValueIdSchema.optional(),
|
|
23
|
+
base_method_id: ActionValueIdSchema.optional(),
|
|
24
|
+
reference_method_id: ActionValueIdSchema.optional(),
|
|
25
|
+
label: z.string().trim().optional(),
|
|
26
|
+
hint: z.string().trim().optional(),
|
|
27
|
+
task_prompt: z.string().trim().min(1, "Agent work is required."),
|
|
28
|
+
portable_output: z.string().trim().optional(),
|
|
29
|
+
readiness_notes: z.string().trim().optional(),
|
|
30
|
+
}).strict();
|
|
31
|
+
export const INTERF_SERVICE_ACTIONS = {
|
|
32
|
+
createPreparation: {
|
|
33
|
+
id: "create-preparation",
|
|
34
|
+
serviceAction: "preparation-setup",
|
|
35
|
+
title: "Create Preparation",
|
|
36
|
+
description: "Save a Source Folder and agent job as a Preparation.",
|
|
37
|
+
},
|
|
38
|
+
runPreparation: {
|
|
39
|
+
id: "prepare-run",
|
|
40
|
+
serviceAction: "compile",
|
|
41
|
+
title: "Run Preparation",
|
|
42
|
+
description: "Build portable context for a saved Preparation.",
|
|
43
|
+
},
|
|
44
|
+
selectMethod: {
|
|
45
|
+
id: "select-method",
|
|
46
|
+
serviceAction: "preparation-setup",
|
|
47
|
+
title: "Select Method",
|
|
48
|
+
description: "Save the Method a Preparation should use for future prepare runs.",
|
|
49
|
+
},
|
|
50
|
+
createMethod: {
|
|
51
|
+
id: "create-method",
|
|
52
|
+
serviceAction: "method-authoring",
|
|
53
|
+
title: "Create Method",
|
|
54
|
+
description: "Draft a reusable local Method for an agent-work pattern.",
|
|
55
|
+
},
|
|
56
|
+
methodChange: {
|
|
57
|
+
id: "method-change",
|
|
58
|
+
serviceAction: "method-change",
|
|
59
|
+
title: "Method Change",
|
|
60
|
+
description: "Modify, duplicate, or remove an existing Method.",
|
|
61
|
+
},
|
|
62
|
+
preparationChange: {
|
|
63
|
+
id: "preparation-change",
|
|
64
|
+
serviceAction: "preparation-change",
|
|
65
|
+
title: "Preparation Change",
|
|
66
|
+
description: "Modify, duplicate, or remove an existing Preparation.",
|
|
67
|
+
},
|
|
68
|
+
confirmAction: {
|
|
69
|
+
id: "confirm-action",
|
|
70
|
+
serviceAction: "action-proposal",
|
|
71
|
+
title: "Send Request",
|
|
72
|
+
description: "Confirm the typed Interf service request before it runs.",
|
|
73
|
+
},
|
|
74
|
+
checkReadiness: {
|
|
75
|
+
id: "check-readiness",
|
|
76
|
+
serviceAction: "test",
|
|
77
|
+
title: "Check Readiness",
|
|
78
|
+
description: "Run saved readiness checks against this Preparation.",
|
|
79
|
+
},
|
|
80
|
+
draftReadinessChecks: {
|
|
81
|
+
id: "draft-readiness-checks",
|
|
82
|
+
serviceAction: "readiness-check-draft",
|
|
83
|
+
title: "Draft Readiness Checks",
|
|
84
|
+
description: "Ask the configured local executor to draft saved readiness checks.",
|
|
85
|
+
},
|
|
86
|
+
improvePreparation: {
|
|
87
|
+
id: "improve-preparation",
|
|
88
|
+
serviceAction: "method-improvement",
|
|
89
|
+
title: "Improve Preparation",
|
|
90
|
+
description: "Use readiness evidence to improve the Method for this Preparation.",
|
|
91
|
+
},
|
|
92
|
+
};
|
|
93
|
+
function optionalLine(label, value) {
|
|
94
|
+
const trimmed = value?.trim();
|
|
95
|
+
return trimmed ? `${label}: ${trimmed}` : null;
|
|
96
|
+
}
|
|
97
|
+
export function methodAuthoringTaskPrompt(values) {
|
|
98
|
+
return [
|
|
99
|
+
`Agent work: ${values.task_prompt}`,
|
|
100
|
+
optionalLine("Portable-context output", values.portable_output),
|
|
101
|
+
optionalLine("Readiness checks", values.readiness_notes),
|
|
102
|
+
].filter((line) => Boolean(line)).join("\n");
|
|
103
|
+
}
|
|
104
|
+
const requiredActionText = (field) => z.string().trim().min(1, `${field} is required.`);
|
|
105
|
+
const optionalActionText = z.string().trim();
|
|
106
|
+
const actionIdField = (field) => requiredActionText(field).regex(ActionValueIdPattern, `${field} must use lowercase letters, numbers, and dashes.`);
|
|
107
|
+
const optionalActionIdField = (field) => optionalActionText.refine((value) => value === "" || ActionValueIdPattern.test(value), `${field} must use lowercase letters, numbers, and dashes.`);
|
|
108
|
+
export function packageSchemaFieldErrors(result, pathMap) {
|
|
109
|
+
if (result.success)
|
|
110
|
+
return {};
|
|
111
|
+
const errors = {};
|
|
112
|
+
for (const issue of result.error.issues) {
|
|
113
|
+
const path = issue.path.join(".");
|
|
114
|
+
const key = pathMap[path] ?? pathMap[issue.path.at(-1)?.toString() ?? ""] ?? "";
|
|
115
|
+
if (key && !errors[key])
|
|
116
|
+
errors[key] = issue.message;
|
|
117
|
+
}
|
|
118
|
+
return errors;
|
|
119
|
+
}
|
|
120
|
+
export function slugForActionId(value) {
|
|
121
|
+
const slug = value
|
|
122
|
+
.toLowerCase()
|
|
123
|
+
.replace(/[^a-z0-9]+/g, "-")
|
|
124
|
+
.replace(/^-+|-+$/g, "")
|
|
125
|
+
.slice(0, 72)
|
|
126
|
+
.replace(/-+$/g, "");
|
|
127
|
+
return slug || "preparation";
|
|
128
|
+
}
|
|
129
|
+
export function uniqueActionId(seed, usedIds) {
|
|
130
|
+
const base = slugForActionId(seed);
|
|
131
|
+
if (!usedIds.has(base))
|
|
132
|
+
return base;
|
|
133
|
+
for (let index = 2; index < 100; index += 1) {
|
|
134
|
+
const candidate = `${base}-${index}`;
|
|
135
|
+
if (!usedIds.has(candidate))
|
|
136
|
+
return candidate;
|
|
137
|
+
}
|
|
138
|
+
return `${base}-${Date.now().toString(36)}`;
|
|
139
|
+
}
|
|
140
|
+
export function titleFromActionId(value) {
|
|
141
|
+
return value
|
|
142
|
+
.split("-")
|
|
143
|
+
.filter(Boolean)
|
|
144
|
+
.map((part) => `${part.charAt(0).toUpperCase()}${part.slice(1)}`)
|
|
145
|
+
.join(" ");
|
|
146
|
+
}
|
|
147
|
+
export function maybeActionValue(value) {
|
|
148
|
+
const trimmed = value.trim();
|
|
149
|
+
return trimmed.length > 0 ? trimmed : undefined;
|
|
150
|
+
}
|
|
151
|
+
function inputValue(values, key) {
|
|
152
|
+
return values[key] ?? "";
|
|
153
|
+
}
|
|
154
|
+
export function methodChoiceOptions(methods) {
|
|
155
|
+
const seen = new Set();
|
|
156
|
+
const options = [];
|
|
157
|
+
for (const method of [{ id: "interf-default", label: "interf-default" }, ...methods]) {
|
|
158
|
+
if (seen.has(method.id))
|
|
159
|
+
continue;
|
|
160
|
+
seen.add(method.id);
|
|
161
|
+
options.push({ label: method.label ?? method.id, value: method.id });
|
|
162
|
+
}
|
|
163
|
+
return options;
|
|
164
|
+
}
|
|
165
|
+
export function methodTaskPromptFromInput(values) {
|
|
166
|
+
const parsed = MethodAuthoringActionValuesSchema.safeParse(values);
|
|
167
|
+
if (parsed.success)
|
|
168
|
+
return methodAuthoringTaskPrompt(parsed.data);
|
|
169
|
+
const taskPrompt = inputValue(values, "task_prompt");
|
|
170
|
+
const portableOutput = inputValue(values, "portable_output");
|
|
171
|
+
const readinessNotes = inputValue(values, "readiness_notes");
|
|
172
|
+
return [
|
|
173
|
+
`Agent work: ${taskPrompt}`,
|
|
174
|
+
maybeActionValue(portableOutput) ? `Portable-context output: ${portableOutput}` : null,
|
|
175
|
+
maybeActionValue(readinessNotes) ? `Readiness checks: ${readinessNotes}` : null,
|
|
176
|
+
].filter((line) => Boolean(line)).join("\n");
|
|
177
|
+
}
|
|
178
|
+
function createPreparationSchema(existingNames) {
|
|
179
|
+
return z.object({
|
|
180
|
+
name: actionIdField("Preparation name"),
|
|
181
|
+
path: requiredActionText("Source Folder"),
|
|
182
|
+
about: requiredActionText("Agent work"),
|
|
183
|
+
method: optionalActionIdField("Method"),
|
|
184
|
+
readiness_notes: optionalActionText,
|
|
185
|
+
}).strict().superRefine((values, ctx) => {
|
|
186
|
+
if (existingNames.has(values.name)) {
|
|
187
|
+
ctx.addIssue({
|
|
188
|
+
code: z.ZodIssueCode.custom,
|
|
189
|
+
path: ["name"],
|
|
190
|
+
message: "A Preparation with this name already exists.",
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
function prepareRunSchema() {
|
|
196
|
+
return z.object({
|
|
197
|
+
preparation: actionIdField("Preparation"),
|
|
198
|
+
method: optionalActionIdField("Method"),
|
|
199
|
+
about: optionalActionText,
|
|
200
|
+
source_folder_path: optionalActionText,
|
|
201
|
+
}).strict();
|
|
202
|
+
}
|
|
203
|
+
function selectMethodSchema() {
|
|
204
|
+
return z.object({
|
|
205
|
+
name: actionIdField("Preparation"),
|
|
206
|
+
path: requiredActionText("Source Folder"),
|
|
207
|
+
about: requiredActionText("Agent work"),
|
|
208
|
+
current_method: optionalActionIdField("Current Method"),
|
|
209
|
+
method: optionalActionIdField("Method"),
|
|
210
|
+
}).strict();
|
|
211
|
+
}
|
|
212
|
+
function methodAuthoringSchema(existingMethodIds) {
|
|
213
|
+
return z.object({
|
|
214
|
+
method_id: optionalActionIdField("Method id"),
|
|
215
|
+
label: optionalActionText,
|
|
216
|
+
hint: optionalActionText,
|
|
217
|
+
task_prompt: requiredActionText("Agent work"),
|
|
218
|
+
portable_output: optionalActionText,
|
|
219
|
+
readiness_notes: optionalActionText,
|
|
220
|
+
}).strict().superRefine((values, ctx) => {
|
|
221
|
+
const explicitMethodId = maybeActionValue(values.method_id ?? "");
|
|
222
|
+
if (explicitMethodId && existingMethodIds.has(explicitMethodId)) {
|
|
223
|
+
ctx.addIssue({
|
|
224
|
+
code: z.ZodIssueCode.custom,
|
|
225
|
+
path: ["method_id"],
|
|
226
|
+
message: "A Method with this id already exists.",
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
function methodChangeSchema(action, methodId, existingMethodIds) {
|
|
232
|
+
const base = {
|
|
233
|
+
action: requiredActionText("Action"),
|
|
234
|
+
method: actionIdField("Method"),
|
|
235
|
+
preparation: optionalActionIdField("Preparation"),
|
|
236
|
+
};
|
|
237
|
+
if (action === "modify") {
|
|
238
|
+
return z.object({
|
|
239
|
+
...base,
|
|
240
|
+
change_request: requiredActionText("Requested change"),
|
|
241
|
+
label: optionalActionText,
|
|
242
|
+
hint: optionalActionText,
|
|
243
|
+
}).strict();
|
|
244
|
+
}
|
|
245
|
+
if (action === "duplicate") {
|
|
246
|
+
return z.object({
|
|
247
|
+
...base,
|
|
248
|
+
new_method_id: actionIdField("New Method id"),
|
|
249
|
+
}).strict().superRefine((values, ctx) => {
|
|
250
|
+
if (existingMethodIds.has(values.new_method_id)) {
|
|
251
|
+
ctx.addIssue({
|
|
252
|
+
code: z.ZodIssueCode.custom,
|
|
253
|
+
path: ["new_method_id"],
|
|
254
|
+
message: "A Method with this id already exists.",
|
|
255
|
+
});
|
|
256
|
+
}
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
return z.object({
|
|
260
|
+
...base,
|
|
261
|
+
confirmation: requiredActionText("Confirmation").refine((value) => value === methodId, `Type ${methodId} to confirm.`),
|
|
262
|
+
}).strict();
|
|
263
|
+
}
|
|
264
|
+
function preparationChangeSchema(action, preparation, existingNames) {
|
|
265
|
+
const base = {
|
|
266
|
+
action: requiredActionText("Action"),
|
|
267
|
+
preparation: actionIdField("Preparation"),
|
|
268
|
+
};
|
|
269
|
+
if (action === "modify") {
|
|
270
|
+
return z.object({
|
|
271
|
+
...base,
|
|
272
|
+
name: actionIdField("Preparation id"),
|
|
273
|
+
path: requiredActionText("Source Folder"),
|
|
274
|
+
about: requiredActionText("Agent work"),
|
|
275
|
+
method: optionalActionIdField("Method"),
|
|
276
|
+
}).strict().superRefine((values, ctx) => {
|
|
277
|
+
if (values.name !== preparation && existingNames.has(values.name)) {
|
|
278
|
+
ctx.addIssue({
|
|
279
|
+
code: z.ZodIssueCode.custom,
|
|
280
|
+
path: ["name"],
|
|
281
|
+
message: "A Preparation with this name already exists.",
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
});
|
|
285
|
+
}
|
|
286
|
+
if (action === "duplicate") {
|
|
287
|
+
return z.object({
|
|
288
|
+
...base,
|
|
289
|
+
name: actionIdField("New Preparation id"),
|
|
290
|
+
path: requiredActionText("Source Folder"),
|
|
291
|
+
about: requiredActionText("Agent work"),
|
|
292
|
+
method: optionalActionIdField("Method"),
|
|
293
|
+
}).strict().superRefine((values, ctx) => {
|
|
294
|
+
if (existingNames.has(values.name)) {
|
|
295
|
+
ctx.addIssue({
|
|
296
|
+
code: z.ZodIssueCode.custom,
|
|
297
|
+
path: ["name"],
|
|
298
|
+
message: "A Preparation with this name already exists.",
|
|
299
|
+
});
|
|
300
|
+
}
|
|
301
|
+
});
|
|
302
|
+
}
|
|
303
|
+
return z.object({
|
|
304
|
+
...base,
|
|
305
|
+
confirmation: requiredActionText("Confirmation").refine((value) => value === preparation, `Type ${preparation} to confirm.`),
|
|
306
|
+
}).strict();
|
|
307
|
+
}
|
|
308
|
+
function conciseSummary(value, fallback) {
|
|
309
|
+
const normalized = value.replace(/\s+/g, " ").trim();
|
|
310
|
+
if (!normalized)
|
|
311
|
+
return fallback;
|
|
312
|
+
const sentence = normalized.match(/^.{24,180}?(?:[.!?](?:\s|$)|$)/)?.[0]?.trim() ?? normalized;
|
|
313
|
+
return sentence.length > 180 ? `${sentence.slice(0, 177).trim()}...` : sentence;
|
|
314
|
+
}
|
|
315
|
+
function normalizedMethodActionValues(values, existingMethodIds, defaultSeed) {
|
|
316
|
+
const explicitMethodId = maybeActionValue(inputValue(values, "method_id"));
|
|
317
|
+
const taskPrompt = inputValue(values, "task_prompt").trim();
|
|
318
|
+
const methodId = explicitMethodId ?? uniqueActionId(taskPrompt || defaultSeed || "custom-method", existingMethodIds);
|
|
319
|
+
const output = maybeActionValue(inputValue(values, "portable_output"));
|
|
320
|
+
return {
|
|
321
|
+
...values,
|
|
322
|
+
method_id: methodId,
|
|
323
|
+
label: maybeActionValue(inputValue(values, "label")) ?? titleFromActionId(methodId),
|
|
324
|
+
hint: maybeActionValue(inputValue(values, "hint")) ?? conciseSummary(output ?? taskPrompt, "Reusable Method for preparing source files."),
|
|
325
|
+
task_prompt: taskPrompt,
|
|
326
|
+
};
|
|
327
|
+
}
|
|
328
|
+
function createPreparationActionValues(values) {
|
|
329
|
+
const method = inputValue(values, "method");
|
|
330
|
+
const readinessNotes = inputValue(values, "readiness_notes");
|
|
331
|
+
return {
|
|
332
|
+
name: inputValue(values, "name"),
|
|
333
|
+
path: inputValue(values, "path"),
|
|
334
|
+
about: inputValue(values, "about"),
|
|
335
|
+
prepare_after_setup: true,
|
|
336
|
+
...(maybeActionValue(method) ? { method } : {}),
|
|
337
|
+
...(maybeActionValue(readinessNotes) ? { readiness_notes: readinessNotes } : {}),
|
|
338
|
+
};
|
|
339
|
+
}
|
|
340
|
+
function selectMethodActionValues(values) {
|
|
341
|
+
return {
|
|
342
|
+
name: inputValue(values, "name"),
|
|
343
|
+
path: inputValue(values, "path"),
|
|
344
|
+
about: inputValue(values, "about"),
|
|
345
|
+
method: maybeActionValue(inputValue(values, "method")) ?? "interf-default",
|
|
346
|
+
prepare_after_setup: false,
|
|
347
|
+
setup_mode: "select-method",
|
|
348
|
+
};
|
|
349
|
+
}
|
|
350
|
+
export function preparationSetupRequestFromActionValues(input) {
|
|
351
|
+
const values = PreparationSetupActionValuesSchema.parse(input);
|
|
352
|
+
return {
|
|
353
|
+
prepare_after_setup: values.prepare_after_setup ?? false,
|
|
354
|
+
setup_mode: values.setup_mode === "select-method" ? "select-method" : "create",
|
|
355
|
+
preparation: {
|
|
356
|
+
name: values.name,
|
|
357
|
+
path: values.path,
|
|
358
|
+
about: values.about,
|
|
359
|
+
method: values.method && values.method.length > 0 ? values.method : "interf-default",
|
|
360
|
+
checks: values.checks ?? [],
|
|
361
|
+
...(typeof values.max_attempts === "number" ? { max_attempts: values.max_attempts } : {}),
|
|
362
|
+
...(typeof values.max_loops === "number" ? { max_loops: values.max_loops } : {}),
|
|
363
|
+
},
|
|
364
|
+
};
|
|
365
|
+
}
|
|
366
|
+
export function methodAuthoringRequestFromActionValues(input, context) {
|
|
367
|
+
const values = MethodAuthoringActionValuesSchema.parse(input);
|
|
368
|
+
const methodId = values.method_id;
|
|
369
|
+
if (!methodId) {
|
|
370
|
+
throw new Error("Method id is required.");
|
|
371
|
+
}
|
|
372
|
+
const taskPrompt = methodAuthoringTaskPrompt(values);
|
|
373
|
+
return {
|
|
374
|
+
...(context.preparation ? { preparation: context.preparation } : {}),
|
|
375
|
+
source_folder_path: context.sourceFolderPath,
|
|
376
|
+
...(values.base_method_id ? { base_method_id: values.base_method_id } : {}),
|
|
377
|
+
...(values.reference_method_id ? { reference_method_id: values.reference_method_id } : {}),
|
|
378
|
+
method_id: methodId,
|
|
379
|
+
label: values.label ?? titleFromActionId(methodId),
|
|
380
|
+
hint: values.hint ?? conciseSummary(values.portable_output ?? values.task_prompt, "Reusable Method for preparing source files."),
|
|
381
|
+
task_prompt: taskPrompt,
|
|
382
|
+
checks: context.checks ?? [],
|
|
383
|
+
};
|
|
384
|
+
}
|
|
385
|
+
export function methodImprovementActionValues(options) {
|
|
386
|
+
const readinessNotes = (options.checks ?? [])
|
|
387
|
+
.map((check) => check.question)
|
|
388
|
+
.filter((question) => question.trim().length > 0)
|
|
389
|
+
.join("\n");
|
|
390
|
+
return {
|
|
391
|
+
method_id: options.methodId,
|
|
392
|
+
reference_method_id: options.methodId,
|
|
393
|
+
...(maybeActionValue(options.label ?? "") ? { label: options.label } : {}),
|
|
394
|
+
...(maybeActionValue(options.hint ?? "") ? { hint: options.hint } : {}),
|
|
395
|
+
task_prompt: `Improve Method ${options.methodId} using the latest readiness evidence for Preparation ${options.preparationName}.`,
|
|
396
|
+
...(maybeActionValue(readinessNotes) ? { readiness_notes: readinessNotes } : {}),
|
|
397
|
+
};
|
|
398
|
+
}
|
|
399
|
+
function methodAuthoringActionValues(values) {
|
|
400
|
+
const methodId = inputValue(values, "method_id");
|
|
401
|
+
const label = inputValue(values, "label");
|
|
402
|
+
const hint = inputValue(values, "hint");
|
|
403
|
+
const portableOutput = inputValue(values, "portable_output");
|
|
404
|
+
const readinessNotes = inputValue(values, "readiness_notes");
|
|
405
|
+
return {
|
|
406
|
+
...(maybeActionValue(methodId) ? { method_id: methodId } : {}),
|
|
407
|
+
...(maybeActionValue(label) ? { label } : {}),
|
|
408
|
+
...(maybeActionValue(hint) ? { hint } : {}),
|
|
409
|
+
task_prompt: inputValue(values, "task_prompt"),
|
|
410
|
+
...(maybeActionValue(portableOutput) ? { portable_output: portableOutput } : {}),
|
|
411
|
+
...(maybeActionValue(readinessNotes) ? { readiness_notes: readinessNotes } : {}),
|
|
412
|
+
};
|
|
413
|
+
}
|
|
414
|
+
function methodChangeActionValues(action, values) {
|
|
415
|
+
if (action === "modify") {
|
|
416
|
+
const methodId = inputValue(values, "method");
|
|
417
|
+
return {
|
|
418
|
+
method_id: methodId,
|
|
419
|
+
reference_method_id: methodId,
|
|
420
|
+
...(maybeActionValue(inputValue(values, "label")) ? { label: inputValue(values, "label") } : {}),
|
|
421
|
+
...(maybeActionValue(inputValue(values, "hint")) ? { hint: inputValue(values, "hint") } : {}),
|
|
422
|
+
task_prompt: [
|
|
423
|
+
`Modify Method ${methodId}.`,
|
|
424
|
+
inputValue(values, "change_request"),
|
|
425
|
+
].filter(Boolean).join("\n"),
|
|
426
|
+
};
|
|
427
|
+
}
|
|
428
|
+
if (action === "duplicate") {
|
|
429
|
+
const newMethodId = inputValue(values, "new_method_id");
|
|
430
|
+
return {
|
|
431
|
+
action_type: "method-change",
|
|
432
|
+
operation: "duplicate",
|
|
433
|
+
method: inputValue(values, "method"),
|
|
434
|
+
new_method_id: newMethodId,
|
|
435
|
+
label: titleFromActionId(newMethodId),
|
|
436
|
+
hint: `Duplicate of ${inputValue(values, "method")}`,
|
|
437
|
+
};
|
|
438
|
+
}
|
|
439
|
+
return {
|
|
440
|
+
action_type: "method-change",
|
|
441
|
+
operation: "remove",
|
|
442
|
+
method: inputValue(values, "method"),
|
|
443
|
+
confirmation: inputValue(values, "confirmation"),
|
|
444
|
+
};
|
|
445
|
+
}
|
|
446
|
+
function duplicatePreparationActionValues(values) {
|
|
447
|
+
const method = inputValue(values, "method");
|
|
448
|
+
return {
|
|
449
|
+
name: inputValue(values, "name"),
|
|
450
|
+
path: inputValue(values, "path"),
|
|
451
|
+
about: inputValue(values, "about"),
|
|
452
|
+
prepare_after_setup: false,
|
|
453
|
+
setup_mode: "create",
|
|
454
|
+
...(maybeActionValue(method) ? { method } : {}),
|
|
455
|
+
};
|
|
456
|
+
}
|
|
457
|
+
function preparationChangeActionValues(action, values) {
|
|
458
|
+
if (action === "modify" || action === "duplicate")
|
|
459
|
+
return duplicatePreparationActionValues(values);
|
|
460
|
+
return {
|
|
461
|
+
action_type: "preparation-change",
|
|
462
|
+
operation: "remove",
|
|
463
|
+
preparation: inputValue(values, "preparation"),
|
|
464
|
+
confirmation: inputValue(values, "confirmation"),
|
|
465
|
+
};
|
|
466
|
+
}
|
|
467
|
+
export function buildCreatePreparationActionDefinition(context) {
|
|
468
|
+
const existingNames = new Set(context.existingNames);
|
|
469
|
+
const name = uniqueActionId(context.suggestedName, existingNames);
|
|
470
|
+
return {
|
|
471
|
+
id: INTERF_SERVICE_ACTIONS.createPreparation.id,
|
|
472
|
+
title: INTERF_SERVICE_ACTIONS.createPreparation.title,
|
|
473
|
+
description: "Describe the agent job. Interf saves the Preparation through the local service and starts its first prepare run.",
|
|
474
|
+
submitLabel: "Confirm",
|
|
475
|
+
initialValues: {
|
|
476
|
+
name,
|
|
477
|
+
path: context.sourcePath,
|
|
478
|
+
about: "",
|
|
479
|
+
method: "interf-default",
|
|
480
|
+
readiness_notes: "",
|
|
481
|
+
},
|
|
482
|
+
schema: createPreparationSchema(existingNames),
|
|
483
|
+
validateRequest: (values) => packageSchemaFieldErrors(PreparationSetupActionValuesSchema.safeParse(createPreparationActionValues(values)), {
|
|
484
|
+
name: "name",
|
|
485
|
+
path: "path",
|
|
486
|
+
about: "about",
|
|
487
|
+
method: "method",
|
|
488
|
+
}),
|
|
489
|
+
valuesPreview: createPreparationActionValues,
|
|
490
|
+
buildDraft: (values) => {
|
|
491
|
+
const actionValues = createPreparationActionValues(values);
|
|
492
|
+
const method = inputValue(values, "method");
|
|
493
|
+
const readinessNotes = inputValue(values, "readiness_notes");
|
|
494
|
+
return {
|
|
495
|
+
preparation: inputValue(values, "name"),
|
|
496
|
+
values: actionValues,
|
|
497
|
+
message: [
|
|
498
|
+
`Create Preparation ${inputValue(values, "name")}.`,
|
|
499
|
+
`Agent work: ${inputValue(values, "about")}`,
|
|
500
|
+
maybeActionValue(method) ? `Method: ${method}` : null,
|
|
501
|
+
maybeActionValue(readinessNotes) ? `Readiness checks: ${readinessNotes}` : null,
|
|
502
|
+
`Source folder: ${inputValue(values, "path")}`,
|
|
503
|
+
"Use the attached typed action input as the source of truth.",
|
|
504
|
+
].filter((line) => Boolean(line)).join("\n"),
|
|
505
|
+
};
|
|
506
|
+
},
|
|
507
|
+
fields: [
|
|
508
|
+
{
|
|
509
|
+
name: "about",
|
|
510
|
+
label: "Agent job",
|
|
511
|
+
type: "textarea",
|
|
512
|
+
rows: 4,
|
|
513
|
+
help: "The concrete work this prepared folder should enable.",
|
|
514
|
+
context: "Saved as the Preparation intent and sent as typed action input.",
|
|
515
|
+
placeholder: "Example: Analyze every report chart, extract annual take-up by location, and produce a source data file plus markdown summary.",
|
|
516
|
+
},
|
|
517
|
+
{
|
|
518
|
+
name: "method",
|
|
519
|
+
label: "Method",
|
|
520
|
+
type: "select",
|
|
521
|
+
help: "How Interf should build portable context for this Preparation.",
|
|
522
|
+
context: "Saved as the Method selected for this Preparation.",
|
|
523
|
+
options: methodChoiceOptions(context.methods),
|
|
524
|
+
},
|
|
525
|
+
{
|
|
526
|
+
name: "readiness_notes",
|
|
527
|
+
label: "Ready when",
|
|
528
|
+
type: "textarea",
|
|
529
|
+
rows: 3,
|
|
530
|
+
help: "Concrete checks that prove the prepared context is good enough.",
|
|
531
|
+
context: "Used as guidance when Interf proposes Preparation-level readiness checks.",
|
|
532
|
+
placeholder: "Example: Every output is source-backed, complete for the requested locations, and precise enough to verify.",
|
|
533
|
+
},
|
|
534
|
+
{
|
|
535
|
+
name: "name",
|
|
536
|
+
label: "Preparation id",
|
|
537
|
+
type: "text",
|
|
538
|
+
advanced: true,
|
|
539
|
+
help: "Auto-generated for the CLI and portable-context folder. Change only if needed.",
|
|
540
|
+
context: "Used in the CLI, saved on the Preparation, and used for the portable-context folder name.",
|
|
541
|
+
placeholder: name,
|
|
542
|
+
},
|
|
543
|
+
],
|
|
544
|
+
};
|
|
545
|
+
}
|
|
546
|
+
export function buildPrepareRunActionDefinition(context) {
|
|
547
|
+
return {
|
|
548
|
+
id: INTERF_SERVICE_ACTIONS.runPreparation.id,
|
|
549
|
+
title: INTERF_SERVICE_ACTIONS.runPreparation.title,
|
|
550
|
+
description: "Build portable context for this Preparation. Interf will run the saved Method against the source folder and record a visible run.",
|
|
551
|
+
submitLabel: "Run",
|
|
552
|
+
initialValues: {
|
|
553
|
+
preparation: context.name,
|
|
554
|
+
method: context.methodId,
|
|
555
|
+
about: context.about,
|
|
556
|
+
source_folder_path: context.sourceFolderPath,
|
|
557
|
+
},
|
|
558
|
+
schema: prepareRunSchema(),
|
|
559
|
+
valuesPreview: (values) => ({
|
|
560
|
+
action_type: INTERF_SERVICE_ACTIONS.runPreparation.serviceAction,
|
|
561
|
+
preparation: inputValue(values, "preparation"),
|
|
562
|
+
method: inputValue(values, "method"),
|
|
563
|
+
source_folder_path: inputValue(values, "source_folder_path"),
|
|
564
|
+
about: inputValue(values, "about"),
|
|
565
|
+
}),
|
|
566
|
+
buildDraft: (values) => ({
|
|
567
|
+
preparation: inputValue(values, "preparation"),
|
|
568
|
+
values: {
|
|
569
|
+
action_type: INTERF_SERVICE_ACTIONS.runPreparation.serviceAction,
|
|
570
|
+
preparation: inputValue(values, "preparation"),
|
|
571
|
+
...(maybeActionValue(inputValue(values, "method")) ? { method: inputValue(values, "method") } : {}),
|
|
572
|
+
},
|
|
573
|
+
message: [
|
|
574
|
+
`Run Preparation ${inputValue(values, "preparation")}.`,
|
|
575
|
+
maybeActionValue(inputValue(values, "method")) ? `Method: ${inputValue(values, "method")}` : null,
|
|
576
|
+
maybeActionValue(inputValue(values, "about")) ? `Agent work: ${inputValue(values, "about")}` : null,
|
|
577
|
+
"Build portable context from the saved Source Folder and selected Method.",
|
|
578
|
+
"Use the attached typed action input as the source of truth.",
|
|
579
|
+
].filter((line) => Boolean(line)).join("\n"),
|
|
580
|
+
}),
|
|
581
|
+
fields: [
|
|
582
|
+
{
|
|
583
|
+
name: "preparation",
|
|
584
|
+
label: "Preparation",
|
|
585
|
+
type: "text",
|
|
586
|
+
readOnly: true,
|
|
587
|
+
help: "The saved Preparation that will be built.",
|
|
588
|
+
context: "Sent as the compile target.",
|
|
589
|
+
},
|
|
590
|
+
{
|
|
591
|
+
name: "method",
|
|
592
|
+
label: "Method",
|
|
593
|
+
type: "text",
|
|
594
|
+
readOnly: true,
|
|
595
|
+
help: "The Method Interf will run for this Preparation.",
|
|
596
|
+
context: "Sent as the compile Method override.",
|
|
597
|
+
},
|
|
598
|
+
{
|
|
599
|
+
name: "about",
|
|
600
|
+
label: "Agent job",
|
|
601
|
+
type: "textarea",
|
|
602
|
+
readOnly: true,
|
|
603
|
+
advanced: true,
|
|
604
|
+
help: "The work this Preparation is meant to support.",
|
|
605
|
+
context: "Preserved as context for the prepare-run proposal.",
|
|
606
|
+
placeholder: "No saved job description.",
|
|
607
|
+
},
|
|
608
|
+
{
|
|
609
|
+
name: "source_folder_path",
|
|
610
|
+
label: "Source Folder",
|
|
611
|
+
type: "text",
|
|
612
|
+
readOnly: true,
|
|
613
|
+
advanced: true,
|
|
614
|
+
help: "The local folder Interf will read.",
|
|
615
|
+
context: "Resolved from the saved Preparation.",
|
|
616
|
+
},
|
|
617
|
+
],
|
|
618
|
+
};
|
|
619
|
+
}
|
|
620
|
+
export function buildPrepareRunActionDraft(context) {
|
|
621
|
+
const definition = buildPrepareRunActionDefinition(context);
|
|
622
|
+
return definition.buildDraft(definition.initialValues);
|
|
623
|
+
}
|
|
624
|
+
export function buildSelectMethodActionDefinition(context) {
|
|
625
|
+
const actionValues = (values) => ({
|
|
626
|
+
...selectMethodActionValues(values),
|
|
627
|
+
checks: context.checks ?? [],
|
|
628
|
+
...(typeof context.maxAttempts === "number" ? { max_attempts: context.maxAttempts } : {}),
|
|
629
|
+
...(typeof context.maxLoops === "number" ? { max_loops: context.maxLoops } : {}),
|
|
630
|
+
});
|
|
631
|
+
return {
|
|
632
|
+
id: INTERF_SERVICE_ACTIONS.selectMethod.id,
|
|
633
|
+
title: INTERF_SERVICE_ACTIONS.selectMethod.title,
|
|
634
|
+
description: "Choose which Method this Preparation uses for future prepare runs. This saves the selection without running prepare.",
|
|
635
|
+
submitLabel: "Confirm",
|
|
636
|
+
initialValues: {
|
|
637
|
+
name: context.name,
|
|
638
|
+
path: context.sourceFolderPath,
|
|
639
|
+
about: context.about,
|
|
640
|
+
current_method: context.currentMethodId,
|
|
641
|
+
method: context.currentMethodId || "interf-default",
|
|
642
|
+
},
|
|
643
|
+
schema: selectMethodSchema(),
|
|
644
|
+
validateRequest: (values) => packageSchemaFieldErrors(PreparationSetupActionValuesSchema.safeParse(actionValues(values)), {
|
|
645
|
+
name: "name",
|
|
646
|
+
path: "path",
|
|
647
|
+
about: "about",
|
|
648
|
+
method: "method",
|
|
649
|
+
}),
|
|
650
|
+
valuesPreview: actionValues,
|
|
651
|
+
buildDraft: (values) => ({
|
|
652
|
+
preparation: inputValue(values, "name"),
|
|
653
|
+
values: actionValues(values),
|
|
654
|
+
message: [
|
|
655
|
+
`Select Method ${inputValue(values, "method") || "interf-default"} for Preparation ${inputValue(values, "name")}.`,
|
|
656
|
+
"Save the selected Method. Do not run prepare yet.",
|
|
657
|
+
"Use the attached typed action input as the source of truth.",
|
|
658
|
+
].join("\n"),
|
|
659
|
+
}),
|
|
660
|
+
fields: [
|
|
661
|
+
{
|
|
662
|
+
name: "method",
|
|
663
|
+
label: "Method",
|
|
664
|
+
type: "select",
|
|
665
|
+
help: "The Method future prepare runs should use.",
|
|
666
|
+
context: "Saved on the existing Preparation.",
|
|
667
|
+
options: methodChoiceOptions(context.methods),
|
|
668
|
+
},
|
|
669
|
+
{
|
|
670
|
+
name: "current_method",
|
|
671
|
+
label: "Current Method",
|
|
672
|
+
type: "text",
|
|
673
|
+
readOnly: true,
|
|
674
|
+
help: "The Method currently saved for this Preparation.",
|
|
675
|
+
context: "Shown so the change is explicit before approval.",
|
|
676
|
+
},
|
|
677
|
+
{
|
|
678
|
+
name: "name",
|
|
679
|
+
label: "Preparation",
|
|
680
|
+
type: "text",
|
|
681
|
+
readOnly: true,
|
|
682
|
+
advanced: true,
|
|
683
|
+
help: "The Preparation whose Method selection will be updated.",
|
|
684
|
+
context: "Sent with the setup action.",
|
|
685
|
+
},
|
|
686
|
+
{
|
|
687
|
+
name: "about",
|
|
688
|
+
label: "Agent job",
|
|
689
|
+
type: "textarea",
|
|
690
|
+
readOnly: true,
|
|
691
|
+
advanced: true,
|
|
692
|
+
help: "The saved job intent for this Preparation.",
|
|
693
|
+
context: "Preserved while updating the selected Method.",
|
|
694
|
+
},
|
|
695
|
+
{
|
|
696
|
+
name: "path",
|
|
697
|
+
label: "Source Folder",
|
|
698
|
+
type: "text",
|
|
699
|
+
readOnly: true,
|
|
700
|
+
advanced: true,
|
|
701
|
+
help: "The saved Source Folder path.",
|
|
702
|
+
context: "Preserved while updating the selected Method.",
|
|
703
|
+
},
|
|
704
|
+
],
|
|
705
|
+
};
|
|
706
|
+
}
|
|
707
|
+
export function buildCreateMethodActionDefinition(context) {
|
|
708
|
+
const existingMethodIds = new Set(context.existingMethodIds);
|
|
709
|
+
const defaultSeed = context.defaultPreparation ? `${context.defaultPreparation}-method` : context.suggestedMethodId;
|
|
710
|
+
const methodId = uniqueActionId(defaultSeed, existingMethodIds);
|
|
711
|
+
const label = titleFromActionId(methodId);
|
|
712
|
+
return {
|
|
713
|
+
id: INTERF_SERVICE_ACTIONS.createMethod.id,
|
|
714
|
+
title: INTERF_SERVICE_ACTIONS.createMethod.title,
|
|
715
|
+
description: "Describe the reusable job this Method should make possible. Interf will generate the stable Method metadata unless you override it.",
|
|
716
|
+
submitLabel: "Send Request",
|
|
717
|
+
initialValues: {
|
|
718
|
+
method_id: "",
|
|
719
|
+
label: "",
|
|
720
|
+
hint: "",
|
|
721
|
+
task_prompt: "",
|
|
722
|
+
portable_output: "",
|
|
723
|
+
readiness_notes: "",
|
|
724
|
+
},
|
|
725
|
+
normalizeValues: (values) => normalizedMethodActionValues(values, existingMethodIds, defaultSeed),
|
|
726
|
+
schema: methodAuthoringSchema(existingMethodIds),
|
|
727
|
+
validateRequest: (values) => packageSchemaFieldErrors(MethodAuthoringActionValuesSchema.safeParse(methodAuthoringActionValues(values)), {
|
|
728
|
+
method_id: "method_id",
|
|
729
|
+
label: "label",
|
|
730
|
+
hint: "hint",
|
|
731
|
+
task_prompt: "task_prompt",
|
|
732
|
+
portable_output: "portable_output",
|
|
733
|
+
readiness_notes: "readiness_notes",
|
|
734
|
+
}),
|
|
735
|
+
valuesPreview: (values) => ({
|
|
736
|
+
method_id: inputValue(values, "method_id"),
|
|
737
|
+
label: inputValue(values, "label"),
|
|
738
|
+
hint: inputValue(values, "hint"),
|
|
739
|
+
task_prompt: methodTaskPromptFromInput(values),
|
|
740
|
+
}),
|
|
741
|
+
buildDraft: (values) => ({
|
|
742
|
+
preparation: context.defaultPreparation,
|
|
743
|
+
values: methodAuthoringActionValues(values),
|
|
744
|
+
message: [
|
|
745
|
+
`Create Method ${inputValue(values, "method_id")}${context.defaultPreparation ? ` for Preparation ${context.defaultPreparation}` : ""}.`,
|
|
746
|
+
`Label: ${inputValue(values, "label")}`,
|
|
747
|
+
`Summary: ${inputValue(values, "hint")}`,
|
|
748
|
+
methodTaskPromptFromInput(values),
|
|
749
|
+
"Use the attached typed action input as the Method authoring request.",
|
|
750
|
+
].join("\n"),
|
|
751
|
+
}),
|
|
752
|
+
fields: [
|
|
753
|
+
{
|
|
754
|
+
name: "task_prompt",
|
|
755
|
+
label: "Agent work",
|
|
756
|
+
type: "textarea",
|
|
757
|
+
rows: 4,
|
|
758
|
+
help: "The reusable job this Method should make possible for agents.",
|
|
759
|
+
context: "Used as the main Method-authoring instruction.",
|
|
760
|
+
placeholder: "Example: Analyze every report chart, extract annual take-up by location, and produce a source data file plus markdown summary.",
|
|
761
|
+
},
|
|
762
|
+
{
|
|
763
|
+
name: "portable_output",
|
|
764
|
+
label: "Portable-context output",
|
|
765
|
+
type: "textarea",
|
|
766
|
+
rows: 3,
|
|
767
|
+
help: "Files, sections, or evidence agents should receive in portable context.",
|
|
768
|
+
context: "Guides the Method output shape and stage artifact plan.",
|
|
769
|
+
placeholder: "Describe the files or sections agents should receive.",
|
|
770
|
+
},
|
|
771
|
+
{
|
|
772
|
+
name: "readiness_notes",
|
|
773
|
+
label: "Readiness guidance",
|
|
774
|
+
type: "textarea",
|
|
775
|
+
rows: 3,
|
|
776
|
+
help: "What a Preparation using this Method should be able to prove.",
|
|
777
|
+
context: "Guides Preparation-level readiness checks. Method acceptance criteria stay separate.",
|
|
778
|
+
placeholder: "Describe the evidence that should make a Preparation ready.",
|
|
779
|
+
},
|
|
780
|
+
{
|
|
781
|
+
name: "method_id",
|
|
782
|
+
label: "Method id",
|
|
783
|
+
type: "text",
|
|
784
|
+
advanced: true,
|
|
785
|
+
help: "Optional. Leave blank and Interf generates a stable id from the job.",
|
|
786
|
+
context: "Saved under the Workspace methods folder and referenced by Preparations.",
|
|
787
|
+
placeholder: methodId,
|
|
788
|
+
},
|
|
789
|
+
{
|
|
790
|
+
name: "label",
|
|
791
|
+
label: "Label",
|
|
792
|
+
type: "text",
|
|
793
|
+
advanced: true,
|
|
794
|
+
help: "Optional readable name people can choose later.",
|
|
795
|
+
context: "Shown in the UI and sent to the local agent while drafting the Method.",
|
|
796
|
+
placeholder: label,
|
|
797
|
+
},
|
|
798
|
+
{
|
|
799
|
+
name: "hint",
|
|
800
|
+
label: "Summary",
|
|
801
|
+
type: "textarea",
|
|
802
|
+
advanced: true,
|
|
803
|
+
rows: 2,
|
|
804
|
+
help: "Optional short description. Interf derives one from the job if left blank.",
|
|
805
|
+
context: "Gives the local agent quick context before it drafts stages and outputs.",
|
|
806
|
+
placeholder: "Prepare charts, tables, and cited findings for analyst agents.",
|
|
807
|
+
},
|
|
808
|
+
],
|
|
809
|
+
};
|
|
810
|
+
}
|
|
811
|
+
export function buildMethodChangeActionDefinition(context) {
|
|
812
|
+
const existingMethodIds = new Set(context.existingMethodIds);
|
|
813
|
+
const actionLabel = titleFromActionId(context.action);
|
|
814
|
+
const newMethodId = context.action === "duplicate"
|
|
815
|
+
? uniqueActionId(`${context.methodId}-copy`, existingMethodIds)
|
|
816
|
+
: "";
|
|
817
|
+
const initialValues = {
|
|
818
|
+
action: `method-${context.action}`,
|
|
819
|
+
method: context.methodId,
|
|
820
|
+
preparation: context.preparation,
|
|
821
|
+
...(context.action === "modify" ? { change_request: "", label: context.label ?? "", hint: context.hint ?? "" } : {}),
|
|
822
|
+
...(context.action === "duplicate" ? { new_method_id: newMethodId } : {}),
|
|
823
|
+
...(context.action === "remove" ? { confirmation: "" } : {}),
|
|
824
|
+
};
|
|
825
|
+
const actionValues = (values) => methodChangeActionValues(context.action, values);
|
|
826
|
+
const messageFor = (values) => {
|
|
827
|
+
if (context.action === "modify") {
|
|
828
|
+
return [
|
|
829
|
+
`Modify Method ${inputValue(values, "method")}.`,
|
|
830
|
+
`Requested change: ${inputValue(values, "change_request")}`,
|
|
831
|
+
"Use the attached typed Method-authoring input as the source of truth.",
|
|
832
|
+
].join("\n");
|
|
833
|
+
}
|
|
834
|
+
if (context.action === "duplicate") {
|
|
835
|
+
return [
|
|
836
|
+
`Duplicate Method ${inputValue(values, "method")} as ${inputValue(values, "new_method_id")}.`,
|
|
837
|
+
"Use the attached typed Method change input as the source of truth.",
|
|
838
|
+
].join("\n");
|
|
839
|
+
}
|
|
840
|
+
return [
|
|
841
|
+
`Remove Method ${inputValue(values, "method")}.`,
|
|
842
|
+
"The user typed the Method id to confirm removal.",
|
|
843
|
+
"Use the attached typed Method change input as the source of truth.",
|
|
844
|
+
].join("\n");
|
|
845
|
+
};
|
|
846
|
+
const fields = [
|
|
847
|
+
{
|
|
848
|
+
name: "method",
|
|
849
|
+
label: "Method",
|
|
850
|
+
type: "text",
|
|
851
|
+
readOnly: true,
|
|
852
|
+
help: "The Method this request targets.",
|
|
853
|
+
context: "Sent as the Method change target.",
|
|
854
|
+
},
|
|
855
|
+
{
|
|
856
|
+
name: "change_request",
|
|
857
|
+
label: context.action === "duplicate" ? "Requested difference" : "Requested change",
|
|
858
|
+
type: "textarea",
|
|
859
|
+
rows: 4,
|
|
860
|
+
advanced: context.action === "remove",
|
|
861
|
+
help: context.action === "duplicate"
|
|
862
|
+
? "What should be different in the duplicate Method."
|
|
863
|
+
: "What should change in the existing Method.",
|
|
864
|
+
context: "Sent as the human-authored Method change request.",
|
|
865
|
+
placeholder: "Describe the concrete change Interf should make.",
|
|
866
|
+
},
|
|
867
|
+
{
|
|
868
|
+
name: "new_method_id",
|
|
869
|
+
label: "New Method id",
|
|
870
|
+
type: "text",
|
|
871
|
+
advanced: context.action !== "duplicate",
|
|
872
|
+
help: "Stable id for the duplicated Method.",
|
|
873
|
+
context: "Used as the target Method id for the duplicate request.",
|
|
874
|
+
placeholder: newMethodId,
|
|
875
|
+
},
|
|
876
|
+
{
|
|
877
|
+
name: "confirmation",
|
|
878
|
+
label: "Confirm removal",
|
|
879
|
+
type: "text",
|
|
880
|
+
advanced: context.action !== "remove",
|
|
881
|
+
help: `Type ${context.methodId} to confirm this removal request.`,
|
|
882
|
+
context: "Prevents accidental destructive Method requests.",
|
|
883
|
+
placeholder: context.methodId,
|
|
884
|
+
},
|
|
885
|
+
{
|
|
886
|
+
name: "label",
|
|
887
|
+
label: "Label",
|
|
888
|
+
type: "text",
|
|
889
|
+
advanced: true,
|
|
890
|
+
help: "Readable Method name to keep while modifying this Method.",
|
|
891
|
+
context: "Sent to the Method-authoring run.",
|
|
892
|
+
placeholder: context.label ?? context.methodId,
|
|
893
|
+
},
|
|
894
|
+
{
|
|
895
|
+
name: "hint",
|
|
896
|
+
label: "Summary",
|
|
897
|
+
type: "textarea",
|
|
898
|
+
rows: 2,
|
|
899
|
+
advanced: true,
|
|
900
|
+
help: "Short Method summary to keep while modifying this Method.",
|
|
901
|
+
context: "Sent to the Method-authoring run.",
|
|
902
|
+
placeholder: context.hint ?? "Reusable Method for preparing source folders.",
|
|
903
|
+
},
|
|
904
|
+
{
|
|
905
|
+
name: "preparation",
|
|
906
|
+
label: "Preparation",
|
|
907
|
+
type: "text",
|
|
908
|
+
readOnly: true,
|
|
909
|
+
advanced: true,
|
|
910
|
+
help: "A related Preparation used as context for this request.",
|
|
911
|
+
context: "Sent with the proposal request when available.",
|
|
912
|
+
placeholder: "No Preparation selected",
|
|
913
|
+
},
|
|
914
|
+
];
|
|
915
|
+
return {
|
|
916
|
+
id: `${INTERF_SERVICE_ACTIONS.methodChange.id}-${context.action}`,
|
|
917
|
+
title: `${actionLabel} Method`,
|
|
918
|
+
description: context.action === "remove"
|
|
919
|
+
? "Confirm the Method removal request. Interf will reject removal while any saved Preparation still uses it."
|
|
920
|
+
: context.action === "duplicate"
|
|
921
|
+
? "Duplicate this Method through the local Interf service."
|
|
922
|
+
: "Describe the change and Interf will run a visible Method draft job.",
|
|
923
|
+
submitLabel: context.action === "modify" ? "Send Request" : "Confirm",
|
|
924
|
+
initialValues,
|
|
925
|
+
schema: methodChangeSchema(context.action, context.methodId, existingMethodIds),
|
|
926
|
+
valuesPreview: actionValues,
|
|
927
|
+
buildDraft: (values) => ({
|
|
928
|
+
preparation: inputValue(values, "preparation"),
|
|
929
|
+
values: actionValues(values),
|
|
930
|
+
message: messageFor(values),
|
|
931
|
+
}),
|
|
932
|
+
fields: fields.filter((field) => {
|
|
933
|
+
if (field.name === "change_request")
|
|
934
|
+
return context.action === "modify";
|
|
935
|
+
if (field.name === "new_method_id")
|
|
936
|
+
return context.action === "duplicate";
|
|
937
|
+
if (field.name === "confirmation")
|
|
938
|
+
return context.action === "remove";
|
|
939
|
+
if (field.name === "label" || field.name === "hint")
|
|
940
|
+
return context.action === "modify";
|
|
941
|
+
return true;
|
|
942
|
+
}),
|
|
943
|
+
};
|
|
944
|
+
}
|
|
945
|
+
export function buildPreparationChangeActionDefinition(context) {
|
|
946
|
+
const existingNames = new Set(context.existingNames);
|
|
947
|
+
const actionLabel = titleFromActionId(context.action);
|
|
948
|
+
const duplicateName = context.action === "duplicate"
|
|
949
|
+
? uniqueActionId(`${context.preparation}-copy`, existingNames)
|
|
950
|
+
: "";
|
|
951
|
+
const initialValues = {
|
|
952
|
+
action: `preparation-${context.action}`,
|
|
953
|
+
preparation: context.preparation,
|
|
954
|
+
...(context.action === "modify" || context.action === "duplicate"
|
|
955
|
+
? {
|
|
956
|
+
name: context.action === "duplicate" ? duplicateName : context.preparation,
|
|
957
|
+
path: context.sourceFolderPath,
|
|
958
|
+
about: context.about ?? "",
|
|
959
|
+
method: context.methodId ?? "interf-default",
|
|
960
|
+
}
|
|
961
|
+
: {}),
|
|
962
|
+
...(context.action === "remove" ? { confirmation: "" } : {}),
|
|
963
|
+
};
|
|
964
|
+
const actionValues = (values) => preparationChangeActionValues(context.action, values);
|
|
965
|
+
const messageFor = (values) => {
|
|
966
|
+
if (context.action === "modify") {
|
|
967
|
+
return [
|
|
968
|
+
`Modify Preparation ${inputValue(values, "preparation")}.`,
|
|
969
|
+
`Agent work: ${inputValue(values, "about")}`,
|
|
970
|
+
maybeActionValue(inputValue(values, "method")) ? `Method: ${inputValue(values, "method")}` : null,
|
|
971
|
+
`Source folder: ${inputValue(values, "path")}`,
|
|
972
|
+
"Use the attached typed Preparation setup input as the source of truth.",
|
|
973
|
+
].filter((line) => Boolean(line)).join("\n");
|
|
974
|
+
}
|
|
975
|
+
if (context.action === "duplicate") {
|
|
976
|
+
return [
|
|
977
|
+
`Duplicate Preparation ${inputValue(values, "preparation")} as ${inputValue(values, "name")}.`,
|
|
978
|
+
`Agent work: ${inputValue(values, "about")}`,
|
|
979
|
+
maybeActionValue(inputValue(values, "method")) ? `Method: ${inputValue(values, "method")}` : null,
|
|
980
|
+
`Source folder: ${inputValue(values, "path")}`,
|
|
981
|
+
"Use the attached typed Preparation setup input as the source of truth.",
|
|
982
|
+
].filter((line) => Boolean(line)).join("\n");
|
|
983
|
+
}
|
|
984
|
+
return [
|
|
985
|
+
`Remove Preparation ${inputValue(values, "preparation")}.`,
|
|
986
|
+
"The user typed the Preparation id to confirm removal.",
|
|
987
|
+
"Use the attached typed Preparation change input as the source of truth.",
|
|
988
|
+
].join("\n");
|
|
989
|
+
};
|
|
990
|
+
const fields = [
|
|
991
|
+
{
|
|
992
|
+
name: "preparation",
|
|
993
|
+
label: "Preparation",
|
|
994
|
+
type: "text",
|
|
995
|
+
readOnly: true,
|
|
996
|
+
help: "The saved Preparation this request targets.",
|
|
997
|
+
context: "Sent as the Preparation target.",
|
|
998
|
+
},
|
|
999
|
+
{
|
|
1000
|
+
name: "name",
|
|
1001
|
+
label: context.action === "duplicate" ? "New Preparation id" : "Preparation id",
|
|
1002
|
+
type: "text",
|
|
1003
|
+
readOnly: context.action === "modify",
|
|
1004
|
+
help: context.action === "duplicate"
|
|
1005
|
+
? "Stable id for the duplicated Preparation."
|
|
1006
|
+
: "Stable id for this Preparation.",
|
|
1007
|
+
context: "Saved as the Preparation name.",
|
|
1008
|
+
placeholder: duplicateName || context.preparation,
|
|
1009
|
+
},
|
|
1010
|
+
{
|
|
1011
|
+
name: "about",
|
|
1012
|
+
label: "Agent job",
|
|
1013
|
+
type: "textarea",
|
|
1014
|
+
rows: 4,
|
|
1015
|
+
help: "The concrete work this Preparation should support.",
|
|
1016
|
+
context: "Saved as the Preparation intent.",
|
|
1017
|
+
placeholder: "Describe the agent job.",
|
|
1018
|
+
},
|
|
1019
|
+
{
|
|
1020
|
+
name: "method",
|
|
1021
|
+
label: "Method",
|
|
1022
|
+
type: "text",
|
|
1023
|
+
help: "The Method future prepare runs should use.",
|
|
1024
|
+
context: "Saved on this Preparation.",
|
|
1025
|
+
placeholder: "interf-default",
|
|
1026
|
+
},
|
|
1027
|
+
{
|
|
1028
|
+
name: "path",
|
|
1029
|
+
label: "Source Folder",
|
|
1030
|
+
type: "text",
|
|
1031
|
+
readOnly: true,
|
|
1032
|
+
advanced: context.action === "modify",
|
|
1033
|
+
help: "The Source Folder for this Preparation.",
|
|
1034
|
+
context: "Saved on this Preparation.",
|
|
1035
|
+
},
|
|
1036
|
+
{
|
|
1037
|
+
name: "confirmation",
|
|
1038
|
+
label: "Confirm removal",
|
|
1039
|
+
type: "text",
|
|
1040
|
+
help: `Type ${context.preparation} to confirm this removal request.`,
|
|
1041
|
+
context: "Prevents accidental destructive Preparation requests.",
|
|
1042
|
+
placeholder: context.preparation,
|
|
1043
|
+
},
|
|
1044
|
+
];
|
|
1045
|
+
return {
|
|
1046
|
+
id: `${INTERF_SERVICE_ACTIONS.preparationChange.id}-${context.action}`,
|
|
1047
|
+
title: `${actionLabel} Preparation`,
|
|
1048
|
+
description: context.action === "remove"
|
|
1049
|
+
? "Confirm the Preparation removal request before Interf removes it from the saved config."
|
|
1050
|
+
: context.action === "duplicate"
|
|
1051
|
+
? "Describe the new Preparation created from this saved Source Folder."
|
|
1052
|
+
: "Update the saved Preparation fields through the local Interf service.",
|
|
1053
|
+
submitLabel: "Confirm",
|
|
1054
|
+
initialValues,
|
|
1055
|
+
schema: preparationChangeSchema(context.action, context.preparation, existingNames),
|
|
1056
|
+
validateRequest: context.action === "modify" || context.action === "duplicate"
|
|
1057
|
+
? (values) => packageSchemaFieldErrors(PreparationSetupActionValuesSchema.safeParse(duplicatePreparationActionValues(values)), {
|
|
1058
|
+
name: "name",
|
|
1059
|
+
path: "path",
|
|
1060
|
+
about: "about",
|
|
1061
|
+
method: "method",
|
|
1062
|
+
})
|
|
1063
|
+
: undefined,
|
|
1064
|
+
valuesPreview: actionValues,
|
|
1065
|
+
buildDraft: (values) => ({
|
|
1066
|
+
preparation: inputValue(values, "preparation"),
|
|
1067
|
+
values: actionValues(values),
|
|
1068
|
+
message: messageFor(values),
|
|
1069
|
+
}),
|
|
1070
|
+
fields: fields.filter((field) => {
|
|
1071
|
+
if (field.name === "name" || field.name === "about" || field.name === "method" || field.name === "path")
|
|
1072
|
+
return context.action === "modify" || context.action === "duplicate";
|
|
1073
|
+
if (field.name === "confirmation")
|
|
1074
|
+
return context.action === "remove";
|
|
1075
|
+
return true;
|
|
1076
|
+
}),
|
|
1077
|
+
};
|
|
1078
|
+
}
|
|
1079
|
+
export function buildConfirmActionDefinition(draft) {
|
|
1080
|
+
return {
|
|
1081
|
+
id: INTERF_SERVICE_ACTIONS.confirmAction.id,
|
|
1082
|
+
title: INTERF_SERVICE_ACTIONS.confirmAction.title,
|
|
1083
|
+
description: "This request will be sent to the local Interf service to create an approval proposal.",
|
|
1084
|
+
submitLabel: "Send Request",
|
|
1085
|
+
initialValues: {
|
|
1086
|
+
preparation: draft.preparation,
|
|
1087
|
+
message: draft.message,
|
|
1088
|
+
},
|
|
1089
|
+
schema: z.object({
|
|
1090
|
+
preparation: optionalActionText,
|
|
1091
|
+
message: requiredActionText("Action"),
|
|
1092
|
+
}).strict(),
|
|
1093
|
+
valuesPreview: () => draft.values ?? { message: draft.message },
|
|
1094
|
+
buildDraft: () => ({ ...draft, confirmed: true }),
|
|
1095
|
+
fields: [
|
|
1096
|
+
{
|
|
1097
|
+
name: "preparation",
|
|
1098
|
+
label: "Preparation",
|
|
1099
|
+
type: "text",
|
|
1100
|
+
readOnly: true,
|
|
1101
|
+
help: "The Preparation this action targets.",
|
|
1102
|
+
context: "Sent with the proposal request.",
|
|
1103
|
+
placeholder: "No Preparation selected",
|
|
1104
|
+
},
|
|
1105
|
+
{
|
|
1106
|
+
name: "message",
|
|
1107
|
+
label: "Request to Interf service",
|
|
1108
|
+
type: "textarea",
|
|
1109
|
+
readOnly: true,
|
|
1110
|
+
rows: 5,
|
|
1111
|
+
help: "Interf sends this request with typed values so the local service can propose the concrete action.",
|
|
1112
|
+
context: "Sent to the local Interf service together with typed action values when available.",
|
|
1113
|
+
},
|
|
1114
|
+
],
|
|
1115
|
+
};
|
|
1116
|
+
}
|
|
1117
|
+
export function buildReadinessActionDraft(options) {
|
|
1118
|
+
if (options.action === "check") {
|
|
1119
|
+
return {
|
|
1120
|
+
preparation: options.preparation,
|
|
1121
|
+
message: `Check readiness for ${options.preparation}.`,
|
|
1122
|
+
values: {
|
|
1123
|
+
action_type: INTERF_SERVICE_ACTIONS.checkReadiness.serviceAction,
|
|
1124
|
+
preparation: options.preparation,
|
|
1125
|
+
mode: "both",
|
|
1126
|
+
},
|
|
1127
|
+
};
|
|
1128
|
+
}
|
|
1129
|
+
if (options.action === "draft-checks") {
|
|
1130
|
+
return {
|
|
1131
|
+
preparation: options.preparation,
|
|
1132
|
+
message: `Draft readiness checks for ${options.preparation}.`,
|
|
1133
|
+
values: {
|
|
1134
|
+
action_type: INTERF_SERVICE_ACTIONS.draftReadinessChecks.serviceAction,
|
|
1135
|
+
preparation: options.preparation,
|
|
1136
|
+
},
|
|
1137
|
+
};
|
|
1138
|
+
}
|
|
1139
|
+
return {
|
|
1140
|
+
preparation: options.preparation,
|
|
1141
|
+
message: `Improve ${options.preparation} using the latest readiness evidence.`,
|
|
1142
|
+
values: {
|
|
1143
|
+
action_type: INTERF_SERVICE_ACTIONS.improvePreparation.serviceAction,
|
|
1144
|
+
...(options.methodId ? { method: options.methodId } : {}),
|
|
1145
|
+
preparation: options.preparation,
|
|
1146
|
+
},
|
|
1147
|
+
};
|
|
1148
|
+
}
|