ai-foreman 1.7.2 → 1.7.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.
@@ -4,6 +4,7 @@ import { type StepStatus } from "./foreman.js";
4
4
  import type { BuilderAdapter, BuilderAdapterOptions, EffortLevel, TurnResult } from "./adapters/types.js";
5
5
  import { type RoleBundle } from "./roles.js";
6
6
  import type { AgentRuntime } from "./runtimeAuth.js";
7
+ import type { AgentRoleDefaultsV1 } from "rafi-spec";
7
8
  export type { EffortLevel } from "./adapters/types.js";
8
9
  export declare const VALID_EFFORT: readonly EffortLevel[];
9
10
  export interface RoleBuilderOptions {
@@ -54,4 +55,5 @@ export declare function makeLogPath(projectDir: string, label: string): string;
54
55
  export declare function mergeSkills(roleSkills: readonly string[], extraSkills?: readonly string[]): string[];
55
56
  export declare function readOnlyPermissionConfig(): PermissionConfig;
56
57
  export declare function createRoleBuilder(opts: RoleBuilderOptions): Promise<RoleBuilder>;
58
+ export declare function readRoleDefaultsForExecution(projectDir: string, role: string): AgentRoleDefaultsV1 | undefined;
57
59
  export declare function runRoleInstruction(opts: RoleInstructionRunOptions): Promise<RoleInstructionRunResult>;
package/dist/agentRun.js CHANGED
@@ -1,4 +1,4 @@
1
- import { existsSync, readFileSync } from "node:fs";
1
+ import { existsSync, readFileSync, statSync } from "node:fs";
2
2
  import { join } from "node:path";
3
3
  import { loadConfig, DEFAULT_CONFIG } from "./config.js";
4
4
  import { Log } from "./log.js";
@@ -86,7 +86,7 @@ export async function createRoleBuilder(opts) {
86
86
  if (!existsSync(opts.projectDir)) {
87
87
  throw new Error(`project directory not found: ${opts.projectDir}`);
88
88
  }
89
- const saved = readRoleDefaults(opts.projectDir, opts.role);
89
+ const saved = readRoleDefaultsForExecution(opts.projectDir, opts.role);
90
90
  const configuredEffort = saved?.reasoning && saved.reasoning !== "default" ? saved.reasoning : undefined;
91
91
  const effectiveEffort = opts.effort ?? (VALID_EFFORT.includes(configuredEffort) ? configuredEffort : undefined);
92
92
  assertEffortLevel(effectiveEffort);
@@ -157,20 +157,47 @@ function phaseForRole(role) {
157
157
  return "uninstaller";
158
158
  return "builder";
159
159
  }
160
- function readRoleDefaults(projectDir, role) {
160
+ export function readRoleDefaultsForExecution(projectDir, role) {
161
161
  const path = join(projectDir, "rafi-config.yaml");
162
162
  if (!existsSync(path))
163
163
  return undefined;
164
164
  try {
165
165
  const config = parseYaml(readFileSync(path, "utf8"));
166
- return config?.agent_defaults?.version === 1
166
+ const saved = config?.agent_defaults?.version === 1
167
167
  ? config.agent_defaults.roles[role]
168
168
  : undefined;
169
+ if (!saved)
170
+ return undefined;
171
+ if (isFullyInitializedTracker(projectDir))
172
+ return saved;
173
+ const { make: _pendingMake, ...active } = saved;
174
+ return active;
169
175
  }
170
176
  catch {
171
177
  return undefined;
172
178
  }
173
179
  }
180
+ function isFullyInitializedTracker(projectDir) {
181
+ try {
182
+ const trackerPath = join(projectDir, ".tickets", "config.yaml");
183
+ const ticketsPath = join(projectDir, ".tickets", "tickets.yaml");
184
+ const statePath = join(projectDir, ".tickets", "ticket-state.sqlite");
185
+ if (!existsSync(trackerPath) || !existsSync(ticketsPath) || !existsSync(statePath))
186
+ return false;
187
+ const tracker = parseYaml(readFileSync(trackerPath, "utf8"));
188
+ if (!tracker || typeof tracker !== "object" || Array.isArray(tracker))
189
+ return false;
190
+ const tickets = parseYaml(readFileSync(ticketsPath, "utf8"));
191
+ if (!tickets || !Array.isArray(tickets.tickets))
192
+ return false;
193
+ if (!statSync(statePath).isFile())
194
+ return false;
195
+ return readFileSync(statePath).subarray(0, 16).toString("utf8") === "SQLite format 3\u0000";
196
+ }
197
+ catch {
198
+ return false;
199
+ }
200
+ }
174
201
  export async function runRoleInstruction(opts) {
175
202
  const logPath = opts.logPath ?? makeLogPath(opts.projectDir, opts.label.replace(/\s+/g, "-"));
176
203
  const log = new Log(logPath);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ai-foreman",
3
- "version": "1.7.2",
3
+ "version": "1.7.3",
4
4
  "description": "An orchestrator that keeps Codex CLI / Claude Code builders moving through their step list unattended. Part of Rafi.",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",