poe-code 4.0.37 → 4.0.39

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.
@@ -1,7 +1,11 @@
1
- import { type GaslightOptions as WorkspaceGaslightOptions, type GaslightResult } from "../../packages/agent-gaslight/dist/index.js";
1
+ import { type GaslightDaemonOptions as WorkspaceGaslightDaemonOptions, type GaslightDaemonResult, type GaslightOptions as WorkspaceGaslightOptions, type GaslightResult } from "../../packages/agent-gaslight/dist/index.js";
2
2
  import type { WorktreeExecutionOptions } from "./types.js";
3
- export { GASLIGHT_CONFIG_EXAMPLE, ingestGaslight, loadGaslightConfig, parseGaslightConfig, type GaslightConfig, type GaslightCollectHumanPrompts, type GaslightEvent, type GaslightFileSystem, type GaslightIngestEvent, type GaslightIngestOptions, type GaslightIngestResult, type GaslightPlanResult, type GaslightResult, type GaslightRound, type GaslightSpawn } from "../../packages/agent-gaslight/dist/index.js";
3
+ export { GASLIGHT_CONFIG_EXAMPLE, ingestGaslight, loadGaslightConfig, parseGaslightConfig, type GaslightConfig, type GaslightDaemonEvent, type GaslightDaemonResult, type GaslightCollectHumanPrompts, type GaslightEvent, type GaslightFileSystem, type GaslightIngestEvent, type GaslightIngestOptions, type GaslightIngestResult, type GaslightPlanResult, type GaslightResult, type GaslightRound, type GaslightSpawn } from "../../packages/agent-gaslight/dist/index.js";
4
4
  export type GaslightOptions = WorkspaceGaslightOptions & {
5
5
  worktree?: WorktreeExecutionOptions;
6
6
  };
7
+ export type GaslightDaemonOptions = Omit<WorkspaceGaslightDaemonOptions, "run"> & {
8
+ worktree?: WorktreeExecutionOptions;
9
+ };
10
+ export declare function runGaslightDaemon(options: GaslightDaemonOptions): Promise<GaslightDaemonResult>;
7
11
  export declare function runGaslight(options: GaslightOptions): Promise<GaslightResult>;
@@ -1,6 +1,12 @@
1
- import { runGaslight as runWorkspaceGaslight } from "@poe-code/agent-gaslight";
1
+ import { runGaslightDaemon as runWorkspaceGaslightDaemon, runGaslight as runWorkspaceGaslight } from "@poe-code/agent-gaslight";
2
2
  import { runWithOptionalWorktree } from "./worktree.js";
3
3
  export { GASLIGHT_CONFIG_EXAMPLE, ingestGaslight, loadGaslightConfig, parseGaslightConfig } from "@poe-code/agent-gaslight";
4
+ export async function runGaslightDaemon(options) {
5
+ return await runWorkspaceGaslightDaemon({
6
+ ...options,
7
+ run: async (gaslightOptions) => await runGaslight({ ...gaslightOptions, worktree: options.worktree })
8
+ });
9
+ }
4
10
  export async function runGaslight(options) {
5
11
  if (!isWorktreeEnabled(options.worktree)) {
6
12
  return await runWorkspaceGaslight(options);
@@ -1 +1 @@
1
- {"version":3,"file":"gaslight.js","sourceRoot":"","sources":["../../src/sdk/gaslight.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,WAAW,IAAI,oBAAoB,EAGpC,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,uBAAuB,EAAE,MAAM,eAAe,CAAC;AAGxD,OAAO,EACL,uBAAuB,EACvB,cAAc,EACd,kBAAkB,EAClB,mBAAmB,EAYpB,MAAM,0BAA0B,CAAC;AAMlC,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,OAAwB;IACxD,IAAI,CAAC,iBAAiB,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC;QACzC,OAAO,MAAM,oBAAoB,CAAC,OAAO,CAAC,CAAC;IAC7C,CAAC;IAED,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;IACzC,MAAM,OAAO,GAAG,MAAM,uBAAuB,CAAiB;QAC5D,GAAG;QACH,aAAa,EAAE,OAAO,CAAC,KAAK;QAC5B,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,aAAa,EAAE,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC1D,QAAQ,EAAE,OAAO,CAAC,QAAQ;QAC1B,MAAM,EAAE,OAAO,CAAC,MAAM;QACtB,GAAG,EAAE,KAAK,EAAE,EAAE,WAAW,EAAE,EAAE,EAAE;YAC7B,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,GAAG,gBAAgB,EAAE,GAAG,OAAO,CAAC;YAC7D,OAAO,MAAM,oBAAoB,CAAC;gBAChC,GAAG,gBAAgB;gBACnB,GAAG,EAAE,WAAW;aACjB,CAAC,CAAC;QACL,CAAC;KACF,CAAC,CAAC;IACH,OAAO,OAAO,CAAC,KAAK,CAAC;AACvB,CAAC;AAED,SAAS,iBAAiB,CAAC,QAA8C;IACvE,OAAO,QAAQ,KAAK,IAAI,CAAC;AAC3B,CAAC"}
1
+ {"version":3,"file":"gaslight.js","sourceRoot":"","sources":["../../src/sdk/gaslight.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,iBAAiB,IAAI,0BAA0B,EAC/C,WAAW,IAAI,oBAAoB,EAKpC,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,uBAAuB,EAAE,MAAM,eAAe,CAAC;AAGxD,OAAO,EACL,uBAAuB,EACvB,cAAc,EACd,kBAAkB,EAClB,mBAAmB,EAcpB,MAAM,0BAA0B,CAAC;AAUlC,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,OAA8B;IAE9B,OAAO,MAAM,0BAA0B,CAAC;QACtC,GAAG,OAAO;QACV,GAAG,EAAE,KAAK,EAAE,eAAyC,EAAE,EAAE,CACvD,MAAM,WAAW,CAAC,EAAE,GAAG,eAAe,EAAE,QAAQ,EAAE,OAAO,CAAC,QAAQ,EAAE,CAAC;KACxE,CAAC,CAAC;AACL,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,OAAwB;IACxD,IAAI,CAAC,iBAAiB,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC;QACzC,OAAO,MAAM,oBAAoB,CAAC,OAAO,CAAC,CAAC;IAC7C,CAAC;IAED,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;IACzC,MAAM,OAAO,GAAG,MAAM,uBAAuB,CAAiB;QAC5D,GAAG;QACH,aAAa,EAAE,OAAO,CAAC,KAAK;QAC5B,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,aAAa,EAAE,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC1D,QAAQ,EAAE,OAAO,CAAC,QAAQ;QAC1B,MAAM,EAAE,OAAO,CAAC,MAAM;QACtB,GAAG,EAAE,KAAK,EAAE,EAAE,WAAW,EAAE,EAAE,EAAE;YAC7B,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,GAAG,gBAAgB,EAAE,GAAG,OAAO,CAAC;YAC7D,OAAO,MAAM,oBAAoB,CAAC;gBAChC,GAAG,gBAAgB;gBACnB,GAAG,EAAE,WAAW;aACjB,CAAC,CAAC;QACL,CAAC;KACF,CAAC,CAAC;IACH,OAAO,OAAO,CAAC,KAAK,CAAC;AACvB,CAAC;AAED,SAAS,iBAAiB,CAAC,QAA8C;IACvE,OAAO,QAAQ,KAAK,IAAI,CAAC;AAC3B,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "poe-code",
3
- "version": "4.0.37",
3
+ "version": "4.0.39",
4
4
  "description": "CLI tool to configure Poe API for developer workflows.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -0,0 +1,26 @@
1
+ import type { GaslightOptions, GaslightResult } from "./types.js";
2
+ export type GaslightDaemonEvent = {
3
+ type: "scan.finished";
4
+ readyPlans: number;
5
+ } | {
6
+ type: "plan.started";
7
+ planPath: string;
8
+ } | {
9
+ type: "plan.finished";
10
+ planPath: string;
11
+ } | {
12
+ type: "plan.failed";
13
+ planPath: string;
14
+ error: string;
15
+ };
16
+ export interface GaslightDaemonOptions extends Omit<GaslightOptions, "planPaths" | "archive" | "onEvent"> {
17
+ planDirectory: string;
18
+ pollIntervalMs?: number;
19
+ onEvent?: (event: GaslightDaemonEvent) => void;
20
+ wait?: (milliseconds: number, signal?: AbortSignal) => Promise<void>;
21
+ run?: (options: GaslightOptions) => Promise<GaslightResult>;
22
+ }
23
+ export interface GaslightDaemonResult {
24
+ completedPlans: number;
25
+ }
26
+ export declare function runGaslightDaemon(options: GaslightDaemonOptions): Promise<GaslightDaemonResult>;
@@ -0,0 +1,65 @@
1
+ import * as fsPromises from "node:fs/promises";
2
+ import { discoverPlans } from "@poe-code/agent-harness-tools";
3
+ import { runGaslight } from "./run.js";
4
+ const DEFAULT_POLL_INTERVAL_MS = 5_000;
5
+ function waitForNextScan(milliseconds, signal) {
6
+ if (signal?.aborted)
7
+ return Promise.resolve();
8
+ return new Promise((resolve) => {
9
+ const timeout = setTimeout(finish, milliseconds);
10
+ function finish() {
11
+ clearTimeout(timeout);
12
+ signal?.removeEventListener("abort", finish);
13
+ resolve();
14
+ }
15
+ signal?.addEventListener("abort", finish, { once: true });
16
+ });
17
+ }
18
+ export async function runGaslightDaemon(options) {
19
+ const cwd = options.cwd ?? process.cwd();
20
+ const homeDir = options.homeDir ?? process.env.HOME ?? cwd;
21
+ const fs = options.fs ?? fsPromises;
22
+ const run = options.run ?? runGaslight;
23
+ const wait = options.wait ?? waitForNextScan;
24
+ const completed = new Set();
25
+ let completedPlans = 0;
26
+ while (!options.signal?.aborted) {
27
+ const plans = await discoverPlans({
28
+ cwd,
29
+ homeDir,
30
+ planDirectory: options.planDirectory,
31
+ kinds: ["plan"],
32
+ fs: fs
33
+ });
34
+ const readyPlans = plans.filter((plan) => plan.readiness === "ready" && !completed.has(plan.absolutePath));
35
+ options.onEvent?.({ type: "scan.finished", readyPlans: readyPlans.length });
36
+ for (const plan of readyPlans) {
37
+ if (options.signal?.aborted)
38
+ break;
39
+ options.onEvent?.({ type: "plan.started", planPath: plan.displayPath });
40
+ const { run: ignoredRun, wait: ignoredWait, pollIntervalMs: ignoredPollIntervalMs, planDirectory: ignoredPlanDirectory, onEvent: ignoredOnEvent, ...gaslightOptions } = options;
41
+ try {
42
+ await run({
43
+ ...gaslightOptions,
44
+ planPaths: [plan.displayPath],
45
+ archive: true,
46
+ fs
47
+ });
48
+ completed.add(plan.absolutePath);
49
+ completedPlans += 1;
50
+ options.onEvent?.({ type: "plan.finished", planPath: plan.displayPath });
51
+ }
52
+ catch (error) {
53
+ options.onEvent?.({
54
+ type: "plan.failed",
55
+ planPath: plan.displayPath,
56
+ error: error instanceof Error ? error.message : String(error)
57
+ });
58
+ }
59
+ }
60
+ if (!options.signal?.aborted) {
61
+ await wait(options.pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS, options.signal);
62
+ }
63
+ }
64
+ return { completedPlans };
65
+ }
@@ -1,4 +1,6 @@
1
1
  export { GASLIGHT_CONFIG_EXAMPLE, loadGaslightConfig, parseGaslightConfig } from "./config.js";
2
2
  export { ingestGaslight } from "./ingest.js";
3
+ export { runGaslightDaemon } from "./daemon.js";
3
4
  export { runGaslight } from "./run.js";
5
+ export type { GaslightDaemonEvent, GaslightDaemonOptions, GaslightDaemonResult } from "./daemon.js";
4
6
  export type { GaslightArchiveFileSystem, GaslightConfig, GaslightCollectHumanPrompts, GaslightEvent, GaslightFileSystem, GaslightIngestEvent, GaslightIngestOptions, GaslightIngestResult, GaslightOptions, GaslightPlanResult, GaslightResult, GaslightRound, GaslightSpawn } from "./types.js";
@@ -1,3 +1,4 @@
1
1
  export { GASLIGHT_CONFIG_EXAMPLE, loadGaslightConfig, parseGaslightConfig } from "./config.js";
2
2
  export { ingestGaslight } from "./ingest.js";
3
+ export { runGaslightDaemon } from "./daemon.js";
3
4
  export { runGaslight } from "./run.js";
@@ -8,8 +8,11 @@ export function buildPlanExplorerConfig(options) {
8
8
  let plans = options.plans;
9
9
  let rows = toRows(plans);
10
10
  let entryByRowId = toEntryMap(plans);
11
+ let preserveOrderOnNextRefresh = false;
11
12
  async function refresh() {
12
- plans = await options.onRefresh();
13
+ const refreshedPlans = await options.onRefresh();
14
+ plans = preserveOrderOnNextRefresh ? preservePlanOrder(plans, refreshedPlans) : refreshedPlans;
15
+ preserveOrderOnNextRefresh = false;
13
16
  rows = toRows(plans);
14
17
  entryByRowId = toEntryMap(plans);
15
18
  }
@@ -22,7 +25,13 @@ export function buildPlanExplorerConfig(options) {
22
25
  const entry = getEntry(entryByRowId, ctx.row.id);
23
26
  const readiness = entry.readiness === "ready" ? "draft" : "ready";
24
27
  await setPlanReadiness(entry.absolutePath, readiness, options.fs);
25
- await ctx.refresh();
28
+ preserveOrderOnNextRefresh = true;
29
+ try {
30
+ await ctx.refresh();
31
+ }
32
+ finally {
33
+ preserveOrderOnNextRefresh = false;
34
+ }
26
35
  ctx.toast(`Marked ${path.basename(entry.path)} ${readiness}`, "info");
27
36
  }
28
37
  },
@@ -100,6 +109,7 @@ export function buildPlanExplorerConfig(options) {
100
109
  },
101
110
  {
102
111
  id: "delete",
112
+ accelerator: "x",
103
113
  label: "Delete",
104
114
  destructive: true,
105
115
  handler: async (ctx) => {
@@ -148,6 +158,24 @@ export function buildPlanExplorerConfig(options) {
148
158
  emptyHint: "No plans found"
149
159
  });
150
160
  }
161
+ function preservePlanOrder(current, refreshed) {
162
+ const refreshedByPath = new Map();
163
+ for (const entry of refreshed) {
164
+ const matches = refreshedByPath.get(entry.absolutePath) ?? [];
165
+ matches.push(entry);
166
+ refreshedByPath.set(entry.absolutePath, matches);
167
+ }
168
+ const ordered = [];
169
+ for (const entry of current) {
170
+ const matches = refreshedByPath.get(entry.absolutePath);
171
+ const match = matches?.shift();
172
+ if (match !== undefined)
173
+ ordered.push(match);
174
+ }
175
+ const remaining = new Set(ordered);
176
+ ordered.push(...refreshed.filter((entry) => !remaining.has(entry)));
177
+ return ordered;
178
+ }
151
179
  function abbreviateHome(filePath, homeDir) {
152
180
  if (homeDir === undefined)
153
181
  return filePath;
@@ -786,14 +786,15 @@ function dispatchAction(state, action, confirmed, runtimeHandles, modalRows) {
786
786
  return mark(state, 0);
787
787
  }
788
788
  if (action.destructive === true && !confirmed) {
789
+ const actionLabel = typeof action.label === "function" ? action.label() : action.label;
789
790
  return {
790
791
  state: {
791
792
  ...state,
792
793
  modal: {
793
794
  kind: "confirm",
794
795
  title: action.destructive ? "Confirm destructive action" : "Confirm action",
795
- message: `${typeof action.label === "function" ? action.label() : action.label} ${rows.length === 1 ? rows[0].title : `${rows.length} items`}?`,
796
- confirmLabel: action.destructive ? "Delete" : "Yes",
796
+ message: `${actionLabel} ${rows.length === 1 ? rows[0].title : `${rows.length} items`}?`,
797
+ confirmLabel: actionLabel,
797
798
  cancelLabel: "Cancel",
798
799
  destructive: action.destructive === true,
799
800
  action,