@fkqfkq123/opencode-autopilot 0.1.2 → 0.1.3

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.
@@ -9,6 +9,7 @@ import { mkdir, readFile, writeFile } from "node:fs/promises";
9
9
  import { homedir } from "node:os";
10
10
  import { join } from "node:path";
11
11
  import { z } from "zod";
12
+ const workflowIdSchema = z.string().min(1).describe("Workflow identifier");
12
13
  const WORKFLOW_PRIMARY_AGENT_PROMPT = `You are the workflow execution agent.
13
14
 
14
15
  Responsibilities:
@@ -252,7 +253,7 @@ export async function workflowPlugin(input) {
252
253
  args: {
253
254
  command: z.enum(commandNames)
254
255
  .describe("Workflow channel command to execute"),
255
- workflowId: z.string().describe("Workflow identifier"),
256
+ workflowId: workflowIdSchema,
256
257
  payload: z.string().optional().describe("Optional JSON/string payload for answer-like commands"),
257
258
  },
258
259
  execute: async (args, context) => {
@@ -262,7 +263,7 @@ export async function workflowPlugin(input) {
262
263
  workflow_open: {
263
264
  description: "Open or initialize a workflow channel and attach to it.",
264
265
  args: {
265
- workflowId: z.string().describe("Workflow identifier"),
266
+ workflowId: workflowIdSchema,
266
267
  payload: z.string().optional().describe("Initial request. Supports plain text or JSON: { prompt, docPaths[], projectContext }"),
267
268
  },
268
269
  execute: async (args, context) => invokeCommand("workflow-open", args.workflowId, args.payload, context?.sessionID),
@@ -270,21 +271,21 @@ export async function workflowPlugin(input) {
270
271
  workflow_attach: {
271
272
  description: "Attach to an existing workflow channel.",
272
273
  args: {
273
- workflowId: z.string().describe("Workflow identifier"),
274
+ workflowId: workflowIdSchema,
274
275
  },
275
276
  execute: async (args, context) => invokeCommand("workflow-attach", args.workflowId, undefined, context?.sessionID),
276
277
  },
277
278
  workflow_status: {
278
279
  description: "Render the current workflow status block.",
279
280
  args: {
280
- workflowId: z.string().describe("Workflow identifier"),
281
+ workflowId: workflowIdSchema,
281
282
  },
282
283
  execute: async (args, context) => invokeCommand("workflow-status", args.workflowId, undefined, context?.sessionID),
283
284
  },
284
285
  workflow_answer: {
285
286
  description: "Answer workflow clarification questions.",
286
287
  args: {
287
- workflowId: z.string().describe("Workflow identifier"),
288
+ workflowId: workflowIdSchema,
288
289
  payload: z.string().describe("JSON string payload for question answers"),
289
290
  },
290
291
  execute: async (args, context) => invokeCommand("workflow-answer", args.workflowId, args.payload, context?.sessionID),
@@ -292,21 +293,21 @@ export async function workflowPlugin(input) {
292
293
  workflow_approve: {
293
294
  description: "Approve the current workflow plan or decision.",
294
295
  args: {
295
- workflowId: z.string().describe("Workflow identifier"),
296
+ workflowId: workflowIdSchema,
296
297
  },
297
298
  execute: async (args, context) => invokeCommand("workflow-approve", args.workflowId, undefined, context?.sessionID),
298
299
  },
299
300
  workflow_resume: {
300
301
  description: "Resume a blocked workflow.",
301
302
  args: {
302
- workflowId: z.string().describe("Workflow identifier"),
303
+ workflowId: workflowIdSchema,
303
304
  },
304
305
  execute: async (args, context) => invokeCommand("workflow-resume", args.workflowId, undefined, context?.sessionID),
305
306
  },
306
307
  workflow_back: {
307
308
  description: "Leave the workflow channel without stopping the workflow.",
308
309
  args: {
309
- workflowId: z.string().describe("Workflow identifier"),
310
+ workflowId: workflowIdSchema,
310
311
  },
311
312
  execute: async (args, context) => invokeCommand("workflow-back", args.workflowId, undefined, context?.sessionID),
312
313
  },
@@ -3,11 +3,17 @@ import { dirname } from "node:path";
3
3
  export async function readJsonFile(filePath) {
4
4
  try {
5
5
  const raw = await readFile(filePath, "utf8");
6
+ if (!raw.trim()) {
7
+ return null;
8
+ }
6
9
  return JSON.parse(raw);
7
10
  }
8
11
  catch (error) {
9
12
  const message = error instanceof Error ? error.message : String(error);
10
- if (message.includes("ENOENT")) {
13
+ if (message.includes("ENOENT") || message.includes("ENOTDIR") || message.includes("EINVAL")) {
14
+ return null;
15
+ }
16
+ if (error instanceof SyntaxError) {
11
17
  return null;
12
18
  }
13
19
  throw error;
@@ -50,7 +50,9 @@ export class FileSystemHumanActionStore {
50
50
  const workflowsDir = this.workspace.workflowsRoot();
51
51
  let workflowIds = [];
52
52
  try {
53
- workflowIds = await readdir(workflowsDir);
53
+ workflowIds = (await readdir(workflowsDir, { withFileTypes: true }))
54
+ .filter((entry) => entry.isDirectory())
55
+ .map((entry) => entry.name);
54
56
  }
55
57
  catch (error) {
56
58
  const message = error instanceof Error ? error.message : String(error);
@@ -7,7 +7,9 @@ export class FileSystemWorkflowStateStore {
7
7
  }
8
8
  async listWorkflows() {
9
9
  try {
10
- const workflowIds = await readdir(this.workspace.workflowsRoot());
10
+ const workflowIds = (await readdir(this.workspace.workflowsRoot(), { withFileTypes: true }))
11
+ .filter((entry) => entry.isDirectory())
12
+ .map((entry) => entry.name);
11
13
  const items = await Promise.all(workflowIds.map((workflowId) => this.getWorkflow(workflowId)));
12
14
  return items.filter((item) => item !== null);
13
15
  }
@@ -16,6 +16,7 @@ export interface WorkflowWorkspace {
16
16
  export declare class DefaultWorkflowWorkspace implements WorkflowWorkspace {
17
17
  private readonly root;
18
18
  constructor(root: string);
19
+ private normalizeWorkflowId;
19
20
  baseDir(): string;
20
21
  workflowsRoot(): string;
21
22
  workflowConfigFile(): string;
@@ -4,6 +4,13 @@ export class DefaultWorkflowWorkspace {
4
4
  constructor(root) {
5
5
  this.root = root;
6
6
  }
7
+ normalizeWorkflowId(workflowId) {
8
+ const normalized = workflowId.trim();
9
+ if (!normalized) {
10
+ throw new Error("workflowId must be a non-empty string");
11
+ }
12
+ return normalized;
13
+ }
7
14
  baseDir() {
8
15
  return this.root;
9
16
  }
@@ -14,7 +21,7 @@ export class DefaultWorkflowWorkspace {
14
21
  return join(this.root, "workflow.json");
15
22
  }
16
23
  workflowDir(workflowId) {
17
- return join(this.workflowsRoot(), workflowId);
24
+ return join(this.workflowsRoot(), this.normalizeWorkflowId(workflowId));
18
25
  }
19
26
  artifactStateFile(workflowId) {
20
27
  return join(this.workflowDir(workflowId), "artifact-state.json");
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@fkqfkq123/opencode-autopilot",
3
3
  "private": false,
4
- "version": "0.1.2",
4
+ "version": "0.1.3",
5
5
  "description": "An OpenCode plugin for attached-session workflow execution with refinement, planning, development, review, and test phases.",
6
6
  "type": "module",
7
7
  "packageManager": "bun@1.3.5",