workplane 0.4.3 → 0.5.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.
package/README.md CHANGED
@@ -3,7 +3,7 @@
3
3
  [![website](https://img.shields.io/badge/website-mindstaq.github.io%2Fworkplane-3dd6c6)](https://mindstaq.github.io/workplane/)
4
4
  [![npm version](https://img.shields.io/npm/v/workplane)](https://www.npmjs.com/package/workplane)
5
5
  [![status](https://img.shields.io/badge/status-alpha-orange)](https://github.com/MindStaq/workplane)
6
- [![license](https://img.shields.io/npm/l/workplane)](https://github.com/MindStaq/workplane/blob/main/packages/workplane/LICENSE)
6
+ [![license](https://img.shields.io/npm/l/workplane)](https://github.com/MindStaq/workplane/blob/main/apps/workplane/LICENSE)
7
7
 
8
8
  > **Alpha software.** APIs and data models are unstable and will change between releases. Not recommended for production use.
9
9
 
package/dist/cli.js CHANGED
@@ -9,15 +9,15 @@ var __export = (target, all) => {
9
9
  __defProp(target, name, { get: all[name], enumerable: true });
10
10
  };
11
11
 
12
- // ../workplans/src/providers/anthropic.ts
12
+ // ../../libs/workplans/src/providers/anthropic.ts
13
13
  var anthropic_exports = {};
14
14
  __export(anthropic_exports, {
15
15
  runAnthropicStep: () => runAnthropicStep
16
16
  });
17
17
  import Anthropic from "@anthropic-ai/sdk";
18
18
  async function runAnthropicStep(opts) {
19
- const client = new Anthropic({ apiKey: opts.apiKey ?? process.env.ANTHROPIC_API_KEY });
20
- const message = await client.messages.create({
19
+ const client2 = new Anthropic({ apiKey: opts.apiKey ?? process.env.ANTHROPIC_API_KEY });
20
+ const message = await client2.messages.create({
21
21
  model: opts.model,
22
22
  max_tokens: 4096,
23
23
  messages: [{ role: "user", content: opts.prompt }]
@@ -26,32 +26,32 @@ async function runAnthropicStep(opts) {
26
26
  return block.type === "text" ? block.text : "";
27
27
  }
28
28
  var init_anthropic = __esm({
29
- "../workplans/src/providers/anthropic.ts"() {
29
+ "../../libs/workplans/src/providers/anthropic.ts"() {
30
30
  "use strict";
31
31
  }
32
32
  });
33
33
 
34
- // ../workplans/src/providers/openai.ts
34
+ // ../../libs/workplans/src/providers/openai.ts
35
35
  var openai_exports = {};
36
36
  __export(openai_exports, {
37
37
  runOpenAIStep: () => runOpenAIStep
38
38
  });
39
39
  import OpenAI from "openai";
40
40
  async function runOpenAIStep(opts) {
41
- const client = new OpenAI({ apiKey: opts.apiKey ?? process.env.OPENAI_API_KEY });
42
- const completion = await client.chat.completions.create({
41
+ const client2 = new OpenAI({ apiKey: opts.apiKey ?? process.env.OPENAI_API_KEY });
42
+ const completion = await client2.chat.completions.create({
43
43
  model: opts.model,
44
44
  messages: [{ role: "user", content: opts.prompt }]
45
45
  });
46
46
  return completion.choices[0]?.message.content ?? "";
47
47
  }
48
48
  var init_openai = __esm({
49
- "../workplans/src/providers/openai.ts"() {
49
+ "../../libs/workplans/src/providers/openai.ts"() {
50
50
  "use strict";
51
51
  }
52
52
  });
53
53
 
54
- // ../workplans/src/providers/ollama.ts
54
+ // ../../libs/workplans/src/providers/ollama.ts
55
55
  var ollama_exports = {};
56
56
  __export(ollama_exports, {
57
57
  runOllamaStep: () => runOllamaStep
@@ -59,17 +59,17 @@ __export(ollama_exports, {
59
59
  import { Ollama } from "ollama";
60
60
  async function runOllamaStep(opts) {
61
61
  const host = opts.host ?? process.env.OLLAMA_HOST ?? "http://localhost:11434";
62
- const client = new Ollama({ host });
63
- const response = await client.generate({ model: opts.model, prompt: opts.prompt });
62
+ const client2 = new Ollama({ host });
63
+ const response = await client2.generate({ model: opts.model, prompt: opts.prompt });
64
64
  return response.response;
65
65
  }
66
66
  var init_ollama = __esm({
67
- "../workplans/src/providers/ollama.ts"() {
67
+ "../../libs/workplans/src/providers/ollama.ts"() {
68
68
  "use strict";
69
69
  }
70
70
  });
71
71
 
72
- // ../workplans/src/providers/shell.ts
72
+ // ../../libs/workplans/src/providers/shell.ts
73
73
  var shell_exports = {};
74
74
  __export(shell_exports, {
75
75
  runShellStep: () => runShellStep
@@ -85,13 +85,13 @@ async function runShellStep(opts) {
85
85
  }
86
86
  var execAsync;
87
87
  var init_shell = __esm({
88
- "../workplans/src/providers/shell.ts"() {
88
+ "../../libs/workplans/src/providers/shell.ts"() {
89
89
  "use strict";
90
90
  execAsync = promisify(exec);
91
91
  }
92
92
  });
93
93
 
94
- // ../workplans/src/providers/file.ts
94
+ // ../../libs/workplans/src/providers/file.ts
95
95
  var file_exports = {};
96
96
  __export(file_exports, {
97
97
  runFileStep: () => runFileStep
@@ -101,12 +101,15 @@ async function runFileStep(opts) {
101
101
  return readFile(opts.path, opts.encoding ?? "utf8");
102
102
  }
103
103
  var init_file = __esm({
104
- "../workplans/src/providers/file.ts"() {
104
+ "../../libs/workplans/src/providers/file.ts"() {
105
105
  "use strict";
106
106
  }
107
107
  });
108
108
 
109
- // ../core/src/env.ts
109
+ // ../../libs/core/src/config.ts
110
+ import { z } from "zod";
111
+
112
+ // ../../libs/core/src/env.ts
110
113
  import { config as dotenvConfig } from "dotenv";
111
114
  import { homedir } from "os";
112
115
  import { join } from "path";
@@ -121,8 +124,7 @@ function loadLocalEnv() {
121
124
  envLoaded = true;
122
125
  }
123
126
 
124
- // ../core/src/config.ts
125
- import { z } from "zod";
127
+ // ../../libs/core/src/config.ts
126
128
  loadLocalEnv();
127
129
  var serverEnvSchema = z.object({
128
130
  DATABASE_URL: z.string().optional().default("sqlite://~/.workplane/workplane.db"),
@@ -144,36 +146,135 @@ function parseCsv(value) {
144
146
  return value.split(",").map((entry) => entry.trim()).filter(Boolean);
145
147
  }
146
148
 
147
- // ../core/src/auth.ts
148
- function authHeaders(token) {
149
- if (!token) {
150
- return {};
149
+ // ../../libs/client/src/client.ts
150
+ var WorkplaneApiError = class extends Error {
151
+ status;
152
+ statusText;
153
+ path;
154
+ body;
155
+ constructor(status, statusText, path, body) {
156
+ super(`${status} ${statusText} from ${path}: ${body}`);
157
+ this.status = status;
158
+ this.statusText = statusText;
159
+ this.path = path;
160
+ this.body = body;
151
161
  }
152
- return { authorization: `Bearer ${token}` };
153
- }
154
-
155
- // ../core/src/http-client.ts
156
- function buildWorkplaneHeaders(options = {}) {
157
- const token = options.nodeToken ?? options.operatorToken;
158
- return {
159
- "content-type": "application/json",
160
- ...authHeaders(token)
161
- };
162
- }
163
- async function workplaneFetch(serverUrl2, path, options = {}) {
164
- const response = await fetch(`${serverUrl2}${path}`, {
165
- method: options.method ?? "GET",
166
- headers: buildWorkplaneHeaders(options),
167
- body: options.body ? JSON.stringify(options.body) : void 0
168
- });
169
- if (!response.ok) {
170
- const text = await response.text();
171
- throw new Error(`${response.status} ${response.statusText} from ${path}: ${text}`);
162
+ };
163
+ function query(params) {
164
+ const search = new URLSearchParams();
165
+ for (const [key, value] of Object.entries(params)) {
166
+ if (value !== void 0) {
167
+ search.set(key, String(value));
168
+ }
172
169
  }
173
- return await response.json();
170
+ const text = search.toString();
171
+ return text ? `?${text}` : "";
174
172
  }
173
+ var segment = encodeURIComponent;
174
+ var WorkplaneClient = class {
175
+ baseUrl;
176
+ token;
177
+ fetchImpl;
178
+ constructor(options) {
179
+ this.baseUrl = options.baseUrl.replace(/\/+$/, "");
180
+ this.token = options.token;
181
+ this.fetchImpl = options.fetch ?? ((input, init) => fetch(input, init));
182
+ }
183
+ /** Low-level escape hatch used by the typed methods below. */
184
+ async request(path, options = {}) {
185
+ const response = await this.fetchImpl(`${this.baseUrl}${path}`, {
186
+ method: options.method ?? "GET",
187
+ headers: {
188
+ "content-type": "application/json",
189
+ ...this.token ? { authorization: `Bearer ${this.token}` } : {}
190
+ },
191
+ body: options.body ? JSON.stringify(options.body) : void 0,
192
+ signal: options.signal
193
+ });
194
+ if (!response.ok) {
195
+ throw new WorkplaneApiError(response.status, response.statusText, path, await response.text());
196
+ }
197
+ return await response.json();
198
+ }
199
+ health() {
200
+ return this.request("/healthz");
201
+ }
202
+ listTasks(filters = {}) {
203
+ return this.request(`/tasks${query(filters)}`);
204
+ }
205
+ getTask(taskId) {
206
+ return this.request(`/tasks/${segment(taskId)}`);
207
+ }
208
+ createTask(input) {
209
+ return this.request("/tasks", { method: "POST", body: input });
210
+ }
211
+ retryTask(taskId) {
212
+ return this.request(`/tasks/${segment(taskId)}/retry`, { method: "POST" });
213
+ }
214
+ cancelTask(taskId) {
215
+ return this.request(`/tasks/${segment(taskId)}/cancel`, { method: "POST" });
216
+ }
217
+ listRuns(filters = {}) {
218
+ return this.request(`/runs${query(filters)}`);
219
+ }
220
+ getRun(runId) {
221
+ return this.request(`/runs/${segment(runId)}`);
222
+ }
223
+ /** Pass `afterId` (the highest log id already seen) to receive only newer rows. */
224
+ getRunLogs(runId, options = {}) {
225
+ return this.request(`/runs/${segment(runId)}/logs${query(options)}`);
226
+ }
227
+ listRunArtifacts(runId) {
228
+ return this.request(`/runs/${segment(runId)}/artifacts`);
229
+ }
230
+ sendRunInput(runId, input) {
231
+ return this.request(`/runs/${segment(runId)}/input`, { method: "POST", body: input });
232
+ }
233
+ listRunInputEvents(runId, options = {}) {
234
+ return this.request(`/runs/${segment(runId)}/input${query(options)}`);
235
+ }
236
+ listNodes() {
237
+ return this.request("/nodes");
238
+ }
239
+ listSkills() {
240
+ return this.request("/skills");
241
+ }
242
+ listPlans() {
243
+ return this.request("/plans");
244
+ }
245
+ listSchedules(filters = {}) {
246
+ return this.request(`/schedules${query(filters)}`);
247
+ }
248
+ getSchedule(scheduleId) {
249
+ return this.request(`/schedules/${segment(scheduleId)}`);
250
+ }
251
+ createSchedule(input) {
252
+ return this.request("/schedules", { method: "POST", body: input });
253
+ }
254
+ updateSchedule(scheduleId, input) {
255
+ return this.request(`/schedules/${segment(scheduleId)}`, { method: "PATCH", body: input });
256
+ }
257
+ deleteSchedule(scheduleId) {
258
+ return this.request(`/schedules/${segment(scheduleId)}`, { method: "DELETE" });
259
+ }
260
+ runScheduleNow(scheduleId) {
261
+ return this.request(`/schedules/${segment(scheduleId)}/run`, { method: "POST" });
262
+ }
263
+ tickSchedules() {
264
+ return this.request("/schedules/tick", { method: "POST" });
265
+ }
266
+ listWorkplanRuns(filters = {}) {
267
+ return this.request(`/workplan-runs${query(filters)}`);
268
+ }
269
+ getWorkplanRun(runId) {
270
+ return this.request(`/workplan-runs/${segment(runId)}`);
271
+ }
272
+ listWorkplanSteps(runId) {
273
+ return this.request(`/workplan-runs/${segment(runId)}/steps`);
274
+ }
275
+ };
175
276
 
176
- // ../agent-skills/src/skills/code-review.ts
277
+ // ../../libs/agent-skills/src/skills/code-review.ts
177
278
  function codeReviewPlan(opts = {}) {
178
279
  const { repoPath = ".", model = "claude-haiku-4-5-20251001", branch } = opts;
179
280
  const diffCmd = branch ? `git diff ${branch}..HEAD` : "git diff HEAD~1";
@@ -210,7 +311,7 @@ function codeReviewPlan(opts = {}) {
210
311
  };
211
312
  }
212
313
 
213
- // ../agent-skills/src/skills/hello.ts
314
+ // ../../libs/agent-skills/src/skills/hello.ts
214
315
  function helloPlan(opts = {}) {
215
316
  const message = opts.message ?? "hello from workplane";
216
317
  return {
@@ -229,7 +330,7 @@ function helloPlan(opts = {}) {
229
330
  };
230
331
  }
231
332
 
232
- // ../agent-skills/src/skills/summarize-file.ts
333
+ // ../../libs/agent-skills/src/skills/summarize-file.ts
233
334
  function summarizeFilePlan(opts) {
234
335
  const { filePath, provider = "ollama", model = "llama3" } = opts;
235
336
  return {
@@ -256,7 +357,7 @@ function summarizeFilePlan(opts) {
256
357
  };
257
358
  }
258
359
 
259
- // ../agent-skills/src/skills/index.ts
360
+ // ../../libs/agent-skills/src/skills/index.ts
260
361
  var SkillRegistry = class {
261
362
  skills = /* @__PURE__ */ new Map();
262
363
  register(entry) {
@@ -274,6 +375,12 @@ function createDefaultRegistry() {
274
375
  registry.register({
275
376
  name: "hello",
276
377
  description: "Shell echo (scheduler smoke test)",
378
+ inputSchema: {
379
+ type: "object",
380
+ properties: {
381
+ message: { type: "string", description: "Text to echo", default: "hello from workplane" }
382
+ }
383
+ },
277
384
  buildPlan: (opts) => helloPlan({
278
385
  message: typeof opts.message === "string" ? opts.message : void 0
279
386
  })
@@ -281,6 +388,14 @@ function createDefaultRegistry() {
281
388
  registry.register({
282
389
  name: "code-review",
283
390
  description: "Git diff \u2192 local summarize (ollama) \u2192 frontier critique (anthropic)",
391
+ inputSchema: {
392
+ type: "object",
393
+ properties: {
394
+ repo: { type: "string", description: "Path to the git repository" },
395
+ model: { type: "string", description: "Model used for the local summarize step" },
396
+ branch: { type: "string", description: "Branch to diff against" }
397
+ }
398
+ },
284
399
  buildPlan: (opts) => codeReviewPlan({
285
400
  repoPath: typeof opts.repo === "string" ? opts.repo : void 0,
286
401
  model: typeof opts.model === "string" ? opts.model : void 0,
@@ -290,6 +405,15 @@ function createDefaultRegistry() {
290
405
  registry.register({
291
406
  name: "summarize-file",
292
407
  description: "Read file \u2192 summarize with configurable provider (default: ollama)",
408
+ inputSchema: {
409
+ type: "object",
410
+ properties: {
411
+ file: { type: "string", description: "Path of the file to summarize" },
412
+ provider: { type: "string", description: "Model provider", default: "ollama" },
413
+ model: { type: "string", description: "Model name" }
414
+ },
415
+ required: ["file"]
416
+ },
293
417
  buildPlan: (opts) => {
294
418
  const filePath = typeof opts.file === "string" ? opts.file : "";
295
419
  if (!filePath) throw new Error("--file is required for summarize-file");
@@ -309,7 +433,7 @@ function listSkills(registry) {
309
433
  }
310
434
  }
311
435
 
312
- // ../workplans/src/template.ts
436
+ // ../../libs/workplans/src/template.ts
313
437
  function applyTemplate(payload, prevOutput) {
314
438
  return Object.fromEntries(
315
439
  Object.entries(payload).map(([k, v]) => [
@@ -319,7 +443,7 @@ function applyTemplate(payload, prevOutput) {
319
443
  );
320
444
  }
321
445
 
322
- // ../workplans/src/runner.ts
446
+ // ../../libs/workplans/src/runner.ts
323
447
  var INLINE_PROVIDERS = /* @__PURE__ */ new Set(["anthropic", "openai", "ollama", "shell", "file"]);
324
448
  async function runInlineStep(step, prompt) {
325
449
  const provider = step.provider;
@@ -415,7 +539,7 @@ var SequentialWorkplanRunner = class {
415
539
  }
416
540
  };
417
541
 
418
- // ../workplans/src/sinks/stdout.ts
542
+ // ../../libs/workplans/src/sinks/stdout.ts
419
543
  function printStepResult(stepName, output) {
420
544
  process.stdout.write(`=== step: ${stepName} ===
421
545
  ${output}
@@ -423,7 +547,7 @@ ${output}
423
547
  `);
424
548
  }
425
549
 
426
- // ../workplans/src/context.ts
550
+ // ../../libs/workplans/src/context.ts
427
551
  var WorkplaneNodeHandle = class {
428
552
  constructor(serverUrl2, nodeToken) {
429
553
  this.serverUrl = serverUrl2;
@@ -489,12 +613,9 @@ var LocalWorkplanContext = class {
489
613
  loadLocalEnv();
490
614
  var serverUrl = process.env.WORKPLANE_SERVER_URL ?? "http://localhost:8787";
491
615
  var operatorToken = process.env.WORKPLANE_OPERATOR_TOKEN;
616
+ var client = new WorkplaneClient({ baseUrl: serverUrl, token: operatorToken });
492
617
  async function httpJson(path, options) {
493
- return workplaneFetch(serverUrl, path, {
494
- method: options?.method,
495
- body: options?.body,
496
- operatorToken: options?.operator ? operatorToken : void 0
497
- });
618
+ return client.request(path, { method: options?.method, body: options?.body });
498
619
  }
499
620
  function valueArg(args, flag) {
500
621
  const index = args.indexOf(flag);
@@ -591,7 +712,6 @@ async function submitShell(args) {
591
712
  const cwd = valueArg(args, "--cwd");
592
713
  const task = await httpJson("/tasks", {
593
714
  method: "POST",
594
- operator: true,
595
715
  body: {
596
716
  kind: "shell.exec",
597
717
  adapter: "shell",
@@ -616,7 +736,6 @@ async function submitAider(args) {
616
736
  const requires = parseCsv(valueArg(args, "--requires") ?? "git,aider");
617
737
  const task = await httpJson("/tasks", {
618
738
  method: "POST",
619
- operator: true,
620
739
  body: {
621
740
  kind: "agent.run",
622
741
  adapter: "aider",
@@ -637,7 +756,6 @@ async function submitInference(args) {
637
756
  const inputFile = valueArg(args, "--input-file");
638
757
  const task = await httpJson("/tasks", {
639
758
  method: "POST",
640
- operator: true,
641
759
  body: {
642
760
  kind: "inference.batch",
643
761
  adapter,
@@ -664,7 +782,6 @@ async function submitHarness(args) {
664
782
  const requires = parseCsv(valueArg(args, "--requires") ?? `${harness},git`);
665
783
  const task = await httpJson("/tasks", {
666
784
  method: "POST",
667
- operator: true,
668
785
  body: {
669
786
  kind: "agent.run",
670
787
  adapter: harness,
@@ -729,7 +846,7 @@ async function main() {
729
846
  if (!taskId) {
730
847
  throw new Error("task id is required");
731
848
  }
732
- const task = await httpJson(`/tasks/${taskId}/retry`, { method: "POST", operator: true });
849
+ const task = await httpJson(`/tasks/${taskId}/retry`, { method: "POST" });
733
850
  printJson(task);
734
851
  return;
735
852
  }
@@ -746,21 +863,21 @@ async function main() {
746
863
  if (!taskId) {
747
864
  throw new Error("task id is required");
748
865
  }
749
- const task = await httpJson(`/tasks/${taskId}/cancel`, { method: "POST", operator: true });
866
+ const task = await httpJson(`/tasks/${taskId}/cancel`, { method: "POST" });
750
867
  printJson(task);
751
868
  return;
752
869
  }
753
870
  if (command === "runs") {
754
871
  const taskId = valueArg(rest, "--task-id");
755
872
  const status = valueArg(rest, "--status");
756
- const query = new URLSearchParams();
873
+ const query2 = new URLSearchParams();
757
874
  if (taskId) {
758
- query.set("taskId", taskId);
875
+ query2.set("taskId", taskId);
759
876
  }
760
877
  if (status) {
761
- query.set("status", status);
878
+ query2.set("status", status);
762
879
  }
763
- const runs = await httpJson(query.size > 0 ? `/runs?${query.toString()}` : "/runs");
880
+ const runs = await httpJson(query2.size > 0 ? `/runs?${query2.toString()}` : "/runs");
764
881
  printJson(runs);
765
882
  return;
766
883
  }
@@ -790,7 +907,7 @@ async function main() {
790
907
  } else {
791
908
  throw new Error("one of --stdin, --signal, or --resize is required");
792
909
  }
793
- const result = await httpJson(`/runs/${runId}/input`, { method: "POST", operator: true, body });
910
+ const result = await httpJson(`/runs/${runId}/input`, { method: "POST", body });
794
911
  printJson(result);
795
912
  return;
796
913
  }
@@ -862,7 +979,6 @@ async function main() {
862
979
  }
863
980
  const schedule = await httpJson("/schedules", {
864
981
  method: "POST",
865
- operator: true,
866
982
  body: {
867
983
  planId,
868
984
  name: valueArg(createArgs, "--name") ?? planId,
@@ -898,7 +1014,6 @@ async function main() {
898
1014
  }
899
1015
  const schedule = await httpJson(`/schedules/${scheduleId}`, {
900
1016
  method: "PATCH",
901
- operator: true,
902
1017
  body: { enabled: subcommand === "enable" }
903
1018
  });
904
1019
  printJson(schedule);
@@ -909,7 +1024,7 @@ async function main() {
909
1024
  if (!scheduleId) {
910
1025
  throw new Error("schedule id is required");
911
1026
  }
912
- const result = await httpJson(`/schedules/${scheduleId}`, { method: "DELETE", operator: true });
1027
+ const result = await httpJson(`/schedules/${scheduleId}`, { method: "DELETE" });
913
1028
  printJson(result);
914
1029
  return;
915
1030
  }
@@ -918,12 +1033,12 @@ async function main() {
918
1033
  if (!scheduleId) {
919
1034
  throw new Error("schedule id is required");
920
1035
  }
921
- const run = await httpJson(`/schedules/${scheduleId}/run`, { method: "POST", operator: true });
1036
+ const run = await httpJson(`/schedules/${scheduleId}/run`, { method: "POST" });
922
1037
  printJson(run);
923
1038
  return;
924
1039
  }
925
1040
  if (command === "schedule" && subcommand === "tick") {
926
- const result = await httpJson("/schedules/tick", { method: "POST", operator: true });
1041
+ const result = await httpJson("/schedules/tick", { method: "POST" });
927
1042
  printJson(result);
928
1043
  return;
929
1044
  }