mirror of
https://github.com/mvschwarz/openrig.git
synced 2026-11-08 17:31:56 -10:00
fix(settings): wire fresh workspace defaults
This commit is contained in:
1 parent
cca3baada1
commit
d2243da13b
8 files changed
+72
-8
No files matched your search
@@ -160,12 +160,16 @@ function setNestedValue(obj: Record<string, unknown>, parts: string[], value: un
|
||||
// Per-subdir defaults derived from workspace.root. v0 uses canonical
|
||||
// subdir names per founder dialog (slices/ steering/ progress/ field-notes/
|
||||
// specs/). Steering is a FILE path (STEERING.md) under the steering subdir.
|
||||
// Files and Progress default to the whole workspace so a fresh
|
||||
// `rig config init-workspace` install is browsable without extra env wiring.
|
||||
export function deriveWorkspaceDefault(key: ValidKey, workspaceRoot: string): string {
|
||||
switch (key) {
|
||||
case "workspace.slices_root": return join(workspaceRoot, "slices");
|
||||
case "workspace.steering_path": return join(workspaceRoot, "steering", "STEERING.md");
|
||||
case "workspace.field_notes_root": return join(workspaceRoot, "field-notes");
|
||||
case "workspace.specs_root": return join(workspaceRoot, "specs");
|
||||
case "files.allowlist": return `workspace:${workspaceRoot}`;
|
||||
case "progress.scan_roots": return `workspace:${workspaceRoot}`;
|
||||
default: return "";
|
||||
}
|
||||
}
|
||||
@@ -175,6 +179,8 @@ const WORKSPACE_DERIVED_KEYS: ReadonlySet<ValidKey> = new Set([
|
||||
"workspace.steering_path",
|
||||
"workspace.field_notes_root",
|
||||
"workspace.specs_root",
|
||||
"files.allowlist",
|
||||
"progress.scan_roots",
|
||||
]);
|
||||
|
||||
function getDefaultValue(key: ValidKey, workspaceRoot: string): string | number | boolean {
|
||||
|
||||
@@ -92,6 +92,8 @@ describe("ConfigStore — extended namespaces (User Settings v0)", () => {
|
||||
expect(cfg.workspace.steeringPath).toBe(join(cfg.workspace.root, "steering", "STEERING.md"));
|
||||
expect(cfg.workspace.fieldNotesRoot).toBe(join(cfg.workspace.root, "field-notes"));
|
||||
expect(cfg.workspace.specsRoot).toBe(join(cfg.workspace.root, "specs"));
|
||||
expect(cfg.files.allowlist).toBe(`workspace:${cfg.workspace.root}`);
|
||||
expect(cfg.progress.scanRoots).toBe(`workspace:${cfg.workspace.root}`);
|
||||
});
|
||||
|
||||
it("setting workspace.root cascades into per-subdir defaults", () => {
|
||||
@@ -101,6 +103,8 @@ describe("ConfigStore — extended namespaces (User Settings v0)", () => {
|
||||
expect(cfg.workspace.root).toBe("/custom/ws");
|
||||
expect(cfg.workspace.slicesRoot).toBe("/custom/ws/slices");
|
||||
expect(cfg.workspace.steeringPath).toBe("/custom/ws/steering/STEERING.md");
|
||||
expect(cfg.files.allowlist).toBe("workspace:/custom/ws");
|
||||
expect(cfg.progress.scanRoots).toBe("workspace:/custom/ws");
|
||||
});
|
||||
|
||||
it("per-subdir override beats workspace.root cascade", () => {
|
||||
|
||||
@@ -118,6 +118,24 @@ export function steeringOptsFromEnv(env: NodeJS.ProcessEnv = process.env): Steer
|
||||
};
|
||||
}
|
||||
|
||||
export interface SteeringSettingsDefaults {
|
||||
workspaceRoot: string;
|
||||
workspaceSteeringPath: string;
|
||||
}
|
||||
|
||||
export function steeringOptsFromSettings(
|
||||
settings: SteeringSettingsDefaults,
|
||||
env: NodeJS.ProcessEnv = process.env,
|
||||
): SteeringComposerOpts {
|
||||
const envOpts = steeringOptsFromEnv(env);
|
||||
return {
|
||||
workspaceRoot: envOpts.workspaceRoot ?? settings.workspaceRoot,
|
||||
steeringPath: envOpts.steeringPath ?? settings.workspaceSteeringPath,
|
||||
roadmapPath: envOpts.roadmapPath ?? null,
|
||||
deliveryReadyDir: envOpts.deliveryReadyDir ?? null,
|
||||
};
|
||||
}
|
||||
|
||||
export class SteeringComposer {
|
||||
private readonly opts: Required<Omit<SteeringComposerOpts, "workspaceRoot">> & { workspaceRoot: string | null };
|
||||
|
||||
|
||||
@@ -132,6 +132,8 @@ function deriveWorkspaceDefault(key: SettingsValidKey, workspaceRoot: string): s
|
||||
case "workspace.steering_path": return path.join(workspaceRoot, "steering", "STEERING.md");
|
||||
case "workspace.field_notes_root": return path.join(workspaceRoot, "field-notes");
|
||||
case "workspace.specs_root": return path.join(workspaceRoot, "specs");
|
||||
case "files.allowlist": return `workspace:${workspaceRoot}`;
|
||||
case "progress.scan_roots": return `workspace:${workspaceRoot}`;
|
||||
default: return "";
|
||||
}
|
||||
}
|
||||
@@ -141,6 +143,8 @@ const WORKSPACE_DERIVED_KEYS: ReadonlySet<SettingsValidKey> = new Set([
|
||||
"workspace.steering_path",
|
||||
"workspace.field_notes_root",
|
||||
"workspace.specs_root",
|
||||
"files.allowlist",
|
||||
"progress.scan_roots",
|
||||
]);
|
||||
|
||||
function getDefaultValue(key: SettingsValidKey, workspaceRoot: string): string | number | boolean {
|
||||
@@ -154,8 +158,6 @@ function getDefaultValue(key: SettingsValidKey, workspaceRoot: string): string |
|
||||
case "transcripts.enabled": return true;
|
||||
case "transcripts.path": return path.join(path.dirname(DEFAULT_CONFIG_PATH), "transcripts");
|
||||
case "workspace.root": return DEFAULT_WORKSPACE_ROOT;
|
||||
case "files.allowlist": return "";
|
||||
case "progress.scan_roots": return "";
|
||||
// Preview Terminal v0 (PL-018) defaults — match cli/src/config-store.ts.
|
||||
case "ui.preview.refresh_interval_seconds": return 3;
|
||||
case "ui.preview.max_pins": return 4;
|
||||
|
||||
@@ -24,7 +24,7 @@ export function steeringRoutes(): Hono {
|
||||
if (!composer.isReady()) {
|
||||
return c.json({
|
||||
error: "steering_workspace_not_configured",
|
||||
hint: "Set OPENRIG_STEERING_WORKSPACE=/abs/path (and optionally OPENRIG_STEERING_PATH / OPENRIG_ROADMAP_PATH / OPENRIG_DELIVERY_READY_DIR for non-canonical layouts) and restart the daemon.",
|
||||
hint: "Run rig config init-workspace, or set workspace.steering_path / OPENRIG_STEERING_PATH for non-canonical layouts, then restart the daemon.",
|
||||
}, 503);
|
||||
}
|
||||
return c.json(composer.compose());
|
||||
|
||||
@@ -795,11 +795,13 @@ export async function createDaemon(opts?: DaemonOptions): Promise<DaemonResult>
|
||||
deps.progressIndexer = new ProgressIndexer({ roots: decodeProgressScanRoots(cfg.progressScanRootsRaw) });
|
||||
|
||||
// Operator Surface Reconciliation v0 — steering composer (item 1).
|
||||
// Reads workspace root + per-section overrides from env. Empty
|
||||
// workspace root → composer.isReady() = false → /api/steering
|
||||
// returns 503 with structured setup hint.
|
||||
const { SteeringComposer, steeringOptsFromEnv } = await import("./domain/steering/steering-composer.js");
|
||||
deps.steeringComposer = new SteeringComposer(steeringOptsFromEnv());
|
||||
// Reads typed workspace settings by default while preserving the
|
||||
// OPENRIG_STEERING_* env override family for non-canonical layouts.
|
||||
const { SteeringComposer, steeringOptsFromSettings } = await import("./domain/steering/steering-composer.js");
|
||||
deps.steeringComposer = new SteeringComposer(steeringOptsFromSettings({
|
||||
workspaceRoot: cfg.workspaceRoot,
|
||||
workspaceSteeringPath: cfg.workspaceSteeringPath,
|
||||
}));
|
||||
|
||||
// Workflows in Spec Library + Activation Lens v0 — active lens
|
||||
// persistence under OPENRIG_HOME/active-workflow-lens.json. Same
|
||||
|
||||
@@ -21,6 +21,7 @@ import {
|
||||
SteeringComposer,
|
||||
matchRailItemCode,
|
||||
steeringOptsFromEnv,
|
||||
steeringOptsFromSettings,
|
||||
} from "../src/domain/steering/steering-composer.js";
|
||||
|
||||
describe("Operator Surface Reconciliation v0 — matchRailItemCode", () => {
|
||||
@@ -53,6 +54,35 @@ describe("Operator Surface Reconciliation v0 — steeringOptsFromEnv", () => {
|
||||
expect(steeringOptsFromEnv({ OPENRIG_STEERING_WORKSPACE: "", RIGGED_STEERING_WORKSPACE: "/legacy" }))
|
||||
.toMatchObject({ workspaceRoot: "/legacy" });
|
||||
});
|
||||
|
||||
it("uses typed workspace settings as the fresh-install default, with env overrides still winning", () => {
|
||||
const opts = steeringOptsFromSettings(
|
||||
{
|
||||
workspaceRoot: "/Users/me/.openrig/workspace",
|
||||
workspaceSteeringPath: "/Users/me/.openrig/workspace/steering/STEERING.md",
|
||||
},
|
||||
{},
|
||||
);
|
||||
expect(opts).toMatchObject({
|
||||
workspaceRoot: "/Users/me/.openrig/workspace",
|
||||
steeringPath: "/Users/me/.openrig/workspace/steering/STEERING.md",
|
||||
});
|
||||
|
||||
const overridden = steeringOptsFromSettings(
|
||||
{
|
||||
workspaceRoot: "/Users/me/.openrig/workspace",
|
||||
workspaceSteeringPath: "/Users/me/.openrig/workspace/steering/STEERING.md",
|
||||
},
|
||||
{
|
||||
OPENRIG_STEERING_WORKSPACE: "/env/workspace",
|
||||
OPENRIG_STEERING_PATH: "/env/STEERING.md",
|
||||
},
|
||||
);
|
||||
expect(overridden).toMatchObject({
|
||||
workspaceRoot: "/env/workspace",
|
||||
steeringPath: "/env/STEERING.md",
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("Operator Surface Reconciliation v0 — SteeringComposer", () => {
|
||||
|
||||
@@ -104,6 +104,8 @@ describe("SettingsStore (User Settings v0)", () => {
|
||||
expect(cfg.workspaceSteeringPath).toBe("/custom/ws/steering/STEERING.md");
|
||||
expect(cfg.workspaceFieldNotesRoot).toBe("/custom/ws/field-notes");
|
||||
expect(cfg.workspaceSpecsRoot).toBe("/custom/ws/specs");
|
||||
expect(cfg.filesAllowlistRaw).toBe("workspace:/custom/ws");
|
||||
expect(cfg.progressScanRootsRaw).toBe("workspace:/custom/ws");
|
||||
});
|
||||
|
||||
it("per-subdir override beats the workspace.root cascade", () => {
|
||||
|
||||
Reference in new issue
Block a user