@tomflow/proflow-task-orchestration 0.1.12 → 0.1.13

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.
@@ -0,0 +1,193 @@
1
+ import { z } from "zod";
2
+ import { publicOperationNames as legacyPublicOperationNames, validatePublicInput as validateLegacyPublicInput, } from "./contracts.js";
3
+ import { requiredTaskAgentPackageRefs } from "./model.js";
4
+ const id = z.string().min(1);
5
+ const version = z.number().int().positive();
6
+ const revision = z.number().int().nonnegative();
7
+ const actor = { actorRef: id, idempotencyKey: id };
8
+ const startAuthority = z.discriminatedUnion("type", [
9
+ z.object({ type: z.literal("HUMAN_CONFIRMATION") }).strict(),
10
+ z
11
+ .object({
12
+ type: z.literal("CAMPAIGN_AUTHORIZATION"),
13
+ authorizationRef: id,
14
+ expectedAuthorizationVersion: version,
15
+ expectedCampaignVersion: version,
16
+ })
17
+ .strict(),
18
+ ]);
19
+ const planNode = z
20
+ .object({
21
+ nodeId: id,
22
+ title: id,
23
+ objective: id,
24
+ requiredAgentPackageRef: z.enum(requiredTaskAgentPackageRefs),
25
+ inputDocuments: z.array(id),
26
+ outputDocuments: z.array(id),
27
+ })
28
+ .strict();
29
+ const trustedRoleBinding = z
30
+ .object({
31
+ agentPackageRef: z.enum(requiredTaskAgentPackageRefs),
32
+ roleRef: id,
33
+ })
34
+ .strict();
35
+ const productDocument = z
36
+ .object({
37
+ documentRef: id,
38
+ documentType: id,
39
+ filePath: id,
40
+ contentHash: id,
41
+ revision: version,
42
+ })
43
+ .strict();
44
+ export const phase4OperationNames = [
45
+ "createCampaignAuthorization",
46
+ "getProductCampaign",
47
+ "getCampaignAuthorization",
48
+ "revokeCampaignAuthorization",
49
+ "putProductDocument",
50
+ "getProductDocument",
51
+ "submitProductTaskIntent",
52
+ "transferProductIntentToTask",
53
+ "recordProductGapReview",
54
+ "recordProductGoalSatisfied",
55
+ "getProductContinuationProjection",
56
+ ];
57
+ const submitProductTaskIntentSchema = z
58
+ .object({
59
+ intentRef: id,
60
+ campaignRef: id.optional(),
61
+ discussionRef: id,
62
+ goalRevision: version,
63
+ intentRevision: version,
64
+ predecessorTaskId: id.optional(),
65
+ title: id,
66
+ objective: id,
67
+ scope: z.unknown(),
68
+ constraints: z.unknown(),
69
+ plan: z.object({ nodes: z.array(planNode).min(1) }).strict(),
70
+ productDocuments: z.array(productDocument).optional().default([]),
71
+ roleBindings: z.array(trustedRoleBinding).length(3),
72
+ expectedCampaignVersion: version.optional(),
73
+ ...actor,
74
+ })
75
+ .strict()
76
+ .superRefine((input, context) => {
77
+ if ((input.campaignRef === undefined) !== (input.expectedCampaignVersion === undefined))
78
+ context.addIssue({
79
+ code: "custom",
80
+ message: "campaignRef and expectedCampaignVersion must be supplied together",
81
+ path: ["expectedCampaignVersion"],
82
+ });
83
+ const packages = new Set(input.roleBindings.map((binding) => binding.agentPackageRef));
84
+ if (packages.size !== requiredTaskAgentPackageRefs.length ||
85
+ requiredTaskAgentPackageRefs.some((packageRef) => !packages.has(packageRef)))
86
+ context.addIssue({
87
+ code: "custom",
88
+ message: "roleBindings must declare exactly the fixed Product, Dev, and Test packages",
89
+ path: ["roleBindings"],
90
+ });
91
+ });
92
+ const continuationProjectionSchema = z
93
+ .object({ campaignRef: id.optional(), taskId: id.optional() })
94
+ .strict()
95
+ .superRefine((input, context) => {
96
+ if (input.campaignRef === undefined && input.taskId === undefined)
97
+ context.addIssue({
98
+ code: "custom",
99
+ message: "campaignRef or taskId is required",
100
+ path: ["campaignRef"],
101
+ });
102
+ });
103
+ const phase4Schemas = {
104
+ createCampaignAuthorization: z
105
+ .object({
106
+ authorizationRef: id.optional(),
107
+ campaignRef: id,
108
+ discussionRef: id,
109
+ goalRevision: version,
110
+ goalSummary: id,
111
+ scope: z.unknown(),
112
+ constraints: z.unknown(),
113
+ ...actor,
114
+ })
115
+ .strict(),
116
+ getProductCampaign: z.object({ campaignRef: id }).strict(),
117
+ getCampaignAuthorization: z.object({ authorizationRef: id }).strict(),
118
+ revokeCampaignAuthorization: z
119
+ .object({
120
+ authorizationRef: id,
121
+ expectedAuthorizationVersion: version,
122
+ reason: id,
123
+ ...actor,
124
+ })
125
+ .strict(),
126
+ putProductDocument: z
127
+ .object({
128
+ documentRef: id,
129
+ campaignRef: id,
130
+ discussionRef: id,
131
+ documentType: id,
132
+ content: z.string().min(1),
133
+ expectedRevision: revision,
134
+ ...actor,
135
+ })
136
+ .strict(),
137
+ getProductDocument: z.object({ documentRef: id, campaignRef: id, discussionRef: id }).strict(),
138
+ submitProductTaskIntent: submitProductTaskIntentSchema,
139
+ transferProductIntentToTask: z
140
+ .object({
141
+ intentRef: id,
142
+ taskId: id,
143
+ expectedIntentVersion: version,
144
+ expectedTaskVersion: version,
145
+ ...actor,
146
+ })
147
+ .strict(),
148
+ recordProductGapReview: z
149
+ .object({
150
+ discussionRef: id,
151
+ campaignRef: id,
152
+ intentRef: id,
153
+ taskId: id,
154
+ gapIdentity: id,
155
+ progressEvidenceRefs: z.array(id),
156
+ terminalTaskVersion: version,
157
+ expectedIntentVersion: version,
158
+ ...actor,
159
+ })
160
+ .strict(),
161
+ recordProductGoalSatisfied: z
162
+ .object({
163
+ discussionRef: id,
164
+ campaignRef: id,
165
+ taskId: id,
166
+ goalRevision: version,
167
+ terminalTaskVersion: version,
168
+ expectedCampaignVersion: version,
169
+ closureSummary: id,
170
+ ...actor,
171
+ })
172
+ .strict(),
173
+ getProductContinuationProjection: continuationProjectionSchema,
174
+ };
175
+ const startTaskSchema = z
176
+ .object({
177
+ taskId: id,
178
+ expectedTaskVersion: version,
179
+ startAuthority: startAuthority.optional(),
180
+ ...actor,
181
+ })
182
+ .strict();
183
+ export const publicOperationNames = [
184
+ ...legacyPublicOperationNames,
185
+ ...phase4OperationNames,
186
+ ];
187
+ export function validatePublicInput(operation, input) {
188
+ if (operation === "startTask")
189
+ return startTaskSchema.parse(input);
190
+ if (phase4OperationNames.includes(operation))
191
+ return phase4Schemas[operation].parse(input);
192
+ return validateLegacyPublicInput(operation, input);
193
+ }
@@ -0,0 +1,122 @@
1
+ import type { TaskRepositories, TaskStore } from "./model.ts";
2
+ export type ProductCampaignStatus = "OPEN" | "CLOSED";
3
+ export interface ProductCampaign {
4
+ campaignRef: string;
5
+ discussionRef: string;
6
+ goalRevision: number;
7
+ goalSummary: string;
8
+ scope: unknown;
9
+ constraints: unknown;
10
+ status: ProductCampaignStatus;
11
+ version: number;
12
+ createdByRef: string;
13
+ createdAt: string;
14
+ closedAt: string | null;
15
+ closureSummary: string | null;
16
+ }
17
+ export interface ProductIntent {
18
+ intentRef: string;
19
+ campaignRef: string | null;
20
+ discussionRef: string;
21
+ goalRevision: number;
22
+ intentRevision: number;
23
+ predecessorTaskId: string | null;
24
+ title: string;
25
+ objective: string;
26
+ scope: unknown;
27
+ constraints: unknown;
28
+ plan: unknown;
29
+ materializedTaskId: string | null;
30
+ version: number;
31
+ createdByRef: string;
32
+ createdAt: string;
33
+ materializedAt: string | null;
34
+ }
35
+ export interface ProductDocument {
36
+ documentRef: string;
37
+ campaignRef: string;
38
+ intentRef: string | null;
39
+ documentType: string;
40
+ filePath: string;
41
+ contentHash: string;
42
+ revision: number;
43
+ updatedByRef: string;
44
+ updatedAt: string;
45
+ }
46
+ export interface CampaignAuthorization {
47
+ authorizationRef: string;
48
+ campaignRef: string;
49
+ discussionRef: string;
50
+ goalRevision: number;
51
+ goalSummary: string;
52
+ scope: unknown;
53
+ constraints: unknown;
54
+ version: number;
55
+ createdByRef: string;
56
+ createdAt: string;
57
+ revokedAt: string | null;
58
+ revokedByRef: string | null;
59
+ revokeReason: string | null;
60
+ }
61
+ export interface ProductGapReview {
62
+ reviewRef: string;
63
+ campaignRef: string;
64
+ intentRef: string;
65
+ taskId: string;
66
+ discussionRef: string;
67
+ gapIdentity: string;
68
+ progressEvidenceRefs: string[];
69
+ terminalTaskVersion: number;
70
+ createdByRef: string;
71
+ createdAt: string;
72
+ }
73
+ export interface TaskProductLink {
74
+ taskId: string;
75
+ sourceProductIntentRef: string | null;
76
+ campaignRef: string | null;
77
+ }
78
+ export interface Phase4TaskRepositories {
79
+ productCampaigns: {
80
+ get(campaignRef: string): ProductCampaign | undefined;
81
+ insert(value: ProductCampaign): void;
82
+ update(value: ProductCampaign): void;
83
+ };
84
+ productIntents: {
85
+ get(intentRef: string): ProductIntent | undefined;
86
+ insert(value: ProductIntent): void;
87
+ update(value: ProductIntent): void;
88
+ listByCampaign(campaignRef: string): ProductIntent[];
89
+ };
90
+ productDocuments: {
91
+ get(documentRef: string): ProductDocument | undefined;
92
+ insert(value: ProductDocument): void;
93
+ update(value: ProductDocument): void;
94
+ bindIntent(input: {
95
+ documentRef: string;
96
+ intentRef: string;
97
+ expectedRevision: number;
98
+ }): void;
99
+ listByIntent(intentRef: string): ProductDocument[];
100
+ };
101
+ campaignAuthorizations: {
102
+ get(authorizationRef: string): CampaignAuthorization | undefined;
103
+ insert(value: CampaignAuthorization): void;
104
+ update(value: CampaignAuthorization): void;
105
+ listByCampaign(campaignRef: string): CampaignAuthorization[];
106
+ };
107
+ productGapReviews: {
108
+ getByIntent(intentRef: string): ProductGapReview | undefined;
109
+ getByTask(taskId: string): ProductGapReview | undefined;
110
+ insert(value: ProductGapReview): void;
111
+ listByCampaign(campaignRef: string): ProductGapReview[];
112
+ };
113
+ taskProductLinks: {
114
+ get(taskId: string): TaskProductLink | undefined;
115
+ set(value: TaskProductLink): void;
116
+ };
117
+ }
118
+ export type Phase4TaskRepositoryView = TaskRepositories & Phase4TaskRepositories;
119
+ export interface Phase4TaskStore extends TaskStore {
120
+ phase4Transaction<T>(work: (repositories: Phase4TaskRepositoryView) => T): T;
121
+ phase4Read<T>(work: (repositories: Phase4TaskRepositoryView) => T): T;
122
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,118 @@
1
+ import type { CampaignAuthorization, ProductCampaign, ProductGapReview, ProductIntent } from "./phase4-model.ts";
2
+ import type { Task, TaskResult } from "./model.ts";
3
+ import { createTaskServices as createLegacyTaskServices, type DocumentResult, type NodeResult, type TaskSummary, type TaskView } from "./services.ts";
4
+ export type { DocumentResult, NodeResult, TaskSummary, TaskView } from "./services.ts";
5
+ type ServiceOptions = Parameters<typeof createLegacyTaskServices>[0];
6
+ export declare function createTaskServices(options: ServiceOptions): {
7
+ commands: {
8
+ createTaskGroup: (raw: unknown) => TaskResult<import("./model.ts").TaskGroup>;
9
+ startTaskGroup: (raw: unknown) => TaskResult<import("./model.ts").TaskGroup & {
10
+ firstEligibleTaskId: string | null;
11
+ }>;
12
+ createTask: (raw: unknown) => TaskResult<import("./services.ts").CreateTaskResult>;
13
+ bindTaskWorker: (raw: unknown) => TaskResult<import("./services.ts").BindTaskWorkerResult>;
14
+ pauseTask: (raw: unknown) => TaskResult<Task>;
15
+ resumeTask: (raw: unknown) => TaskResult<Task>;
16
+ terminateTask: (raw: unknown) => TaskResult<Task>;
17
+ startNode: (raw: unknown) => TaskResult<NodeResult>;
18
+ completeNode: (raw: unknown) => TaskResult<import("./services.ts").CompleteNodeResult>;
19
+ waitNode: (raw: unknown) => TaskResult<Task>;
20
+ failNode: (raw: unknown) => TaskResult<Task>;
21
+ reopenNode: (raw: unknown) => TaskResult<NodeResult & {
22
+ currentNodeId: string;
23
+ }>;
24
+ acknowledgeMessage: (raw: unknown) => TaskResult<import("./model.ts").TaskMessage>;
25
+ createCampaignAuthorization: (raw: unknown) => TaskResult<{
26
+ campaign: ProductCampaign;
27
+ authorization: CampaignAuthorization;
28
+ }>;
29
+ revokeCampaignAuthorization: (raw: unknown) => TaskResult<CampaignAuthorization>;
30
+ submitProductTaskIntent: (raw: unknown) => TaskResult<{
31
+ intentRef: string;
32
+ campaignRef: string | null;
33
+ taskId: string;
34
+ status: Task["status"];
35
+ version: number;
36
+ roleBindings: Array<{
37
+ agentPackageRef: string;
38
+ roleRef: string;
39
+ workerRef: null;
40
+ conversationLocator: null;
41
+ }>;
42
+ }>;
43
+ transferProductIntentToTask: (raw: unknown) => TaskResult<TaskView>;
44
+ recordProductGapReview: (raw: unknown) => TaskResult<ProductGapReview>;
45
+ recordProductGoalSatisfied: (raw: unknown) => TaskResult<ProductCampaign>;
46
+ startTask: (raw: unknown) => TaskResult<TaskView>;
47
+ };
48
+ queries: {
49
+ getTaskGroup: (raw: unknown) => TaskResult<import("./model.ts").TaskGroup & {
50
+ currentTaskId: string | null;
51
+ tasks: Task[];
52
+ }>;
53
+ listTasks: (raw: unknown) => TaskResult<{
54
+ tasks: TaskSummary[];
55
+ }>;
56
+ getTask: (raw: unknown) => TaskResult<TaskView>;
57
+ getTaskDriveProjection: (raw: unknown) => TaskResult<{
58
+ taskId: string;
59
+ taskStatus: Task["status"];
60
+ taskVersion: number;
61
+ terminal: boolean;
62
+ currentNode: {
63
+ nodeId: string;
64
+ status: import("./model.ts").NodeStatus;
65
+ version: number;
66
+ runNo: number;
67
+ requiredAgentPackageRef: string;
68
+ } | null;
69
+ roleBinding: {
70
+ agentPackageRef: string;
71
+ roleRef: string;
72
+ workerRef: string | null;
73
+ conversationLocator: string | null;
74
+ } | null;
75
+ canDrive: boolean;
76
+ blockedReason: string | null;
77
+ resumeSignalRef: string | null;
78
+ }>;
79
+ getNodeContext: (raw: unknown) => TaskResult<{
80
+ task: Pick<Task, "taskId" | "title" | "objective" | "status" | "version">;
81
+ node: Pick<import("./model.ts").TaskNode, "nodeId" | "title" | "objective" | "status" | "version" | "runNo" | "requiredAgentPackageRef" | "workerRef" | "inputDocuments" | "outputDocuments">;
82
+ documents: Array<{
83
+ documentType: string;
84
+ path: string;
85
+ contentHash: string;
86
+ sizeBytes: number;
87
+ }>;
88
+ }>;
89
+ listPendingMessages: (raw: unknown) => TaskResult<{
90
+ messages: import("./model.ts").TaskMessage[];
91
+ }>;
92
+ listTaskEvents: (raw: unknown) => TaskResult<{
93
+ events: import("./model.ts").TaskEvent[];
94
+ }>;
95
+ getTaskDocument: (raw: unknown) => TaskResult<DocumentResult>;
96
+ getProductCampaign: (raw: unknown) => TaskResult<ProductCampaign>;
97
+ getCampaignAuthorization: (raw: unknown) => TaskResult<CampaignAuthorization>;
98
+ getProductContinuationProjection: (raw: unknown) => TaskResult<{
99
+ campaign: ProductCampaign;
100
+ intent: ProductIntent | null;
101
+ task: {
102
+ taskId: string;
103
+ status: Task["status"];
104
+ version: number;
105
+ } | null;
106
+ nextAction: "NONE" | "PROVISION" | "TRANSFER_REQUIREMENT" | "CONSIDER_START" | "PRODUCT_REVIEW_REQUIRED";
107
+ }>;
108
+ };
109
+ documents: {
110
+ putTaskDocument: (raw: unknown) => TaskResult<DocumentResult>;
111
+ reconcileDocumentIndex: (input: {
112
+ taskId: string;
113
+ actorRef: string;
114
+ }) => TaskResult<{
115
+ reconciled: number;
116
+ }>;
117
+ };
118
+ };