astrocode-workflow 0.4.1 → 0.4.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.
@@ -1,36 +1,16 @@
1
1
  // src/astro/workflow-runner.ts
2
- import { acquireRepoLock } from "../state/repo-lock";
3
- import { workflowRepoLock } from "../state/workflow-repo-lock";
4
2
 
5
3
  /**
6
- * This is the only place you should hold the repo lock.
4
+ * Executes the workflow loop.
7
5
  * Everything that mutates the repo (tool calls, steps) runs inside this scope.
8
6
  *
9
7
  * Replace the internals with your actual astro/opencode driver loop.
10
8
  */
11
9
  export async function runAstroWorkflow(opts: {
12
- lockPath: string;
13
- repoRoot: string;
14
- sessionId: string;
15
- owner?: string;
16
-
17
- // Hook in your existing workflow engine
18
10
  proceedOneStep: () => Promise<{ done: boolean }>;
19
11
  }): Promise<void> {
20
- await workflowRepoLock(
21
- { acquireRepoLock },
22
- {
23
- lockPath: opts.lockPath,
24
- repoRoot: opts.repoRoot,
25
- sessionId: opts.sessionId,
26
- owner: opts.owner,
27
- fn: async () => {
28
- // ✅ Lock is held ONCE for the entire run. Tool calls can "rattle through".
29
- while (true) {
30
- const { done } = await opts.proceedOneStep();
31
- if (done) return;
32
- }
33
- },
34
- }
35
- );
12
+ while (true) {
13
+ const { done } = await opts.proceedOneStep();
14
+ if (done) return;
15
+ }
36
16
  }
package/src/index.ts CHANGED
@@ -59,13 +59,6 @@ const Astrocode: Plugin = async (ctx) => {
59
59
  }
60
60
  const repoRoot = ctx.directory;
61
61
 
62
- // NOTE: Repo locking is handled at the workflow level via workflowRepoLock.
63
- // The workflow tool correctly acquires and holds the lock for the entire workflow execution.
64
- // Plugin-level locking is unnecessary and architecturally incorrect since:
65
- // - The lock would be held for the entire session lifecycle (too long)
66
- // - Individual tools are designed to be called within workflow context where lock is held
67
- // - Workflow-level locking with refcounting prevents lock churn during tool execution
68
-
69
62
  // Always load config first - this provides defaults even in limited mode
70
63
  let pluginConfig: AstrocodeConfig;
71
64
  try {
@@ -25,34 +25,6 @@ export function createAstroHealthTool(opts: { ctx: any; config: AstrocodeConfig;
25
25
  lines.push(`- Repo: ${repoRoot}`);
26
26
  lines.push(`- DB Path: ${fullDbPath}`);
27
27
 
28
- // Lock status
29
- const lockPath = `${repoRoot}/.astro/astro.lock`;
30
- try {
31
- if (fs.existsSync(lockPath)) {
32
- const lockContent = fs.readFileSync(lockPath, "utf8").trim();
33
- const parts = lockContent.split(" ");
34
- if (parts.length >= 2) {
35
- const pid = parseInt(parts[0]);
36
- const startedAt = parts[1];
37
-
38
- // Check if PID is still running
39
- try {
40
- (process as any).kill(pid, 0); // Signal 0 just checks if process exists
41
- lines.push(`- Lock: HELD by PID ${pid} (started ${startedAt})`);
42
- } catch {
43
- lines.push(`- Lock: STALE (PID ${pid} not running, started ${startedAt})`);
44
- lines.push(` → Run: rm "${lockPath}"`);
45
- }
46
- } else {
47
- lines.push(`- Lock: MALFORMED (${lockContent})`);
48
- }
49
- } else {
50
- lines.push(`- Lock: NONE (no lock file)`);
51
- }
52
- } catch (e) {
53
- lines.push(`- Lock: ERROR (${String(e)})`);
54
- }
55
-
56
28
  // DB file status
57
29
  const dbExists = fs.existsSync(fullDbPath);
58
30
  const walExists = fs.existsSync(`${fullDbPath}-wal`);
@@ -116,7 +88,6 @@ export function createAstroHealthTool(opts: { ctx: any; config: AstrocodeConfig;
116
88
  lines.push(`## Status`);
117
89
  lines.push(`✅ DB accessible`);
118
90
  lines.push(`✅ Schema valid`);
119
- lines.push(`✅ Lock file checked`);
120
91
 
121
92
  if (walExists || shmExists) {
122
93
  lines.push(`⚠️ WAL/SHM files present - indicates unclean shutdown or active transaction`);
@@ -15,7 +15,6 @@ import { createAstroRepairTool } from "./repair";
15
15
  import { createAstroHealthTool } from "./health";
16
16
  import { createAstroResetTool } from "./reset";
17
17
  import { createAstroMetricsTool } from "./metrics";
18
- import { createAstroLockStatusTool } from "./lock";
19
18
 
20
19
  import { AgentConfig } from "@opencode-ai/sdk";
21
20
 
@@ -44,8 +43,7 @@ export function createAstroTools(opts: CreateAstroToolsOptions): Record<string,
44
43
  tools.astro_spec_get = createAstroSpecGetTool({ ctx, config });
45
44
  tools.astro_health = createAstroHealthTool({ ctx, config, db });
46
45
  tools.astro_reset = createAstroResetTool({ ctx, config, db });
47
- tools.astro_metrics = createAstroMetricsTool({ ctx, config });
48
- tools.astro_lock_status = createAstroLockStatusTool({ ctx });
46
+ tools.astro_metrics = createAstroMetricsTool({ ctx, config });
49
47
 
50
48
  // Recovery tool - available even in limited mode to allow DB initialization
51
49
  tools.astro_init = createAstroInitTool({ ctx, config, runtime });
@@ -110,8 +108,7 @@ export function createAstroTools(opts: CreateAstroToolsOptions): Record<string,
110
108
  ["_astro_repair", "astro_repair"],
111
109
  ["_astro_health", "astro_health"],
112
110
  ["_astro_reset", "astro_reset"],
113
- ["_astro_metrics", "astro_metrics"],
114
- ["_astro_lock_status", "astro_lock_status"],
111
+ ["_astro_metrics", "astro_metrics"],
115
112
  ];
116
113
 
117
114
  // Only add aliases for tools that exist
@@ -6,56 +6,22 @@ import { withTx } from "../state/db";
6
6
  import { repairState, formatRepairReport } from "../workflow/repair";
7
7
  import { putArtifact } from "../workflow/artifacts";
8
8
  import { nowISO } from "../shared/time";
9
- import { getLockStatus, tryRemoveStaleLock } from "../state/repo-lock";
10
9
 
11
10
 
12
11
  export function createAstroRepairTool(opts: { ctx: any; config: AstrocodeConfig; db: SqliteDb }): ToolDefinition {
13
12
  const { ctx, config, db } = opts;
14
13
 
15
14
  return tool({
16
- description: "Repair Astrocode invariants and recover from inconsistent DB state. Also checks and repairs lock files. Writes a repair report artifact.",
15
+ description: "Repair Astrocode invariants and recover from inconsistent DB state. Writes a repair report artifact.",
17
16
  args: {
18
17
  write_report_artifact: tool.schema.boolean().default(true),
19
- repair_lock: tool.schema.boolean().default(true).describe("Attempt to remove stale/dead lock files"),
20
18
  },
21
- execute: async ({ write_report_artifact, repair_lock }) => {
19
+ execute: async ({ write_report_artifact }) => {
22
20
  const repoRoot = ctx.directory as string;
23
- const lockPath = path.join(repoRoot, ".astro", "astro.lock");
24
21
 
25
- // First, check and repair lock if requested
26
- const lockLines: string[] = [];
27
- const lockStatus = getLockStatus(lockPath);
28
-
29
- if (lockStatus.exists) {
30
- lockLines.push("## Lock Status");
31
- lockLines.push(`- Lock found: ${lockPath}`);
32
- lockLines.push(`- PID: ${lockStatus.pid} (${lockStatus.pidAlive ? 'alive' : 'dead'})`);
33
- lockLines.push(`- Age: ${lockStatus.ageMs ? Math.floor(lockStatus.ageMs / 1000) : '?'}s`);
34
- lockLines.push(`- Status: ${lockStatus.isStale ? 'stale' : 'fresh'}`);
35
-
36
- if (repair_lock) {
37
- const result = tryRemoveStaleLock(lockPath);
38
- if (result.removed) {
39
- lockLines.push(`- **Removed**: ${result.reason}`);
40
- } else {
41
- lockLines.push(`- **Not removed**: ${result.reason}`);
42
- }
43
- } else {
44
- if (!lockStatus.pidAlive || lockStatus.isStale) {
45
- lockLines.push(`- **Recommendation**: Run with repair_lock=true to remove this ${!lockStatus.pidAlive ? 'dead' : 'stale'} lock`);
46
- }
47
- }
48
- lockLines.push("");
49
- }
50
-
51
- // Then repair database state
22
+ // Repair database state
52
23
  const report = withTx(db, () => repairState(db, config));
53
- const dbMd = formatRepairReport(report);
54
-
55
- // Combine lock and DB repair
56
- const fullMd = lockLines.length > 0
57
- ? `# Astrocode Repair Report\n\n${lockLines.join("\n")}\n${dbMd.replace(/^# Astrocode repair report\n*/i, "")}`
58
- : dbMd;
24
+ const fullMd = formatRepairReport(report);
59
25
 
60
26
  if (write_report_artifact) {
61
27
  const rel = `.astro/repair/repair_${nowISO().replace(/[:.]/g, "-")}.md`;
@@ -24,8 +24,6 @@ import { newEventId } from "../state/ids";
24
24
  import { debug } from "../shared/log";
25
25
  import { createToastManager } from "../ui/toasts";
26
26
  import type { AgentConfig } from "@opencode-ai/sdk";
27
- import { acquireRepoLock } from "../state/repo-lock";
28
- import { workflowRepoLock } from "../state/workflow-repo-lock";
29
27
 
30
28
  // Agent name mapping for case-sensitive resolution
31
29
  export const STAGE_TO_AGENT_MAP: Record<string, string> = {
@@ -188,20 +186,8 @@ export function createAstroWorkflowProceedTool(opts: { ctx: any; config: Astroco
188
186
  max_steps: tool.schema.number().int().positive().default(config.workflow.default_max_steps),
189
187
  },
190
188
  execute: async ({ mode, max_steps }) => {
191
- const repoRoot = (ctx as any).directory as string;
192
- const lockPath = path.join(repoRoot, ".astro", "astro.lock");
193
189
  const sessionId = (ctx as any).sessionID as string | undefined;
194
-
195
- return workflowRepoLock(
196
- { acquireRepoLock },
197
- {
198
- lockPath,
199
- repoRoot,
200
- sessionId,
201
- owner: "astro_workflow_proceed",
202
- advisory: true, // Advisory mode: warn instead of blocking on lock contention
203
- fn: async () => {
204
- const steps = Math.min(max_steps, config.workflow.loop_max_steps_hard_cap);
190
+ const steps = Math.min(max_steps, config.workflow.loop_max_steps_hard_cap);
205
191
 
206
192
  const actions: string[] = [];
207
193
  const warnings: string[] = [];
@@ -424,8 +410,6 @@ export function createAstroWorkflowProceedTool(opts: { ctx: any; config: Astroco
424
410
  }
425
411
 
426
412
  return lines.join("\n").trim();
427
- },
428
- });
429
413
  },
430
414
  });
431
415
  }