even-pf 0.5.1 → 0.5.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "even-pf",
3
- "version": "0.5.1",
3
+ "version": "0.5.2",
4
4
  "description": "AI-assisted responsible grading tool for programming assignments",
5
5
  "module": "src/hosts/cli-host.ts",
6
6
  "type": "module",
@@ -32,11 +32,11 @@
32
32
  "zod-defaults": "^0.2.3"
33
33
  },
34
34
  "optionalDependencies": {
35
- "even-pf-linux-x64": "0.5.1",
36
- "even-pf-linux-arm64": "0.5.1",
37
- "even-pf-windows-x64": "0.5.1",
38
- "even-pf-darwin-x64": "0.5.1",
39
- "even-pf-darwin-arm64": "0.5.1"
35
+ "even-pf-linux-x64": "0.5.2",
36
+ "even-pf-linux-arm64": "0.5.2",
37
+ "even-pf-windows-x64": "0.5.2",
38
+ "even-pf-darwin-x64": "0.5.2",
39
+ "even-pf-darwin-arm64": "0.5.2"
40
40
  },
41
41
  "files": [
42
42
  "bin/even-pf.js",
@@ -8,6 +8,7 @@ export type CommandResult = {
8
8
  /** All recognized command names — exported for tab-completion. */
9
9
  export const COMMAND_NAMES: readonly string[] = [
10
10
  "run",
11
+ "rerun",
11
12
  "clear",
12
13
  "status",
13
14
  "list",
@@ -18,7 +19,8 @@ export const COMMAND_NAMES: readonly string[] = [
18
19
  ] as const;
19
20
 
20
21
  const HELP_TEXT = `Available commands:
21
- run [slug...] Re-run workflows (all if no slug given)
22
+ run [slug...] Run workflows (all if no slug given)
23
+ rerun [slug...] Clear outputs then re-run workflows (all if no slug given)
22
24
  clear [slug...] Clear output files (all if no slug given)
23
25
  status Show in-flight workflows and output file count
24
26
  list Show all configured workflow slugs
@@ -44,6 +46,8 @@ export async function parseAndExecute(engine: Engine, rawInput: string): Promise
44
46
  switch (command) {
45
47
  case "run":
46
48
  return await handleRun(engine, args);
49
+ case "rerun":
50
+ return await handleRerun(engine, args);
47
51
  case "clear":
48
52
  return handleClear(engine, args);
49
53
  case "status":
@@ -103,6 +107,16 @@ function handleClear(engine: Engine, slugs: string[]): CommandResult {
103
107
  return { kind: "output", message: `Cleared results: ${target}` };
104
108
  }
105
109
 
110
+ async function handleRerun(engine: Engine, slugs: string[]): Promise<CommandResult> {
111
+ // Resolve output_filename prefixes from config for the matched workflows so that
112
+ // clearing uses the config-defined filename pattern rather than the raw slug args.
113
+ // This is necessary because output filenames may be abbreviated relative to the slug.
114
+ const onlySlugs = slugs.length > 0 ? slugs : undefined;
115
+ const filePatterns = engine.resolveOutputFilePatterns(onlySlugs);
116
+ engine.clearResults(filePatterns.length > 0 ? filePatterns : undefined);
117
+ return await handleRun(engine, slugs);
118
+ }
119
+
106
120
  function handleStatus(engine: Engine): CommandResult {
107
121
  const status = engine.getStatus();
108
122
  const lines: string[] = [];
@@ -141,6 +141,25 @@ export class Engine {
141
141
  this.outputViewer.clearFiles(slugFilter);
142
142
  }
143
143
 
144
+ /**
145
+ * Resolve the static filename prefix for each workflow matched by the slug filter.
146
+ * Uses the literal portion of `output_filename` before the first `[` placeholder,
147
+ * which is the stable, config-defined part of the filename regardless of runtime
148
+ * values ([seed], [model], [run], etc.).
149
+ * Pass the result to clearResults() to accurately target the right output files.
150
+ */
151
+ resolveOutputFilePatterns(slugs?: string[]): string[] {
152
+ const onlySlugs = slugs && slugs.length > 0 ? slugs : undefined;
153
+ const allWorkflows = [
154
+ ...this.applyFilters(this.config.analysis_workflows, onlySlugs),
155
+ ...this.applyFilters(this.config.testing_workflows, onlySlugs),
156
+ ];
157
+ return allWorkflows.map((w) => {
158
+ const bracketIdx = w.output_filename.indexOf("[");
159
+ return bracketIdx === -1 ? w.output_filename : w.output_filename.slice(0, bracketIdx);
160
+ });
161
+ }
162
+
144
163
  /** Return current engine state snapshot. */
145
164
  getStatus(): EngineStatus {
146
165
  return {
@@ -81,9 +81,9 @@ function completer(line: string): [string[], string] {
81
81
  return [hits, trimmed];
82
82
  }
83
83
 
84
- // Completing workflow slugs for "run" and "clear"
84
+ // Completing workflow slugs for "run", "rerun", and "clear"
85
85
  const command = parts[0]!.toLowerCase();
86
- if (command === "run" || command === "clear") {
86
+ if (command === "run" || command === "rerun" || command === "clear") {
87
87
  const partial = parts[parts.length - 1]!;
88
88
  const workflows = engine.listWorkflows();
89
89
  const allSlugs = [...workflows.analysis, ...workflows.testing];