@hilbras/omninode 2.0.0-alpha.11 → 2.0.0-alpha.12

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/dist/index.d.ts CHANGED
@@ -2391,27 +2391,55 @@ declare class RoleRegistry {
2391
2391
  /** Builds a role registry from the project configuration. */
2392
2392
  declare function buildRoleRegistry(config: AppConfig): RoleRegistry;
2393
2393
 
2394
+ /** Current on-disk schema version. */
2395
+ declare const SCHEMA_VERSION = 2;
2394
2396
  interface JsonDocument<T> {
2395
- /** Bumped when the persisted shape changes in a breaking way (v2 Phase 12). */
2396
2397
  schemaVersion?: number;
2397
2398
  items: T[];
2398
2399
  }
2400
+ type DocumentState = {
2401
+ status: "missing";
2402
+ } | {
2403
+ status: "empty";
2404
+ } | {
2405
+ status: "v1-legacy";
2406
+ } | {
2407
+ status: "current";
2408
+ schemaVersion: number;
2409
+ count: number;
2410
+ } | {
2411
+ status: "future";
2412
+ schemaVersion: number;
2413
+ } | {
2414
+ status: "corrupt";
2415
+ detail: string;
2416
+ };
2399
2417
  interface JsonFileStoreOptions {
2400
2418
  directory?: string;
2401
2419
  fileName: string;
2420
+ /** Schema version to write (defaults to the current version). */
2402
2421
  schemaVersion?: number;
2403
- /** Called when a persisted file cannot be parsed. */
2422
+ /** Called when a persisted file is corrupt (after quarantine). */
2404
2423
  onCorrupt?: (path: string, error: unknown) => void;
2405
- }
2424
+ /** Disable file moves (used by dry runs / tests that inspect in place). */
2425
+ quarantine?: boolean;
2426
+ }
2427
+ /** Durably writes a file: temp → fsync → rename → directory fsync. */
2428
+ declare function writeFileAtomic(target: string, contents: string): Promise<void>;
2429
+ /** Reads and classifies a persisted document without modifying it. */
2430
+ declare function inspectDocument(path: string): Promise<DocumentState>;
2431
+ /** Reads a document, migrating v1 shapes and quarantining corruption. */
2432
+ declare function readDocument<T>(path: string, onCorrupt?: (path: string, error: unknown) => void, quarantine?: boolean): Promise<T[]>;
2406
2433
  declare class JsonFileStore<T> {
2407
2434
  private readonly filePath;
2408
2435
  private readonly schemaVersion;
2409
2436
  private readonly onCorrupt?;
2437
+ private readonly quarantine;
2410
2438
  private readonly log;
2411
2439
  private queue;
2412
2440
  constructor(options: JsonFileStoreOptions);
2413
2441
  get path(): string;
2414
- /** All items, or [] when missing/corrupt. */
2442
+ /** All items, or [] when missing/migrated-from-v1/corrupt. */
2415
2443
  protected readAll(): Promise<T[]>;
2416
2444
  protected writeAll(items: T[]): Promise<void>;
2417
2445
  /** Serializes an async operation against this file. */
@@ -3017,11 +3045,9 @@ declare function createDefaultChatFn(providers: AppConfig["project"]["providers"
3017
3045
  declare function buildPipelineEngine(config: AppConfig, log?: Logger): PipelineEngine;
3018
3046
 
3019
3047
  /**
3020
- * Persistence layer (v2 Phase 1): one entry point to every local store.
3021
- *
3022
- * All stores are interfaces with a local JSON default
3023
- * (TaskStore, PipelineRunStore, ReportStore, PlanStore, IMemoryProvider,
3024
- * AuditSink) — see docs/API.md for the inventory and stability status.
3048
+ * Persistence layer (v2 Phase 12): one entry point to every local store,
3049
+ * the canonical storage interface names, and the migration path that upgrades
3050
+ * v1 data in place.
3025
3051
  */
3026
3052
 
3027
3053
  /** Bundles every store for a single project directory. */
@@ -3034,7 +3060,26 @@ declare class ProjectStores {
3034
3060
  readonly audit: FileAuditLog;
3035
3061
  constructor(directory?: string);
3036
3062
  }
3063
+ interface MigrationReport {
3064
+ file: string;
3065
+ state: DocumentState["status"];
3066
+ before?: number;
3067
+ after?: number;
3068
+ migrated: boolean;
3069
+ note?: string;
3070
+ }
3071
+ /** Every persisted store file OmniNode manages in a project. */
3072
+ declare const STORE_FILES: readonly ["tasks.json", "pipelines.json", "reports.json", "plans.json", "memory.json"];
3073
+ /**
3074
+ * Migration (roadmap §16): inspects every store file, reports its schema
3075
+ * state, and — unless `checkOnly` — rewrites v1 documents at the current
3076
+ * schema version. Idempotent and safe: unknown/future versions are reported,
3077
+ * never rewritten.
3078
+ */
3079
+ declare function migrateProjectStores(directory?: string, options?: {
3080
+ checkOnly?: boolean;
3081
+ }): Promise<MigrationReport[]>;
3037
3082
 
3038
- declare const OMNINODE_VERSION = "2.0.0-alpha.11";
3083
+ declare const OMNINODE_VERSION = "2.0.0-alpha.12";
3039
3084
 
3040
- export { AgentAdapterRegistry, type AgentConfig, type AgentConfigYaml, type AgentDescriptor, AgentError, type AgentInfo, type AgentInputMode, type AgentIntegrationType, AgentRegistry, type AgentStatus, type AgentTaskInput, type AgentTaskOutput, type AgentToNodeMessage, type AggregateOptions, type AggregatedFinding, type AggregatedRecommendation, type AppConfig, type AppConfigYaml, type ArtifactKind, type ArtifactPayload, type AskedQuestion, type AuditAction, type AuditEvent, type AuditSink, type ChatFn, type ChatMessage, type ChatRequest, type ChatResponse, type ChatRole, type ChatStreamChunk, type ChatUsage, type CollectionDiagnostics, type CombinedMeta, type CombinedReport, type CombinedReportFilter, type Confidence, ConfigError, type ConflictPosition, ConsoleLogSink, type CreateTaskInput, type CwdValidation, DEFAULT_MAX_OUTPUT_BYTES, type DecodeResult, type DiscoveryResult, type EnvPolicy, type EnvelopeMeta, type Evidence, type EvidenceInput, type EvidenceKind, type ExecutionRecord, type ExtractionMeta, FileAuditLog, FilePipelineRunStore, FilePlanStore, FileReportStore, FileTaskStore, type Finding, type FindingOrigin, type FindingSeverity, type FindingSource, type HelloResult, HeuristicPlanner, type HttpRequestOptions, type HttpResponse, type IAgent, type IAgentAdapter, type IChatProvider, type IMemoryProvider, type IPipelineExecutor, type IPlanner, type IProvider, type JsonDocument, JsonFileStore, type JsonFileStoreOptions, type LoadConfigOptions, LocalMemoryProvider, type LogLevel, type LogSink, Logger, type LoggerOptions, MAX_CONTEXT_CHARS, MAX_MESSAGE_BYTES, type MemoryCategory, type MemoryContextQuery, type MemoryEntry, MemoryError, type MemoryProviderConfig, type MemoryProviderMetadata, type MemoryQuery, type MemoryScope, MemoryService, type MemoryServiceOptions, type MemoryTaskContext, type MessageEnvelope, type Modality, type ModelCapabilities, type ModelFilter, type ModelInfo, ModelPlanner, ModelRegistry, type ModelStatus, type NodeToAgentMessage, OMNINODE_VERSION, OPENAI_COMPATIBLE_TYPES, type OmniHilbrasConnectionResult, OmniHilbrasProvider, OmniNodeError, type OmniNodeErrorCode, type OmniNodeErrorOptions, OpenAICompatibleProvider, PROTOCOL_V2, type PipelineConfigYaml, type PipelineDefinition, PipelineEngine, type PipelineEngineOptions, PipelineError, type PipelineRun, type PipelineRunAttempt, type PipelineRunFilter, type PipelineRunOptions, type PipelineRunStatus, type PipelineRunStore, type PipelineStep, type PipelineStepCondition, type PipelineStepConfigYaml, type PipelineStepKind, type PipelineStepRun, type Plan, type PlanFilter, type PlanJsonResult, type PlanRequest, type PlanStep, type PlanStore, type PlanValidationIssue, type PlanValidationResult, type PlannerConfigYaml, PlannerError, ProcessAgent, ProcessAgentAdapter, type Project, type ProjectConfigYaml, ProjectStores, type ProtocolAgentToNodeType, ProtocolDecoder, type ProtocolEnvelope, ProtocolError, type ProtocolMessageType, type ProtocolNodeToAgentType, ProtocolSession, type ProtocolViolation, type ProtocolViolationCode, type ProviderAuthentication, type ProviderCapability, type ProviderConfig, type ProviderConfigYaml, ProviderError, type ProviderErrorKind, type ProviderHealth, type ProviderStatus, type ProviderType, type QuestionPayload, type QuestionResponder, type RememberaConfig, RememberaMemoryProvider, type Report, type ReportArtifact, type ReportConflict, type ReportFilter, type ReportPayload, ReportService, type ReportStore, type ReportValidationIssue, type ReportValidationResult, type RoleConfigYaml, type RoleDefinition, RoleRegistry, type RunPipelineOptions, SUPPORTED_PROTOCOL_VERSIONS, type SessionIds, TERMINAL_TASK_STATUSES, type Task, type TaskContext, TaskEngine, type TaskEngineOptions, TaskError, type TaskPayload, type TaskResult, type TaskStatus, type TaskStore, type TaskStoreFilter, type WritableLike, agentConfigSchema, aggregateReports, appConfigSchema, authHeaders, buildAgentRegistry, buildChildEnv, buildHello, buildHelloAck, buildPipelineEngine, buildPlanner, buildPlannerContext, buildRoleRegistry, composeTaskText, createAgent, createDefaultChatFn, createMemoryProvider, createProvider, createTaskEngine, decodeMessage, decodeStream, defaultMetadata, defaultProjectConfigYaml, defaultSearch, describeExit, detectConflicts, encodeMessage, envelope, expandEnvRefs, extractMessage, extractReportFromText, findConfigFile, isNetworkError, isOmniNodeError, isRetryable, isSupportedProtocol, isTimeoutError, keywords, killTree, kindFromStatus, loadConfig, logger, newMessageId, normalizeEvidence, normalizeFinding, parseHello, parsePlanJson, parseRetryAfter, pipelineConfigSchema, pipelineStepConfigSchema, planJsonSchema, plannerConfigSchema, projectConfigSchema, providerConfigSchema, providerHttpError, providerTransportError, registryKey, requestJson, requireCompletion, resolveApiKey, resolveEnvPolicy, roleConfigSchema, sanitizeChunk, similar, validateEnvelope, validatePlan, validateReport, validateWorkingDirectory };
3085
+ export { AgentAdapterRegistry, type AgentConfig, type AgentConfigYaml, type AgentDescriptor, AgentError, type AgentInfo, type AgentInputMode, type AgentIntegrationType, AgentRegistry, type AgentStatus, type AgentTaskInput, type AgentTaskOutput, type AgentToNodeMessage, type AggregateOptions, type AggregatedFinding, type AggregatedRecommendation, type AppConfig, type AppConfigYaml, type ArtifactKind, type ArtifactPayload, type AskedQuestion, type AuditAction, type AuditEvent, type AuditSink, type AuditSink as AuditStore, type ChatFn, type ChatMessage, type ChatRequest, type ChatResponse, type ChatRole, type ChatStreamChunk, type ChatUsage, type CollectionDiagnostics, type CombinedMeta, type CombinedReport, type CombinedReportFilter, type Confidence, ConfigError, type ConflictPosition, ConsoleLogSink, type CreateTaskInput, type CwdValidation, DEFAULT_MAX_OUTPUT_BYTES, type DecodeResult, type DiscoveryResult, type DocumentState, type EnvPolicy, type EnvelopeMeta, type Evidence, type EvidenceInput, type EvidenceKind, type ExecutionRecord, type ExtractionMeta, FileAuditLog, FilePipelineRunStore, FilePlanStore, FileReportStore, FileTaskStore, type Finding, type FindingOrigin, type FindingSeverity, type FindingSource, type HelloResult, HeuristicPlanner, type HttpRequestOptions, type HttpResponse, type IAgent, type IAgentAdapter, type IChatProvider, type IMemoryProvider, type IPipelineExecutor, type IPlanner, type IProvider, type JsonDocument, JsonFileStore, type JsonFileStoreOptions, type LoadConfigOptions, LocalMemoryProvider, type LogLevel, type LogSink, Logger, type LoggerOptions, MAX_CONTEXT_CHARS, MAX_MESSAGE_BYTES, type MemoryCategory, type MemoryContextQuery, type MemoryEntry, MemoryError, type MemoryProviderConfig, type MemoryProviderMetadata, type MemoryQuery, type MemoryScope, MemoryService, type MemoryServiceOptions, LocalMemoryProvider as MemoryStore, type MemoryTaskContext, type MessageEnvelope, type MigrationReport, type Modality, type ModelCapabilities, type ModelFilter, type ModelInfo, ModelPlanner, ModelRegistry, type ModelStatus, type NodeToAgentMessage, OMNINODE_VERSION, OPENAI_COMPATIBLE_TYPES, type OmniHilbrasConnectionResult, OmniHilbrasProvider, OmniNodeError, type OmniNodeErrorCode, type OmniNodeErrorOptions, OpenAICompatibleProvider, PROTOCOL_V2, type PipelineConfigYaml, type PipelineDefinition, PipelineEngine, type PipelineEngineOptions, PipelineError, type PipelineRun, type PipelineRunAttempt, type PipelineRunFilter, type PipelineRunOptions, type PipelineRunStatus, type PipelineRunStore, type PipelineStep, type PipelineStepCondition, type PipelineStepConfigYaml, type PipelineStepKind, type PipelineStepRun, type PipelineRunStore as PipelineStore, type Plan, type PlanFilter, type PlanJsonResult, type PlanRequest, type PlanStep, type PlanStore, type PlanValidationIssue, type PlanValidationResult, type PlannerConfigYaml, PlannerError, ProcessAgent, ProcessAgentAdapter, type Project, type ProjectConfigYaml, ProjectStores, type ProtocolAgentToNodeType, ProtocolDecoder, type ProtocolEnvelope, ProtocolError, type ProtocolMessageType, type ProtocolNodeToAgentType, ProtocolSession, type ProtocolViolation, type ProtocolViolationCode, type ProviderAuthentication, type ProviderCapability, type ProviderConfig, type ProviderConfigYaml, ProviderError, type ProviderErrorKind, type ProviderHealth, type ProviderStatus, type ProviderType, type QuestionPayload, type QuestionResponder, type RememberaConfig, RememberaMemoryProvider, type Report, type ReportArtifact, type ReportConflict, type ReportFilter, type ReportPayload, ReportService, type ReportStore, type ReportValidationIssue, type ReportValidationResult, type RoleConfigYaml, type RoleDefinition, RoleRegistry, type RunPipelineOptions, SCHEMA_VERSION, STORE_FILES, SUPPORTED_PROTOCOL_VERSIONS, type SessionIds, TERMINAL_TASK_STATUSES, type Task, type TaskContext, TaskEngine, type TaskEngineOptions, TaskError, type TaskPayload, type TaskResult, type TaskStatus, type TaskStore, type TaskStoreFilter, type WritableLike, agentConfigSchema, aggregateReports, appConfigSchema, authHeaders, buildAgentRegistry, buildChildEnv, buildHello, buildHelloAck, buildPipelineEngine, buildPlanner, buildPlannerContext, buildRoleRegistry, composeTaskText, createAgent, createDefaultChatFn, createMemoryProvider, createProvider, createTaskEngine, decodeMessage, decodeStream, defaultMetadata, defaultProjectConfigYaml, defaultSearch, describeExit, detectConflicts, encodeMessage, envelope, expandEnvRefs, extractMessage, extractReportFromText, findConfigFile, inspectDocument, isNetworkError, isOmniNodeError, isRetryable, isSupportedProtocol, isTimeoutError, keywords, killTree, kindFromStatus, loadConfig, logger, migrateProjectStores, newMessageId, normalizeEvidence, normalizeFinding, parseHello, parsePlanJson, parseRetryAfter, pipelineConfigSchema, pipelineStepConfigSchema, planJsonSchema, plannerConfigSchema, projectConfigSchema, providerConfigSchema, providerHttpError, providerTransportError, readDocument, registryKey, requestJson, requireCompletion, resolveApiKey, resolveEnvPolicy, roleConfigSchema, sanitizeChunk, similar, validateEnvelope, validatePlan, validateReport, validateWorkingDirectory, writeFileAtomic };
package/dist/index.js CHANGED
@@ -1820,51 +1820,119 @@ function buildRoleRegistry(config) {
1820
1820
  }
1821
1821
 
1822
1822
  // src/persistence/json-file-store.ts
1823
- import { mkdir, readFile, rename, writeFile } from "fs/promises";
1823
+ import { open, mkdir, readFile, rename, stat } from "fs/promises";
1824
1824
  import { dirname } from "path";
1825
+ var SCHEMA_VERSION = 2;
1826
+ async function writeFileAtomic(target, contents) {
1827
+ const tmp = `${target}.tmp`;
1828
+ await mkdir(dirname(target), { recursive: true });
1829
+ const handle = await open(tmp, "w");
1830
+ try {
1831
+ await handle.writeFile(contents, "utf8");
1832
+ await handle.sync();
1833
+ } finally {
1834
+ await handle.close();
1835
+ }
1836
+ await rename(tmp, target);
1837
+ try {
1838
+ const dir = await open(dirname(target), "r");
1839
+ try {
1840
+ await dir.sync();
1841
+ } finally {
1842
+ await dir.close();
1843
+ }
1844
+ } catch {
1845
+ }
1846
+ }
1847
+ async function inspectDocument(path) {
1848
+ let raw;
1849
+ try {
1850
+ await stat(path);
1851
+ } catch {
1852
+ return { status: "missing" };
1853
+ }
1854
+ try {
1855
+ raw = await readFile(path, "utf8");
1856
+ } catch (error) {
1857
+ return { status: "corrupt", detail: `unreadable: ${error instanceof Error ? error.message : String(error)}` };
1858
+ }
1859
+ if (raw.trim().length === 0) return { status: "empty" };
1860
+ let parsed;
1861
+ try {
1862
+ parsed = JSON.parse(raw);
1863
+ } catch (error) {
1864
+ return { status: "corrupt", detail: error instanceof Error ? error.message : "invalid JSON" };
1865
+ }
1866
+ if (Array.isArray(parsed)) return { status: "v1-legacy" };
1867
+ if (parsed === null || typeof parsed !== "object") return { status: "corrupt", detail: "not an object" };
1868
+ const doc = parsed;
1869
+ if (!Array.isArray(doc.items)) return { status: "corrupt", detail: "missing items array" };
1870
+ const version = typeof doc.schemaVersion === "number" ? doc.schemaVersion : 1;
1871
+ if (version > SCHEMA_VERSION) return { status: "future", schemaVersion: version };
1872
+ if (version < SCHEMA_VERSION) return { status: "v1-legacy" };
1873
+ return { status: "current", schemaVersion: version, count: doc.items.length };
1874
+ }
1875
+ async function readDocument(path, onCorrupt, quarantine = true) {
1876
+ const state = await inspectDocument(path);
1877
+ if (state.status === "missing" || state.status === "empty") return [];
1878
+ if (state.status === "future") {
1879
+ const error = new Error(
1880
+ `${path} was written by a newer OmniNode (schema v${state.schemaVersion} > v${SCHEMA_VERSION})`
1881
+ );
1882
+ onCorrupt?.(path, error);
1883
+ return [];
1884
+ }
1885
+ let raw;
1886
+ try {
1887
+ raw = await readFile(path, "utf8");
1888
+ } catch (error) {
1889
+ onCorrupt?.(path, error);
1890
+ return [];
1891
+ }
1892
+ try {
1893
+ const parsed = JSON.parse(raw);
1894
+ if (Array.isArray(parsed)) return parsed;
1895
+ return parsed.items ?? [];
1896
+ } catch (error) {
1897
+ if (quarantine) {
1898
+ const quarantinePath = `${path}.corrupt-${Date.now()}`;
1899
+ try {
1900
+ await rename(path, quarantinePath);
1901
+ logger.child({ component: "persistence" }).warn(
1902
+ `Quarantined unreadable store file ${path} \u2192 ${quarantinePath}`
1903
+ );
1904
+ } catch {
1905
+ }
1906
+ }
1907
+ onCorrupt?.(path, error);
1908
+ return [];
1909
+ }
1910
+ }
1825
1911
  var JsonFileStore = class {
1826
1912
  filePath;
1827
1913
  schemaVersion;
1828
1914
  onCorrupt;
1915
+ quarantine;
1829
1916
  log;
1830
1917
  queue = Promise.resolve();
1831
1918
  constructor(options) {
1832
1919
  this.filePath = `${options.directory ?? `${process.cwd()}/.omninode`}/${options.fileName}`;
1833
- this.schemaVersion = options.schemaVersion ?? 1;
1920
+ this.schemaVersion = options.schemaVersion ?? SCHEMA_VERSION;
1834
1921
  this.onCorrupt = options.onCorrupt;
1922
+ this.quarantine = options.quarantine ?? true;
1835
1923
  this.log = logger.child({ component: "persistence", file: options.fileName });
1836
1924
  }
1837
1925
  get path() {
1838
1926
  return this.filePath;
1839
1927
  }
1840
- /** All items, or [] when missing/corrupt. */
1928
+ /** All items, or [] when missing/migrated-from-v1/corrupt. */
1841
1929
  async readAll() {
1842
- let raw;
1843
- try {
1844
- raw = await readFile(this.filePath, "utf8");
1845
- } catch {
1846
- return [];
1847
- }
1848
- try {
1849
- const parsed = JSON.parse(raw);
1850
- if (Array.isArray(parsed)) return parsed;
1851
- if (parsed !== null && typeof parsed === "object" && Array.isArray(parsed.items)) {
1852
- return parsed.items;
1853
- }
1854
- throw new Error("persisted file has an unrecognized shape");
1855
- } catch (error) {
1856
- this.log.warn(`Treating ${this.filePath} as empty \u2014 it could not be parsed.`);
1857
- this.onCorrupt?.(this.filePath, error);
1858
- return [];
1859
- }
1930
+ return readDocument(this.filePath, this.onCorrupt, this.quarantine);
1860
1931
  }
1861
1932
  async writeAll(items) {
1862
1933
  const document = { schemaVersion: this.schemaVersion, items };
1863
- const tmp = `${this.filePath}.tmp`;
1864
- await mkdir(dirname(this.filePath), { recursive: true });
1865
- await writeFile(tmp, `${JSON.stringify(document, null, 2)}
1866
- `, "utf8");
1867
- await rename(tmp, this.filePath);
1934
+ await writeFileAtomic(this.filePath, `${JSON.stringify(document, null, 2)}
1935
+ `);
1868
1936
  }
1869
1937
  /** Serializes an async operation against this file. */
1870
1938
  synchronized(operation) {
@@ -2167,7 +2235,7 @@ function sleep(ms) {
2167
2235
  }
2168
2236
 
2169
2237
  // src/audit/index.ts
2170
- import { appendFile, mkdir as mkdir2 } from "fs/promises";
2238
+ import { mkdir as mkdir2, readFile as readFile2 } from "fs/promises";
2171
2239
  import { dirname as dirname2 } from "path";
2172
2240
  var FileAuditLog = class {
2173
2241
  filePath;
@@ -2179,8 +2247,15 @@ var FileAuditLog = class {
2179
2247
  async record(event) {
2180
2248
  try {
2181
2249
  await mkdir2(dirname2(this.filePath), { recursive: true });
2182
- await appendFile(this.filePath, `${JSON.stringify(event)}
2250
+ const { open: open2 } = await import("fs/promises");
2251
+ const handle = await open2(this.filePath, "a");
2252
+ try {
2253
+ await handle.appendFile(`${JSON.stringify(event)}
2183
2254
  `, "utf8");
2255
+ await handle.sync();
2256
+ } finally {
2257
+ await handle.close();
2258
+ }
2184
2259
  } catch (error) {
2185
2260
  this.log.warn(
2186
2261
  `Audit write failed: ${error instanceof Error ? error.message : String(error)}`
@@ -2189,7 +2264,6 @@ var FileAuditLog = class {
2189
2264
  }
2190
2265
  /** Recent events, oldest first; used by the CLI. */
2191
2266
  async recent(limit = 20) {
2192
- const { readFile: readFile2 } = await import("fs/promises");
2193
2267
  let raw;
2194
2268
  try {
2195
2269
  raw = await readFile2(this.filePath, "utf8");
@@ -3976,9 +4050,59 @@ var ProjectStores = class {
3976
4050
  this.audit = new FileAuditLog(directory);
3977
4051
  }
3978
4052
  };
4053
+ var STORE_FILES = [
4054
+ "tasks.json",
4055
+ "pipelines.json",
4056
+ "reports.json",
4057
+ "plans.json",
4058
+ "memory.json"
4059
+ ];
4060
+ async function migrateProjectStores(directory = `${process.cwd()}/.omninode`, options = {}) {
4061
+ const reports = [];
4062
+ for (const file of STORE_FILES) {
4063
+ const path = `${directory}/${file}`;
4064
+ const state = await inspectDocument(path);
4065
+ if (state.status === "missing") {
4066
+ reports.push({ file, state: state.status, migrated: false });
4067
+ continue;
4068
+ }
4069
+ if (state.status === "current") {
4070
+ reports.push({ file, state: state.status, before: state.count, after: state.count, migrated: false });
4071
+ continue;
4072
+ }
4073
+ if (state.status === "future") {
4074
+ reports.push({
4075
+ file,
4076
+ state: state.status,
4077
+ migrated: false,
4078
+ note: `written by a newer OmniNode (schema v${state.schemaVersion}); not touched`
4079
+ });
4080
+ continue;
4081
+ }
4082
+ if (state.status === "corrupt") {
4083
+ reports.push({ file, state: state.status, migrated: false, note: state.detail });
4084
+ continue;
4085
+ }
4086
+ const items = await readDocument(path, void 0, false);
4087
+ if (!options.checkOnly) {
4088
+ await writeFileAtomic(path, `${JSON.stringify({ schemaVersion: SCHEMA_VERSION, items }, null, 2)}
4089
+ `);
4090
+ }
4091
+ const beforeCount = items.length;
4092
+ reports.push({
4093
+ file,
4094
+ state: state.status,
4095
+ before: beforeCount,
4096
+ after: items.length,
4097
+ migrated: !options.checkOnly,
4098
+ ...options.checkOnly ? { note: "would migrate" } : {}
4099
+ });
4100
+ }
4101
+ return reports;
4102
+ }
3979
4103
 
3980
4104
  // src/version.ts
3981
- var OMNINODE_VERSION = "2.0.0-alpha.11";
4105
+ var OMNINODE_VERSION = "2.0.0-alpha.12";
3982
4106
  export {
3983
4107
  AgentAdapterRegistry,
3984
4108
  AgentError,
@@ -4020,6 +4144,8 @@ export {
4020
4144
  RememberaMemoryProvider,
4021
4145
  ReportService,
4022
4146
  RoleRegistry,
4147
+ SCHEMA_VERSION,
4148
+ STORE_FILES,
4023
4149
  SUPPORTED_PROTOCOL_VERSIONS,
4024
4150
  TERMINAL_TASK_STATUSES,
4025
4151
  TaskEngine,
@@ -4055,6 +4181,7 @@ export {
4055
4181
  extractMessage,
4056
4182
  extractReportFromText,
4057
4183
  findConfigFile,
4184
+ inspectDocument,
4058
4185
  isNetworkError,
4059
4186
  isOmniNodeError,
4060
4187
  isRetryable,
@@ -4065,6 +4192,7 @@ export {
4065
4192
  kindFromStatus,
4066
4193
  loadConfig,
4067
4194
  logger,
4195
+ migrateProjectStores,
4068
4196
  newMessageId,
4069
4197
  normalizeEvidence,
4070
4198
  normalizeFinding,
@@ -4079,6 +4207,7 @@ export {
4079
4207
  providerConfigSchema,
4080
4208
  providerHttpError,
4081
4209
  providerTransportError,
4210
+ readDocument,
4082
4211
  registryKey,
4083
4212
  requestJson,
4084
4213
  requireCompletion,
@@ -4090,6 +4219,7 @@ export {
4090
4219
  validateEnvelope,
4091
4220
  validatePlan,
4092
4221
  validateReport,
4093
- validateWorkingDirectory
4222
+ validateWorkingDirectory,
4223
+ writeFileAtomic
4094
4224
  };
4095
4225
  //# sourceMappingURL=index.js.map