@ordewell/cli 0.7.1 → 0.7.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/main.js +328 -486
- package/package.json +3 -3
package/dist/main.js
CHANGED
|
@@ -24,7 +24,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
24
24
|
));
|
|
25
25
|
|
|
26
26
|
// src/main.ts
|
|
27
|
-
var
|
|
27
|
+
var import_core38 = require("@ordewell/core");
|
|
28
28
|
|
|
29
29
|
// src/utils/env.ts
|
|
30
30
|
var import_fs = require("fs");
|
|
@@ -406,15 +406,30 @@ var import_http2 = __toESM(require("http"));
|
|
|
406
406
|
var import_ws = __toESM(require("ws"));
|
|
407
407
|
var import_core3 = require("@ordewell/core");
|
|
408
408
|
var DEFAULT_HTTP_TIMEOUT_MS = 15 * 60 * 1e3;
|
|
409
|
-
var
|
|
410
|
-
constructor(message,
|
|
409
|
+
var DaemonError = class extends Error {
|
|
410
|
+
constructor(message, status, code) {
|
|
411
411
|
super(message);
|
|
412
|
+
this.status = status;
|
|
413
|
+
this.code = code;
|
|
414
|
+
this.name = "DaemonError";
|
|
415
|
+
}
|
|
416
|
+
status;
|
|
417
|
+
code;
|
|
418
|
+
};
|
|
419
|
+
var WorkspaceInitNeededError = class extends DaemonError {
|
|
420
|
+
constructor(message, workspace) {
|
|
421
|
+
super(message, 400, "workspace_not_a_project");
|
|
412
422
|
this.workspace = workspace;
|
|
413
423
|
this.name = "WorkspaceInitNeededError";
|
|
414
424
|
}
|
|
415
425
|
workspace;
|
|
416
426
|
};
|
|
417
427
|
var SESSION_PATH = /^\/api\/(?:plans|sessions)\/([^/?]+)/;
|
|
428
|
+
function daemonError(status, data, fallback) {
|
|
429
|
+
const { error, code, workspace } = typeof data === "object" && data !== null ? data : {};
|
|
430
|
+
if (code === "workspace_not_a_project") return new WorkspaceInitNeededError(error || "Not a project directory", workspace ?? "");
|
|
431
|
+
return new DaemonError(error || fallback, status, code);
|
|
432
|
+
}
|
|
418
433
|
var ApiClient = class _ApiClient {
|
|
419
434
|
/** Where a CLI invocation's sessions live, when a client is built without one: `--workspace`, else the cwd. */
|
|
420
435
|
static defaultWorkspace;
|
|
@@ -422,6 +437,7 @@ var ApiClient = class _ApiClient {
|
|
|
422
437
|
workspace;
|
|
423
438
|
/** A session's open execution stream, so a new one can end it: one run is reported once. */
|
|
424
439
|
executionStreams = /* @__PURE__ */ new Map();
|
|
440
|
+
executionStreamEnds = /* @__PURE__ */ new WeakMap();
|
|
425
441
|
constructor(port, workspace) {
|
|
426
442
|
this.port = port || DEFAULT_PORT;
|
|
427
443
|
this.workspace = workspace ?? _ApiClient.defaultWorkspace ?? process.cwd();
|
|
@@ -436,7 +452,7 @@ var ApiClient = class _ApiClient {
|
|
|
436
452
|
}
|
|
437
453
|
/**
|
|
438
454
|
* A daemon holds only the sessions adopted since it started, so after a
|
|
439
|
-
* restart every session-scoped call answered "
|
|
455
|
+
* restart every session-scoped call answered "session not found" until the
|
|
440
456
|
* user ran `ordewell sessions load`. The saved session is adopted here
|
|
441
457
|
* instead — idempotent for one the daemon still holds — and the call made
|
|
442
458
|
* once more; a 404 means the first attempt never ran, so the retry cannot
|
|
@@ -445,11 +461,17 @@ var ApiClient = class _ApiClient {
|
|
|
445
461
|
async httpRequest(method, urlPath, body) {
|
|
446
462
|
const res = await this.rawRequest(method, urlPath, body);
|
|
447
463
|
const sessionId = urlPath.match(SESSION_PATH)?.[1];
|
|
448
|
-
const missing = res.status === 404 && res.data?.
|
|
464
|
+
const missing = res.status === 404 && res.data?.code === "session_not_found";
|
|
449
465
|
if (!missing || !sessionId || urlPath.split("?")[0].endsWith("/load")) return res;
|
|
450
466
|
const adopted2 = await this.rawRequest("POST", `/api/sessions/${sessionId}/load?workspace=${encodeURIComponent(this.workspace)}`);
|
|
451
467
|
return adopted2.status === 200 ? this.rawRequest(method, urlPath, body) : res;
|
|
452
468
|
}
|
|
469
|
+
/** One request whose only good answer is a 200: anything else becomes a {@link DaemonError} carrying the daemon's code. */
|
|
470
|
+
async call(method, urlPath, fallback, body) {
|
|
471
|
+
const res = await this.httpRequest(method, urlPath, body);
|
|
472
|
+
if (res.status !== 200) throw daemonError(res.status, res.data, fallback);
|
|
473
|
+
return res.data;
|
|
474
|
+
}
|
|
453
475
|
rawRequest(method, urlPath, body) {
|
|
454
476
|
return new Promise((resolve3, reject) => {
|
|
455
477
|
const url = new URL(urlPath, `http://127.0.0.1:${this.port}`);
|
|
@@ -492,15 +514,12 @@ var ApiClient = class _ApiClient {
|
|
|
492
514
|
});
|
|
493
515
|
}
|
|
494
516
|
async generatePlan(goal, runners2, workspace, sessionId = (0, import_core3.mintSessionId)()) {
|
|
495
|
-
const
|
|
517
|
+
const { plan, models, modelsByRunner } = await this.call("POST", `/api/plans/${sessionId}/generate`, "Plan generation failed", {
|
|
496
518
|
goal,
|
|
497
519
|
runners: runners2 || void 0,
|
|
498
520
|
workspace
|
|
499
521
|
});
|
|
500
|
-
|
|
501
|
-
throw new Error(res.data?.error || "Plan generation failed");
|
|
502
|
-
}
|
|
503
|
-
return { sessionId, plan: res.data.plan, models: res.data.models, modelsByRunner: res.data.modelsByRunner };
|
|
522
|
+
return { sessionId, plan, models, modelsByRunner };
|
|
504
523
|
}
|
|
505
524
|
/**
|
|
506
525
|
* Open the ADR-0002 planner dialogue. Unlike `generatePlan`, this path honours
|
|
@@ -508,58 +527,30 @@ var ApiClient = class _ApiClient {
|
|
|
508
527
|
* (empty `tasks`, last word in `conversationHistory`) rather than a committed plan.
|
|
509
528
|
*/
|
|
510
529
|
async startConversation(sessionId, goal, runners2, workspace, allowInit) {
|
|
511
|
-
const res = await this.
|
|
530
|
+
const res = await this.call("POST", `/api/plans/${sessionId}/converse/start`, "Planning failed", {
|
|
512
531
|
goal,
|
|
513
532
|
runners: runners2 || void 0,
|
|
514
533
|
workspace,
|
|
515
534
|
allowInit
|
|
516
535
|
});
|
|
517
|
-
|
|
518
|
-
if (res.data?.code === "workspace_not_a_project") {
|
|
519
|
-
throw new WorkspaceInitNeededError(res.data.error || "Not a project directory", res.data.workspace || workspace || "");
|
|
520
|
-
}
|
|
521
|
-
throw new Error(res.data?.error || "Planning failed");
|
|
522
|
-
}
|
|
523
|
-
return res.data.plan;
|
|
536
|
+
return res.plan;
|
|
524
537
|
}
|
|
525
538
|
async sendConversationMessage(sessionId, message) {
|
|
526
|
-
const res = await this.
|
|
527
|
-
|
|
528
|
-
throw new Error(res.data?.error || "Planner message failed");
|
|
529
|
-
}
|
|
530
|
-
return res.data.plan;
|
|
539
|
+
const res = await this.call("POST", `/api/plans/${sessionId}/converse/message`, "Planner message failed", { message });
|
|
540
|
+
return res.plan;
|
|
531
541
|
}
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
if (res.status !== 200) {
|
|
535
|
-
throw new Error(res.data?.error || "Failed to fetch runners");
|
|
536
|
-
}
|
|
537
|
-
return res.data;
|
|
542
|
+
getRunners() {
|
|
543
|
+
return this.call("GET", "/api/runners", "Failed to fetch runners");
|
|
538
544
|
}
|
|
539
545
|
/** The full provider catalog the daemon has discovered (used by the TUI model picker). */
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
if (res.status !== 200) {
|
|
543
|
-
throw new Error(res.data?.error || "Failed to fetch models");
|
|
544
|
-
}
|
|
545
|
-
return res.data;
|
|
546
|
+
getModels() {
|
|
547
|
+
return this.call("GET", "/api/models", "Failed to fetch models");
|
|
546
548
|
}
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
if (res.status !== 200) {
|
|
550
|
-
throw new Error(res.data?.error || `Failed to ${enabled ? "enable" : "disable"} ${runner}`);
|
|
551
|
-
}
|
|
552
|
-
return res.data;
|
|
549
|
+
setRunnerEnabled(runner, enabled) {
|
|
550
|
+
return this.call("PUT", `/api/runners/${runner}`, `Failed to ${enabled ? "enable" : "disable"} ${runner}`, { enabled });
|
|
553
551
|
}
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
"POST",
|
|
557
|
-
`/api/plans/${sessionId}/execute`
|
|
558
|
-
);
|
|
559
|
-
if (res.status !== 200) {
|
|
560
|
-
throw new Error(res.data?.error || "Execute failed");
|
|
561
|
-
}
|
|
562
|
-
return res.data;
|
|
552
|
+
executePlan(sessionId) {
|
|
553
|
+
return this.call("POST", `/api/plans/${sessionId}/execute`, "Execute failed");
|
|
563
554
|
}
|
|
564
555
|
/**
|
|
565
556
|
* Sign off a plan waiting on `review_needed` and let it continue.
|
|
@@ -568,228 +559,111 @@ var ApiClient = class _ApiClient {
|
|
|
568
559
|
* `resetForRun`) before approving, which is right for starting a plan and
|
|
569
560
|
* wrong for releasing one that is already part-way through a review pause.
|
|
570
561
|
*/
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
"POST",
|
|
574
|
-
`/api/plans/${sessionId}/review/approve`
|
|
575
|
-
);
|
|
576
|
-
if (res.status !== 200) {
|
|
577
|
-
throw new Error(res.data?.error || "Approve failed");
|
|
578
|
-
}
|
|
579
|
-
return res.data;
|
|
562
|
+
approveReview(sessionId) {
|
|
563
|
+
return this.call("POST", `/api/plans/${sessionId}/review/approve`, "Approve failed");
|
|
580
564
|
}
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
"POST",
|
|
584
|
-
`/api/plans/${sessionId}/tasks/${taskId}/complete`
|
|
585
|
-
);
|
|
586
|
-
if (res.status !== 200) {
|
|
587
|
-
throw new Error(res.data?.error || "Mark complete failed");
|
|
588
|
-
}
|
|
589
|
-
return res.data;
|
|
565
|
+
markTaskComplete(sessionId, taskId) {
|
|
566
|
+
return this.call("POST", `/api/plans/${sessionId}/tasks/${taskId}/complete`, "Mark complete failed");
|
|
590
567
|
}
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
"POST",
|
|
594
|
-
`/api/plans/${sessionId}/tasks/${taskId}/uncomplete`
|
|
595
|
-
);
|
|
596
|
-
if (res.status !== 200) {
|
|
597
|
-
throw new Error(res.data?.error || "Mark not done failed");
|
|
598
|
-
}
|
|
599
|
-
return res.data;
|
|
568
|
+
markTaskIncomplete(sessionId, taskId) {
|
|
569
|
+
return this.call("POST", `/api/plans/${sessionId}/tasks/${taskId}/uncomplete`, "Mark not done failed");
|
|
600
570
|
}
|
|
601
571
|
/** run | force-start | retry | cancel — real orchestrator work, not a status patch. */
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
"POST",
|
|
605
|
-
`/api/plans/${sessionId}/tasks/${taskId}/${action}`
|
|
606
|
-
);
|
|
607
|
-
if (res.status !== 200) {
|
|
608
|
-
throw new Error(res.data?.error || `${action} failed`);
|
|
609
|
-
}
|
|
610
|
-
return res.data;
|
|
572
|
+
taskControl(sessionId, taskId, action) {
|
|
573
|
+
return this.call("POST", `/api/plans/${sessionId}/tasks/${taskId}/${action}`, `${action} failed`);
|
|
611
574
|
}
|
|
612
575
|
/** A user message to a structured task: delivered now if it waits for input, else queued behind its turn. */
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
if (res.status !== 200) {
|
|
616
|
-
throw new Error(res.data?.error || "Send message failed");
|
|
617
|
-
}
|
|
618
|
-
return res.data;
|
|
576
|
+
sendTaskMessage(sessionId, taskId, text) {
|
|
577
|
+
return this.call("POST", `/api/plans/${sessionId}/tasks/${taskId}/messages`, "Send message failed", { text });
|
|
619
578
|
}
|
|
620
579
|
/** Force send: interrupt the task's running turn and deliver `text` next, ahead of anything queued (ADR-0023, F1). */
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
if (res.status !== 200) {
|
|
624
|
-
throw new Error(res.data?.error || "Send now failed");
|
|
625
|
-
}
|
|
626
|
-
return res.data;
|
|
580
|
+
forceSendTaskMessage(sessionId, taskId, text) {
|
|
581
|
+
return this.call("POST", `/api/plans/${sessionId}/tasks/${taskId}/messages/now`, "Send now failed", { text });
|
|
627
582
|
}
|
|
628
583
|
/** Force send a message still queued; `sent` is false once the runner already has it. */
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
"POST",
|
|
632
|
-
`/api/plans/${sessionId}/tasks/${taskId}/messages/${encodeURIComponent(messageId)}/now`
|
|
633
|
-
);
|
|
634
|
-
if (res.status !== 200) {
|
|
635
|
-
throw new Error(res.data?.error || "Send now failed");
|
|
636
|
-
}
|
|
637
|
-
return res.data;
|
|
584
|
+
forceSendQueuedTaskMessage(sessionId, taskId, messageId) {
|
|
585
|
+
return this.call("POST", `/api/plans/${sessionId}/tasks/${taskId}/messages/${encodeURIComponent(messageId)}/now`, "Send now failed");
|
|
638
586
|
}
|
|
639
587
|
/** Continue a finished structured task in its saved session, with `text` as its next turn. */
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
if (res.status !== 200) {
|
|
643
|
-
throw new Error(res.data?.error || "Continue failed");
|
|
644
|
-
}
|
|
645
|
-
return res.data;
|
|
588
|
+
continueTask(sessionId, taskId, text) {
|
|
589
|
+
return this.call("POST", `/api/plans/${sessionId}/tasks/${taskId}/continue`, "Continue failed", { text });
|
|
646
590
|
}
|
|
647
591
|
/** `removed` is false once the message was already delivered. */
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
"DELETE",
|
|
651
|
-
`/api/plans/${sessionId}/tasks/${taskId}/messages/${encodeURIComponent(messageId)}`
|
|
652
|
-
);
|
|
653
|
-
if (res.status !== 200) {
|
|
654
|
-
throw new Error(res.data?.error || "Remove message failed");
|
|
655
|
-
}
|
|
656
|
-
return res.data;
|
|
592
|
+
removeQueuedTaskMessage(sessionId, taskId, messageId) {
|
|
593
|
+
return this.call("DELETE", `/api/plans/${sessionId}/tasks/${taskId}/messages/${encodeURIComponent(messageId)}`, "Remove message failed");
|
|
657
594
|
}
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
if (res.status !== 200) {
|
|
661
|
-
throw new Error(res.data?.error || "Interrupt failed");
|
|
662
|
-
}
|
|
663
|
-
return res.data;
|
|
595
|
+
interruptTask(sessionId, taskId) {
|
|
596
|
+
return this.call("POST", `/api/plans/${sessionId}/tasks/${taskId}/interrupt`, "Interrupt failed");
|
|
664
597
|
}
|
|
665
598
|
/** Let a task go on from the checkpoint it waits at; refused, with the reason, when none waits. */
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
if (res.status !== 200) {
|
|
669
|
-
throw new Error(res.data?.error || "Approve checkpoint failed");
|
|
670
|
-
}
|
|
671
|
-
return res.data;
|
|
599
|
+
approveTaskCheckpoint(sessionId, taskId) {
|
|
600
|
+
return this.call("POST", `/api/plans/${sessionId}/tasks/${taskId}/checkpoint/approve`, "Approve checkpoint failed");
|
|
672
601
|
}
|
|
673
602
|
/** Turn a task back at its checkpoint; `reason` is what the agent is told. */
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
"POST",
|
|
677
|
-
`/api/plans/${sessionId}/tasks/${taskId}/checkpoint/reject`,
|
|
678
|
-
reason ? { reason } : {}
|
|
679
|
-
);
|
|
680
|
-
if (res.status !== 200) {
|
|
681
|
-
throw new Error(res.data?.error || "Reject checkpoint failed");
|
|
682
|
-
}
|
|
683
|
-
return res.data;
|
|
603
|
+
rejectTaskCheckpoint(sessionId, taskId, reason) {
|
|
604
|
+
return this.call("POST", `/api/plans/${sessionId}/tasks/${taskId}/checkpoint/reject`, "Reject checkpoint failed", reason ? { reason } : {});
|
|
684
605
|
}
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
if (res.status !== 200) {
|
|
688
|
-
throw new Error(res.data?.error || "Add task failed");
|
|
689
|
-
}
|
|
690
|
-
return res.data;
|
|
606
|
+
addTask(sessionId, task) {
|
|
607
|
+
return this.call("POST", `/api/plans/${sessionId}/tasks`, "Add task failed", task);
|
|
691
608
|
}
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
if (res.status !== 200) {
|
|
695
|
-
throw new Error(res.data?.error || "Update task failed");
|
|
696
|
-
}
|
|
697
|
-
return res.data;
|
|
609
|
+
updateTask(sessionId, taskId, changes) {
|
|
610
|
+
return this.call("PUT", `/api/plans/${sessionId}/tasks/${taskId}`, "Update task failed", changes);
|
|
698
611
|
}
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
if (res.status !== 200) {
|
|
702
|
-
throw new Error(res.data?.error || "Remove task failed");
|
|
703
|
-
}
|
|
704
|
-
return res.data;
|
|
612
|
+
removeTask(sessionId, taskId) {
|
|
613
|
+
return this.call("DELETE", `/api/plans/${sessionId}/tasks/${taskId}`, "Remove task failed");
|
|
705
614
|
}
|
|
706
615
|
/**
|
|
707
616
|
* Make a saved session live on the server. `getSession` only reads the file;
|
|
708
617
|
* until the session is adopted there is no orchestrator behind it, so
|
|
709
|
-
* execute/retry/cancel answer
|
|
618
|
+
* execute/retry/cancel answer `session_not_found`.
|
|
710
619
|
*/
|
|
711
620
|
async adoptSession(sessionId, workspace) {
|
|
712
621
|
const qs = workspace ? `?workspace=${encodeURIComponent(workspace)}` : "";
|
|
713
|
-
const res = await this.
|
|
714
|
-
|
|
715
|
-
throw new Error(res.data?.error || "Failed to load session");
|
|
716
|
-
}
|
|
717
|
-
return { plan: res.data.plan, goal: res.data.goal ?? "" };
|
|
622
|
+
const res = await this.call("POST", `/api/sessions/${sessionId}/load${qs}`, "Failed to load session");
|
|
623
|
+
return { plan: res.plan, goal: res.goal ?? "" };
|
|
718
624
|
}
|
|
719
|
-
|
|
625
|
+
deleteSession(sessionId, workspace) {
|
|
720
626
|
const qs = workspace ? `?workspace=${encodeURIComponent(workspace)}` : "";
|
|
721
|
-
|
|
722
|
-
if (res.status !== 200) {
|
|
723
|
-
throw new Error(res.data?.error || "Delete session failed");
|
|
724
|
-
}
|
|
725
|
-
return res.data;
|
|
627
|
+
return this.call("DELETE", `/api/sessions/${sessionId}${qs}`, "Delete session failed");
|
|
726
628
|
}
|
|
727
629
|
/** Copy the conversation and its tasks into a new session the daemon has already adopted. */
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
if (res.status !== 200) {
|
|
731
|
-
throw new Error(res.data?.error || "Fork failed");
|
|
732
|
-
}
|
|
733
|
-
return { sessionId: res.data.sessionId, goal: res.data.goal, plan: res.data.plan };
|
|
630
|
+
forkConversation(sessionId) {
|
|
631
|
+
return this.call("POST", `/api/plans/${sessionId}/conversation/fork`, "Fork failed");
|
|
734
632
|
}
|
|
735
633
|
async rewindTargets(sessionId) {
|
|
736
|
-
const res = await this.
|
|
737
|
-
|
|
738
|
-
throw new Error(res.data?.error || "Failed to list rewind targets");
|
|
739
|
-
}
|
|
740
|
-
return res.data.targets;
|
|
634
|
+
const res = await this.call("GET", `/api/plans/${sessionId}/conversation/rewind-targets`, "Failed to list rewind targets");
|
|
635
|
+
return res.targets;
|
|
741
636
|
}
|
|
742
637
|
/**
|
|
743
638
|
* Fork the conversation from just before the user message at `index` (a
|
|
744
639
|
* transcript position) into a session the daemon has already adopted. The
|
|
745
640
|
* original is left as it was; `rewoundMessage` is that message in full.
|
|
746
641
|
*/
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
if (res.status !== 200) {
|
|
750
|
-
throw new Error(res.data?.error || "Rewind failed");
|
|
751
|
-
}
|
|
752
|
-
return { sessionId: res.data.sessionId, goal: res.data.goal, plan: res.data.plan, rewoundMessage: res.data.rewoundMessage };
|
|
642
|
+
rewindConversation(sessionId, index) {
|
|
643
|
+
return this.call("POST", `/api/plans/${sessionId}/conversation/rewind`, "Rewind failed", { index });
|
|
753
644
|
}
|
|
754
645
|
/**
|
|
755
646
|
* Condense the conversation into a summary. One planner call, so it can take
|
|
756
647
|
* as long as a reply; a refusal or failure leaves the conversation as it was.
|
|
757
648
|
*/
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
if (res.status !== 200) {
|
|
761
|
-
throw new Error(res.data?.error || "Compaction failed");
|
|
762
|
-
}
|
|
763
|
-
return { plan: res.data.plan, summary: res.data.summary, keptMessages: res.data.keptMessages };
|
|
649
|
+
compactConversation(sessionId) {
|
|
650
|
+
return this.call("POST", `/api/plans/${sessionId}/conversation/compact`, "Compaction failed");
|
|
764
651
|
}
|
|
765
652
|
/** The dependencies a task waits on at its merge gate (ADR-0020); empty when nothing gates it. */
|
|
766
653
|
async getMergeGate(sessionId, taskId) {
|
|
767
|
-
const res = await this.
|
|
768
|
-
|
|
769
|
-
`/api/plans/${sessionId}/tasks/${taskId}/merge-gate`
|
|
770
|
-
);
|
|
771
|
-
if (res.status !== 200) {
|
|
772
|
-
throw new Error(res.data?.error || "Could not read the merge gate");
|
|
773
|
-
}
|
|
774
|
-
return res.data.mergeGate ?? [];
|
|
654
|
+
const res = await this.call("GET", `/api/plans/${sessionId}/tasks/${taskId}/merge-gate`, "Could not read the merge gate");
|
|
655
|
+
return res.mergeGate ?? [];
|
|
775
656
|
}
|
|
776
657
|
async reviewRunDiff(sessionId) {
|
|
777
|
-
const res = await this.
|
|
778
|
-
|
|
779
|
-
throw new Error(res.data?.error || "Could not read the diff");
|
|
780
|
-
}
|
|
781
|
-
return res.data.diff;
|
|
658
|
+
const res = await this.call("GET", `/api/plans/${sessionId}/isolation/diff`, "Could not read the diff");
|
|
659
|
+
return res.diff;
|
|
782
660
|
}
|
|
783
661
|
/**
|
|
784
662
|
* A conflict or a block is an outcome, not an error. Passed on whole: which
|
|
785
663
|
* repos blocked the merge, or landed before it stopped, is the answer.
|
|
786
664
|
*/
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
if (res.status !== 200) {
|
|
790
|
-
throw new Error(res.data?.error || "Merge failed");
|
|
791
|
-
}
|
|
792
|
-
return res.data;
|
|
665
|
+
mergeRun(sessionId) {
|
|
666
|
+
return this.call("POST", `/api/plans/${sessionId}/isolation/merge`, "Merge failed");
|
|
793
667
|
}
|
|
794
668
|
discardRun(sessionId) {
|
|
795
669
|
return this.isolationAction(sessionId, "discard", "Discard failed");
|
|
@@ -804,17 +678,11 @@ var ApiClient = class _ApiClient {
|
|
|
804
678
|
return this.isolationAction(sessionId, "run-without", "Could not continue without isolation");
|
|
805
679
|
}
|
|
806
680
|
async isolationAction(sessionId, segment, failure) {
|
|
807
|
-
|
|
808
|
-
if (res.status !== 200) {
|
|
809
|
-
throw new Error(res.data?.error || failure);
|
|
810
|
-
}
|
|
681
|
+
await this.call("POST", `/api/plans/${sessionId}/isolation/${segment}`, failure);
|
|
811
682
|
}
|
|
812
683
|
async resolveConflictAsTask(sessionId, taskId) {
|
|
813
|
-
const res = await this.
|
|
814
|
-
|
|
815
|
-
throw new Error(res.data?.error || "Could not add a resolver task");
|
|
816
|
-
}
|
|
817
|
-
return res.data.plan;
|
|
684
|
+
const res = await this.call("POST", `/api/plans/${sessionId}/tasks/${taskId}/resolve-conflict`, "Could not add a resolver task");
|
|
685
|
+
return res.plan;
|
|
818
686
|
}
|
|
819
687
|
async closeSession(sessionId) {
|
|
820
688
|
const res = await this.httpRequest("POST", `/api/sessions/${sessionId}/close`);
|
|
@@ -829,42 +697,26 @@ var ApiClient = class _ApiClient {
|
|
|
829
697
|
const res = await this.httpRequest("POST", `/api/plans/${sessionId}/planning/stop`);
|
|
830
698
|
return res.data;
|
|
831
699
|
}
|
|
832
|
-
async processQueued(sessionId) {
|
|
833
|
-
const res = await this.httpRequest("POST", `/api/plans/${sessionId}/process-queued`);
|
|
834
|
-
if (res.status !== 200) {
|
|
835
|
-
throw new Error(res.data?.error || "Process queued failed");
|
|
836
|
-
}
|
|
837
|
-
return res.data;
|
|
838
|
-
}
|
|
839
700
|
async getSessions(workspace) {
|
|
840
701
|
const qs = workspace ? `?workspace=${encodeURIComponent(workspace)}` : "";
|
|
841
702
|
const res = await this.httpRequest("GET", `/api/sessions${qs}`);
|
|
842
703
|
return res.data || [];
|
|
843
704
|
}
|
|
844
|
-
|
|
705
|
+
getSession(sessionId, workspace) {
|
|
845
706
|
const qs = workspace ? `?workspace=${encodeURIComponent(workspace)}` : "";
|
|
846
|
-
|
|
847
|
-
"GET",
|
|
848
|
-
`/api/sessions/${sessionId}${qs}`
|
|
849
|
-
);
|
|
850
|
-
if (res.status !== 200) {
|
|
851
|
-
throw new Error(res.data?.error || "Session not found");
|
|
852
|
-
}
|
|
853
|
-
return res.data;
|
|
707
|
+
return this.call("GET", `/api/sessions/${sessionId}${qs}`, "Session not found");
|
|
854
708
|
}
|
|
855
709
|
/** The attempts of a structured task that have a saved log, oldest first. */
|
|
856
710
|
async getTaskLogAttempts(sessionId, taskId, workspace) {
|
|
857
711
|
const qs = workspace ? `?workspace=${encodeURIComponent(workspace)}` : "";
|
|
858
|
-
const res = await this.
|
|
859
|
-
|
|
860
|
-
return res.data.attempts;
|
|
712
|
+
const res = await this.call("GET", `/api/sessions/${sessionId}/tasks/${encodeURIComponent(taskId)}/log${qs}`, "Could not read the task log");
|
|
713
|
+
return res.attempts;
|
|
861
714
|
}
|
|
862
715
|
/** One attempt's saved log, for `replayTaskLog`. */
|
|
863
716
|
async getTaskLog(sessionId, taskId, attempt, workspace) {
|
|
864
717
|
const qs = workspace ? `?workspace=${encodeURIComponent(workspace)}` : "";
|
|
865
|
-
const res = await this.
|
|
866
|
-
|
|
867
|
-
return res.data.events;
|
|
718
|
+
const res = await this.call("GET", `/api/sessions/${sessionId}/tasks/${encodeURIComponent(taskId)}/log/${attempt}${qs}`, "Could not read the task log");
|
|
719
|
+
return res.events;
|
|
868
720
|
}
|
|
869
721
|
/**
|
|
870
722
|
* The one place a session socket is built, so the token travels on both
|
|
@@ -895,8 +747,14 @@ var ApiClient = class _ApiClient {
|
|
|
895
747
|
});
|
|
896
748
|
return socket;
|
|
897
749
|
}
|
|
750
|
+
/** Ends one stream `streamExecution` returned, leaving any newer stream the session has opened since alone. */
|
|
751
|
+
closeExecutionStream(stream) {
|
|
752
|
+
this.executionStreamEnds.get(stream)?.();
|
|
753
|
+
}
|
|
898
754
|
streamExecution(sessionId, onEvent, onReady) {
|
|
899
|
-
|
|
755
|
+
let endStream = () => {
|
|
756
|
+
};
|
|
757
|
+
const stream = new Promise((resolve3, reject) => {
|
|
900
758
|
this.executionStreams.get(sessionId)?.();
|
|
901
759
|
const socket = this.openSessionSocket(sessionId);
|
|
902
760
|
let resolved = false;
|
|
@@ -912,6 +770,7 @@ var ApiClient = class _ApiClient {
|
|
|
912
770
|
resolve3();
|
|
913
771
|
};
|
|
914
772
|
this.executionStreams.set(sessionId, end);
|
|
773
|
+
endStream = end;
|
|
915
774
|
socket.on("open", () => {
|
|
916
775
|
opened = true;
|
|
917
776
|
onReady?.();
|
|
@@ -928,8 +787,12 @@ var ApiClient = class _ApiClient {
|
|
|
928
787
|
socket.on("error", (err) => {
|
|
929
788
|
forget();
|
|
930
789
|
if (!opened) onReady?.(err);
|
|
931
|
-
if (
|
|
932
|
-
|
|
790
|
+
if (resolved) return;
|
|
791
|
+
resolved = true;
|
|
792
|
+
if (opened) {
|
|
793
|
+
socket.close();
|
|
794
|
+
resolve3("lost");
|
|
795
|
+
} else {
|
|
933
796
|
reject(err);
|
|
934
797
|
}
|
|
935
798
|
});
|
|
@@ -938,10 +801,12 @@ var ApiClient = class _ApiClient {
|
|
|
938
801
|
if (!opened) onReady?.(new Error("Execution stream closed before connecting"));
|
|
939
802
|
if (!resolved) {
|
|
940
803
|
resolved = true;
|
|
941
|
-
resolve3();
|
|
804
|
+
resolve3("lost");
|
|
942
805
|
}
|
|
943
806
|
});
|
|
944
807
|
});
|
|
808
|
+
this.executionStreamEnds.set(stream, endStream);
|
|
809
|
+
return stream;
|
|
945
810
|
}
|
|
946
811
|
/**
|
|
947
812
|
* Answer an approval prompt: the planner's with a yes/no, a task runner's
|
|
@@ -954,7 +819,7 @@ var ApiClient = class _ApiClient {
|
|
|
954
819
|
`/api/approvals/${encodeURIComponent(sessionId)}/${encodeURIComponent(approvalId)}`,
|
|
955
820
|
typeof answer === "boolean" ? { granted: answer } : answer
|
|
956
821
|
);
|
|
957
|
-
if (status !== 200) throw new
|
|
822
|
+
if (status !== 200) throw new DaemonError(`Failed to answer approval ${approvalId} (HTTP ${status})`, status, data.code);
|
|
958
823
|
return data;
|
|
959
824
|
}
|
|
960
825
|
/**
|
|
@@ -979,33 +844,17 @@ var ApiClient = class _ApiClient {
|
|
|
979
844
|
});
|
|
980
845
|
return { ready, close: () => socket.close() };
|
|
981
846
|
}
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
if (res.status !== 200) {
|
|
985
|
-
throw new Error(res.data?.error || "Failed to fetch commands");
|
|
986
|
-
}
|
|
987
|
-
return res.data;
|
|
847
|
+
getCommands() {
|
|
848
|
+
return this.call("GET", "/api/commands", "Failed to fetch commands");
|
|
988
849
|
}
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
if (res.status !== 200) {
|
|
992
|
-
throw new Error(res.data?.error || `Command ${name} failed`);
|
|
993
|
-
}
|
|
994
|
-
return res.data;
|
|
850
|
+
sendCommand(name, args = {}) {
|
|
851
|
+
return this.call("POST", `/api/commands/${name}`, `Command ${name} failed`, { args });
|
|
995
852
|
}
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
if (res.status !== 200) {
|
|
999
|
-
throw new Error(res.data?.error || "Failed to fetch settings");
|
|
1000
|
-
}
|
|
1001
|
-
return res.data;
|
|
853
|
+
getSettings() {
|
|
854
|
+
return this.call("GET", "/api/settings", "Failed to fetch settings");
|
|
1002
855
|
}
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
if (res.status !== 200) {
|
|
1006
|
-
throw new Error(res.data?.error || "Failed to update settings");
|
|
1007
|
-
}
|
|
1008
|
-
return res.data;
|
|
856
|
+
updateSettings(changes) {
|
|
857
|
+
return this.call("PATCH", "/api/settings", "Failed to update settings", changes);
|
|
1009
858
|
}
|
|
1010
859
|
};
|
|
1011
860
|
|
|
@@ -1253,11 +1102,14 @@ var import_core7 = require("@ordewell/core");
|
|
|
1253
1102
|
function planTasks(plan) {
|
|
1254
1103
|
return plan ? allTasksOf(plan) : [];
|
|
1255
1104
|
}
|
|
1105
|
+
function runnersOf(plan, requested) {
|
|
1106
|
+
return "runners" in plan && plan.runners || requested;
|
|
1107
|
+
}
|
|
1256
1108
|
function hasCommittedPlan(plan) {
|
|
1257
1109
|
return planTasks(plan).length > 0;
|
|
1258
1110
|
}
|
|
1259
1111
|
function lastPlannerMessage(plan) {
|
|
1260
|
-
const history = plan
|
|
1112
|
+
const history = "conversationHistory" in plan && plan.conversationHistory || [];
|
|
1261
1113
|
for (let i = history.length - 1; i >= 0; i--) {
|
|
1262
1114
|
if (history[i].role === "assistant") return history[i].content;
|
|
1263
1115
|
}
|
|
@@ -1319,7 +1171,7 @@ function printPlan(plan, sessionId, runners2, models) {
|
|
|
1319
1171
|
return rp ? ` (${task.assignedModel.modelLabel} \xB7 ${label})` : ` (${task.assignedModel.modelLabel})`;
|
|
1320
1172
|
};
|
|
1321
1173
|
console.log(`
|
|
1322
|
-
Plan: ${tasks.length} task${tasks.length === 1 ? "" : "s"} (${aiCount} AI, ${manCount} Manual) \u2014 ${(plan
|
|
1174
|
+
Plan: ${tasks.length} task${tasks.length === 1 ? "" : "s"} (${aiCount} AI, ${manCount} Manual) \u2014 ${runnersOf(plan, runners2).join(", ")}`);
|
|
1323
1175
|
console.log(`Session: ${sessionId}
|
|
1324
1176
|
`);
|
|
1325
1177
|
for (const t of tasks) {
|
|
@@ -1466,7 +1318,7 @@ ${lastPlannerMessage(plan)}
|
|
|
1466
1318
|
if (isTty && lastLineLength > 0) process.stderr.write("\r\x1B[2K");
|
|
1467
1319
|
process.stderr.write("\n");
|
|
1468
1320
|
printPlan(plan, sessionId, runners2, models);
|
|
1469
|
-
saveLastSession(sessionId, goal, plan
|
|
1321
|
+
saveLastSession(sessionId, goal, runnersOf(plan, runners2), workspace);
|
|
1470
1322
|
console.log(`
|
|
1471
1323
|
Run 'ordewell run' to execute, 'ordewell status' to inspect, or 'ordewell tui' for the full UI.`);
|
|
1472
1324
|
} catch (err) {
|
|
@@ -1584,23 +1436,27 @@ function mergeOutcome(result, branch, group, repaired = []) {
|
|
|
1584
1436
|
}
|
|
1585
1437
|
|
|
1586
1438
|
// src/utils/output.ts
|
|
1439
|
+
var import_core9 = require("@ordewell/core");
|
|
1587
1440
|
function iconFor(status) {
|
|
1588
|
-
switch (status) {
|
|
1589
|
-
case "
|
|
1441
|
+
switch ((0, import_core9.taskStatusKind)({ status })) {
|
|
1442
|
+
case "done":
|
|
1590
1443
|
return "\x1B[32m\u2713\x1B[0m";
|
|
1591
|
-
case "
|
|
1444
|
+
case "running":
|
|
1445
|
+
case "quiet":
|
|
1592
1446
|
return "\x1B[34m\u27F3\x1B[0m";
|
|
1593
1447
|
case "failed":
|
|
1594
1448
|
return "\x1B[31m\u2717\x1B[0m";
|
|
1595
1449
|
case "blocked":
|
|
1596
1450
|
return "\x1B[33m\u2298\x1B[0m";
|
|
1597
|
-
|
|
1451
|
+
case "awaiting":
|
|
1452
|
+
return "\x1B[33m?\x1B[0m";
|
|
1453
|
+
case "todo":
|
|
1598
1454
|
return "\x1B[90m\u25CB\x1B[0m";
|
|
1599
1455
|
}
|
|
1600
1456
|
}
|
|
1601
1457
|
|
|
1602
1458
|
// src/commands/run.ts
|
|
1603
|
-
var
|
|
1459
|
+
var import_core10 = require("@ordewell/core");
|
|
1604
1460
|
|
|
1605
1461
|
// src/commands/shared.ts
|
|
1606
1462
|
var import_readline2 = require("readline");
|
|
@@ -1756,11 +1612,11 @@ async function followExecution(api, sessionId, start, onBlocked) {
|
|
|
1756
1612
|
});
|
|
1757
1613
|
const stream = api.streamExecution(sessionId, (event) => {
|
|
1758
1614
|
if (event.type === "task_started") {
|
|
1759
|
-
process.stderr.write(`\xB7 ${(0,
|
|
1615
|
+
process.stderr.write(`\xB7 ${(0, import_core10.taskStartedNotice)(event.title, event.runner)}
|
|
1760
1616
|
`);
|
|
1761
1617
|
}
|
|
1762
1618
|
if (event.type === "checkpoint") {
|
|
1763
|
-
process.stderr.write(`\xB7 Checkpoint \u2014 ${event.taskTitle}: ${(0,
|
|
1619
|
+
process.stderr.write(`\xB7 Checkpoint \u2014 ${event.taskTitle}: ${(0, import_core10.truncateCheckpointSummary)(event.summary)} \u2014 \`ordewell checkpoint <id> approve|reject [reason]\` answers it
|
|
1764
1620
|
`);
|
|
1765
1621
|
}
|
|
1766
1622
|
if (event.type === "status_update" && event.tasks) {
|
|
@@ -1805,7 +1661,11 @@ Run finished on ${handoffBranch(event)}${where} \u2014 ${n} task${n === 1 ? "" :
|
|
|
1805
1661
|
void stream.catch(settleReady);
|
|
1806
1662
|
await streamReady.catch(streamFailed);
|
|
1807
1663
|
await start();
|
|
1808
|
-
await Promise.race([stream, blockedSeen]).catch(streamFailed);
|
|
1664
|
+
const outcome = await Promise.race([stream, blockedSeen]).catch(streamFailed);
|
|
1665
|
+
if (outcome === "lost") {
|
|
1666
|
+
console.error("Lost the connection to the daemon \u2014 the run is no longer being followed, but the daemon may still be running it. `ordewell status` shows where it stands.");
|
|
1667
|
+
process.exit(1);
|
|
1668
|
+
}
|
|
1809
1669
|
if (blocked === null) return;
|
|
1810
1670
|
if (!onBlocked) {
|
|
1811
1671
|
await api.stopExecution(sessionId);
|
|
@@ -1833,7 +1693,7 @@ async function handleRun(subArgs, injectedApi) {
|
|
|
1833
1693
|
|
|
1834
1694
|
// src/commands/status.ts
|
|
1835
1695
|
var import_fs4 = require("fs");
|
|
1836
|
-
var
|
|
1696
|
+
var import_core11 = require("@ordewell/core");
|
|
1837
1697
|
async function handleStatus(subArgs, injectedApi) {
|
|
1838
1698
|
const sessionId = flag(subArgs, "--session-id");
|
|
1839
1699
|
const workspace = flag(subArgs, "--workspace") || process.cwd();
|
|
@@ -1904,12 +1764,12 @@ function printOneSession(sessionId, meta, plan) {
|
|
|
1904
1764
|
const icon = iconFor(t.status);
|
|
1905
1765
|
const model = t.assignedModel ? ` (${t.assignedModel.modelLabel})` : "";
|
|
1906
1766
|
const shortId = (t.id ?? "").slice(-8);
|
|
1907
|
-
console.log(` ${(0,
|
|
1767
|
+
console.log(` ${(0, import_core11.taskOrderLabel)(t).padStart(2)}. ${icon} [${shortId}] ${t.title}${model}`);
|
|
1908
1768
|
for (const sub of t.subtasks || []) {
|
|
1909
1769
|
const subIcon = iconFor(sub.status);
|
|
1910
1770
|
const subModel = sub.assignedModel ? ` (${sub.assignedModel.modelLabel})` : "";
|
|
1911
1771
|
const subShortId = (sub.id ?? "").slice(-8);
|
|
1912
|
-
console.log(` ${(0,
|
|
1772
|
+
console.log(` ${(0, import_core11.taskOrderLabel)(sub, t)}. ${subIcon} [${subShortId}] ${sub.title}${subModel}`);
|
|
1913
1773
|
}
|
|
1914
1774
|
}
|
|
1915
1775
|
}
|
|
@@ -1961,10 +1821,10 @@ async function handleWeb(subArgs) {
|
|
|
1961
1821
|
}
|
|
1962
1822
|
|
|
1963
1823
|
// src/commands/models.ts
|
|
1964
|
-
var
|
|
1824
|
+
var import_core13 = require("@ordewell/core");
|
|
1965
1825
|
|
|
1966
1826
|
// src/commands/model.ts
|
|
1967
|
-
var
|
|
1827
|
+
var import_core12 = require("@ordewell/core");
|
|
1968
1828
|
var USAGE = "Usage: ordewell model [show | set <model-id>]";
|
|
1969
1829
|
async function handleModel(subArgs, injectedApi) {
|
|
1970
1830
|
const [action, modelId] = positionals(subArgs);
|
|
@@ -1979,7 +1839,7 @@ async function handleModel(subArgs, injectedApi) {
|
|
|
1979
1839
|
if (!modelId) fail(USAGE);
|
|
1980
1840
|
const settings = await api.getSettings();
|
|
1981
1841
|
const provider = typeof settings.aiProvider === "string" ? settings.aiProvider : "";
|
|
1982
|
-
const runner = (0,
|
|
1842
|
+
const runner = (0, import_core12.runnerForProvider)(provider);
|
|
1983
1843
|
if (runner) {
|
|
1984
1844
|
const known = (await fetchCatalog(api)).models.filter((m) => m.runners?.includes(runner));
|
|
1985
1845
|
if (known.length > 0 && !known.some((m) => m.id === modelId)) {
|
|
@@ -1998,7 +1858,7 @@ async function showModels(api) {
|
|
|
1998
1858
|
const [settings, catalog] = await Promise.all([api.getSettings(), fetchCatalog(api)]);
|
|
1999
1859
|
const provider = typeof settings.aiProvider === "string" ? settings.aiProvider : "";
|
|
2000
1860
|
const current = typeof settings.orchestratorModel === "string" ? settings.orchestratorModel : "";
|
|
2001
|
-
const runner = (0,
|
|
1861
|
+
const runner = (0, import_core12.runnerForProvider)(provider);
|
|
2002
1862
|
const options = runner ? catalog.models.filter((m) => m.runners?.includes(runner)) : catalog.orchestratorModels;
|
|
2003
1863
|
console.log(`
|
|
2004
1864
|
Planner model: ${current || "(backend default)"}`);
|
|
@@ -2032,8 +1892,8 @@ async function handleModels(subArgs) {
|
|
|
2032
1892
|
const rest = subArgs.filter((_, i) => i !== setIdx && i !== setIdx + 1);
|
|
2033
1893
|
return handleModel(["set", subArgs[setIdx + 1], ...rest]);
|
|
2034
1894
|
}
|
|
2035
|
-
const config = new
|
|
2036
|
-
const providers = (0,
|
|
1895
|
+
const config = new import_core13.EnvConfig();
|
|
1896
|
+
const providers = (0, import_core13.configuredProviders)(config);
|
|
2037
1897
|
if (providers.length === 0) {
|
|
2038
1898
|
console.error("No providers configured. Set an API key for a provider, e.g.:");
|
|
2039
1899
|
console.error(" OPENROUTER_API_KEY=... (OpenRouter)");
|
|
@@ -2042,19 +1902,19 @@ async function handleModels(subArgs) {
|
|
|
2042
1902
|
console.error(" OPENAI_COMPATIBLE_BASE_URL=... (self-hosted / OpenAI-compatible)");
|
|
2043
1903
|
process.exit(1);
|
|
2044
1904
|
}
|
|
2045
|
-
const { apiKeys, baseUrls } = (0,
|
|
1905
|
+
const { apiKeys, baseUrls } = (0, import_core13.collectProviderCredentials)(config);
|
|
2046
1906
|
let models;
|
|
2047
1907
|
let errors;
|
|
2048
1908
|
try {
|
|
2049
|
-
const result = await (0,
|
|
2050
|
-
models = (0,
|
|
1909
|
+
const result = await (0, import_core13.fetchAllProviderModels)({ apiKeys, baseUrls });
|
|
1910
|
+
models = (0, import_core13.toOrchestratorOptions)(result.models, import_core13.ORCHESTRATOR_SHORTCUTS);
|
|
2051
1911
|
errors = result.errors;
|
|
2052
1912
|
} catch (err) {
|
|
2053
1913
|
console.error(`Failed to fetch models: ${err instanceof Error ? err.message : String(err)}`);
|
|
2054
1914
|
process.exit(1);
|
|
2055
1915
|
return;
|
|
2056
1916
|
}
|
|
2057
|
-
const providerLabel = (p) => (0,
|
|
1917
|
+
const providerLabel = (p) => (0, import_core13.getProviderMeta)(p)?.label ?? p;
|
|
2058
1918
|
console.log(
|
|
2059
1919
|
`
|
|
2060
1920
|
Available models (${models.length}) across ${providers.length} configured provider(s):`
|
|
@@ -2094,7 +1954,7 @@ ${providerLabel(provider)}`);
|
|
|
2094
1954
|
|
|
2095
1955
|
// src/commands/setup.ts
|
|
2096
1956
|
var import_fs6 = require("fs");
|
|
2097
|
-
var
|
|
1957
|
+
var import_core14 = require("@ordewell/core");
|
|
2098
1958
|
function handleSetup(subArgs) {
|
|
2099
1959
|
const modelIdx = subArgs.indexOf("--model");
|
|
2100
1960
|
const chosenModel = modelIdx !== -1 ? subArgs[modelIdx + 1] : null;
|
|
@@ -2166,15 +2026,15 @@ function handleSetup(subArgs) {
|
|
|
2166
2026
|
# STEPFUN_API_KEY=...
|
|
2167
2027
|
# SILICONFLOW_API_KEY=...
|
|
2168
2028
|
`;
|
|
2169
|
-
(0,
|
|
2029
|
+
(0, import_core14.writePrivateFile)(envFile, content);
|
|
2170
2030
|
console.log(`Wrote: ${envFile}`);
|
|
2171
2031
|
console.log("Review and edit the file, then run: ordewell tui");
|
|
2172
2032
|
}
|
|
2173
2033
|
|
|
2174
2034
|
// src/commands/plugins.ts
|
|
2175
|
-
var
|
|
2035
|
+
var import_core15 = require("@ordewell/core");
|
|
2176
2036
|
function handlePlugins(subArgs) {
|
|
2177
|
-
const registry = new
|
|
2037
|
+
const registry = new import_core15.RunnerRegistry();
|
|
2178
2038
|
registry.loadUserPlugins();
|
|
2179
2039
|
const sub = subArgs[0];
|
|
2180
2040
|
if (sub === "list" || !sub) {
|
|
@@ -2210,7 +2070,7 @@ ${plugins.length} plugin(s):
|
|
|
2210
2070
|
process.exit(1);
|
|
2211
2071
|
}
|
|
2212
2072
|
try {
|
|
2213
|
-
const resolved = (0,
|
|
2073
|
+
const resolved = (0, import_core15.classifyPluginSource)(source);
|
|
2214
2074
|
const manifest = resolved.kind === "git" ? registry.installFromGit(resolved.url) : registry.installFromPath(resolved.path);
|
|
2215
2075
|
console.log(`Installed plugin: ${manifest.name} v${manifest.version}`);
|
|
2216
2076
|
} catch (err) {
|
|
@@ -2388,7 +2248,7 @@ async function handleTransport(subArgs, api) {
|
|
|
2388
2248
|
}
|
|
2389
2249
|
|
|
2390
2250
|
// src/commands/task-control.ts
|
|
2391
|
-
var
|
|
2251
|
+
var import_core16 = require("@ordewell/core");
|
|
2392
2252
|
var PAST_TENSE = {
|
|
2393
2253
|
run: "Task started.",
|
|
2394
2254
|
"force-start": "Task force-started.",
|
|
@@ -2431,7 +2291,7 @@ async function confirmPastGate(subArgs, api, sessionId, taskId, confirm) {
|
|
|
2431
2291
|
if (hasFlag(subArgs, "--yes")) return;
|
|
2432
2292
|
const unmerged = await api.getMergeGate(sessionId, taskId).catch(() => []);
|
|
2433
2293
|
if (unmerged.length === 0) return;
|
|
2434
|
-
const question = `${(0,
|
|
2294
|
+
const question = `${(0, import_core16.pastGateConfirmation)(unmerged.map((d) => (0, import_core16.titledTaskRef)(d)))} Start it anyway?`;
|
|
2435
2295
|
if (!await confirm(question)) fail("Not started \u2014 nothing was changed. Pass --yes to start it without a prompt.");
|
|
2436
2296
|
}
|
|
2437
2297
|
function makeHandler(action, command = action) {
|
|
@@ -2744,24 +2604,24 @@ async function handleRewind(subArgs, injectedApi) {
|
|
|
2744
2604
|
}
|
|
2745
2605
|
|
|
2746
2606
|
// src/tui/transcript.ts
|
|
2747
|
-
var
|
|
2607
|
+
var import_core17 = require("@ordewell/core");
|
|
2748
2608
|
function show(state, { view: conversation, gate: turnGate }) {
|
|
2749
2609
|
const gated = turnGate === state.turnGate ? state : { ...state, turnGate };
|
|
2750
2610
|
if (conversation === state.conversation) return gated;
|
|
2751
2611
|
return { ...gated, conversation };
|
|
2752
2612
|
}
|
|
2753
2613
|
function fold(state, input) {
|
|
2754
|
-
return show(state, { view: (0,
|
|
2614
|
+
return show(state, { view: (0, import_core17.reduceConversation)(state.conversation, input), gate: state.turnGate });
|
|
2755
2615
|
}
|
|
2756
2616
|
function say(state, role, text) {
|
|
2757
2617
|
const said = fold(state, { type: "local_entry", role, text });
|
|
2758
2618
|
return said.conversation.nextId > state.conversation.nextId ? { ...said, scroll: 0 } : said;
|
|
2759
2619
|
}
|
|
2760
2620
|
function hear(state, message) {
|
|
2761
|
-
return show(state, (0,
|
|
2621
|
+
return show(state, (0, import_core17.followTurn)(state.conversation, state.turnGate, message));
|
|
2762
2622
|
}
|
|
2763
2623
|
function cutTurn(state) {
|
|
2764
|
-
return show(state, (0,
|
|
2624
|
+
return show(state, (0, import_core17.stopTurn)(state.conversation, state.turnGate));
|
|
2765
2625
|
}
|
|
2766
2626
|
function wiped(view) {
|
|
2767
2627
|
return { ...view, blocks: view.blocks.filter((b) => b.type === "usage") };
|
|
@@ -3175,26 +3035,17 @@ async function handleHandoff(subArgs, injectedApi, confirm = askYesNo) {
|
|
|
3175
3035
|
}
|
|
3176
3036
|
|
|
3177
3037
|
// src/commands/planner.ts
|
|
3178
|
-
var
|
|
3038
|
+
var import_core18 = require("@ordewell/core");
|
|
3179
3039
|
|
|
3180
3040
|
// src/plannerModelSwitch.ts
|
|
3181
|
-
function
|
|
3182
|
-
|
|
3183
|
-
const
|
|
3184
|
-
|
|
3185
|
-
return rememberedModelFor(settings, provider) === model ? { model, effort, source: "remembered" } : { model, effort, source: "catalog-default" };
|
|
3186
|
-
}
|
|
3187
|
-
function rememberedModelFor(settings, provider) {
|
|
3188
|
-
const map = settings.plannerModels;
|
|
3189
|
-
if (!map || typeof map !== "object") return void 0;
|
|
3190
|
-
const entry = map[provider];
|
|
3191
|
-
if (!entry || typeof entry !== "object") return void 0;
|
|
3192
|
-
const { model } = entry;
|
|
3193
|
-
return typeof model === "string" ? model : void 0;
|
|
3041
|
+
function plannerSwitchRecall(settings) {
|
|
3042
|
+
if (settings.switchRecall) return settings.switchRecall;
|
|
3043
|
+
const model = settings.orchestratorModel;
|
|
3044
|
+
return model ? { model, effort: settings.plannerThinkingEffort, source: "remembered" } : { model: "", effort: "", source: "none" };
|
|
3194
3045
|
}
|
|
3195
3046
|
|
|
3196
3047
|
// src/commands/planner.ts
|
|
3197
|
-
var
|
|
3048
|
+
var isAiProvider = (id) => Object.hasOwn(import_core18.ALL_PROVIDERS, id);
|
|
3198
3049
|
async function handlePlanner(subArgs, injectedApi) {
|
|
3199
3050
|
const api = await connect(subArgs, injectedApi);
|
|
3200
3051
|
const [wanted] = positionals(subArgs);
|
|
@@ -3203,19 +3054,19 @@ async function handlePlanner(subArgs, injectedApi) {
|
|
|
3203
3054
|
return;
|
|
3204
3055
|
}
|
|
3205
3056
|
const provider = wanted.toLowerCase();
|
|
3206
|
-
if (!
|
|
3057
|
+
if (!isAiProvider(provider)) {
|
|
3207
3058
|
fail(`Unknown planner: ${provider}`, "Run `ordewell planner` with no arguments to see the list.");
|
|
3208
3059
|
}
|
|
3209
3060
|
const settings = await persistEnv(api, { AI_PROVIDER: provider });
|
|
3210
|
-
const recall2 =
|
|
3061
|
+
const recall2 = plannerSwitchRecall(settings);
|
|
3211
3062
|
writeEnv({ ORCHESTRATOR_MODEL: recall2.model, ORDEWELL_PLANNER_EFFORT: recall2.effort });
|
|
3212
|
-
const meta =
|
|
3063
|
+
const meta = import_core18.ALL_PROVIDERS[provider];
|
|
3213
3064
|
const catalog = await fetchCatalog(api);
|
|
3214
3065
|
console.log(
|
|
3215
|
-
(0,
|
|
3066
|
+
(0, import_core18.isCliProvider)(provider) ? `Planning with ${meta.label} \u2014 no API key needed, it uses that agent's own subscription.` : `Planner set to ${meta.label}.`
|
|
3216
3067
|
);
|
|
3217
3068
|
console.log(plannerModelLine(recall2));
|
|
3218
|
-
if (!(0,
|
|
3069
|
+
if (!(0, import_core18.isCliProvider)(provider) && !catalog.providers.includes(provider)) {
|
|
3219
3070
|
console.log(` No ${meta.apiKeyEnvVar} configured yet \u2014 set one with \`ordewell key set ${provider} <key>\`.`);
|
|
3220
3071
|
}
|
|
3221
3072
|
}
|
|
@@ -3233,15 +3084,15 @@ async function showPlanners(api) {
|
|
|
3233
3084
|
const [settings, catalog] = await Promise.all([api.getSettings(), fetchCatalog(api)]);
|
|
3234
3085
|
const current = typeof settings.aiProvider === "string" ? settings.aiProvider : "";
|
|
3235
3086
|
console.log("\nCoding agents (no API key \u2014 they use their own subscription)");
|
|
3236
|
-
for (const id of
|
|
3237
|
-
const runner = (0,
|
|
3087
|
+
for (const id of import_core18.CLI_PROVIDERS) {
|
|
3088
|
+
const runner = (0, import_core18.runnerForProvider)(id);
|
|
3238
3089
|
const discovered = runner ? catalog.models.some((m) => m.runners?.includes(runner)) : false;
|
|
3239
|
-
console.log(` ${marker(id === current)} ${id.padEnd(14)} ${
|
|
3090
|
+
console.log(` ${marker(id === current)} ${id.padEnd(14)} ${import_core18.ALL_PROVIDERS[id].label}${discovered ? "" : " (not detected)"}`);
|
|
3240
3091
|
}
|
|
3241
3092
|
console.log("\nAPI providers");
|
|
3242
|
-
for (const id of
|
|
3093
|
+
for (const id of import_core18.PROVIDER_PRIORITY) {
|
|
3243
3094
|
const configured = catalog.providers.includes(id);
|
|
3244
|
-
const meta =
|
|
3095
|
+
const meta = import_core18.ALL_PROVIDERS[id];
|
|
3245
3096
|
console.log(` ${marker(id === current)} ${id.padEnd(14)} ${meta.label}${configured ? "" : ` (no ${meta.apiKeyEnvVar})`}`);
|
|
3246
3097
|
}
|
|
3247
3098
|
console.log(`
|
|
@@ -3258,7 +3109,7 @@ async function handlePlannerEffort(subArgs, injectedApi) {
|
|
|
3258
3109
|
const provider = typeof settings.aiProvider === "string" ? settings.aiProvider : "";
|
|
3259
3110
|
const modelId = typeof settings.orchestratorModel === "string" ? settings.orchestratorModel : "";
|
|
3260
3111
|
const currentEffort = typeof settings.plannerThinkingEffort === "string" ? settings.plannerThinkingEffort : "";
|
|
3261
|
-
const runner = (0,
|
|
3112
|
+
const runner = isAiProvider(provider) ? (0, import_core18.runnerForProvider)(provider) : null;
|
|
3262
3113
|
if (!runner) {
|
|
3263
3114
|
fail(
|
|
3264
3115
|
"Thinking effort applies to a coding-agent planner.",
|
|
@@ -3298,7 +3149,7 @@ async function handlePlannerEffort(subArgs, injectedApi) {
|
|
|
3298
3149
|
}
|
|
3299
3150
|
|
|
3300
3151
|
// src/commands/parallel.ts
|
|
3301
|
-
var
|
|
3152
|
+
var import_core19 = require("@ordewell/core");
|
|
3302
3153
|
var USAGE5 = "Usage: ordewell parallel [<number of tasks, 1 or more>]";
|
|
3303
3154
|
async function handleParallel(subArgs, injectedApi) {
|
|
3304
3155
|
const [wanted] = positionals(subArgs);
|
|
@@ -3308,14 +3159,14 @@ async function handleParallel(subArgs, injectedApi) {
|
|
|
3308
3159
|
console.log(`Up to ${String(settings.maxParallel ?? "?")} AI tasks run at once. Change with: ordewell parallel <n>`);
|
|
3309
3160
|
return;
|
|
3310
3161
|
}
|
|
3311
|
-
const limit = (0,
|
|
3162
|
+
const limit = (0, import_core19.parseMaxParallel)(wanted);
|
|
3312
3163
|
if (limit === null) fail(`"${wanted}" is not a number of tasks (1 or more).`, USAGE5);
|
|
3313
3164
|
await persistEnv(api, { ORDEWELL_MAX_PARALLEL: String(limit) });
|
|
3314
3165
|
console.log(`Up to ${limit} AI task${limit === 1 ? "" : "s"} now run at once.`);
|
|
3315
3166
|
}
|
|
3316
3167
|
|
|
3317
3168
|
// src/commands/key.ts
|
|
3318
|
-
var
|
|
3169
|
+
var import_core20 = require("@ordewell/core");
|
|
3319
3170
|
var USAGE6 = "Usage: ordewell key [list | set <provider> <key>]";
|
|
3320
3171
|
async function handleKey(subArgs, injectedApi) {
|
|
3321
3172
|
const [action, provider, ...keyParts] = positionals(subArgs);
|
|
@@ -3326,8 +3177,8 @@ async function handleKey(subArgs, injectedApi) {
|
|
|
3326
3177
|
if (action !== "set") {
|
|
3327
3178
|
const catalog = await fetchCatalog(api);
|
|
3328
3179
|
console.log("\nAPI provider keys\n");
|
|
3329
|
-
for (const id2 of
|
|
3330
|
-
const meta2 =
|
|
3180
|
+
for (const id2 of import_core20.PROVIDER_PRIORITY) {
|
|
3181
|
+
const meta2 = import_core20.ALL_PROVIDERS[id2];
|
|
3331
3182
|
const configured = catalog.providers.includes(id2);
|
|
3332
3183
|
console.log(` ${configured ? "\u2713" : " "} ${id2.padEnd(14)} ${meta2.apiKeyEnvVar.padEnd(28)} ${meta2.label}`);
|
|
3333
3184
|
}
|
|
@@ -3337,7 +3188,7 @@ async function handleKey(subArgs, injectedApi) {
|
|
|
3337
3188
|
}
|
|
3338
3189
|
if (!provider) fail(USAGE6);
|
|
3339
3190
|
const id = provider.toLowerCase();
|
|
3340
|
-
const meta =
|
|
3191
|
+
const meta = import_core20.ALL_PROVIDERS[id];
|
|
3341
3192
|
if (!meta) {
|
|
3342
3193
|
fail(`Unknown provider: ${provider}`, "Run `ordewell key` to see the list.");
|
|
3343
3194
|
}
|
|
@@ -3348,7 +3199,7 @@ async function handleKey(subArgs, injectedApi) {
|
|
|
3348
3199
|
}
|
|
3349
3200
|
|
|
3350
3201
|
// src/commands/runners.ts
|
|
3351
|
-
var
|
|
3202
|
+
var import_core21 = require("@ordewell/core");
|
|
3352
3203
|
var USAGE7 = "Usage: ordewell runners [<runner-id> on|off]";
|
|
3353
3204
|
async function handleRunners(subArgs, injectedApi) {
|
|
3354
3205
|
const [runner, toggle] = positionals(subArgs);
|
|
@@ -3379,15 +3230,15 @@ function handleAuto(subArgs) {
|
|
|
3379
3230
|
const currentRaw = process.env.ORDEWELL_AUTONOMOUS_MODE;
|
|
3380
3231
|
const current = currentRaw !== "false" && currentRaw !== "0";
|
|
3381
3232
|
if (!arg) {
|
|
3382
|
-
console.log(`Autonomy level: ${(0,
|
|
3233
|
+
console.log(`Autonomy level: ${(0, import_core21.autonomyLevelLabel)(current)}`);
|
|
3383
3234
|
console.log(` ${AUTO_USAGE}`);
|
|
3384
3235
|
return;
|
|
3385
3236
|
}
|
|
3386
|
-
const enabled = (0,
|
|
3237
|
+
const enabled = (0, import_core21.parseAutonomyLevel)(arg);
|
|
3387
3238
|
if (enabled === null) fail(AUTO_USAGE);
|
|
3388
3239
|
writeEnvVar(findEnvFile(), "ORDEWELL_AUTONOMOUS_MODE", String(enabled));
|
|
3389
3240
|
process.env.ORDEWELL_AUTONOMOUS_MODE = String(enabled);
|
|
3390
|
-
console.log(`Autonomy level: ${(0,
|
|
3241
|
+
console.log(`Autonomy level: ${(0, import_core21.autonomyLevelLabel)(enabled)} for new sessions.`);
|
|
3391
3242
|
}
|
|
3392
3243
|
async function handleRefresh(subArgs, injectedApi) {
|
|
3393
3244
|
const api = await connect(subArgs, injectedApi);
|
|
@@ -3419,7 +3270,7 @@ async function handleApprove(subArgs, injectedApi) {
|
|
|
3419
3270
|
// src/tui/terminalLauncher.ts
|
|
3420
3271
|
var import_child_process3 = require("child_process");
|
|
3421
3272
|
var import_util = require("util");
|
|
3422
|
-
var
|
|
3273
|
+
var import_core22 = require("@ordewell/core");
|
|
3423
3274
|
var execFileAsync = (0, import_util.promisify)(import_child_process3.execFile);
|
|
3424
3275
|
var defaultExecFile = async (command, args) => {
|
|
3425
3276
|
const { stdout, stderr } = await execFileAsync(command, args);
|
|
@@ -3439,16 +3290,16 @@ var defaultWhich = (bin) => {
|
|
|
3439
3290
|
async function openTaskTerminal(port, planSessionId, taskId, deps = {}) {
|
|
3440
3291
|
const platform = deps.platform ?? process.platform;
|
|
3441
3292
|
const env = deps.env ?? process.env;
|
|
3442
|
-
const hasTmuxImpl = deps.hasTmuxImpl ??
|
|
3293
|
+
const hasTmuxImpl = deps.hasTmuxImpl ?? import_core22.hasTmux;
|
|
3443
3294
|
const execFileImpl = deps.execFileImpl ?? defaultExecFile;
|
|
3444
3295
|
const spawnImpl = deps.spawnImpl ?? defaultSpawn;
|
|
3445
3296
|
const which = deps.which ?? defaultWhich;
|
|
3446
3297
|
if (!hasTmuxImpl()) {
|
|
3447
3298
|
return { ok: false, message: "No terminal window for this task: tmux is not installed. Install tmux to get one for terminal-transport tasks; a structured task has its log view instead." };
|
|
3448
3299
|
}
|
|
3449
|
-
const session = (0,
|
|
3450
|
-
const socket = (0,
|
|
3451
|
-
const base = (0,
|
|
3300
|
+
const session = (0, import_core22.tmuxSessionName)(port);
|
|
3301
|
+
const socket = (0, import_core22.tmuxSocketName)(port);
|
|
3302
|
+
const base = (0, import_core22.tmuxWindowName)(taskId, planSessionId);
|
|
3452
3303
|
let windows;
|
|
3453
3304
|
try {
|
|
3454
3305
|
const { stdout } = await execFileImpl("tmux", ["-L", socket, "list-windows", "-t", session, "-F", "#{window_name}"]);
|
|
@@ -3760,7 +3611,7 @@ ${(0, import_plan_utils.titledTaskRef)(task)} is ${task.ops ? "an ops task: it r
|
|
|
3760
3611
|
}
|
|
3761
3612
|
|
|
3762
3613
|
// src/tui/index.ts
|
|
3763
|
-
var
|
|
3614
|
+
var import_core37 = require("@ordewell/core");
|
|
3764
3615
|
|
|
3765
3616
|
// src/tui/editor.ts
|
|
3766
3617
|
function emptyEditor() {
|
|
@@ -4010,7 +3861,7 @@ function tokenCompletions(token) {
|
|
|
4010
3861
|
}
|
|
4011
3862
|
|
|
4012
3863
|
// src/tui/blocks.ts
|
|
4013
|
-
var
|
|
3864
|
+
var import_core23 = require("@ordewell/core");
|
|
4014
3865
|
|
|
4015
3866
|
// src/tui/markdown.ts
|
|
4016
3867
|
function renderMarkdown(source, cols) {
|
|
@@ -4230,16 +4081,16 @@ function resultLines(block, room, detailAll) {
|
|
|
4230
4081
|
const fit2 = (line) => detailAll ? wrap(line, room) : [truncate(line, room)];
|
|
4231
4082
|
const outcome = unsettledOutcome(block);
|
|
4232
4083
|
if (outcome) {
|
|
4233
|
-
const [reason, ...rest] = (0,
|
|
4084
|
+
const [reason, ...rest] = (0, import_core23.outputLines)(block.output).map(sanitize);
|
|
4234
4085
|
const status = fit2(reason ? `${outcome.label}: ${reason}` : outcome.label).map(outcome.paint);
|
|
4235
4086
|
return detailAll ? [...status, ...rest.flatMap(fit2).map(style.grey)] : status;
|
|
4236
4087
|
}
|
|
4237
4088
|
if (detailAll) {
|
|
4238
|
-
const lines2 = (0,
|
|
4089
|
+
const lines2 = (0, import_core23.outputLines)(block.output).map(sanitize);
|
|
4239
4090
|
const note = lines2.length > PREVIEW_LINES ? ["\u2026 (ctrl+o to collapse)"] : [];
|
|
4240
4091
|
return lines2.length > 0 ? [...lines2.flatMap(fit2), ...note].map(style.grey) : [style.grey("(no output)")];
|
|
4241
4092
|
}
|
|
4242
|
-
const { lines, hiddenLineCount } = (0,
|
|
4093
|
+
const { lines, hiddenLineCount } = (0, import_core23.outputPreview)(block.output, PREVIEW_LINES);
|
|
4243
4094
|
if (lines.length === 0) return [style.grey("(no output)")];
|
|
4244
4095
|
const more = hiddenLineCount > 0 ? [`\u2026 +${countOf(hiddenLineCount, "line")} (ctrl+o to expand)`] : [];
|
|
4245
4096
|
return [...lines.map(sanitize), ...more].map((line) => style.grey(truncate(line, room)));
|
|
@@ -4253,7 +4104,7 @@ var DIFF_PAINT = {
|
|
|
4253
4104
|
};
|
|
4254
4105
|
var DIFF_SIGN = { added: "+", removed: "-", context: " ", gap: "" };
|
|
4255
4106
|
function diffLines(block, diff, room, detailAll) {
|
|
4256
|
-
const rows = (0,
|
|
4107
|
+
const rows = (0, import_core23.diffRows)(block.output);
|
|
4257
4108
|
const gutter = Math.max(0, ...rows.map((row) => String(row.line ?? "").length));
|
|
4258
4109
|
const draw = (row) => {
|
|
4259
4110
|
const text = row.kind === "gap" ? `${" ".repeat(gutter)} \u22EE` : `${String(row.line ?? "").padStart(gutter)} ${DIFF_SIGN[row.kind]} ${sanitize(row.text)}`;
|
|
@@ -4262,7 +4113,7 @@ function diffLines(block, diff, room, detailAll) {
|
|
|
4262
4113
|
const shown = detailAll ? rows : rows.slice(0, DIFF_PREVIEW_ROWS);
|
|
4263
4114
|
const hidden = rows.length - shown.length;
|
|
4264
4115
|
const more = hidden > 0 ? [style.grey(`\u2026 +${countOf(hidden, "line")} (ctrl+o to expand)`)] : [];
|
|
4265
|
-
return [(0,
|
|
4116
|
+
return [(0, import_core23.diffSummary)(diff), ...shown.flatMap(draw), ...more];
|
|
4266
4117
|
}
|
|
4267
4118
|
function toolLines(block, cols, detailAll) {
|
|
4268
4119
|
const room = Math.max(1, cols - OUTPUT_INDENT.length);
|
|
@@ -4397,7 +4248,7 @@ function tokenLine(blocks, cols) {
|
|
|
4397
4248
|
}
|
|
4398
4249
|
|
|
4399
4250
|
// src/tui/state.ts
|
|
4400
|
-
var
|
|
4251
|
+
var import_core24 = require("@ordewell/core");
|
|
4401
4252
|
var SKILL_IDS = ["tdd", "verify"];
|
|
4402
4253
|
function noSkills() {
|
|
4403
4254
|
return { tdd: false, verify: false };
|
|
@@ -4409,7 +4260,7 @@ function visibleItems(picker2) {
|
|
|
4409
4260
|
(i) => i.id.toLowerCase().includes(filter) || i.label.toLowerCase().includes(filter) || (i.detail ?? "").toLowerCase().includes(filter)
|
|
4410
4261
|
);
|
|
4411
4262
|
}
|
|
4412
|
-
var anyTaskRunning = (state) => state.tasks.some(
|
|
4263
|
+
var anyTaskRunning = (state) => state.tasks.some(import_core24.isTaskRunning);
|
|
4413
4264
|
var plannerInFlight = (state) => state.status === "planning" || state.status === "researching";
|
|
4414
4265
|
function planRows(state) {
|
|
4415
4266
|
const rows = [];
|
|
@@ -4446,9 +4297,9 @@ function findTask(tasks, id) {
|
|
|
4446
4297
|
function initialState(overrides = {}) {
|
|
4447
4298
|
return {
|
|
4448
4299
|
editor: emptyEditor(),
|
|
4449
|
-
conversation:
|
|
4300
|
+
conversation: import_core24.EMPTY_CONVERSATION,
|
|
4450
4301
|
taskView: null,
|
|
4451
|
-
turnGate:
|
|
4302
|
+
turnGate: import_core24.NO_TURN,
|
|
4452
4303
|
detailAll: false,
|
|
4453
4304
|
status: "idle",
|
|
4454
4305
|
busyLabel: "",
|
|
@@ -4473,7 +4324,7 @@ function initialState(overrides = {}) {
|
|
|
4473
4324
|
orchestratorModel: "",
|
|
4474
4325
|
plannerProvider: "",
|
|
4475
4326
|
plannerEffort: "",
|
|
4476
|
-
maxParallel:
|
|
4327
|
+
maxParallel: import_core24.DEFAULT_MAX_PARALLEL,
|
|
4477
4328
|
configuredProviders: [],
|
|
4478
4329
|
allowlist: {},
|
|
4479
4330
|
autonomous: true,
|
|
@@ -4485,7 +4336,7 @@ function initialState(overrides = {}) {
|
|
|
4485
4336
|
gate: null,
|
|
4486
4337
|
overlay: null,
|
|
4487
4338
|
pendingApprovals: [],
|
|
4488
|
-
queuedPrompts:
|
|
4339
|
+
queuedPrompts: import_core24.EMPTY_HOLD,
|
|
4489
4340
|
stopArmed: false,
|
|
4490
4341
|
stopArmToken: 0,
|
|
4491
4342
|
stopRequested: false,
|
|
@@ -4533,7 +4384,7 @@ function chatEditorRoomFor(state, active) {
|
|
|
4533
4384
|
}
|
|
4534
4385
|
|
|
4535
4386
|
// src/tui/layout.ts
|
|
4536
|
-
var
|
|
4387
|
+
var import_core25 = require("@ordewell/core");
|
|
4537
4388
|
var CHROME_ROWS = 4;
|
|
4538
4389
|
function chatInputWrap(state) {
|
|
4539
4390
|
const active = state.focus === "chat" && !state.overlay;
|
|
@@ -4542,7 +4393,7 @@ function chatInputWrap(state) {
|
|
|
4542
4393
|
}
|
|
4543
4394
|
function footerHints(state) {
|
|
4544
4395
|
const selected = selectedPlanRow(state)?.task;
|
|
4545
|
-
const markHint = selected && (0,
|
|
4396
|
+
const markHint = selected && (0, import_core25.markAction)(selected) === "uncomplete" ? "m undone" : "m done";
|
|
4546
4397
|
const resolveHint = selected?.isolation?.state === "conflict" ? ["x resolve conflict"] : [];
|
|
4547
4398
|
const planning = plannerInFlight(state) && !state.taskView;
|
|
4548
4399
|
const escHint = !planning ? null : state.queuedPrompts.length > 0 ? "esc unsend" : "esc \xD72 stop planning";
|
|
@@ -4573,7 +4424,7 @@ function footerHints(state) {
|
|
|
4573
4424
|
"tab chat"
|
|
4574
4425
|
];
|
|
4575
4426
|
}
|
|
4576
|
-
const detailHint = (0,
|
|
4427
|
+
const detailHint = (0, import_core25.hasHiddenDetail)(state.taskView ? state.taskView.view.blocks : state.conversation.blocks) ? [state.detailAll ? "ctrl-o collapse all" : "ctrl-o expand all"] : [];
|
|
4577
4428
|
return [
|
|
4578
4429
|
"/help",
|
|
4579
4430
|
"tab plan",
|
|
@@ -4609,10 +4460,10 @@ function queuedTaskBubble(message, selected, cols) {
|
|
|
4609
4460
|
return wrap(text, room).map((line, i) => i === 0 ? truncate(`${marker2} ${selected ? style.bold(line) : line}${style.grey(tag)}`, cols) : truncate(` ${line}`, cols));
|
|
4610
4461
|
}
|
|
4611
4462
|
function taskActivity(task, working) {
|
|
4612
|
-
const approvals = (0,
|
|
4463
|
+
const approvals = (0, import_core25.approvalLabel)(task?.awaitingApproval);
|
|
4613
4464
|
if (approvals) return inRow(approvals);
|
|
4614
4465
|
if (working) return "working";
|
|
4615
|
-
if (task?.status === "awaiting_user") return inRow((0,
|
|
4466
|
+
if (task?.status === "awaiting_user") return inRow((0, import_core25.awaitingLabel)(task) ?? "Waiting for your input");
|
|
4616
4467
|
return task?.status ?? "";
|
|
4617
4468
|
}
|
|
4618
4469
|
function taskHeaderLines(state, tv, cols) {
|
|
@@ -4687,9 +4538,9 @@ function chatScrollMax(state) {
|
|
|
4687
4538
|
}
|
|
4688
4539
|
function plannerSetup(state) {
|
|
4689
4540
|
const provider = state.plannerProvider;
|
|
4690
|
-
const registration =
|
|
4541
|
+
const registration = import_core25.ALL_PROVIDERS[provider];
|
|
4691
4542
|
if (!registration) return { label: "not set", ready: false };
|
|
4692
|
-
const runner = (0,
|
|
4543
|
+
const runner = (0, import_core25.runnerForProvider)(provider);
|
|
4693
4544
|
const ready = runner ? state.runners.some((r) => r.id === runner) : state.configuredProviders.includes(provider);
|
|
4694
4545
|
return { label: registration.label, ready };
|
|
4695
4546
|
}
|
|
@@ -4861,7 +4712,7 @@ function planScrollExtent(state) {
|
|
|
4861
4712
|
}
|
|
4862
4713
|
function taskLines(state, planRow, index, cols, orderOf) {
|
|
4863
4714
|
const { task, parent } = planRow;
|
|
4864
|
-
const row = (0,
|
|
4715
|
+
const row = (0, import_core25.taskRowView)(task, { parent, orderOf, modes: modesForTask(state.modesByRunner, task) });
|
|
4865
4716
|
const selected = state.focus === "plan" && index === state.selectedTask;
|
|
4866
4717
|
const expanded = state.expandedTaskId === task.id;
|
|
4867
4718
|
const rawIcon = row.status === "running" ? SPINNER[state.spinnerFrame % SPINNER.length] : STATUS_ICON[row.status];
|
|
@@ -5008,7 +4859,7 @@ function helpScrollMax(state) {
|
|
|
5008
4859
|
}
|
|
5009
4860
|
|
|
5010
4861
|
// src/tui/render.ts
|
|
5011
|
-
var
|
|
4862
|
+
var import_core26 = require("@ordewell/core");
|
|
5012
4863
|
function render(state) {
|
|
5013
4864
|
const { rows, cols } = state;
|
|
5014
4865
|
const rowsForBody = bodyRows(state);
|
|
@@ -5273,8 +5124,8 @@ function renderHandoff(state, overlay, rows, cols) {
|
|
|
5273
5124
|
return frame(`Diff \u2014 ${handoffBranch(handoff)}`, [...shown, "", style.grey(`${more}enter or esc goes back`)], rows, cols);
|
|
5274
5125
|
}
|
|
5275
5126
|
const landed = handoff.landed.length === 0 ? [style.grey("Nothing landed on it.")] : handoff.landed.map((task) => {
|
|
5276
|
-
const repaired = task.repairedFiles?.length ? style.yellow(` \u2014 repaired (${(0,
|
|
5277
|
-
return ` ${style.green("\u2713")} ${(0,
|
|
5127
|
+
const repaired = task.repairedFiles?.length ? style.yellow(` \u2014 repaired (${(0, import_core26.capConflictFiles)(task.repairedFiles)})`) : "";
|
|
5128
|
+
return ` ${style.green("\u2713")} ${(0, import_core26.titledTaskRef)(task)}${repaired}`;
|
|
5278
5129
|
});
|
|
5279
5130
|
const actions = handoffActions(handoff).map((action, index) => {
|
|
5280
5131
|
const active = index === overlay.index;
|
|
@@ -5363,10 +5214,10 @@ function frame(title, body, rows, cols) {
|
|
|
5363
5214
|
}
|
|
5364
5215
|
|
|
5365
5216
|
// src/tui/reducer.ts
|
|
5366
|
-
var
|
|
5217
|
+
var import_core34 = require("@ordewell/core");
|
|
5367
5218
|
|
|
5368
5219
|
// src/tui/reducers/overlays.ts
|
|
5369
|
-
var
|
|
5220
|
+
var import_core32 = require("@ordewell/core");
|
|
5370
5221
|
|
|
5371
5222
|
// src/tui/reducers/shared.ts
|
|
5372
5223
|
function step(state, effects = []) {
|
|
@@ -5415,10 +5266,10 @@ function handleApprovalKey(state, overlay, key) {
|
|
|
5415
5266
|
}
|
|
5416
5267
|
|
|
5417
5268
|
// src/tui/reducers/commands.ts
|
|
5418
|
-
var
|
|
5269
|
+
var import_core31 = require("@ordewell/core");
|
|
5419
5270
|
|
|
5420
5271
|
// src/tui/reducers/pickers.ts
|
|
5421
|
-
var
|
|
5272
|
+
var import_core27 = require("@ordewell/core");
|
|
5422
5273
|
var import_plan_utils2 = require("@ordewell/core/plan-utils");
|
|
5423
5274
|
var DEFAULT_EFFORT = "__runner_default__";
|
|
5424
5275
|
function picker(title, items, action, extra = {}) {
|
|
@@ -5437,11 +5288,11 @@ function modelDetail(m) {
|
|
|
5437
5288
|
function providerErrorHint(state) {
|
|
5438
5289
|
const failed = Object.keys(state.providerErrors ?? {});
|
|
5439
5290
|
if (failed.length === 0) return void 0;
|
|
5440
|
-
const names = failed.map((p) =>
|
|
5291
|
+
const names = failed.map((p) => import_core27.ALL_PROVIDERS[p]?.label ?? p);
|
|
5441
5292
|
return `\u26A0 Unavailable (key or fetch failed): ${names.join(", ")} \u2014 showing working providers only.`;
|
|
5442
5293
|
}
|
|
5443
5294
|
function plannerModelItems(state) {
|
|
5444
|
-
const runner = (0,
|
|
5295
|
+
const runner = (0, import_core27.runnerForProvider)(state.plannerProvider);
|
|
5445
5296
|
if (!runner) return state.orchestratorModels.map((m) => ({ id: m.id, label: m.label, detail: modelDetail(m) }));
|
|
5446
5297
|
const items = state.models.filter((m) => m.runners?.includes(runner)).map((m) => ({
|
|
5447
5298
|
id: m.id,
|
|
@@ -5455,7 +5306,7 @@ function plannerModelItems(state) {
|
|
|
5455
5306
|
return items.length > 0 ? items : [{ id: "", label: `No ${runner} models discovered yet`, detail: "run /refresh", disabled: true }];
|
|
5456
5307
|
}
|
|
5457
5308
|
function plannerEffortItems(state) {
|
|
5458
|
-
const runner = (0,
|
|
5309
|
+
const runner = (0, import_core27.runnerForProvider)(state.plannerProvider);
|
|
5459
5310
|
if (!runner) {
|
|
5460
5311
|
return [{ id: "", label: "Thinking effort applies to a coding-agent planner", detail: "switch with /planner", disabled: true }];
|
|
5461
5312
|
}
|
|
@@ -5519,7 +5370,7 @@ function pickerItemsFor(state, action) {
|
|
|
5519
5370
|
if (action.kind === "set-task-deps") {
|
|
5520
5371
|
return (0, import_plan_utils2.dependencyCandidates)(state.tasks, action.taskId).map((candidate) => ({
|
|
5521
5372
|
id: candidate.id,
|
|
5522
|
-
label: (0,
|
|
5373
|
+
label: (0, import_core27.titledTaskRef)(candidate),
|
|
5523
5374
|
detail: candidate.status === "completed" ? "already completed" : void 0
|
|
5524
5375
|
}));
|
|
5525
5376
|
}
|
|
@@ -5564,28 +5415,24 @@ function pickerItemsFor(state, action) {
|
|
|
5564
5415
|
}
|
|
5565
5416
|
function plannerItems(state) {
|
|
5566
5417
|
const installed = new Set(state.runners.map((r) => r.id));
|
|
5567
|
-
const
|
|
5568
|
-
|
|
5569
|
-
const
|
|
5570
|
-
|
|
5571
|
-
|
|
5572
|
-
|
|
5573
|
-
|
|
5574
|
-
|
|
5575
|
-
|
|
5576
|
-
|
|
5577
|
-
|
|
5578
|
-
|
|
5579
|
-
id,
|
|
5580
|
-
label: import_core26.ALL_PROVIDERS[id].label,
|
|
5581
|
-
detail: import_core26.ALL_PROVIDERS[id].apiKeyEnvVar,
|
|
5582
|
-
selected: state.plannerProvider === id
|
|
5418
|
+
const usability = {};
|
|
5419
|
+
for (const id of import_core27.CLI_PROVIDERS) {
|
|
5420
|
+
const runner = (0, import_core27.runnerForProvider)(id);
|
|
5421
|
+
usability[runner] = installed.has(runner) ? { usable: true } : { usable: false, reason: "CLI not installed or not on PATH" };
|
|
5422
|
+
}
|
|
5423
|
+
const entries = (0, import_core27.plannerBackendEntries)(usability, state.configuredProviders);
|
|
5424
|
+
const items = entries.map((entry) => ({
|
|
5425
|
+
id: entry.id,
|
|
5426
|
+
label: entry.label,
|
|
5427
|
+
detail: entry.reason,
|
|
5428
|
+
selected: state.plannerProvider === entry.id,
|
|
5429
|
+
disabled: !entry.usable
|
|
5583
5430
|
}));
|
|
5584
|
-
return
|
|
5431
|
+
return entries.some((entry) => entry.kind === "vendor") ? items : [...items, { id: "", label: "No API providers configured", detail: "add a key with /key", disabled: true }];
|
|
5585
5432
|
}
|
|
5586
5433
|
|
|
5587
5434
|
// src/tui/reducers/planPane.ts
|
|
5588
|
-
var
|
|
5435
|
+
var import_core29 = require("@ordewell/core");
|
|
5589
5436
|
|
|
5590
5437
|
// src/tui/reducers/pointer.ts
|
|
5591
5438
|
var WHEEL_NOTCH = 3;
|
|
@@ -5663,13 +5510,13 @@ function handleMouseSelect(state, key) {
|
|
|
5663
5510
|
}
|
|
5664
5511
|
|
|
5665
5512
|
// src/tui/reducers/taskView.ts
|
|
5666
|
-
var
|
|
5513
|
+
var import_core28 = require("@ordewell/core");
|
|
5667
5514
|
function openTaskView(state, sessionId, taskId) {
|
|
5668
5515
|
const task = findTask(state.tasks, taskId);
|
|
5669
5516
|
if (!task) return step(say(state, "system", `No task ${taskId} in this plan.`));
|
|
5670
5517
|
const taskView = {
|
|
5671
5518
|
taskId,
|
|
5672
|
-
view:
|
|
5519
|
+
view: import_core28.EMPTY_TASK_LOG,
|
|
5673
5520
|
attempts: [],
|
|
5674
5521
|
attempt: 0,
|
|
5675
5522
|
pending: [],
|
|
@@ -5702,13 +5549,13 @@ function applyLive(tv, attempt, events) {
|
|
|
5702
5549
|
}
|
|
5703
5550
|
next = {
|
|
5704
5551
|
...next,
|
|
5705
|
-
view:
|
|
5552
|
+
view: import_core28.EMPTY_TASK_LOG,
|
|
5706
5553
|
attempt,
|
|
5707
5554
|
attempts: next.attempts.includes(attempt) ? next.attempts : [...next.attempts, attempt]
|
|
5708
5555
|
};
|
|
5709
5556
|
}
|
|
5710
5557
|
if (attempt < next.attempt) return next;
|
|
5711
|
-
return clampQueueIndex({ ...next, view: events.reduce(
|
|
5558
|
+
return clampQueueIndex({ ...next, view: events.reduce(import_core28.reduceTaskLog, next.view) });
|
|
5712
5559
|
}
|
|
5713
5560
|
function taskLogAbandoned(state) {
|
|
5714
5561
|
const tv = state.taskView;
|
|
@@ -5728,14 +5575,14 @@ function taskLogArrived(state, action) {
|
|
|
5728
5575
|
function announceApprovals(state, action) {
|
|
5729
5576
|
if (state.taskView?.taskId === action.taskId) return state;
|
|
5730
5577
|
const task = findTask(state.tasks, action.taskId);
|
|
5731
|
-
const spoken = action.events.reduce((s, event) => event.type === "approval_requested" ? say(s, "system", `\xB7 Task ${task?.order ?? "?"} waits for approval: ${(0,
|
|
5578
|
+
const spoken = action.events.reduce((s, event) => event.type === "approval_requested" ? say(s, "system", `\xB7 Task ${task?.order ?? "?"} waits for approval: ${(0, import_core28.runnerToolSubject)(event.tool, event.args)} \u2014 t on it, then ctrl-y to allow or ctrl-g to deny`) : s, state);
|
|
5732
5579
|
return spoken !== state ? { ...spoken, scroll: state.scroll } : spoken;
|
|
5733
5580
|
}
|
|
5734
5581
|
function announceCheckpoint(state, action) {
|
|
5735
5582
|
const task = findTask(state.tasks, action.taskId) ?? state.tasks.find((t) => t.title === action.title);
|
|
5736
5583
|
const label = task ? `Task ${task.order}` : action.title;
|
|
5737
5584
|
const where = task?.transport?.kind === "structured" ? "t on it to answer" : `/checkpoint ${task?.order ?? "<id>"} approve|reject to answer`;
|
|
5738
|
-
const spoken = say(state, "system", `\xB7 ${label} asks: ${(0,
|
|
5585
|
+
const spoken = say(state, "system", `\xB7 ${label} asks: ${(0, import_core28.truncateCheckpointSummary)(action.summary)} \u2014 ${where}`);
|
|
5739
5586
|
return { ...spoken, scroll: state.scroll };
|
|
5740
5587
|
}
|
|
5741
5588
|
function taskLogLoaded(state, action) {
|
|
@@ -5743,7 +5590,7 @@ function taskLogLoaded(state, action) {
|
|
|
5743
5590
|
if (!tv || tv.taskId !== action.taskId) return state;
|
|
5744
5591
|
const loaded = action.attempt >= 1 ? {
|
|
5745
5592
|
...tv,
|
|
5746
|
-
view: (0,
|
|
5593
|
+
view: (0, import_core28.replayTaskLog)(action.events),
|
|
5747
5594
|
attempts: action.attempts ?? tv.attempts,
|
|
5748
5595
|
attempt: action.attempt
|
|
5749
5596
|
} : { ...tv, attempts: action.attempts ?? tv.attempts };
|
|
@@ -6120,7 +5967,7 @@ function handlePlanKey(state, key) {
|
|
|
6120
5967
|
if (!state.sessionId || key.name !== "char") return step(state);
|
|
6121
5968
|
if (key.char === "E") return step(state, [{ type: "execute", sessionId: state.sessionId }]);
|
|
6122
5969
|
if (key.char === "S") return step(state, [{ type: "stopExecution", sessionId: state.sessionId }]);
|
|
6123
|
-
const action = key.char === "m" ? (0,
|
|
5970
|
+
const action = key.char === "m" ? (0, import_core29.markAction)(task) : PLAN_SHORTCUTS[key.char ?? ""];
|
|
6124
5971
|
if (action === "force-start" && task.mergeGate?.length) return confirmForceStartPastGate(state, task);
|
|
6125
5972
|
if (action) {
|
|
6126
5973
|
return step(state, [taskActionEffect(state, state.sessionId, task.id, action)]);
|
|
@@ -6155,14 +6002,14 @@ function commitTaskEdit(state, task, editor) {
|
|
|
6155
6002
|
sessionId: state.sessionId,
|
|
6156
6003
|
taskId: task.id,
|
|
6157
6004
|
changes: { prompt },
|
|
6158
|
-
message: `Task ${(0,
|
|
6005
|
+
message: `Task ${(0, import_core29.taskRef)(task)} prompt updated.`
|
|
6159
6006
|
}]);
|
|
6160
6007
|
}
|
|
6161
6008
|
|
|
6162
6009
|
// src/tui/reducers/turnQueue.ts
|
|
6163
|
-
var
|
|
6010
|
+
var import_core30 = require("@ordewell/core");
|
|
6164
6011
|
function drainQueue(state, settled) {
|
|
6165
|
-
const next = (0,
|
|
6012
|
+
const next = (0, import_core30.drainNext)(state.queuedPrompts);
|
|
6166
6013
|
const ended = disarmStop({ ...settled, stopRequested: false });
|
|
6167
6014
|
if (!next) return step(ended);
|
|
6168
6015
|
const spoken = say(ended, "user", next.text);
|
|
@@ -6181,14 +6028,14 @@ function stopPlanning(state, sessionId) {
|
|
|
6181
6028
|
return step(queueToEditor(cutTurn({ ...dismissed, stopArmed: false, stopRequested: true })), [{ type: "cancelPlanning", sessionId }]);
|
|
6182
6029
|
}
|
|
6183
6030
|
function queueToEditor(state) {
|
|
6184
|
-
const all = (0,
|
|
6031
|
+
const all = (0, import_core30.unsendAll)(state.queuedPrompts);
|
|
6185
6032
|
if (!all) return state;
|
|
6186
6033
|
return { ...state, queuedPrompts: all.rest, editor: { ...state.editor, text: all.text, cursor: all.text.length } };
|
|
6187
6034
|
}
|
|
6188
6035
|
function unsendLatest(state) {
|
|
6189
|
-
const latest = (0,
|
|
6036
|
+
const latest = (0, import_core30.unsendLatest)(state.queuedPrompts);
|
|
6190
6037
|
if (!latest) return step(state);
|
|
6191
|
-
const text = (0,
|
|
6038
|
+
const text = (0, import_core30.aheadOfDraft)(latest.text, state.editor.text);
|
|
6192
6039
|
return step({
|
|
6193
6040
|
...state,
|
|
6194
6041
|
queuedPrompts: latest.rest,
|
|
@@ -6205,7 +6052,7 @@ function plannerEscape(state) {
|
|
|
6205
6052
|
}
|
|
6206
6053
|
|
|
6207
6054
|
// src/tui/reducers/commands.ts
|
|
6208
|
-
var
|
|
6055
|
+
var KNOWN_PROVIDERS = Object.keys(import_core31.ALL_PROVIDERS);
|
|
6209
6056
|
function runCommand(state, { name, args }) {
|
|
6210
6057
|
if (!findCommand(name)) {
|
|
6211
6058
|
return fail3(state, `Unknown command: /${name} \u2014 type /help to see what's available.`);
|
|
@@ -6371,8 +6218,8 @@ function newSession(state) {
|
|
|
6371
6218
|
taskView: null,
|
|
6372
6219
|
tasks: [],
|
|
6373
6220
|
planApproved: false,
|
|
6374
|
-
conversation:
|
|
6375
|
-
turnGate:
|
|
6221
|
+
conversation: import_core31.EMPTY_CONVERSATION,
|
|
6222
|
+
turnGate: import_core31.NO_TURN,
|
|
6376
6223
|
selectedTask: 0,
|
|
6377
6224
|
expandedTaskId: null,
|
|
6378
6225
|
taskEditor: null,
|
|
@@ -6383,14 +6230,14 @@ function newSession(state) {
|
|
|
6383
6230
|
// Prompts belong to the session that raised them; the old planner is gone
|
|
6384
6231
|
// and its pending requests deny on their own timeout.
|
|
6385
6232
|
pendingApprovals: [],
|
|
6386
|
-
queuedPrompts:
|
|
6233
|
+
queuedPrompts: import_core31.EMPTY_HOLD,
|
|
6387
6234
|
stopArmed: false,
|
|
6388
6235
|
overlay: state.overlay?.kind === "approval" ? null : state.overlay
|
|
6389
6236
|
}, closeEffects);
|
|
6390
6237
|
}
|
|
6391
6238
|
function setModel(state, args) {
|
|
6392
6239
|
if (args[0] === "set" && args[1]) {
|
|
6393
|
-
const runner = (0,
|
|
6240
|
+
const runner = (0, import_core31.runnerForProvider)(state.plannerProvider);
|
|
6394
6241
|
const known = runner ? modelsForRunner(state.models, runner) : [];
|
|
6395
6242
|
if (runner && known.length > 0 && !known.some((m) => m.id === args[1])) {
|
|
6396
6243
|
return fail3(state, `${args[1]} was not discovered for ${runner}.`);
|
|
@@ -6413,7 +6260,7 @@ function setModel(state, args) {
|
|
|
6413
6260
|
function setPlanner(state, args) {
|
|
6414
6261
|
if (args[0]) {
|
|
6415
6262
|
const id = args[0].toLowerCase();
|
|
6416
|
-
if (!
|
|
6263
|
+
if (!KNOWN_PROVIDERS.includes(id)) {
|
|
6417
6264
|
return fail3(state, `Unknown planner: ${id}. Run /planner with no arguments to see the list.`);
|
|
6418
6265
|
}
|
|
6419
6266
|
return step(state, [{ type: "setPlanner", provider: id }]);
|
|
@@ -6452,7 +6299,7 @@ function setPlannerEffort(state, args) {
|
|
|
6452
6299
|
function setKey(state, args) {
|
|
6453
6300
|
if (args[0] === "set" && args[1]) {
|
|
6454
6301
|
const provider = args[1].toLowerCase();
|
|
6455
|
-
if (!
|
|
6302
|
+
if (!KNOWN_PROVIDERS.includes(provider)) {
|
|
6456
6303
|
return fail3(state, `Unknown provider: ${provider}. Run /key with no arguments to see the list.`);
|
|
6457
6304
|
}
|
|
6458
6305
|
if (!args[2]) {
|
|
@@ -6463,16 +6310,16 @@ function setKey(state, args) {
|
|
|
6463
6310
|
}
|
|
6464
6311
|
return step(state, [{ type: "setApiKey", provider, key: args.slice(2).join(" ") }]);
|
|
6465
6312
|
}
|
|
6466
|
-
const items =
|
|
6313
|
+
const items = import_core31.PROVIDER_PRIORITY.map((id) => ({
|
|
6467
6314
|
id,
|
|
6468
|
-
label:
|
|
6469
|
-
detail:
|
|
6315
|
+
label: import_core31.ALL_PROVIDERS[id].label,
|
|
6316
|
+
detail: import_core31.ALL_PROVIDERS[id].apiKeyEnvVar,
|
|
6470
6317
|
selected: state.configuredProviders.includes(id)
|
|
6471
6318
|
}));
|
|
6472
6319
|
return step({ ...state, overlay: { kind: "picker", picker: picker("API provider key", items, { kind: "set-key" }) } });
|
|
6473
6320
|
}
|
|
6474
6321
|
function keyPrompt(provider) {
|
|
6475
|
-
const meta =
|
|
6322
|
+
const meta = import_core31.ALL_PROVIDERS[provider];
|
|
6476
6323
|
return {
|
|
6477
6324
|
kind: "prompt",
|
|
6478
6325
|
title: `${meta.label} API key`,
|
|
@@ -6549,19 +6396,19 @@ function runners(state, args) {
|
|
|
6549
6396
|
}
|
|
6550
6397
|
function setMaxParallel(state, arg) {
|
|
6551
6398
|
if (!arg) return step(say(state, "system", `Up to ${state.maxParallel} AI task${state.maxParallel === 1 ? "" : "s"} run at once \u2014 /parallel <n> changes it.`));
|
|
6552
|
-
const limit = (0,
|
|
6399
|
+
const limit = (0, import_core31.parseMaxParallel)(arg);
|
|
6553
6400
|
if (limit === null) return fail3(state, "Usage: /parallel [<number of tasks, 1 or more>]");
|
|
6554
6401
|
return step({ ...state, maxParallel: limit }, [{ type: "setMaxParallel", limit }]);
|
|
6555
6402
|
}
|
|
6556
6403
|
function setAutonomous(state, arg) {
|
|
6557
|
-
if (arg === void 0) return step(say(state, "system", `Autonomy level: ${(0,
|
|
6558
|
-
const enabled = (0,
|
|
6404
|
+
if (arg === void 0) return step(say(state, "system", `Autonomy level: ${(0, import_core31.autonomyLevelLabel)(state.autonomous)} \u2014 /auto full or /auto guarded changes it for new plans.`));
|
|
6405
|
+
const enabled = (0, import_core31.parseAutonomyLevel)(arg);
|
|
6559
6406
|
if (enabled === null) return fail3(state, "Usage: /auto [full|guarded]");
|
|
6560
6407
|
return step({ ...state, autonomous: enabled }, [{ type: "setAutonomous", enabled }]);
|
|
6561
6408
|
}
|
|
6562
6409
|
function setTransport(state, arg) {
|
|
6563
6410
|
const value = arg?.toLowerCase() ?? (state.runnerTransport === "structured" ? "terminal" : "structured");
|
|
6564
|
-
if (!(0,
|
|
6411
|
+
if (!(0, import_core31.isRunnerTransport)(value)) return fail3(state, "Usage: /transport [terminal|structured]");
|
|
6565
6412
|
return step(state, [{ type: "setTransport", transport: value }]);
|
|
6566
6413
|
}
|
|
6567
6414
|
function setMouseCapture(state, arg) {
|
|
@@ -6738,7 +6585,7 @@ function choose(state, picker2, item) {
|
|
|
6738
6585
|
sessionId: state.sessionId,
|
|
6739
6586
|
taskId: task.id,
|
|
6740
6587
|
changes: { dependencies: picker2.chosen },
|
|
6741
|
-
message: picker2.chosen.length > 0 ? `Task ${(0,
|
|
6588
|
+
message: picker2.chosen.length > 0 ? `Task ${(0, import_core32.taskRef)(task)} now depends on ${picker2.chosen.length} task${picker2.chosen.length === 1 ? "" : "s"}.` : `Task ${(0, import_core32.taskRef)(task)} no longer depends on anything.`
|
|
6742
6589
|
}]);
|
|
6743
6590
|
}
|
|
6744
6591
|
if (!item) return step(state);
|
|
@@ -6815,7 +6662,7 @@ function choose(state, picker2, item) {
|
|
|
6815
6662
|
}
|
|
6816
6663
|
|
|
6817
6664
|
// src/tui/reducers/incoming.ts
|
|
6818
|
-
var
|
|
6665
|
+
var import_core33 = require("@ordewell/core");
|
|
6819
6666
|
var planText = (value, fallback = "") => sanitize(String(value ?? fallback));
|
|
6820
6667
|
var planLabel = (value, fallback = "") => planText(value, fallback).replace(/\n+/g, " ");
|
|
6821
6668
|
var asRecord = (value) => typeof value === "object" && value !== null ? value : {};
|
|
@@ -6846,7 +6693,7 @@ function toTaskView2(t, index) {
|
|
|
6846
6693
|
prompt: typeof t.prompt === "string" ? sanitize(t.prompt) : void 0,
|
|
6847
6694
|
type: t.type === "user" ? "user" : "ai",
|
|
6848
6695
|
status: planLabel(t.status, "pending"),
|
|
6849
|
-
awaitingReason: t.status === "awaiting_user" && (0,
|
|
6696
|
+
awaitingReason: t.status === "awaiting_user" && (0, import_core33.isAwaitingReason)(t.awaitingReason) ? t.awaitingReason : void 0,
|
|
6850
6697
|
dependencies: Array.isArray(t.dependencies) ? t.dependencies.map((id) => planLabel(id)) : [],
|
|
6851
6698
|
assignedRunner: typeof t.assignedRunner === "string" ? planLabel(t.assignedRunner) : void 0,
|
|
6852
6699
|
taskMode: typeof t.taskMode === "string" ? planLabel(t.taskMode) : void 0,
|
|
@@ -6879,12 +6726,12 @@ function applySettings(state, settings) {
|
|
|
6879
6726
|
plannerProvider: typeof settings.aiProvider === "string" ? settings.aiProvider : state.plannerProvider,
|
|
6880
6727
|
plannerEffort: typeof settings.plannerThinkingEffort === "string" ? settings.plannerThinkingEffort : state.plannerEffort,
|
|
6881
6728
|
maxParallel: typeof settings.maxParallel === "number" ? settings.maxParallel : state.maxParallel,
|
|
6882
|
-
runnerTransport: (0,
|
|
6729
|
+
runnerTransport: (0, import_core33.isRunnerTransport)(settings.runnerTransport) ? settings.runnerTransport : state.runnerTransport,
|
|
6883
6730
|
allowlist: settings.modelAllowlist && typeof settings.modelAllowlist === "object" ? settings.modelAllowlist : state.allowlist
|
|
6884
6731
|
};
|
|
6885
6732
|
}
|
|
6886
6733
|
function runLabel(tasks, gate = null) {
|
|
6887
|
-
const running = tasks.filter(
|
|
6734
|
+
const running = tasks.filter(import_core24.isTaskRunning);
|
|
6888
6735
|
if (running.length > 0) {
|
|
6889
6736
|
const [first] = running;
|
|
6890
6737
|
const name = first.assignedRunner ? `${first.title} \xB7 ${first.assignedRunner}` : first.title;
|
|
@@ -6950,13 +6797,13 @@ function reduceAction(state, action) {
|
|
|
6950
6797
|
goal: "",
|
|
6951
6798
|
taskView: null,
|
|
6952
6799
|
pendingApprovals: [],
|
|
6953
|
-
queuedPrompts:
|
|
6800
|
+
queuedPrompts: import_core34.EMPTY_HOLD,
|
|
6954
6801
|
stopArmed: false,
|
|
6955
6802
|
overlay: state.overlay?.kind === "approval" ? null : state.overlay
|
|
6956
6803
|
});
|
|
6957
6804
|
case "chatRestored":
|
|
6958
6805
|
if (stale(state, action.sessionId)) return step(state);
|
|
6959
|
-
return step({ ...state, conversation: (0,
|
|
6806
|
+
return step({ ...state, conversation: (0, import_core34.fromTranscript)(action.history, action.researchLog, action.plannerUsage), scroll: 0 });
|
|
6960
6807
|
case "planUpdated": {
|
|
6961
6808
|
if (stale(state, action.sessionId)) return step(state);
|
|
6962
6809
|
const isolation = isolationOfPlan(action.plan);
|
|
@@ -7003,9 +6850,9 @@ function reduceAction(state, action) {
|
|
|
7003
6850
|
case "taskStarted": {
|
|
7004
6851
|
if (stale(state, action.sessionId)) return step(state);
|
|
7005
6852
|
const existing = findTask(state.tasks, action.taskId);
|
|
7006
|
-
if (existing && (0,
|
|
7007
|
-
const tasks = state.tasks.map((t) => t.id === action.taskId && !(0,
|
|
7008
|
-
const spoken = say(state, "system", (0,
|
|
6853
|
+
if (existing && (0, import_core24.isTaskRunning)(existing)) return step(state);
|
|
6854
|
+
const tasks = state.tasks.map((t) => t.id === action.taskId && !(0, import_core24.isTaskRunning)(t) ? { ...t, status: "in_progress" } : t);
|
|
6855
|
+
const spoken = say(state, "system", (0, import_core34.taskStartedNotice)(action.title, action.runner));
|
|
7009
6856
|
return step({ ...spoken, tasks, status: "executing", busyLabel: runLabel(tasks) });
|
|
7010
6857
|
}
|
|
7011
6858
|
case "taskCheckpoint":
|
|
@@ -7046,12 +6893,6 @@ function reduceAction(state, action) {
|
|
|
7046
6893
|
const status = runStatus(next, tasks);
|
|
7047
6894
|
return step({ ...next, status, busyLabel: status === "executing" ? runLabel(tasks, gate) : state.busyLabel });
|
|
7048
6895
|
}
|
|
7049
|
-
case "queueReady": {
|
|
7050
|
-
if (stale(state, action.sessionId)) return step(state);
|
|
7051
|
-
const sessionId = action.sessionId ?? state.sessionId;
|
|
7052
|
-
if (sessionId === null) return step(state);
|
|
7053
|
-
return step(state, [{ type: "processQueued", sessionId }]);
|
|
7054
|
-
}
|
|
7055
6896
|
case "isolationBlocked": {
|
|
7056
6897
|
if (stale(state, action.sessionId)) return step(state);
|
|
7057
6898
|
return step(blockedPicker(state, action.message, action.repos));
|
|
@@ -7084,6 +6925,14 @@ function reduceAction(state, action) {
|
|
|
7084
6925
|
busyLabel: ""
|
|
7085
6926
|
});
|
|
7086
6927
|
}
|
|
6928
|
+
case "executionLost": {
|
|
6929
|
+
if (stale(state, action.sessionId)) return step(state);
|
|
6930
|
+
return step({
|
|
6931
|
+
...say(state, "error", "Lost the connection to the daemon \u2014 this view is no longer following the run, but the daemon may still be running it. /load this session again to see where it stands."),
|
|
6932
|
+
status: "idle",
|
|
6933
|
+
busyLabel: ""
|
|
6934
|
+
});
|
|
6935
|
+
}
|
|
7087
6936
|
case "settingsLoaded":
|
|
7088
6937
|
return step(applySettings(state, action.settings));
|
|
7089
6938
|
case "modelsLoaded":
|
|
@@ -7118,7 +6967,7 @@ function reduceAction(state, action) {
|
|
|
7118
6967
|
busyLabel: "",
|
|
7119
6968
|
planApproved: false,
|
|
7120
6969
|
pendingApprovals: [],
|
|
7121
|
-
queuedPrompts:
|
|
6970
|
+
queuedPrompts: import_core34.EMPTY_HOLD,
|
|
7122
6971
|
stopArmed: false,
|
|
7123
6972
|
overlay: state.overlay?.kind === "approval" ? null : state.overlay
|
|
7124
6973
|
});
|
|
@@ -7185,7 +7034,7 @@ function sameGate(a, b) {
|
|
|
7185
7034
|
return a.paused === b.paused && JSON.stringify(a.handoff) === JSON.stringify(b.handoff);
|
|
7186
7035
|
}
|
|
7187
7036
|
function runStatus(state, tasks) {
|
|
7188
|
-
if (tasks.some(
|
|
7037
|
+
if (tasks.some(import_core24.isTaskRunning)) return "executing";
|
|
7189
7038
|
if (tasks.some((t) => t.status === "awaiting_user") || state.gate?.paused) return "executing";
|
|
7190
7039
|
return plannerInFlight(state) ? state.status : "idle";
|
|
7191
7040
|
}
|
|
@@ -7254,7 +7103,7 @@ function submit(state) {
|
|
|
7254
7103
|
return step(cleared, [{ type: "sendTaskMessage", sessionId: state.sessionId, taskId, text }]);
|
|
7255
7104
|
}
|
|
7256
7105
|
if (plannerInFlight(state)) {
|
|
7257
|
-
return step({ ...cleared, queuedPrompts: (0,
|
|
7106
|
+
return step({ ...cleared, queuedPrompts: (0, import_core34.holdPrompt)(state.queuedPrompts, text) });
|
|
7258
7107
|
}
|
|
7259
7108
|
const spoken = say(cleared, "user", text);
|
|
7260
7109
|
const effect = state.sessionId ? { type: "sendMessage", sessionId: state.sessionId, message: text } : { type: "startConversation", goal: text };
|
|
@@ -7314,10 +7163,10 @@ function createApp(deps) {
|
|
|
7314
7163
|
|
|
7315
7164
|
// src/tui/effects.ts
|
|
7316
7165
|
var import_child_process4 = require("child_process");
|
|
7317
|
-
var
|
|
7166
|
+
var import_core36 = require("@ordewell/core");
|
|
7318
7167
|
|
|
7319
7168
|
// src/tui/inbound.ts
|
|
7320
|
-
var
|
|
7169
|
+
var import_core35 = require("@ordewell/core");
|
|
7321
7170
|
var CONVERSATION_TYPES = /* @__PURE__ */ new Set([
|
|
7322
7171
|
"planner_message",
|
|
7323
7172
|
"planner_turn_started",
|
|
@@ -7532,7 +7381,7 @@ function dispatchLifecycle(dispatch, event, sessionId) {
|
|
|
7532
7381
|
idleSince: task.idleSince ?? null,
|
|
7533
7382
|
isolation: task.isolation,
|
|
7534
7383
|
transport: task.transport,
|
|
7535
|
-
awaitingReason: (0,
|
|
7384
|
+
awaitingReason: (0, import_core35.isAwaitingReason)(task.awaitingReason) ? task.awaitingReason : void 0,
|
|
7536
7385
|
...typeof task.checkpoint === "string" && task.checkpoint ? { checkpoint: sanitize(task.checkpoint) } : {},
|
|
7537
7386
|
...task.continuable ? { continuable: true } : {},
|
|
7538
7387
|
awaitingApproval: typeof task.awaitingApproval === "number" && task.awaitingApproval > 0 ? task.awaitingApproval : void 0,
|
|
@@ -7558,13 +7407,6 @@ function dispatchLifecycle(dispatch, event, sessionId) {
|
|
|
7558
7407
|
case "review_approved":
|
|
7559
7408
|
dispatch({ type: "notice", message: "Plan approved." });
|
|
7560
7409
|
return;
|
|
7561
|
-
// The orchestrator paused fan-out because a structural edit is queued; drain
|
|
7562
|
-
// it so the planner reconciles the plan and dependents resume spawning.
|
|
7563
|
-
// Dropped on the floor, the queue suppresses every later tick() — which is
|
|
7564
|
-
// exactly "tasks did not fan out when the dependent ones finished."
|
|
7565
|
-
case "queue_ready":
|
|
7566
|
-
dispatch({ type: "queueReady", sessionId });
|
|
7567
|
-
return;
|
|
7568
7410
|
case "execution_complete":
|
|
7569
7411
|
dispatch({ type: "executionComplete", summary: event.summary, sessionId });
|
|
7570
7412
|
return;
|
|
@@ -7614,8 +7456,7 @@ async function runEffect(effect, deps) {
|
|
|
7614
7456
|
await perform(effect, deps);
|
|
7615
7457
|
} catch (err) {
|
|
7616
7458
|
if (!isConnectionRefused(err)) {
|
|
7617
|
-
|
|
7618
|
-
deps.dispatch({ type: "failed", message: explain(message) });
|
|
7459
|
+
deps.dispatch({ type: "failed", message: explain(err) });
|
|
7619
7460
|
return;
|
|
7620
7461
|
}
|
|
7621
7462
|
let revived = false;
|
|
@@ -7632,21 +7473,20 @@ async function runEffect(effect, deps) {
|
|
|
7632
7473
|
try {
|
|
7633
7474
|
await perform(effect, deps);
|
|
7634
7475
|
} catch (retryErr) {
|
|
7635
|
-
const message = retryErr instanceof Error ? retryErr.message : String(retryErr);
|
|
7636
7476
|
deps.dispatch({
|
|
7637
7477
|
type: "failed",
|
|
7638
7478
|
// A fresh daemon holds no sessions, so the retry of anything
|
|
7639
7479
|
// session-scoped legitimately 404s. Say which of the two happened.
|
|
7640
|
-
message: isConnectionRefused(retryErr) ? describeConnectionRefused(deps.port) : explain(
|
|
7480
|
+
message: isConnectionRefused(retryErr) ? describeConnectionRefused(deps.port) : explain(retryErr)
|
|
7641
7481
|
});
|
|
7642
7482
|
}
|
|
7643
7483
|
}
|
|
7644
7484
|
}
|
|
7645
|
-
function explain(
|
|
7646
|
-
if (
|
|
7485
|
+
function explain(err) {
|
|
7486
|
+
if (err instanceof DaemonError && err.code === "session_not_found") {
|
|
7647
7487
|
return "This server is no longer holding that session \u2014 it was probably restarted. Reload it with /sessions.";
|
|
7648
7488
|
}
|
|
7649
|
-
return message;
|
|
7489
|
+
return err instanceof Error ? err.message : String(err);
|
|
7650
7490
|
}
|
|
7651
7491
|
function persistAfterDaemon(deps, env) {
|
|
7652
7492
|
for (const [key, value] of Object.entries(env)) deps.setEnvVar(key, value);
|
|
@@ -7702,19 +7542,15 @@ async function perform(effect, deps) {
|
|
|
7702
7542
|
timer.unref?.();
|
|
7703
7543
|
return;
|
|
7704
7544
|
}
|
|
7705
|
-
case "processQueued":
|
|
7706
|
-
await api.processQueued(effect.sessionId);
|
|
7707
|
-
await refreshPlan(deps, effect.sessionId);
|
|
7708
|
-
return;
|
|
7709
7545
|
case "taskAction": {
|
|
7710
7546
|
const { sessionId, taskId, action } = effect;
|
|
7711
|
-
const request = action === "cancel" || action === "retry" || action === "force-start" ? () => api.taskControl(sessionId, taskId, action) : (0,
|
|
7547
|
+
const request = action === "cancel" || action === "retry" || action === "force-start" ? () => api.taskControl(sessionId, taskId, action) : (0, import_core36.markRequestFor)(action) === "uncomplete" ? () => api.markTaskIncomplete(sessionId, taskId) : () => api.markTaskComplete(sessionId, taskId);
|
|
7712
7548
|
await (effect.watch ? withExecutionStream(deps, sessionId, request) : request());
|
|
7713
7549
|
await refreshPlan(deps, sessionId);
|
|
7714
7550
|
return;
|
|
7715
7551
|
}
|
|
7716
7552
|
case "addTask": {
|
|
7717
|
-
const fields = (0,
|
|
7553
|
+
const fields = (0, import_core36.newTaskFields)(effect.title);
|
|
7718
7554
|
if (!fields) return;
|
|
7719
7555
|
await api.addTask(effect.sessionId, { ...fields });
|
|
7720
7556
|
await refreshPlan(deps, effect.sessionId);
|
|
@@ -7835,11 +7671,11 @@ async function perform(effect, deps) {
|
|
|
7835
7671
|
dispatch({ type: "notice", message: `Orchestrator model set to ${effect.modelId}.` });
|
|
7836
7672
|
return;
|
|
7837
7673
|
case "setPlanner": {
|
|
7838
|
-
const meta =
|
|
7674
|
+
const meta = import_core36.ALL_PROVIDERS[effect.provider];
|
|
7839
7675
|
if (!meta) throw new Error(`Unknown planner: ${effect.provider}`);
|
|
7840
7676
|
const env = { AI_PROVIDER: effect.provider };
|
|
7841
7677
|
const settings = await api.updateSettings({ env });
|
|
7842
|
-
const recall2 =
|
|
7678
|
+
const recall2 = plannerSwitchRecall(settings);
|
|
7843
7679
|
persistAfterDaemon(deps, { ...env, ORCHESTRATOR_MODEL: recall2.model, ORDEWELL_PLANNER_EFFORT: recall2.effort });
|
|
7844
7680
|
dispatch({
|
|
7845
7681
|
type: "settingsLoaded",
|
|
@@ -7847,7 +7683,7 @@ async function perform(effect, deps) {
|
|
|
7847
7683
|
});
|
|
7848
7684
|
dispatch({
|
|
7849
7685
|
type: "notice",
|
|
7850
|
-
message: `${(0,
|
|
7686
|
+
message: `${(0, import_core36.isCliProvider)(effect.provider) ? `Planning with ${meta.label} \u2014 no API key needed.` : `Planner set to ${meta.label}.`} ${plannerModelNotice(recall2)}`
|
|
7851
7687
|
});
|
|
7852
7688
|
await loadModels(deps);
|
|
7853
7689
|
return;
|
|
@@ -7859,7 +7695,7 @@ async function perform(effect, deps) {
|
|
|
7859
7695
|
dispatch({ type: "notice", message: `Planner effort set to ${effect.effort || "the runner default"}.` });
|
|
7860
7696
|
return;
|
|
7861
7697
|
case "setApiKey": {
|
|
7862
|
-
const meta =
|
|
7698
|
+
const meta = import_core36.ALL_PROVIDERS[effect.provider];
|
|
7863
7699
|
if (!meta) throw new Error(`Unknown provider: ${effect.provider}`);
|
|
7864
7700
|
await api.updateSettings({ env: { [meta.apiKeyEnvVar]: effect.key } });
|
|
7865
7701
|
deps.setEnvVar(meta.apiKeyEnvVar, effect.key);
|
|
@@ -7897,7 +7733,7 @@ async function perform(effect, deps) {
|
|
|
7897
7733
|
return;
|
|
7898
7734
|
case "setAutonomous":
|
|
7899
7735
|
deps.setEnvVar("ORDEWELL_AUTONOMOUS_MODE", String(effect.enabled));
|
|
7900
|
-
dispatch({ type: "notice", message: `Autonomy level: ${(0,
|
|
7736
|
+
dispatch({ type: "notice", message: `Autonomy level: ${(0, import_core36.autonomyLevelLabel)(effect.enabled)} for new plans.` });
|
|
7901
7737
|
return;
|
|
7902
7738
|
case "setMouseCapture":
|
|
7903
7739
|
deps.setMouseCapture(effect.enabled);
|
|
@@ -8031,7 +7867,7 @@ function osc52(text) {
|
|
|
8031
7867
|
function copySelection(deps, text) {
|
|
8032
7868
|
if (!text) return;
|
|
8033
7869
|
const lines = text.split("\n").length;
|
|
8034
|
-
const command = (0,
|
|
7870
|
+
const command = (0, import_core36.clipboardCopyCommand)(deps.hasBin);
|
|
8035
7871
|
if (command) {
|
|
8036
7872
|
try {
|
|
8037
7873
|
(deps.pipeToClipboard ?? pipeToClipboardDefault)(command, text);
|
|
@@ -8055,9 +7891,14 @@ async function withExecutionStream(deps, sessionId, request) {
|
|
|
8055
7891
|
const inbound = inboundFor(deps.api, deps.dispatch, sessionId);
|
|
8056
7892
|
const stream = deps.api.streamExecution(sessionId, inbound.execution(), settleReady);
|
|
8057
7893
|
void stream.catch(settleReady);
|
|
8058
|
-
|
|
8059
|
-
|
|
8060
|
-
|
|
7894
|
+
try {
|
|
7895
|
+
await streamReady;
|
|
7896
|
+
await request();
|
|
7897
|
+
} catch (err) {
|
|
7898
|
+
deps.api.closeExecutionStream(stream);
|
|
7899
|
+
throw err;
|
|
7900
|
+
}
|
|
7901
|
+
if (await stream === "lost") deps.dispatch({ type: "executionLost", sessionId });
|
|
8061
7902
|
}
|
|
8062
7903
|
async function converse(deps, sessionId, call) {
|
|
8063
7904
|
const inbound = inboundFor(deps.api, deps.dispatch, sessionId);
|
|
@@ -8422,7 +8263,7 @@ async function handleTui(subArgs) {
|
|
|
8422
8263
|
}
|
|
8423
8264
|
const workspace = flag(subArgs, "--workspace") || process.cwd();
|
|
8424
8265
|
try {
|
|
8425
|
-
(0,
|
|
8266
|
+
(0, import_core37.assertWorkspaceExists)(workspace);
|
|
8426
8267
|
} catch {
|
|
8427
8268
|
console.error(
|
|
8428
8269
|
`Workspace "${workspace}" does not exist.
|
|
@@ -8431,7 +8272,7 @@ cd into a directory that exists, or pass --workspace <path> naming one that does
|
|
|
8431
8272
|
);
|
|
8432
8273
|
process.exit(1);
|
|
8433
8274
|
}
|
|
8434
|
-
registerSkillCommands((0,
|
|
8275
|
+
registerSkillCommands((0, import_core37.createSkillsService)(workspace).listSkills());
|
|
8435
8276
|
const explicitPort = flag(subArgs, "--port") || process.env.ORDEWELL_PORT;
|
|
8436
8277
|
const targetPort = explicitPort ? resolvePort(subArgs) : await findFreePort();
|
|
8437
8278
|
const { port, owned: ownedAtLaunch } = await ensureDaemonOwned(targetPort, { detached: false });
|
|
@@ -8448,7 +8289,7 @@ cd into a directory that exists, or pass --workspace <path> naming one that does
|
|
|
8448
8289
|
workspace,
|
|
8449
8290
|
port,
|
|
8450
8291
|
dispatch: (action) => app.dispatch(action),
|
|
8451
|
-
newSessionId: () => (0,
|
|
8292
|
+
newSessionId: () => (0, import_core37.mintSessionId)(),
|
|
8452
8293
|
setEnvVar: (key, value) => {
|
|
8453
8294
|
writeEnvVar(findEnvFile(), key, value);
|
|
8454
8295
|
process.env[key] = value;
|
|
@@ -8499,6 +8340,7 @@ cd into a directory that exists, or pass --workspace <path> naming one that does
|
|
|
8499
8340
|
app.dispatch({ type: "resize", rows: r, cols: c });
|
|
8500
8341
|
});
|
|
8501
8342
|
process.on("uncaughtException", (err) => {
|
|
8343
|
+
terminal?.close();
|
|
8502
8344
|
console.error(`Fatal: ${err.message}`);
|
|
8503
8345
|
shutdown(1);
|
|
8504
8346
|
});
|
|
@@ -8573,7 +8415,7 @@ function cliVersion() {
|
|
|
8573
8415
|
// src/main.ts
|
|
8574
8416
|
var TUI_FLAGS = /* @__PURE__ */ new Set(["--workspace", "--port"]);
|
|
8575
8417
|
async function main() {
|
|
8576
|
-
(0,
|
|
8418
|
+
(0, import_core38.migrateOldConfigDir)();
|
|
8577
8419
|
loadEnvFile();
|
|
8578
8420
|
const argv = process.argv.slice(2);
|
|
8579
8421
|
if (TUI_FLAGS.has(argv[0] ?? "")) argv.unshift("tui");
|