@boboddy/sdk 0.5.1 → 0.5.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/definitions/pipelines/chain-graph.d.ts +29 -0
- package/dist/definitions/pipelines/compile-node-definitions.d.ts +0 -8
- package/dist/definitions/pipelines/define-pipeline.d.ts +2 -0
- package/dist/definitions/pipelines/index.js +2 -21
- package/dist/definitions/steps/define-code-step.d.ts +17 -5
- package/dist/definitions/steps/define-step.d.ts +1 -1
- package/dist/definitions/steps/index.js +96 -31
- package/dist/definitions/steps/step-features.d.ts +92 -31
- package/dist/definitions/validation/index.d.ts +2 -0
- package/dist/definitions/validation/index.js +394 -32
- package/dist/definitions/validation/json-schema-paths.d.ts +29 -0
- package/dist/definitions/validation/validate-definition-specs.d.ts +12 -23
- package/dist/definitions/validation/validate-input-bindings.d.ts +7 -0
- package/dist/definitions/validation/validation-issue.d.ts +52 -0
- package/dist/generated/types.gen.d.ts +2 -0
- package/dist/index.js +98 -52
- package/dist/push/index.js +483 -63
- package/package.json +1 -1
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
export type DefinitionValidationIssue = {
|
|
2
|
+
readonly check: "signal-source-path" | "route-target" | "signal-binding" | "health-check-mcp-server" | "health-check-double-qualified" | "unbound-required-input" | "binding-target-field" | "binding-type-mismatch";
|
|
3
|
+
/**
|
|
4
|
+
* Whether this issue blocks a push. The 4 original checks are all
|
|
5
|
+
* unconditionally `"error"`, matching their implicit all-blocking
|
|
6
|
+
* behavior before this field existed. `"binding-type-mismatch"` is a
|
|
7
|
+
* `"warning"`-tier check — a resolved type disagreement is worth
|
|
8
|
+
* surfacing but, per §4's own bias, never provably a runtime failure the
|
|
9
|
+
* way an unresolved binding or a missing required input is.
|
|
10
|
+
* `"binding-target-field"`'s "unbound field name isn't a declared
|
|
11
|
+
* `additionalInput`" sub-check is `"info"`-tier — passing extra context
|
|
12
|
+
* a step doesn't declare as an `additionalInput` is allowed (the value is
|
|
13
|
+
* just dropped), so it's worth surfacing for awareness but never rises to
|
|
14
|
+
* even a warning. Only `assertValidDefinitionSpecs` treats these tiers
|
|
15
|
+
* differently: it blocks a push on `"error"` alone.
|
|
16
|
+
*/
|
|
17
|
+
readonly severity: "error" | "warning" | "info";
|
|
18
|
+
readonly message: string;
|
|
19
|
+
/**
|
|
20
|
+
* The pipeline this issue belongs to, when the check is pipeline-scoped
|
|
21
|
+
* (`route-target`/`signal-binding`/the three Phase 2 binding checks) —
|
|
22
|
+
* absent for step-only checks (`signal-source-path`/`health-check-*`),
|
|
23
|
+
* which have no pipeline context of their own. Required before the
|
|
24
|
+
* designer (Phase 5) can attach an error to the right graph node.
|
|
25
|
+
*/
|
|
26
|
+
readonly pipelineKey?: string;
|
|
27
|
+
/** The node this issue is about, when pipeline-scoped. */
|
|
28
|
+
readonly nodeKey?: string;
|
|
29
|
+
/**
|
|
30
|
+
* A second, related node this issue is about — e.g. `signal-binding`'s
|
|
31
|
+
* producer node, when different from `nodeKey`'s consumer. Absent when
|
|
32
|
+
* the issue is about a single node, or when the "other end" isn't a
|
|
33
|
+
* node in this pipeline at all (`route-target`'s target is a different
|
|
34
|
+
* *pipeline*, not a node).
|
|
35
|
+
*/
|
|
36
|
+
readonly targetNodeKey?: string;
|
|
37
|
+
/**
|
|
38
|
+
* The specific `parallel` branch this issue is about, when `nodeKey`
|
|
39
|
+
* names a `parallel` node — one of that node's `branches` keys. Set only
|
|
40
|
+
* by the three Phase 2 binding checks (`unbound-required-input`/
|
|
41
|
+
* `binding-target-field`/`binding-type-mismatch`) when the
|
|
42
|
+
* `BindingContext` they're walking is a `parallel` branch's own bindings
|
|
43
|
+
* (`bindingContexts`' `ctx.branchKey`), not the node's own bindings.
|
|
44
|
+
* Absent for every other check, and absent for those three checks' own
|
|
45
|
+
* non-`parallel` (`step`/`fanOut`/`loop`) cases — without this, issues
|
|
46
|
+
* from two different branches of the same `parallel` node are
|
|
47
|
+
* indistinguishable by branch.
|
|
48
|
+
*/
|
|
49
|
+
readonly branchKey?: string;
|
|
50
|
+
};
|
|
51
|
+
/** Formats a path list for an error message, capped so it stays readable. */
|
|
52
|
+
export declare function listPaths(paths: readonly string[], limit?: number): string;
|
|
@@ -4814,6 +4814,7 @@ export type PostApiPipelineDefinitionsData = {
|
|
|
4814
4814
|
[key: string]: unknown;
|
|
4815
4815
|
} | unknown;
|
|
4816
4816
|
}>;
|
|
4817
|
+
entryNodeKey?: string;
|
|
4817
4818
|
};
|
|
4818
4819
|
path?: never;
|
|
4819
4820
|
query?: never;
|
|
@@ -5260,6 +5261,7 @@ export type PutApiPipelineDefinitionsData = {
|
|
|
5260
5261
|
[key: string]: unknown;
|
|
5261
5262
|
} | unknown;
|
|
5262
5263
|
}>;
|
|
5264
|
+
entryNodeKey?: string;
|
|
5263
5265
|
};
|
|
5264
5266
|
path?: never;
|
|
5265
5267
|
query?: never;
|
package/dist/index.js
CHANGED
|
@@ -16126,6 +16126,12 @@ ${feature._promptAddition}` : feature._promptAddition;
|
|
|
16126
16126
|
}
|
|
16127
16127
|
// src/definitions/steps/define-code-step.ts
|
|
16128
16128
|
function codeStep(config2) {
|
|
16129
|
+
const features = config2.features ?? [];
|
|
16130
|
+
let effectiveResult = config2.resultSchema;
|
|
16131
|
+
for (const feature of features) {
|
|
16132
|
+
effectiveResult = effectiveResult ? effectiveResult.extend(feature._resultExtension.shape) : feature._resultExtension;
|
|
16133
|
+
}
|
|
16134
|
+
const featureSignals = features.flatMap((f) => f._signals);
|
|
16129
16135
|
const spec = {
|
|
16130
16136
|
key: config2.key,
|
|
16131
16137
|
name: config2.name,
|
|
@@ -16135,14 +16141,23 @@ function codeStep(config2) {
|
|
|
16135
16141
|
status: config2.status ?? "active",
|
|
16136
16142
|
prompt: null,
|
|
16137
16143
|
inputSchemaJson: config2.inputSchema ? toJSONSchema(config2.inputSchema) : null,
|
|
16138
|
-
resultSchemaJson:
|
|
16139
|
-
signalExtractorDefinitions:
|
|
16140
|
-
|
|
16141
|
-
|
|
16142
|
-
|
|
16143
|
-
|
|
16144
|
-
|
|
16145
|
-
|
|
16144
|
+
resultSchemaJson: effectiveResult ? toJSONSchema(effectiveResult) : null,
|
|
16145
|
+
signalExtractorDefinitions: [
|
|
16146
|
+
...(config2.signals ?? []).map((signal) => ({
|
|
16147
|
+
key: signal.key ?? signal.sourcePath,
|
|
16148
|
+
sourcePath: signal.sourcePath,
|
|
16149
|
+
type: signal.type,
|
|
16150
|
+
required: signal.required ?? true,
|
|
16151
|
+
availableWhenResultStatusIn: signal.availableWhenResultStatusIn ?? null
|
|
16152
|
+
})),
|
|
16153
|
+
...featureSignals.map((signal) => ({
|
|
16154
|
+
key: signal.key,
|
|
16155
|
+
sourcePath: signal.sourcePath,
|
|
16156
|
+
type: signal.type,
|
|
16157
|
+
required: signal.required ?? true,
|
|
16158
|
+
availableWhenResultStatusIn: signal.availableWhenResultStatusIn ?? null
|
|
16159
|
+
}))
|
|
16160
|
+
],
|
|
16146
16161
|
opencodeMcpJson: null,
|
|
16147
16162
|
opencodePluginJson: null,
|
|
16148
16163
|
healthChecksJson: null,
|
|
@@ -16205,20 +16220,29 @@ var buildStepDefinitionsClient = (stepDefinitions) => {
|
|
|
16205
16220
|
};
|
|
16206
16221
|
};
|
|
16207
16222
|
// src/definitions/steps/step-features.ts
|
|
16223
|
+
var notificationKindSchema = exports_external.enum([
|
|
16224
|
+
"feedback_request",
|
|
16225
|
+
"status_update",
|
|
16226
|
+
"blocked",
|
|
16227
|
+
"result_ready",
|
|
16228
|
+
"warning"
|
|
16229
|
+
]);
|
|
16230
|
+
var notificationPrioritySchema = exports_external.enum(["low", "normal", "high", "urgent"]);
|
|
16231
|
+
var notificationChannelSchema = exports_external.enum([
|
|
16232
|
+
"in_app",
|
|
16233
|
+
"work_item_platform_comment",
|
|
16234
|
+
"email",
|
|
16235
|
+
"slack"
|
|
16236
|
+
]);
|
|
16208
16237
|
var NOTIFICATION_SIGNAL_KEY = "$boboddy_notifications_v1";
|
|
16209
16238
|
var NOTIFICATION_RESULT_KEY = "$boboddy_notifications_v1";
|
|
16239
|
+
var DEFAULT_NOTIFICATION_KIND = "status_update";
|
|
16210
16240
|
var notificationItemSchema = exports_external.object({
|
|
16211
|
-
kind:
|
|
16212
|
-
"feedback_request",
|
|
16213
|
-
"status_update",
|
|
16214
|
-
"blocked",
|
|
16215
|
-
"result_ready",
|
|
16216
|
-
"warning"
|
|
16217
|
-
]).describe("The kind of user notification."),
|
|
16241
|
+
kind: notificationKindSchema.describe("The kind of user notification."),
|
|
16218
16242
|
title: exports_external.string().describe("Short, human-readable notification title."),
|
|
16219
16243
|
body: exports_external.string().describe("The notification body / details."),
|
|
16220
|
-
priority:
|
|
16221
|
-
suggestedChannels: exports_external.array(
|
|
16244
|
+
priority: notificationPrioritySchema.describe("How important this notification is for the user."),
|
|
16245
|
+
suggestedChannels: exports_external.array(notificationChannelSchema).optional().describe("Channels the agent thinks are worth using. The platform policy decides the final channels."),
|
|
16222
16246
|
payload: exports_external.record(exports_external.string(), exports_external.unknown()).optional().describe('Kind-specific structured data. For "feedback_request": { category, urgency, suggestedKey? }.')
|
|
16223
16247
|
}).describe("A single user notification emitted by the agent.");
|
|
16224
16248
|
var notificationsFeature = {
|
|
@@ -16248,23 +16272,62 @@ var notificationsFeature = {
|
|
|
16248
16272
|
}
|
|
16249
16273
|
]
|
|
16250
16274
|
};
|
|
16275
|
+
var feedbackRequestsFeature = {
|
|
16276
|
+
_resultExtension: exports_external.object({
|
|
16277
|
+
[NOTIFICATION_RESULT_KEY]: exports_external.array(notificationItemSchema.extend({ kind: exports_external.literal("feedback_request") })).optional()
|
|
16278
|
+
}),
|
|
16279
|
+
_promptAddition: [
|
|
16280
|
+
"## Feedback Requests",
|
|
16281
|
+
"",
|
|
16282
|
+
`If you need to ask a human a clarifying question, populate the \`${NOTIFICATION_RESULT_KEY}\` array with items of kind \`"feedback_request"\`.`,
|
|
16283
|
+
"Each item must include:",
|
|
16284
|
+
"- **title**: A short, human-readable summary of the question.",
|
|
16285
|
+
"- **body**: The full question.",
|
|
16286
|
+
"- **priority**: One of `low`, `normal`, `high`, `urgent`.",
|
|
16287
|
+
'- **payload**: `{ "category": string, "urgency": "blocking"|"clarification"|"assumption"|"informational", "suggestedKey"?: string }`.'
|
|
16288
|
+
].join(`
|
|
16289
|
+
`),
|
|
16290
|
+
_signals: notificationsFeature._signals
|
|
16291
|
+
};
|
|
16251
16292
|
var Features = {
|
|
16252
|
-
notifications:
|
|
16253
|
-
|
|
16254
|
-
|
|
16255
|
-
|
|
16256
|
-
|
|
16257
|
-
|
|
16258
|
-
|
|
16259
|
-
|
|
16260
|
-
|
|
16261
|
-
|
|
16262
|
-
|
|
16293
|
+
notifications: () => notificationsFeature,
|
|
16294
|
+
feedbackRequests: () => feedbackRequestsFeature
|
|
16295
|
+
};
|
|
16296
|
+
var NotificationSignal = {
|
|
16297
|
+
key: NOTIFICATION_SIGNAL_KEY,
|
|
16298
|
+
find(signals) {
|
|
16299
|
+
const match = signals.find((s) => s.key === NOTIFICATION_SIGNAL_KEY);
|
|
16300
|
+
if (!match)
|
|
16301
|
+
return;
|
|
16302
|
+
const parsed = exports_external.array(notificationItemSchema).safeParse(match.valueJson);
|
|
16303
|
+
return parsed.success ? parsed.data : undefined;
|
|
16304
|
+
}
|
|
16305
|
+
};
|
|
16306
|
+
var Notify = {
|
|
16307
|
+
create: (item) => ({
|
|
16308
|
+
[NOTIFICATION_RESULT_KEY]: [item]
|
|
16309
|
+
}),
|
|
16310
|
+
inApp: (title, body, priority, options) => Notify.create({
|
|
16311
|
+
kind: options?.kind ?? DEFAULT_NOTIFICATION_KIND,
|
|
16312
|
+
title,
|
|
16313
|
+
body,
|
|
16314
|
+
priority,
|
|
16315
|
+
suggestedChannels: ["in_app"],
|
|
16316
|
+
...options?.payload ? { payload: options.payload } : {}
|
|
16263
16317
|
}),
|
|
16264
|
-
|
|
16265
|
-
|
|
16266
|
-
|
|
16318
|
+
feedbackRequest: (question, category, urgency, suggestedKey) => Notify.create({
|
|
16319
|
+
kind: "feedback_request",
|
|
16320
|
+
title: question,
|
|
16321
|
+
body: question,
|
|
16322
|
+
priority: "normal",
|
|
16323
|
+
payload: {
|
|
16324
|
+
category,
|
|
16325
|
+
urgency,
|
|
16326
|
+
...suggestedKey ? { suggestedKey } : {}
|
|
16267
16327
|
}
|
|
16328
|
+
}),
|
|
16329
|
+
merge: (...fragments) => ({
|
|
16330
|
+
[NOTIFICATION_RESULT_KEY]: fragments.flatMap((fragment) => fragment[NOTIFICATION_RESULT_KEY])
|
|
16268
16331
|
})
|
|
16269
16332
|
};
|
|
16270
16333
|
// src/definitions/advancement-policies/define-advancement-policy.ts
|
|
@@ -16961,25 +17024,6 @@ function compileLoopState(stateKey, state, ctx) {
|
|
|
16961
17024
|
function compileTerminalState(stateKey, kind) {
|
|
16962
17025
|
return { nodeDefinitions: [{ nodeKey: stateKey, kind }], edges: [] };
|
|
16963
17026
|
}
|
|
16964
|
-
function assertNoIllegalConvergentEdges(pipelineKey, nodeKindByKey, edges) {
|
|
16965
|
-
const incoming = new Map;
|
|
16966
|
-
for (const edge of edges) {
|
|
16967
|
-
const list = incoming.get(edge.toNodeKey) ?? [];
|
|
16968
|
-
list.push(edge);
|
|
16969
|
-
incoming.set(edge.toNodeKey, list);
|
|
16970
|
-
}
|
|
16971
|
-
for (const [targetKey, incomingEdges] of incoming) {
|
|
16972
|
-
if (incomingEdges.length <= 1)
|
|
16973
|
-
continue;
|
|
16974
|
-
const hasInvalidSource = incomingEdges.some((edge) => {
|
|
16975
|
-
const kind = nodeKindByKey.get(edge.fromNodeKey);
|
|
16976
|
-
return kind !== "choice" && kind !== "loop";
|
|
16977
|
-
});
|
|
16978
|
-
if (hasInvalidSource) {
|
|
16979
|
-
throw new Error(`Pipeline "${pipelineKey}": state "${targetKey}" has more than one incoming edge, but not every source is a 'choice'/'loop' state (unconditional convergent edges are not allowed \u2014 see docs/research/flat-pipeline-sdk-and-visual-designer.md \xA76).`);
|
|
16980
|
-
}
|
|
16981
|
-
}
|
|
16982
|
-
}
|
|
16983
17027
|
|
|
16984
17028
|
// src/definitions/pipelines/define-pipeline.ts
|
|
16985
17029
|
function isWorkingNodeDefinition(node) {
|
|
@@ -17016,8 +17060,6 @@ function definePipeline(config2) {
|
|
|
17016
17060
|
nodeDefinitions.push(...compiled.nodeDefinitions);
|
|
17017
17061
|
dependencyEdges.push(...compiled.edges);
|
|
17018
17062
|
}
|
|
17019
|
-
const nodeKindByKey = new Map(nodeDefinitions.map((node) => [node.nodeKey, node.kind]));
|
|
17020
|
-
assertNoIllegalConvergentEdges(config2.key, nodeKindByKey, dependencyEdges);
|
|
17021
17063
|
let inputSchemaJson = null;
|
|
17022
17064
|
if (config2.input) {
|
|
17023
17065
|
try {
|
|
@@ -17033,6 +17075,7 @@ function definePipeline(config2) {
|
|
|
17033
17075
|
version: config2.version ?? 1,
|
|
17034
17076
|
status: config2.status ?? "active",
|
|
17035
17077
|
inputSchemaJson,
|
|
17078
|
+
entryNodeKey: config2.startAt,
|
|
17036
17079
|
_stepDefinitions: [...stepDefMap.values()],
|
|
17037
17080
|
nodeDefinitions,
|
|
17038
17081
|
dependencyEdges
|
|
@@ -17145,6 +17188,7 @@ var buildPipelineDefinitionsClient = (pipelineDefinitions) => {
|
|
|
17145
17188
|
description: spec.description,
|
|
17146
17189
|
status: spec.status,
|
|
17147
17190
|
inputSchemaJson: spec.inputSchemaJson,
|
|
17191
|
+
entryNodeKey: spec.entryNodeKey,
|
|
17148
17192
|
nodeDefinitions,
|
|
17149
17193
|
dependencyEdges
|
|
17150
17194
|
};
|
|
@@ -17624,6 +17668,8 @@ export {
|
|
|
17624
17668
|
Features,
|
|
17625
17669
|
GitHubIntegrations,
|
|
17626
17670
|
NotificationRules,
|
|
17671
|
+
NotificationSignal,
|
|
17672
|
+
Notify,
|
|
17627
17673
|
PipelineDefinitions,
|
|
17628
17674
|
PipelineExecutions,
|
|
17629
17675
|
ProjectContext,
|