@osolmaz/pi-workflows 0.2.0 → 0.3.0

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.
Files changed (133) hide show
  1. package/README.md +71 -5
  2. package/dist/builtins/monitor.workflow.d.ts +71 -0
  3. package/dist/builtins/monitor.workflow.js +234 -0
  4. package/dist/builtins/monitor.workflow.js.map +1 -0
  5. package/dist/controllers/conditions.d.ts +6 -0
  6. package/dist/controllers/conditions.js +68 -0
  7. package/dist/controllers/conditions.js.map +1 -0
  8. package/dist/controllers/definition.d.ts +6 -0
  9. package/dist/controllers/definition.js +45 -0
  10. package/dist/controllers/definition.js.map +1 -0
  11. package/dist/controllers/effects.d.ts +14 -0
  12. package/dist/controllers/effects.js +104 -0
  13. package/dist/controllers/effects.js.map +1 -0
  14. package/dist/controllers/errors.d.ts +12 -0
  15. package/dist/controllers/errors.js +25 -0
  16. package/dist/controllers/errors.js.map +1 -0
  17. package/dist/controllers/index.d.ts +13 -0
  18. package/dist/controllers/index.js +13 -0
  19. package/dist/controllers/index.js.map +1 -0
  20. package/dist/controllers/json.d.ts +5 -0
  21. package/dist/controllers/json.js +57 -0
  22. package/dist/controllers/json.js.map +1 -0
  23. package/dist/controllers/loader.d.ts +23 -0
  24. package/dist/controllers/loader.js +74 -0
  25. package/dist/controllers/loader.js.map +1 -0
  26. package/dist/controllers/manager.d.ts +58 -0
  27. package/dist/controllers/manager.js +399 -0
  28. package/dist/controllers/manager.js.map +1 -0
  29. package/dist/controllers/results.d.ts +5 -0
  30. package/dist/controllers/results.js +32 -0
  31. package/dist/controllers/results.js.map +1 -0
  32. package/dist/controllers/sqlite.d.ts +212 -0
  33. package/dist/controllers/sqlite.js +1009 -0
  34. package/dist/controllers/sqlite.js.map +1 -0
  35. package/dist/controllers/store.d.ts +112 -0
  36. package/dist/controllers/store.js +32 -0
  37. package/dist/controllers/store.js.map +1 -0
  38. package/dist/controllers/types.d.ts +159 -0
  39. package/dist/controllers/types.js +2 -0
  40. package/dist/controllers/types.js.map +1 -0
  41. package/dist/controllers/workflow-engine-scheduler.d.ts +25 -0
  42. package/dist/controllers/workflow-engine-scheduler.js +93 -0
  43. package/dist/controllers/workflow-engine-scheduler.js.map +1 -0
  44. package/dist/controllers/workflows.d.ts +27 -0
  45. package/dist/controllers/workflows.js +109 -0
  46. package/dist/controllers/workflows.js.map +1 -0
  47. package/dist/extension/controller-host.d.ts +47 -0
  48. package/dist/extension/controller-host.js +110 -0
  49. package/dist/extension/controller-host.js.map +1 -0
  50. package/dist/extension/executor.js +1 -1
  51. package/dist/extension/executor.js.map +1 -1
  52. package/dist/extension/index.d.ts +7 -0
  53. package/dist/extension/index.js +1053 -96
  54. package/dist/extension/index.js.map +1 -1
  55. package/dist/extension/recorder.d.ts +6 -0
  56. package/dist/extension/recorder.js +20 -8
  57. package/dist/extension/recorder.js.map +1 -1
  58. package/dist/extension/workflow-tool.d.ts +28 -0
  59. package/dist/extension/workflow-tool.js +33 -0
  60. package/dist/extension/workflow-tool.js.map +1 -0
  61. package/dist/host/processes.d.ts +24 -0
  62. package/dist/host/processes.js +114 -0
  63. package/dist/host/processes.js.map +1 -0
  64. package/dist/host/rpc-bridge.d.ts +9 -0
  65. package/dist/host/rpc-bridge.js +39 -0
  66. package/dist/host/rpc-bridge.js.map +1 -0
  67. package/dist/host/rpc-executor.d.ts +38 -0
  68. package/dist/host/rpc-executor.js +254 -0
  69. package/dist/host/rpc-executor.js.map +1 -0
  70. package/dist/host/runner.d.ts +49 -0
  71. package/dist/host/runner.js +350 -0
  72. package/dist/host/runner.js.map +1 -0
  73. package/dist/viewer/cli.d.ts +7 -3
  74. package/dist/viewer/cli.js +150 -19
  75. package/dist/viewer/cli.js.map +1 -1
  76. package/dist/workflows/engine.d.ts +36 -0
  77. package/dist/workflows/engine.js +244 -14
  78. package/dist/workflows/engine.js.map +1 -1
  79. package/dist/workflows/errors.d.ts +23 -0
  80. package/dist/workflows/errors.js +38 -0
  81. package/dist/workflows/errors.js.map +1 -1
  82. package/dist/workflows/graph.js +0 -5
  83. package/dist/workflows/graph.js.map +1 -1
  84. package/dist/workflows/loader.d.ts +5 -3
  85. package/dist/workflows/loader.js +10 -1
  86. package/dist/workflows/loader.js.map +1 -1
  87. package/dist/workflows/schema.js +1 -1
  88. package/dist/workflows/schema.js.map +1 -1
  89. package/dist/workflows/store.d.ts +50 -6
  90. package/dist/workflows/store.js +446 -51
  91. package/dist/workflows/store.js.map +1 -1
  92. package/dist/workflows/types.d.ts +10 -0
  93. package/docs/CONTROLLERS.md +215 -0
  94. package/docs/development.md +12 -9
  95. package/docs/plans/2026-08-04-controller-runtime-plan.md +169 -0
  96. package/docs/plans/2026-08-05-always-on-workflows-plan.md +125 -0
  97. package/docs/plans/2026-08-10-agent-managed-monitor-workflows-plan.md +184 -0
  98. package/docs/run-bundles.md +66 -27
  99. package/docs/workflows.md +131 -11
  100. package/examples/controllers/pull-request.controller.ts +215 -0
  101. package/package.json +10 -2
  102. package/src/builtins/monitor.workflow.ts +278 -0
  103. package/src/controllers/conditions.ts +110 -0
  104. package/src/controllers/definition.ts +65 -0
  105. package/src/controllers/effects.ts +123 -0
  106. package/src/controllers/errors.ts +27 -0
  107. package/src/controllers/index.ts +90 -0
  108. package/src/controllers/json.ts +62 -0
  109. package/src/controllers/loader.ts +104 -0
  110. package/src/controllers/manager.ts +533 -0
  111. package/src/controllers/results.ts +46 -0
  112. package/src/controllers/sqlite.ts +1427 -0
  113. package/src/controllers/store.ts +160 -0
  114. package/src/controllers/types.ts +183 -0
  115. package/src/controllers/workflow-engine-scheduler.ts +145 -0
  116. package/src/controllers/workflows.ts +152 -0
  117. package/src/extension/controller-host.ts +163 -0
  118. package/src/extension/executor.ts +1 -1
  119. package/src/extension/index.ts +1243 -117
  120. package/src/extension/recorder.ts +65 -36
  121. package/src/extension/workflow-tool.ts +59 -0
  122. package/src/host/processes.ts +119 -0
  123. package/src/host/rpc-bridge.ts +44 -0
  124. package/src/host/rpc-executor.ts +299 -0
  125. package/src/host/runner.ts +406 -0
  126. package/src/viewer/cli.ts +167 -21
  127. package/src/workflows/engine.ts +327 -13
  128. package/src/workflows/errors.ts +45 -0
  129. package/src/workflows/graph.ts +0 -5
  130. package/src/workflows/loader.ts +13 -3
  131. package/src/workflows/schema.ts +1 -1
  132. package/src/workflows/store.ts +555 -46
  133. package/src/workflows/types.ts +10 -0
@@ -0,0 +1,163 @@
1
+ import {
2
+ ControllerManager,
3
+ SqliteControllerStore,
4
+ projectControllerStorePath,
5
+ loadDiscoveredControllers,
6
+ type AnyControllerDefinition,
7
+ type ControllerResource,
8
+ type WorkflowSchedulerRequest,
9
+ type WorkflowSchedulerResult,
10
+ } from "../controllers/index.js";
11
+
12
+ export type ParsedControllerArgs =
13
+ | { kind: "list" }
14
+ | { kind: "get"; controller: string; key: string }
15
+ | { kind: "apply"; controller: string; key: string; spec: unknown }
16
+ | { kind: "reconcile"; controller: string; key: string }
17
+ | { kind: "delete"; controller: string; key: string }
18
+ | { kind: "start" }
19
+ | { kind: "stop" };
20
+
21
+ export type PiChildWorkflowStarter = (
22
+ request: WorkflowSchedulerRequest,
23
+ signal: AbortSignal,
24
+ onComplete: (result: WorkflowSchedulerResult) => void,
25
+ ) => Promise<WorkflowSchedulerResult>;
26
+
27
+ export function parseControllerArgs(args: string): ParsedControllerArgs {
28
+ const trimmed = args.trim();
29
+ if (trimmed.length === 0 || trimmed === "list") {
30
+ return { kind: "list" };
31
+ }
32
+ if (trimmed === "start" || trimmed === "stop") {
33
+ return { kind: trimmed };
34
+ }
35
+ const apply = trimmed.match(/^apply\s+(\S+)\s+(\S+)\s+([\s\S]+)$/);
36
+ if (apply !== null) {
37
+ let spec: unknown;
38
+ try {
39
+ spec = JSON.parse(apply[3] as string) as unknown;
40
+ } catch (error) {
41
+ throw new Error(
42
+ `Invalid controller spec JSON: ${error instanceof Error ? error.message : String(error)}`,
43
+ );
44
+ }
45
+ return {
46
+ kind: "apply",
47
+ controller: apply[1] as string,
48
+ key: apply[2] as string,
49
+ spec,
50
+ };
51
+ }
52
+ const operation = trimmed.match(/^(get|reconcile|delete)\s+(\S+)\s+(\S+)$/);
53
+ if (operation !== null) {
54
+ return {
55
+ kind: operation[1] as "get" | "reconcile" | "delete",
56
+ controller: operation[2] as string,
57
+ key: operation[3] as string,
58
+ };
59
+ }
60
+ throw new Error(
61
+ "Usage: /controller [list|get <controller> <key>|apply <controller> <key> <json>|reconcile <controller> <key>|delete <controller> <key>|start|stop]",
62
+ );
63
+ }
64
+
65
+ export class PiControllerHost {
66
+ readonly definitions: AnyControllerDefinition[];
67
+ readonly store: SqliteControllerStore;
68
+ readonly manager: ControllerManager;
69
+ private running = false;
70
+
71
+ private constructor(
72
+ definitions: AnyControllerDefinition[],
73
+ store: SqliteControllerStore,
74
+ manager: ControllerManager,
75
+ ) {
76
+ this.definitions = definitions;
77
+ this.store = store;
78
+ this.manager = manager;
79
+ }
80
+
81
+ static async create(options: {
82
+ cwd: string;
83
+ startChild: PiChildWorkflowStarter;
84
+ }): Promise<PiControllerHost | undefined> {
85
+ const definitions = await loadDiscoveredControllers({ cwd: options.cwd });
86
+ if (definitions.length === 0) {
87
+ return undefined;
88
+ }
89
+ const store = new SqliteControllerStore(projectControllerStorePath(options.cwd));
90
+ const manager = new ControllerManager({
91
+ store,
92
+ controllers: definitions,
93
+ workflowScheduler: { ensure: options.startChild },
94
+ });
95
+ return new PiControllerHost(definitions, store, manager);
96
+ }
97
+
98
+ start(): void {
99
+ this.manager.start();
100
+ this.running = true;
101
+ }
102
+
103
+ async stop(): Promise<void> {
104
+ await this.manager.stop();
105
+ this.running = false;
106
+ }
107
+
108
+ async close(): Promise<void> {
109
+ await this.stop();
110
+ this.store.close();
111
+ }
112
+
113
+ get isRunning(): boolean {
114
+ return this.running;
115
+ }
116
+
117
+ list(): string {
118
+ const names = this.definitions.map((item) => item.name).join(", ");
119
+ const resources = this.store.listResources();
120
+ if (resources.length === 0) {
121
+ return `Controllers: ${names}. No resources.`;
122
+ }
123
+ const rows = resources.map((resource) => resourceSummary(resource)).join("; ");
124
+ return `Controllers: ${names}. Resources: ${rows}.`;
125
+ }
126
+
127
+ get(controller: string, key: string): string {
128
+ const resource = this.store.getResource({ controller, key });
129
+ if (resource === undefined) {
130
+ throw new Error(`Controller resource not found: ${controller}/${key}`);
131
+ }
132
+ return JSON.stringify(
133
+ {
134
+ resource,
135
+ effects: this.store.listEffects(resource.metadata.uid),
136
+ workflows: this.store.listWorkflows(resource.metadata.uid),
137
+ },
138
+ null,
139
+ 2,
140
+ );
141
+ }
142
+
143
+ apply(controller: string, key: string, spec: unknown): ControllerResource {
144
+ return this.manager.putResourceByName(controller, key, spec);
145
+ }
146
+
147
+ reconcile(controller: string, key: string): void {
148
+ this.manager.enqueue({ controller, key });
149
+ }
150
+
151
+ delete(controller: string, key: string): void {
152
+ this.manager.requestDeletion({ controller, key });
153
+ }
154
+ }
155
+
156
+ function resourceSummary(resource: ControllerResource): string {
157
+ const condition =
158
+ resource.status.conditions.find((item) => item.type === "Ready") ??
159
+ resource.status.conditions[0];
160
+ const state =
161
+ condition === undefined ? "unknown" : `${String(condition.status)}:${condition.reason}`;
162
+ return `${resource.metadata.controller}/${resource.metadata.key} generation=${resource.metadata.generation} ready=${state}`;
163
+ }
@@ -255,7 +255,7 @@ export class ConversationStepExecutor implements AgentStepExecutor {
255
255
  prompt: [
256
256
  `Reminder: workflow step ${JSON.stringify(nodeId)} is still awaiting your output.`,
257
257
  "Complete it by calling the `workflow` tool with:",
258
- `{"step": ${JSON.stringify(nodeId)}, "attempt": ${JSON.stringify(attemptId)}, "output": <your result>}`,
258
+ `{"action": "submit", "step": ${JSON.stringify(nodeId)}, "attempt": ${JSON.stringify(attemptId)}, "output": <your result>}`,
259
259
  `Expected output: ${pending.request.contract.expectedOutput ?? "a JSON object with your result"}`,
260
260
  ].join("\n"),
261
261
  streaming: this.streaming,