@ordewell/cli 0.4.13 → 0.4.15

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 (2) hide show
  1. package/dist/main.js +54 -19
  2. package/package.json +1 -1
package/dist/main.js CHANGED
@@ -376,6 +376,14 @@ var import_http2 = __toESM(require("http"));
376
376
  var import_ws = __toESM(require("ws"));
377
377
  var import_core3 = require("@ordewell/core");
378
378
  var DEFAULT_HTTP_TIMEOUT_MS = 15 * 60 * 1e3;
379
+ var WorkspaceInitNeededError = class extends Error {
380
+ constructor(message, workspace) {
381
+ super(message);
382
+ this.workspace = workspace;
383
+ this.name = "WorkspaceInitNeededError";
384
+ }
385
+ workspace;
386
+ };
379
387
  var ApiClient = class {
380
388
  port;
381
389
  constructor(port) {
@@ -446,13 +454,17 @@ var ApiClient = class {
446
454
  * the verify toggle, so the returned plan may be a question
447
455
  * (empty `tasks`, last word in `conversationHistory`) rather than a committed plan.
448
456
  */
449
- async startConversation(sessionId, goal, runners2, workspace) {
457
+ async startConversation(sessionId, goal, runners2, workspace, allowInit) {
450
458
  const res = await this.httpRequest("POST", `/api/plans/${sessionId}/converse/start`, {
451
459
  goal,
452
460
  runners: runners2 || void 0,
453
- workspace
461
+ workspace,
462
+ allowInit
454
463
  });
455
464
  if (res.status !== 200) {
465
+ if (res.data?.code === "workspace_not_a_project") {
466
+ throw new WorkspaceInitNeededError(res.data.error || "Not a project directory", res.data.workspace || workspace || "");
467
+ }
456
468
  throw new Error(res.data?.error || "Planning failed");
457
469
  }
458
470
  return res.data.plan;
@@ -4133,6 +4145,19 @@ function reduce(state, action) {
4133
4145
  }, ["set-planner", "set-task-runner"]));
4134
4146
  case "failed":
4135
4147
  return step({ ...say(state, "error", action.message), status: "idle", busyLabel: "", thinkingLine: "" });
4148
+ case "workspaceNeedsInit":
4149
+ return step({
4150
+ ...state,
4151
+ status: "idle",
4152
+ busyLabel: "",
4153
+ thinkingLine: "",
4154
+ overlay: {
4155
+ kind: "confirm",
4156
+ title: "Initialize new workspace?",
4157
+ message: `"${action.workspace}" isn't a recognized project yet (no .git or manifest found). Start a new ordewell workspace here?`,
4158
+ action: { kind: "init-workspace", goal: action.goal, workspace: action.workspace }
4159
+ }
4160
+ });
4136
4161
  case "notice":
4137
4162
  return step(say(state, "system", action.message));
4138
4163
  case "resize": {
@@ -4225,7 +4250,10 @@ function plannerModelItems(state) {
4225
4250
  const items = state.models.filter((m) => m.runners?.includes(runner)).map((m) => ({
4226
4251
  id: m.id,
4227
4252
  label: m.label,
4228
- detail: m.variants?.length ? `${m.variants.length} effort level${m.variants.length === 1 ? "" : "s"}` : "runner default effort",
4253
+ detail: [
4254
+ m.provider,
4255
+ m.variants?.length ? `${m.variants.length} effort level${m.variants.length === 1 ? "" : "s"}` : "runner default effort"
4256
+ ].filter(Boolean).join(" \xB7 "),
4229
4257
  selected: m.id === state.orchestratorModel
4230
4258
  }));
4231
4259
  return items.length > 0 ? items : [{ id: "", label: `No ${runner} models discovered yet`, detail: "run /refresh", disabled: true }];
@@ -4276,7 +4304,7 @@ function pickerItemsFor(state, action) {
4276
4304
  return state.runners.map((runner) => ({ id: runner.id, label: runner.name }));
4277
4305
  }
4278
4306
  if (action.kind === "set-task-runner") {
4279
- const task = state.tasks.find((candidate) => candidate.id === action.taskId);
4307
+ const task = findTask(state.tasks, action.taskId);
4280
4308
  if (!task) return [];
4281
4309
  return state.runners.map((runner) => ({
4282
4310
  id: runner.id,
@@ -4293,7 +4321,7 @@ function pickerItemsFor(state, action) {
4293
4321
  }));
4294
4322
  }
4295
4323
  if (action.kind === "set-task-mode") {
4296
- const task = state.tasks.find((candidate) => candidate.id === action.taskId);
4324
+ const task = findTask(state.tasks, action.taskId);
4297
4325
  if (!task) return [];
4298
4326
  return modesForTask(state.modesByRunner, task).map((mode) => ({
4299
4327
  id: mode.id,
@@ -4303,7 +4331,7 @@ function pickerItemsFor(state, action) {
4303
4331
  }));
4304
4332
  }
4305
4333
  if (action.kind === "set-task-model") {
4306
- const task = state.tasks.find((candidate) => candidate.id === action.taskId);
4334
+ const task = findTask(state.tasks, action.taskId);
4307
4335
  if (!task) return [];
4308
4336
  const items = modelsForTask(state.models, task).map((model) => ({
4309
4337
  id: model.id,
@@ -4317,7 +4345,7 @@ function pickerItemsFor(state, action) {
4317
4345
  return items.length > 0 ? items : [{ id: "", label: `No ${task.assignedRunner ?? "runner"} models discovered yet`, detail: "run /refresh", disabled: true }];
4318
4346
  }
4319
4347
  if (action.kind === "set-task-effort") {
4320
- const task = state.tasks.find((candidate) => candidate.id === action.taskId);
4348
+ const task = findTask(state.tasks, action.taskId);
4321
4349
  if (!task) return [];
4322
4350
  const current = task.assignedModel?.thinkingEffort;
4323
4351
  return [
@@ -4558,6 +4586,9 @@ function handleConfirmKey(state, overlay, key) {
4558
4586
  if (!state.sessionId) return step(closed);
4559
4587
  return step(closed, [{ type: "removeTask", sessionId: state.sessionId, taskId: overlay.action.taskId }]);
4560
4588
  }
4589
+ if (overlay.action.kind === "init-workspace") {
4590
+ return step({ ...closed, status: "planning" }, [{ type: "startConversation", goal: overlay.action.goal, allowInit: true }]);
4591
+ }
4561
4592
  return step(closed);
4562
4593
  }
4563
4594
  function handleHelpKey(state, scroll, key) {
@@ -4630,7 +4661,7 @@ function choose(state, picker2, item) {
4630
4661
  }
4631
4662
  if (picker2.action.kind === "set-task-deps") {
4632
4663
  const taskId = picker2.action.taskId;
4633
- const task = state.tasks.find((candidate) => candidate.id === taskId);
4664
+ const task = findTask(state.tasks, taskId);
4634
4665
  if (!task || !state.sessionId) return step(closed);
4635
4666
  return step(closed, [{
4636
4667
  type: "updateTask",
@@ -4685,26 +4716,26 @@ function choose(state, picker2, item) {
4685
4716
  }
4686
4717
  case "set-task-runner": {
4687
4718
  const taskId = picker2.action.taskId;
4688
- const task = state.tasks.find((candidate) => candidate.id === taskId);
4719
+ const task = findTask(state.tasks, taskId);
4689
4720
  if (!task || !state.sessionId) return step(closed);
4690
4721
  return assignTaskRunner(closed, state.sessionId, task, item.id, item.label);
4691
4722
  }
4692
4723
  case "set-task-mode": {
4693
4724
  const taskId = picker2.action.taskId;
4694
- const task = state.tasks.find((candidate) => candidate.id === taskId);
4725
+ const task = findTask(state.tasks, taskId);
4695
4726
  if (!task || !state.sessionId) return step(closed);
4696
4727
  return assignTaskMode(closed, state.sessionId, task, item.id, item.label);
4697
4728
  }
4698
4729
  case "set-task-model": {
4699
4730
  const taskId = picker2.action.taskId;
4700
- const task = state.tasks.find((candidate) => candidate.id === taskId);
4731
+ const task = findTask(state.tasks, taskId);
4701
4732
  const model = state.models.find((candidate) => candidate.id === item.id);
4702
4733
  if (!task || !model || !state.sessionId) return step(closed);
4703
4734
  return assignTaskModel(closed, state.sessionId, task, model);
4704
4735
  }
4705
4736
  case "set-task-effort": {
4706
4737
  const taskId = picker2.action.taskId;
4707
- const task = state.tasks.find((candidate) => candidate.id === taskId);
4738
+ const task = findTask(state.tasks, taskId);
4708
4739
  if (!task || !state.sessionId) return step(closed);
4709
4740
  return assignTaskEffort(closed, state.sessionId, task, item.id === DEFAULT_EFFORT ? void 0 : item.id);
4710
4741
  }
@@ -4803,7 +4834,7 @@ function runCommand(state, { name, args }) {
4803
4834
  return taskCommand(
4804
4835
  state,
4805
4836
  args[0],
4806
- (_sessionId, taskId) => openTaskDepsPicker(state, state.tasks.find((candidate) => candidate.id === taskId))
4837
+ (_sessionId, taskId) => openTaskDepsPicker(state, findTask(state.tasks, taskId))
4807
4838
  );
4808
4839
  case "complete":
4809
4840
  case "uncomplete":
@@ -5211,7 +5242,7 @@ function assignTaskEffort(state, sessionId, task, thinkingEffort) {
5211
5242
  }
5212
5243
  function taskModelCommand(state, args) {
5213
5244
  return taskCommand(state, args[0], (sessionId, taskId) => {
5214
- const task = state.tasks.find((candidate) => candidate.id === taskId);
5245
+ const task = findTask(state.tasks, taskId);
5215
5246
  if (!args[1]) return openTaskModelPicker(state, task);
5216
5247
  const model = state.models.find((candidate) => candidate.id === args[1]) ?? {
5217
5248
  id: args[1],
@@ -5227,7 +5258,7 @@ function taskModelCommand(state, args) {
5227
5258
  }
5228
5259
  function taskRunnerCommand(state, args) {
5229
5260
  return taskCommand(state, args[0], (sessionId, taskId) => {
5230
- const task = state.tasks.find((candidate) => candidate.id === taskId);
5261
+ const task = findTask(state.tasks, taskId);
5231
5262
  if (!args[1]) return openTaskRunnerPicker(state, task);
5232
5263
  const runner = state.runners.find((candidate) => candidate.id === args[1]);
5233
5264
  if (!runner) return fail2(state, `Unknown runner "${args[1]}".`);
@@ -5236,7 +5267,7 @@ function taskRunnerCommand(state, args) {
5236
5267
  }
5237
5268
  function taskModeCommand(state, args) {
5238
5269
  return taskCommand(state, args[0], (sessionId, taskId) => {
5239
- const task = state.tasks.find((candidate) => candidate.id === taskId);
5270
+ const task = findTask(state.tasks, taskId);
5240
5271
  if (!args[1]) return openTaskModePicker(state, task);
5241
5272
  const mode = modesForTask(state.modesByRunner, task).find((candidate) => candidate.id === args[1]);
5242
5273
  if (!mode) return fail2(state, `Unsupported mode "${args[1]}" for ${task.assignedRunner}.`);
@@ -5245,7 +5276,7 @@ function taskModeCommand(state, args) {
5245
5276
  }
5246
5277
  function taskEffortCommand(state, args) {
5247
5278
  return taskCommand(state, args[0], (sessionId, taskId) => {
5248
- const task = state.tasks.find((candidate) => candidate.id === taskId);
5279
+ const task = findTask(state.tasks, taskId);
5249
5280
  if (!args[1]) return openTaskEffortPicker(state, task);
5250
5281
  if (!task.assignedModel) return fail2(state, "Choose a model for this task before setting its thinking effort.");
5251
5282
  const effort = args[1].toLowerCase();
@@ -5277,7 +5308,7 @@ function taskCommand(state, token, run) {
5277
5308
  });
5278
5309
  }
5279
5310
  function resolveTaskId2(state, token) {
5280
- const byId = state.tasks.find((t) => t.id === token);
5311
+ const byId = findTask(state.tasks, token);
5281
5312
  if (byId) return byId.id;
5282
5313
  const order = Number(token);
5283
5314
  if (Number.isInteger(order)) {
@@ -5428,9 +5459,13 @@ async function perform(effect, deps) {
5428
5459
  const sessionId = deps.newSessionId();
5429
5460
  dispatch({ type: "sessionStarted", sessionId, goal: effect.goal });
5430
5461
  try {
5431
- await converse(deps, sessionId, () => api.startConversation(sessionId, effect.goal, void 0, workspace));
5462
+ await converse(deps, sessionId, () => api.startConversation(sessionId, effect.goal, void 0, workspace, effect.allowInit));
5432
5463
  } catch (err) {
5433
5464
  dispatch({ type: "sessionCleared" });
5465
+ if (err instanceof WorkspaceInitNeededError && !effect.allowInit) {
5466
+ dispatch({ type: "workspaceNeedsInit", goal: effect.goal, workspace: err.workspace });
5467
+ return;
5468
+ }
5434
5469
  throw err;
5435
5470
  }
5436
5471
  return;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ordewell/cli",
3
- "version": "0.4.13",
3
+ "version": "0.4.15",
4
4
  "description": "Ordewell CLI and TUI — plan, run and verify coding-agent tasks from the terminal.",
5
5
  "license": "Apache-2.0",
6
6
  "author": "Alessandro Costanzo Ciano",