@caseyharalson/orrery 0.11.0 → 0.13.0

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,9 +1,15 @@
1
+ const fs = require("fs");
1
2
  const path = require("path");
2
3
 
3
- const { getPlansDir } = require("../../utils/paths");
4
+ const {
5
+ getPlansDir,
6
+ getCompletedDir,
7
+ getWorkDir
8
+ } = require("../../utils/paths");
4
9
  const { getPlanFiles, loadPlan } = require("../../orchestration/plan-loader");
5
10
  const { findPlanForCurrentBranch } = require("../../utils/plan-detect");
6
- const { getCurrentBranch } = require("../../utils/git");
11
+ const { getCurrentBranch, derivePlanId } = require("../../utils/git");
12
+ const { getLockStatus, listPlanLocks } = require("../../utils/lock");
7
13
 
8
14
  function supportsColor() {
9
15
  return Boolean(process.stdout.isTTY) && !process.env.NO_COLOR;
@@ -47,7 +53,21 @@ function resolvePlanPath(planArg) {
47
53
  if (!planArg) return null;
48
54
  if (path.isAbsolute(planArg)) return planArg;
49
55
  if (planArg.includes(path.sep)) return path.resolve(process.cwd(), planArg);
50
- return path.join(getPlansDir(), planArg);
56
+
57
+ // Build candidate filenames: exact name, then with .yaml/.yml appended
58
+ const names = [planArg];
59
+ if (!planArg.endsWith(".yaml") && !planArg.endsWith(".yml")) {
60
+ names.push(`${planArg}.yaml`, `${planArg}.yml`);
61
+ }
62
+
63
+ // Check active plans first, then completed
64
+ for (const dir of [getPlansDir(), getCompletedDir()]) {
65
+ for (const name of names) {
66
+ const candidate = path.join(dir, name);
67
+ if (fs.existsSync(candidate)) return candidate;
68
+ }
69
+ }
70
+ return path.join(getPlansDir(), planArg); // default so caller's error message still works
51
71
  }
52
72
 
53
73
  function summarizePlans(plans) {
@@ -75,6 +95,14 @@ function renderPlanList(plans) {
75
95
  function renderPlanDetail(plan) {
76
96
  const status = getPlanStatus(plan);
77
97
  console.log(`${formatStatusLabel(status)} ${plan.fileName}`);
98
+ if (plan.metadata.completed_at) {
99
+ console.log(` Completed: ${plan.metadata.completed_at}`);
100
+ }
101
+ const planId = derivePlanId(plan.fileName);
102
+ const logFile = path.join(getWorkDir(), `exec-${planId}.log`);
103
+ if (fs.existsSync(logFile)) {
104
+ console.log(` Log: ${logFile}`);
105
+ }
78
106
  for (const step of plan.steps) {
79
107
  const stepLabel = formatStatusLabel(step.status || "pending");
80
108
  const description = step.description ? ` - ${step.description}` : "";
@@ -92,12 +120,44 @@ module.exports = function registerStatusCommand(program) {
92
120
  .description("Show orchestration status for plans in the current project")
93
121
  .option("--plan <file>", "Show detailed status for a specific plan")
94
122
  .action((options) => {
123
+ // Check for active global execution
124
+ const lock = getLockStatus();
125
+ if (lock.locked) {
126
+ console.log(
127
+ `Execution in progress (PID ${lock.pid}, started ${lock.startedAt})\n`
128
+ );
129
+ } else if (lock.stale) {
130
+ console.log(
131
+ `Note: Stale lock detected (PID ${lock.pid} no longer running)\n`
132
+ );
133
+ }
134
+
135
+ // Check for per-plan executions
136
+ const planLocks = listPlanLocks();
137
+ const activePlanLocks = planLocks.filter((l) => l.active);
138
+ const stalePlanLocks = planLocks.filter((l) => l.stale);
139
+
140
+ if (activePlanLocks.length > 0) {
141
+ console.log(`Active plan executions (${activePlanLocks.length}):`);
142
+ for (const pl of activePlanLocks) {
143
+ let line = ` - ${pl.planId} (PID ${pl.pid}, started ${pl.startedAt})`;
144
+ if (pl.worktreePath) line += `\n worktree: ${pl.worktreePath}`;
145
+ console.log(line);
146
+ }
147
+ console.log();
148
+ }
149
+ if (stalePlanLocks.length > 0) {
150
+ console.log(
151
+ `Note: ${stalePlanLocks.length} stale per-plan lock(s) detected\n`
152
+ );
153
+ }
154
+
95
155
  const plansDir = getPlansDir();
96
156
  const planArg = options.plan;
97
157
 
98
158
  if (planArg) {
99
159
  const planPath = resolvePlanPath(planArg);
100
- if (!planPath || !require("fs").existsSync(planPath)) {
160
+ if (!planPath || !fs.existsSync(planPath)) {
101
161
  console.error(`Plan not found: ${planArg}`);
102
162
  process.exitCode = 1;
103
163
  return;
@@ -122,16 +182,28 @@ module.exports = function registerStatusCommand(program) {
122
182
  }
123
183
 
124
184
  const planFiles = getPlanFiles(plansDir);
125
- if (planFiles.length === 0) {
185
+ const completedDir = getCompletedDir();
186
+ const completedFiles = getPlanFiles(completedDir);
187
+
188
+ if (planFiles.length === 0 && completedFiles.length === 0) {
126
189
  console.log("No plans found");
127
190
  return;
128
191
  }
129
192
 
130
- const plans = planFiles.map((planFile) => loadPlan(planFile));
131
- const { pendingSteps, completedSteps } = summarizePlans(plans);
132
- console.log(
133
- `${plans.length} plans, ${pendingSteps} pending steps, ${completedSteps} completed`
134
- );
135
- renderPlanList(plans);
193
+ if (planFiles.length > 0) {
194
+ const plans = planFiles.map((planFile) => loadPlan(planFile));
195
+ const { pendingSteps, completedSteps } = summarizePlans(plans);
196
+ console.log(
197
+ `${plans.length} plans, ${pendingSteps} pending steps, ${completedSteps} completed`
198
+ );
199
+ renderPlanList(plans);
200
+ }
201
+
202
+ if (completedFiles.length > 0) {
203
+ if (planFiles.length > 0) console.log();
204
+ console.log(`Completed (${completedFiles.length}):`);
205
+ const completedPlans = completedFiles.map((f) => loadPlan(f));
206
+ renderPlanList(completedPlans);
207
+ }
136
208
  });
137
209
  };
package/lib/cli/index.js CHANGED
@@ -10,6 +10,7 @@ const registerResume = require("./commands/resume");
10
10
  const registerValidatePlan = require("./commands/validate-plan");
11
11
  const registerIngestPlan = require("./commands/ingest-plan");
12
12
  const registerManual = require("./commands/manual");
13
+ const registerPlansDir = require("./commands/plans-dir");
13
14
  const registerHelp = require("./commands/help");
14
15
 
15
16
  function getPackageVersion() {
@@ -36,6 +37,7 @@ function buildProgram() {
36
37
  registerValidatePlan(program);
37
38
  registerIngestPlan(program);
38
39
  registerManual(program);
40
+ registerPlansDir(program);
39
41
  registerHelp(program);
40
42
 
41
43
  program.on("command:*", (operands) => {