tubeless 0.2.2 → 0.2.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.
- package/README.md +5 -5
- package/dist/core/child-execution.js +8 -1
- package/dist/core/child-execution.js.map +1 -1
- package/dist/core/lifecycle.js +2 -0
- package/dist/core/lifecycle.js.map +1 -1
- package/dist/core/pipeline-execute.d.ts +2 -0
- package/dist/core/pipeline-execute.js +132 -395
- package/dist/core/pipeline-execute.js.map +1 -1
- package/dist/core/pipeline-plan.js +96 -34
- package/dist/core/pipeline-plan.js.map +1 -1
- package/dist/core/pipeline-run-state.d.ts +49 -0
- package/dist/core/pipeline-run-state.js +284 -0
- package/dist/core/pipeline-run-state.js.map +1 -0
- package/dist/core/pipeline-step-executor.d.ts +20 -0
- package/dist/core/pipeline-step-executor.js +52 -0
- package/dist/core/pipeline-step-executor.js.map +1 -0
- package/dist/core/pipeline-types.d.ts +11 -2
- package/dist/core/pipeline-types.js.map +1 -1
- package/dist/core/pipeline-validation.d.ts +6 -0
- package/dist/core/pipeline-validation.js +41 -0
- package/dist/core/pipeline-validation.js.map +1 -0
- package/dist/run-store/run-store-ndjson.js +2 -295
- package/dist/run-store/run-store-ndjson.js.map +1 -1
- package/dist/run-store/run-store-sqlite.js +91 -42
- package/dist/run-store/run-store-sqlite.js.map +1 -1
- package/dist/run-store/run-store.d.ts +3 -2
- package/dist/run-store/run-store.js +38 -195
- package/dist/run-store/run-store.js.map +1 -1
- package/dist/studio/run-store-ui-client-controller.d.ts +9 -0
- package/dist/studio/run-store-ui-client-controller.js +479 -0
- package/dist/studio/run-store-ui-client-controller.js.map +1 -0
- package/dist/studio/run-store-ui-client-form.d.ts +9 -0
- package/dist/studio/run-store-ui-client-form.js +44 -0
- package/dist/studio/run-store-ui-client-form.js.map +1 -0
- package/dist/studio/run-store-ui-client-model.d.ts +40 -0
- package/dist/studio/run-store-ui-client-model.js +211 -0
- package/dist/studio/run-store-ui-client-model.js.map +1 -0
- package/dist/studio/run-store-ui-client-source.js +1 -1
- package/dist/studio/run-store-ui-client-transport.d.ts +25 -0
- package/dist/studio/run-store-ui-client-transport.js +322 -0
- package/dist/studio/run-store-ui-client-transport.js.map +1 -0
- package/dist/studio/run-store-ui-client-views.d.ts +24 -0
- package/dist/studio/run-store-ui-client-views.js +676 -0
- package/dist/studio/run-store-ui-client-views.js.map +1 -0
- package/dist/studio/run-store-ui-client.d.ts +2 -14
- package/dist/studio/run-store-ui-client.js +7 -1360
- package/dist/studio/run-store-ui-client.js.map +1 -1
- package/dist/studio/run-store-ui-page.d.ts +1 -1
- package/dist/studio/run-store-ui.js +44 -25
- package/dist/studio/run-store-ui.js.map +1 -1
- package/dist/tracing/tracing-codec.d.ts +6 -0
- package/dist/tracing/tracing-codec.js +829 -0
- package/dist/tracing/tracing-codec.js.map +1 -0
- package/dist/tracing/tracing-constants.d.ts +4 -0
- package/dist/tracing/tracing-constants.js +5 -0
- package/dist/tracing/tracing-constants.js.map +1 -0
- package/dist/tracing/tracing-internal.js +116 -81
- package/dist/tracing/tracing-internal.js.map +1 -1
- package/dist/tracing/tracing-otel.js +19 -3
- package/dist/tracing/tracing-otel.js.map +1 -1
- package/dist/tracing/tracing.d.ts +149 -10
- package/dist/tracing/tracing.js.map +1 -1
- package/dist/workbench/workbench-history.js +8 -1
- package/dist/workbench/workbench-history.js.map +1 -1
- package/dist/workbench/workbench-ui.js +26 -6
- package/dist/workbench/workbench-ui.js.map +1 -1
- package/docs/README.md +21 -15
- package/docs/agent-guide.md +48 -35
- package/docs/agent-skills.md +59 -0
- package/docs/api-reference.md +28 -12
- package/docs/api-report.json +29 -13
- package/docs/child-pipeline-composition.md +142 -193
- package/docs/cli.md +83 -61
- package/docs/comparison.md +63 -62
- package/docs/concepts.md +210 -272
- package/docs/getting-started.md +59 -48
- package/docs/llms.txt +7 -4
- package/docs/recipes.md +21 -18
- package/docs/remote-step-composition.md +69 -74
- package/docs/studio.md +146 -71
- package/examples/catalog/pipelines/enrich.ts +2 -2
- package/examples/catalog/tubeless.project.ts +4 -2
- package/examples/host-embedding.ts +4 -5
- package/examples/remote-steps.ts +8 -5
- package/package.json +11 -10
- package/skills/tubeless/SKILL.md +83 -0
- package/skills/tubeless-make-pipeline/SKILL.md +126 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run-store-sqlite.js","sourceRoot":"","sources":["../../src/run-store/run-store-sqlite.ts"],"names":[],"mappings":"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","sourcesContent":["import { lstat, mkdir, realpath, stat } from \"node:fs/promises\";\nimport * as path from \"node:path\";\nimport { pathToFileURL } from \"node:url\";\nimport type { PipelineTraceEvent } from \"../tracing/tracing.js\";\nimport type {\n PipelineRunEventQuery,\n PipelineRunEventStore,\n StoredPipelineEvent,\n} from \"./run-store.js\";\n\ninterface SqliteStatement {\n all(...params: unknown[]): unknown[];\n run(...params: unknown[]): void;\n}\n\ninterface SqliteDatabase {\n close(): void;\n exec(sql: string): void;\n prepare?(sql: string): SqliteStatement;\n query?(sql: string): SqliteStatement;\n}\n\ninterface SqliteOpenOptions {\n create?: boolean;\n readOnly?: boolean;\n readonly?: boolean;\n readwrite?: boolean;\n}\n\ninterface SqliteModule {\n Database?: new (filename: string, options?: SqliteOpenOptions) => SqliteDatabase;\n DatabaseSync?: new (filename: string, options?: SqliteOpenOptions) => SqliteDatabase;\n}\n\ninterface StoredEventRow {\n attempt_id: string | null;\n attributes_json: string;\n duration_ms: number | null;\n error_json: string | null;\n event_name: PipelineTraceEvent[\"name\"];\n id: number | bigint;\n item_key: string | null;\n parent_run_id: string | null;\n pipeline_id: string;\n run_id: string;\n step_id: string | null;\n timestamp_ms: number | bigint;\n version: 1;\n}\n\nconst RUN_EVENT_STORE_VERSION = 1;\n/** Larger batches mean fewer commits but more tail loss on crash. */\nconst EXPORT_BATCH_SIZE = 64;\n\ntype EventRow = readonly [\n version: PipelineTraceEvent[\"version\"],\n runId: string,\n parentRunId: string | null,\n pipelineId: string,\n stepId: string | null,\n attemptId: string | null,\n itemKey: string | null,\n name: PipelineTraceEvent[\"name\"],\n timestampMs: number,\n durationMs: number | null,\n attributesJson: string,\n errorJson: string | null,\n];\n\nfunction eventRow(event: PipelineTraceEvent): EventRow {\n return [\n event.version,\n event.runId,\n event.parentRunId ?? null,\n event.pipelineId,\n event.stepId ?? null,\n event.attemptId ?? null,\n event.itemKey ?? null,\n event.name,\n event.timestampMs,\n event.durationMs ?? null,\n JSON.stringify(event.attributes),\n event.error ? JSON.stringify(event.error) : null,\n ];\n}\n\nconst RUN_EVENT_STORE_APPEND_ONLY_TRIGGERS = `\n CREATE TRIGGER IF NOT EXISTS pipeline_run_events_no_update\n BEFORE UPDATE ON pipeline_run_events\n BEGIN\n SELECT RAISE(ABORT, 'pipeline_run_events is append-only');\n END;\n\n CREATE TRIGGER IF NOT EXISTS pipeline_run_events_no_delete\n BEFORE DELETE ON pipeline_run_events\n BEGIN\n SELECT RAISE(ABORT, 'pipeline_run_events is append-only');\n END;\n`;\n\nconst RUN_EVENT_STORE_SCHEMA = `\n PRAGMA journal_mode = WAL;\n PRAGMA synchronous = NORMAL;\n PRAGMA foreign_keys = ON;\n\n CREATE TABLE IF NOT EXISTS pipeline_run_events (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n version INTEGER NOT NULL,\n run_id TEXT NOT NULL,\n parent_run_id TEXT,\n pipeline_id TEXT NOT NULL,\n step_id TEXT,\n attempt_id TEXT,\n item_key TEXT,\n event_name TEXT NOT NULL,\n timestamp_ms INTEGER NOT NULL,\n duration_ms REAL,\n attributes_json TEXT NOT NULL,\n error_json TEXT\n );\n\n CREATE INDEX IF NOT EXISTS pipeline_run_events_run_id_idx\n ON pipeline_run_events(run_id, id);\n CREATE INDEX IF NOT EXISTS pipeline_run_events_pipeline_id_idx\n ON pipeline_run_events(pipeline_id, id DESC);\n CREATE INDEX IF NOT EXISTS pipeline_run_events_timestamp_idx\n ON pipeline_run_events(timestamp_ms DESC);\n\n ${RUN_EVENT_STORE_APPEND_ONLY_TRIGGERS}\n`;\n\n/** SQLite event store plus the explicit all-history maintenance operation. */\nexport interface SqlitePipelineRunStore extends PipelineRunEventStore {\n /** Delete every recorded event and compact the database; individual mutation stays forbidden. */\n clearHistory(): void | Promise<void>;\n}\n\nfunction statement(database: SqliteDatabase, sql: string): SqliteStatement {\n const prepared = database.query?.(sql) ?? database.prepare?.(sql);\n if (!prepared) throw new Error(\"The current SQLite runtime does not support prepared queries.\");\n return prepared;\n}\n\nasync function loadSqliteModule(): Promise<SqliteModule> {\n const specifier = \"Bun\" in globalThis ? \"bun:sqlite\" : \"node:sqlite\";\n // SAFETY: The dynamic import resolves to the built-in sqlite module whose\n // runtime shape is the `SqliteModule` interface we depend on.\n return (await import(specifier)) as SqliteModule;\n}\n\nasync function openDatabase(\n filename: string,\n options: { create?: boolean; readOnly?: boolean } = {}\n): Promise<SqliteDatabase> {\n const module = await loadSqliteModule();\n const Database = module.Database ?? module.DatabaseSync;\n if (!Database) throw new Error(\"No synchronous SQLite database implementation is available.\");\n const bunSqlite = \"Bun\" in globalThis;\n const create = options.create !== false;\n const readOnly = options.readOnly === true;\n if (readOnly) {\n await sqliteAssertImmutableInspect(filename);\n const database = openReadableDatabase(\n Database,\n `${pathToFileURL(filename).href}?mode=ro&immutable=1`\n );\n try {\n await sqliteAssertImmutableInspect(filename);\n return database;\n } catch (error) {\n database.close();\n throw error;\n }\n }\n if (!create) {\n if (bunSqlite) {\n return openReadableDatabase(Database, filename, { create: false, readwrite: true });\n }\n // Node's DatabaseSync ignores `{ create: false }` and creates an empty\n // file. `mode=rw` fails closed when the path is missing.\n return openReadableDatabase(Database, `${pathToFileURL(filename).href}?mode=rw`);\n }\n return new Database(filename);\n}\n\nfunction isMissingDirectoryEntry(error: NodeJS.ErrnoException): boolean {\n return error.code === \"ENOENT\";\n}\n\nasync function sqliteSidecarExists(filename: string): Promise<boolean> {\n try {\n await stat(filename);\n return true;\n } catch (error) {\n // SAFETY: Node fs rejects with ErrnoException. Only ENOENT is a missing\n // directory entry; EACCES/EPERM and other inspect failures stay present.\n if (isMissingDirectoryEntry(error as NodeJS.ErrnoException) === false) return true;\n }\n try {\n await lstat(filename);\n return true;\n } catch (error) {\n // SAFETY: Same Node fs ErrnoException contract as the stat() branch.\n return isMissingDirectoryEntry(error as NodeJS.ErrnoException) === false;\n }\n}\n\nasync function sqliteSidecarTargets(filename: string): Promise<readonly string[]> {\n const targets: string[] = [];\n try {\n targets.push(await realpath(filename));\n } catch {\n // Missing or unresolvable; still check the given name.\n }\n if (targets.includes(filename) === false) targets.push(filename);\n return targets;\n}\n\nasync function sqliteDatabaseHasMultipleLinks(filename: string): Promise<boolean> {\n for (const target of await sqliteSidecarTargets(filename)) {\n try {\n if ((await stat(target)).nlink > 1) return true;\n } catch {\n return true;\n }\n }\n return false;\n}\n\nasync function sqliteAssertImmutableInspect(filename: string): Promise<void> {\n const pending = await sqlitePendingTransactionalSidecar(filename);\n if (pending !== undefined) {\n throw new Error(\n `${filename} has a write-ahead log or rollback journal that a read-only open cannot apply without writing a sidecar.`\n );\n }\n if (await sqliteDatabaseHasMultipleLinks(filename)) {\n throw new Error(\n `${filename} has multiple hard links; a read-only open cannot locate a writer's write-ahead log beside another name.`\n );\n }\n}\n\nasync function sqlitePendingTransactionalSidecar(filename: string): Promise<string | undefined> {\n for (const target of await sqliteSidecarTargets(filename)) {\n for (const suffix of [\"-journal\", \"-wal\"] as const) {\n const sidecar = `${target}${suffix}`;\n if ((await sqliteSidecarExists(sidecar)) === false) continue;\n try {\n if ((await stat(sidecar)).size > 0) return sidecar;\n } catch {\n return sidecar;\n }\n }\n }\n return undefined;\n}\n\nfunction openReadableDatabase(\n Database: new (filename: string, options?: SqliteOpenOptions) => SqliteDatabase,\n filename: string,\n options?: SqliteOpenOptions\n): SqliteDatabase {\n const database = options === undefined ? new Database(filename) : new Database(filename, options);\n try {\n statement(database, \"PRAGMA user_version\").all();\n return database;\n } catch (error) {\n database.close();\n throw error;\n }\n}\n\nfunction mapRow(row: StoredEventRow): StoredPipelineEvent {\n const event: StoredPipelineEvent = {\n // SAFETY: attributes_json was written by this store via JSON.stringify of a\n // PipelineTraceEvent[\"attributes\"] value, so parsing yields the same shape.\n attributes: JSON.parse(row.attributes_json) as PipelineTraceEvent[\"attributes\"],\n id: Number(row.id),\n name: row.event_name,\n pipelineId: row.pipeline_id,\n runId: row.run_id,\n timestampMs: Number(row.timestamp_ms),\n version: row.version,\n };\n if (row.attempt_id) event.attemptId = row.attempt_id;\n if (row.duration_ms !== null) event.durationMs = Number(row.duration_ms);\n if (row.error_json) {\n // SAFETY: error_json was written by this store via JSON.stringify of a\n // NonNullable<PipelineTraceEvent[\"error\"]> value, so parsing yields the same shape.\n event.error = JSON.parse(row.error_json) as NonNullable<PipelineTraceEvent[\"error\"]>;\n }\n if (row.item_key) event.itemKey = row.item_key;\n if (row.parent_run_id) event.parentRunId = row.parent_run_id;\n if (row.step_id) event.stepId = row.step_id;\n return event;\n}\n\n/** Options for `openSqlitePipelineRunStore`. */\nexport interface OpenSqlitePipelineRunStoreOptions {\n /**\n * When `false`, reject a path that is not already a versioned run store\n * and do not create parent directories or a database file.\n * Defaults to `true` so `run --store` and `ui` can create the database.\n */\n readonly initialize?: boolean;\n /**\n * Open the file without creating it or writing WAL/sidecars.\n * A leftover empty `-wal` is ignored and the main file is opened\n * immutable. A non-empty `-wal` or `-journal`, a multiply linked\n * database file, or a WAL that appears during the open or a later\n * `listEvents` is refused so pending events are not dropped.\n * `history` uses this so a supplied finished artifact can be inspected\n * without rewriting `-shm`.\n */\n readonly readOnly?: boolean;\n}\n\n/**\n * Open the optional local SQLite trace store used by `tubeless run --store`,\n * `tubeless history`, and `tubeless ui`. The main executor never imports this\n * module. `export()` buffers up to 64 events and commits them in one\n * transaction, plus on `flush()`, same-instance `listEvents`/`clearHistory`,\n * and `close()`. Other connections cannot see the unflushed tail; a crash can\n * lose it. Finished `tubeless run --store` invocations flush at completion.\n */\nexport async function openSqlitePipelineRunStore(\n filename: string,\n options: OpenSqlitePipelineRunStoreOptions = {}\n): Promise<SqlitePipelineRunStore> {\n const readOnly = options.readOnly === true;\n const initialize = options.initialize !== false && !readOnly;\n const resolvedFilename = filename === \":memory:\" ? filename : path.resolve(filename);\n if (resolvedFilename !== \":memory:\" && initialize) {\n await mkdir(path.dirname(resolvedFilename), { recursive: true });\n }\n if (resolvedFilename !== \":memory:\" && !initialize) {\n try {\n await stat(resolvedFilename);\n } catch {\n throw new Error(`${resolvedFilename} is not a pipeline run store.`);\n }\n }\n const database = await openDatabase(resolvedFilename, { create: initialize, readOnly });\n try {\n // SAFETY: `PRAGMA user_version` always returns a single row with a\n // `user_version` column, so the first result row matches this shape.\n const versionRow = statement(database, \"PRAGMA user_version\").all()[0] as\n | { user_version?: number | bigint }\n | undefined;\n const version = Number(versionRow?.user_version ?? 0);\n if (version !== 0 && version !== RUN_EVENT_STORE_VERSION) {\n throw new Error(\n `Unsupported pipeline run store schema version ${version}; expected ${RUN_EVENT_STORE_VERSION}.`\n );\n }\n if (!initialize && version !== RUN_EVENT_STORE_VERSION) {\n throw new Error(`${resolvedFilename} is not a pipeline run store.`);\n }\n if (initialize) {\n database.exec(RUN_EVENT_STORE_SCHEMA);\n database.exec(`PRAGMA user_version = ${RUN_EVENT_STORE_VERSION}`);\n }\n } catch (error) {\n database.close();\n throw error;\n }\n const insert = statement(\n database,\n `INSERT INTO pipeline_run_events (\n version, run_id, parent_run_id, pipeline_id, step_id, attempt_id, item_key,\n event_name, timestamp_ms, duration_ms, attributes_json, error_json\n ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`\n );\n let closed = false;\n let exportError: Error | undefined;\n const pending: EventRow[] = [];\n\n function drain(): void {\n if (pending.length === 0) return;\n try {\n database.exec(\"BEGIN IMMEDIATE\");\n for (const row of pending) insert.run(...row);\n database.exec(\"COMMIT\");\n pending.length = 0;\n } catch (error) {\n try {\n database.exec(\"ROLLBACK\");\n } catch {}\n exportError = error instanceof Error ? error : new Error(String(error));\n throw exportError;\n }\n }\n\n return {\n export(event) {\n if (closed) throw new Error(\"Cannot append to a closed pipeline run store.\");\n if (exportError) throw exportError;\n try {\n pending.push(eventRow(event));\n if (pending.length >= EXPORT_BATCH_SIZE) drain();\n } catch (error) {\n exportError = error instanceof Error ? error : new Error(String(error));\n throw exportError;\n }\n },\n flush() {\n if (exportError) throw exportError;\n drain();\n },\n async listEvents(query: PipelineRunEventQuery = {}) {\n if (closed) throw new Error(\"Cannot query a closed pipeline run store.\");\n drain();\n if (readOnly && resolvedFilename !== \":memory:\") {\n await sqliteAssertImmutableInspect(resolvedFilename);\n }\n const predicates: string[] = [];\n const params: unknown[] = [];\n if (query.afterId !== undefined) {\n predicates.push(\"id > ?\");\n params.push(query.afterId);\n }\n if (query.pipelineId !== undefined) {\n predicates.push(\"pipeline_id = ?\");\n params.push(query.pipelineId);\n }\n if (query.runId !== undefined) {\n predicates.push(\"run_id = ?\");\n params.push(query.runId);\n }\n const limit = Math.max(1, Math.min(100_000, Math.floor(query.limit ?? 20_000)));\n params.push(limit);\n const where = predicates.length > 0 ? `WHERE ${predicates.join(\" AND \")}` : \"\";\n // SAFETY: The SELECT * columns match the StoredEventRow interface exactly\n // (the table schema is owned by this module), so each result row is one.\n const rows = statement(\n database,\n `SELECT * FROM pipeline_run_events ${where} ORDER BY id ASC LIMIT ?`\n ).all(...params) as StoredEventRow[];\n if (readOnly && resolvedFilename !== \":memory:\") {\n await sqliteAssertImmutableInspect(resolvedFilename);\n }\n return rows.map(mapRow);\n },\n clearHistory() {\n if (closed) throw new Error(\"Cannot clear a closed pipeline run store.\");\n drain();\n try {\n database.exec(`\n BEGIN IMMEDIATE;\n DROP TRIGGER IF EXISTS pipeline_run_events_no_update;\n DROP TRIGGER IF EXISTS pipeline_run_events_no_delete;\n DELETE FROM pipeline_run_events;\n ${RUN_EVENT_STORE_APPEND_ONLY_TRIGGERS}\n COMMIT;\n `);\n } catch (error) {\n try {\n database.exec(\"ROLLBACK\");\n } catch {}\n throw error;\n }\n database.exec(\"VACUUM; PRAGMA wal_checkpoint(TRUNCATE);\");\n },\n close() {\n if (closed) return;\n closed = true;\n try {\n if (!exportError) drain();\n } catch {\n // exportError is recorded by drain; close still releases the handle.\n }\n database.close();\n if (exportError) throw exportError;\n },\n };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"run-store-sqlite.js","sourceRoot":"","sources":["../../src/run-store/run-store-sqlite.ts"],"names":[],"mappings":"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","sourcesContent":["import { lstat, mkdir, realpath, stat } from \"node:fs/promises\";\nimport * as path from \"node:path\";\nimport { pathToFileURL } from \"node:url\";\nimport { decodePipelineTraceEvent } from \"../tracing/tracing-codec.js\";\nimport type { PipelineTraceEvent } from \"../tracing/tracing.js\";\nimport type {\n PipelineRunEventQuery,\n PipelineRunEventStore,\n StoredPipelineEvent,\n} from \"./run-store.js\";\n\ninterface SqliteStatement {\n all(...params: unknown[]): unknown[];\n run(...params: unknown[]): void;\n}\n\ninterface SqliteDatabase {\n close(): void;\n exec(sql: string): void;\n prepare?(sql: string): SqliteStatement;\n query?(sql: string): SqliteStatement;\n}\n\ninterface SqliteOpenOptions {\n create?: boolean;\n readOnly?: boolean;\n readonly?: boolean;\n readwrite?: boolean;\n}\n\ninterface SqliteModule {\n Database?: new (filename: string, options?: SqliteOpenOptions) => SqliteDatabase;\n DatabaseSync?: new (filename: string, options?: SqliteOpenOptions) => SqliteDatabase;\n}\n\ninterface StoredEventRow {\n attempt_id: string | null;\n attributes_json: string;\n correlation_id?: string | null;\n duration_ms: number | null;\n error_json: string | null;\n event_name: string;\n id: number | bigint;\n item_key: string | null;\n parent_run_id: string | null;\n pipeline_id: string;\n run_id: string;\n step_id: string | null;\n timestamp_ms: number | bigint;\n version: number;\n}\n\nconst RUN_EVENT_STORE_VERSION = 2;\nconst LEGACY_RUN_EVENT_STORE_VERSION = 1;\n/** Larger batches mean fewer commits but more tail loss on crash. */\nconst EXPORT_BATCH_SIZE = 64;\n\ntype EventRow = readonly [\n version: number,\n runId: string,\n correlationId: string | null,\n parentRunId: string | null,\n pipelineId: string,\n stepId: string | null,\n attemptId: string | null,\n itemKey: string | null,\n name: string,\n timestampMs: number,\n durationMs: number | null,\n attributesJson: string,\n errorJson: string | null,\n];\n\nfunction eventRow(event: PipelineTraceEvent): EventRow {\n const canonical = decodePipelineTraceEvent(event);\n return [\n canonical.version,\n canonical.runId,\n canonical.correlationId ?? null,\n canonical.parentRunId ?? null,\n canonical.pipelineId,\n \"stepId\" in canonical ? (canonical.stepId ?? null) : null,\n \"attemptId\" in canonical ? (canonical.attemptId ?? null) : null,\n canonical.itemKey ?? null,\n canonical.name,\n canonical.timestampMs,\n \"durationMs\" in canonical ? (canonical.durationMs ?? null) : null,\n JSON.stringify(canonical.payload),\n \"error\" in canonical && canonical.error ? JSON.stringify(canonical.error) : null,\n ];\n}\n\nconst RUN_EVENT_STORE_APPEND_ONLY_TRIGGERS = `\n CREATE TRIGGER IF NOT EXISTS pipeline_run_events_no_update\n BEFORE UPDATE ON pipeline_run_events\n BEGIN\n SELECT RAISE(ABORT, 'pipeline_run_events is append-only');\n END;\n\n CREATE TRIGGER IF NOT EXISTS pipeline_run_events_no_delete\n BEFORE DELETE ON pipeline_run_events\n BEGIN\n SELECT RAISE(ABORT, 'pipeline_run_events is append-only');\n END;\n`;\n\nconst RUN_EVENT_STORE_SCHEMA = `\n PRAGMA journal_mode = WAL;\n PRAGMA synchronous = NORMAL;\n PRAGMA foreign_keys = ON;\n\n CREATE TABLE IF NOT EXISTS pipeline_run_events (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n version INTEGER NOT NULL,\n run_id TEXT NOT NULL,\n correlation_id TEXT,\n parent_run_id TEXT,\n pipeline_id TEXT NOT NULL,\n step_id TEXT,\n attempt_id TEXT,\n item_key TEXT,\n event_name TEXT NOT NULL,\n timestamp_ms INTEGER NOT NULL,\n duration_ms REAL,\n attributes_json TEXT NOT NULL,\n error_json TEXT\n );\n\n CREATE INDEX IF NOT EXISTS pipeline_run_events_run_id_idx\n ON pipeline_run_events(run_id, id);\n CREATE INDEX IF NOT EXISTS pipeline_run_events_pipeline_id_idx\n ON pipeline_run_events(pipeline_id, id DESC);\n CREATE INDEX IF NOT EXISTS pipeline_run_events_timestamp_idx\n ON pipeline_run_events(timestamp_ms DESC);\n\n ${RUN_EVENT_STORE_APPEND_ONLY_TRIGGERS}\n`;\n\n/** SQLite event store plus the explicit all-history maintenance operation. */\nexport interface SqlitePipelineRunStore extends PipelineRunEventStore {\n /** Delete every recorded event and compact the database; individual mutation stays forbidden. */\n clearHistory(): void | Promise<void>;\n}\n\nfunction statement(database: SqliteDatabase, sql: string): SqliteStatement {\n const prepared = database.query?.(sql) ?? database.prepare?.(sql);\n if (!prepared) throw new Error(\"The current SQLite runtime does not support prepared queries.\");\n return prepared;\n}\n\nfunction readStoreVersion(database: SqliteDatabase): number {\n // SAFETY: `PRAGMA user_version` always returns a single row with a\n // `user_version` column, so the first result row matches this shape.\n const versionRow = statement(database, \"PRAGMA user_version\").all()[0] as\n | { user_version?: number | bigint }\n | undefined;\n return Number(versionRow?.user_version ?? 0);\n}\n\nasync function loadSqliteModule(): Promise<SqliteModule> {\n const specifier = \"Bun\" in globalThis ? \"bun:sqlite\" : \"node:sqlite\";\n // SAFETY: The dynamic import resolves to the built-in sqlite module whose\n // runtime shape is the `SqliteModule` interface we depend on.\n return (await import(specifier)) as SqliteModule;\n}\n\nasync function openDatabase(\n filename: string,\n options: { create?: boolean; readOnly?: boolean } = {}\n): Promise<SqliteDatabase> {\n const module = await loadSqliteModule();\n const Database = module.Database ?? module.DatabaseSync;\n if (!Database) throw new Error(\"No synchronous SQLite database implementation is available.\");\n const bunSqlite = \"Bun\" in globalThis;\n const create = options.create !== false;\n const readOnly = options.readOnly === true;\n if (readOnly) {\n await sqliteAssertImmutableInspect(filename);\n const database = openReadableDatabase(\n Database,\n `${pathToFileURL(filename).href}?mode=ro&immutable=1`\n );\n try {\n await sqliteAssertImmutableInspect(filename);\n return database;\n } catch (error) {\n database.close();\n throw error;\n }\n }\n if (!create) {\n if (bunSqlite) {\n return openReadableDatabase(Database, filename, { create: false, readwrite: true });\n }\n // Node's DatabaseSync ignores `{ create: false }` and creates an empty\n // file. `mode=rw` fails closed when the path is missing.\n return openReadableDatabase(Database, `${pathToFileURL(filename).href}?mode=rw`);\n }\n return new Database(filename);\n}\n\nfunction isMissingDirectoryEntry(error: NodeJS.ErrnoException): boolean {\n return error.code === \"ENOENT\";\n}\n\nasync function sqliteSidecarExists(filename: string): Promise<boolean> {\n try {\n await stat(filename);\n return true;\n } catch (error) {\n // SAFETY: Node fs rejects with ErrnoException. Only ENOENT is a missing\n // directory entry; EACCES/EPERM and other inspect failures stay present.\n if (isMissingDirectoryEntry(error as NodeJS.ErrnoException) === false) return true;\n }\n try {\n await lstat(filename);\n return true;\n } catch (error) {\n // SAFETY: Same Node fs ErrnoException contract as the stat() branch.\n return isMissingDirectoryEntry(error as NodeJS.ErrnoException) === false;\n }\n}\n\nasync function sqliteSidecarTargets(filename: string): Promise<readonly string[]> {\n const targets: string[] = [];\n try {\n targets.push(await realpath(filename));\n } catch {\n // Missing or unresolvable; still check the given name.\n }\n if (targets.includes(filename) === false) targets.push(filename);\n return targets;\n}\n\nasync function sqliteDatabaseHasMultipleLinks(filename: string): Promise<boolean> {\n for (const target of await sqliteSidecarTargets(filename)) {\n try {\n if ((await stat(target)).nlink > 1) return true;\n } catch {\n return true;\n }\n }\n return false;\n}\n\nasync function sqliteAssertImmutableInspect(filename: string): Promise<void> {\n const pending = await sqlitePendingTransactionalSidecar(filename);\n if (pending !== undefined) {\n throw new Error(\n `${filename} has a write-ahead log or rollback journal that a read-only open cannot apply without writing a sidecar.`\n );\n }\n if (await sqliteDatabaseHasMultipleLinks(filename)) {\n throw new Error(\n `${filename} has multiple hard links; a read-only open cannot locate a writer's write-ahead log beside another name.`\n );\n }\n}\n\nasync function sqlitePendingTransactionalSidecar(filename: string): Promise<string | undefined> {\n for (const target of await sqliteSidecarTargets(filename)) {\n for (const suffix of [\"-journal\", \"-wal\"] as const) {\n const sidecar = `${target}${suffix}`;\n if ((await sqliteSidecarExists(sidecar)) === false) continue;\n try {\n if ((await stat(sidecar)).size > 0) return sidecar;\n } catch {\n return sidecar;\n }\n }\n }\n return undefined;\n}\n\nfunction openReadableDatabase(\n Database: new (filename: string, options?: SqliteOpenOptions) => SqliteDatabase,\n filename: string,\n options?: SqliteOpenOptions\n): SqliteDatabase {\n const database = options === undefined ? new Database(filename) : new Database(filename, options);\n try {\n statement(database, \"PRAGMA user_version\").all();\n return database;\n } catch (error) {\n database.close();\n throw error;\n }\n}\n\nfunction mapRow(row: StoredEventRow): StoredPipelineEvent {\n const encoded: Record<string, unknown> = {\n name: row.event_name,\n pipelineId: row.pipeline_id,\n runId: row.run_id,\n timestampMs: Number(row.timestamp_ms),\n version: row.version,\n };\n encoded[row.version === 1 ? \"attributes\" : \"payload\"] = JSON.parse(row.attributes_json);\n if (row.attempt_id) encoded.attemptId = row.attempt_id;\n if (row.correlation_id != null) encoded.correlationId = row.correlation_id;\n if (row.duration_ms !== null) encoded.durationMs = Number(row.duration_ms);\n if (row.error_json) encoded.error = JSON.parse(row.error_json);\n if (row.item_key) encoded.itemKey = row.item_key;\n if (row.parent_run_id) encoded.parentRunId = row.parent_run_id;\n if (row.step_id) encoded.stepId = row.step_id;\n return { ...decodePipelineTraceEvent(encoded), id: Number(row.id) };\n}\n\n/** Options for `openSqlitePipelineRunStore`. */\nexport interface OpenSqlitePipelineRunStoreOptions {\n /**\n * When `false`, reject a path that is not already a versioned run store\n * and do not create parent directories or a database file.\n * Defaults to `true` so `run --store` and `ui` can create the database.\n */\n readonly initialize?: boolean;\n /**\n * Open the file without creating it or writing WAL/sidecars.\n * A leftover empty `-wal` is ignored and the main file is opened\n * immutable. A non-empty `-wal` or `-journal`, a multiply linked\n * database file, or a WAL that appears during the open or a later\n * `listEvents` is refused so pending events are not dropped.\n * `history` uses this so a supplied finished artifact can be inspected\n * without rewriting `-shm`.\n */\n readonly readOnly?: boolean;\n}\n\n/**\n * Open the optional local SQLite trace store used by `tubeless run --store`,\n * `tubeless history`, and `tubeless ui`. The main executor never imports this\n * module. `export()` buffers up to 64 events and commits them in one\n * transaction, plus on `flush()`, same-instance `listEvents`/`clearHistory`,\n * and `close()`. Other connections cannot see the unflushed tail; a crash can\n * lose it. Finished `tubeless run --store` invocations flush at completion.\n */\nexport async function openSqlitePipelineRunStore(\n filename: string,\n options: OpenSqlitePipelineRunStoreOptions = {}\n): Promise<SqlitePipelineRunStore> {\n const readOnly = options.readOnly === true;\n const initialize = options.initialize !== false && !readOnly;\n const resolvedFilename = filename === \":memory:\" ? filename : path.resolve(filename);\n if (resolvedFilename !== \":memory:\" && initialize) {\n await mkdir(path.dirname(resolvedFilename), { recursive: true });\n }\n if (resolvedFilename !== \":memory:\" && !initialize) {\n try {\n await stat(resolvedFilename);\n } catch {\n throw new Error(`${resolvedFilename} is not a pipeline run store.`);\n }\n }\n const database = await openDatabase(resolvedFilename, { create: initialize, readOnly });\n let storeVersion = 0;\n try {\n const version = readStoreVersion(database);\n storeVersion = version;\n if (\n version !== 0 &&\n version !== LEGACY_RUN_EVENT_STORE_VERSION &&\n version !== RUN_EVENT_STORE_VERSION\n ) {\n throw new Error(\n `Unsupported pipeline run store schema version ${version}; expected ${RUN_EVENT_STORE_VERSION}.`\n );\n }\n if (!initialize && version === 0) {\n throw new Error(`${resolvedFilename} is not a pipeline run store.`);\n }\n if (!readOnly && version === LEGACY_RUN_EVENT_STORE_VERSION) {\n database.exec(\"PRAGMA busy_timeout = 5000\");\n database.exec(\"BEGIN IMMEDIATE\");\n try {\n const lockedVersion = readStoreVersion(database);\n if (lockedVersion === LEGACY_RUN_EVENT_STORE_VERSION) {\n database.exec(\"ALTER TABLE pipeline_run_events ADD COLUMN correlation_id TEXT\");\n database.exec(`PRAGMA user_version = ${RUN_EVENT_STORE_VERSION}`);\n storeVersion = RUN_EVENT_STORE_VERSION;\n } else if (lockedVersion === RUN_EVENT_STORE_VERSION) {\n storeVersion = lockedVersion;\n } else {\n throw new Error(\n `Unsupported pipeline run store schema version ${lockedVersion}; expected ${RUN_EVENT_STORE_VERSION}.`\n );\n }\n database.exec(\"COMMIT\");\n } catch (error) {\n try {\n database.exec(\"ROLLBACK\");\n } catch {\n // Preserve the migration failure when SQLite already ended the transaction.\n }\n throw error;\n }\n } else if (initialize) {\n database.exec(RUN_EVENT_STORE_SCHEMA);\n database.exec(`PRAGMA user_version = ${RUN_EVENT_STORE_VERSION}`);\n storeVersion = RUN_EVENT_STORE_VERSION;\n }\n } catch (error) {\n database.close();\n throw error;\n }\n const legacyReadOnly = readOnly && storeVersion === LEGACY_RUN_EVENT_STORE_VERSION;\n const insert = statement(\n database,\n legacyReadOnly\n ? `INSERT INTO pipeline_run_events (\n version, run_id, parent_run_id, pipeline_id, step_id, attempt_id, item_key,\n event_name, timestamp_ms, duration_ms, attributes_json, error_json\n ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`\n : `INSERT INTO pipeline_run_events (\n version, run_id, correlation_id, parent_run_id, pipeline_id, step_id, attempt_id,\n item_key, event_name, timestamp_ms, duration_ms, attributes_json, error_json\n ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`\n );\n let closed = false;\n let exportError: Error | undefined;\n const pending: EventRow[] = [];\n\n function drain(): void {\n if (pending.length === 0) return;\n try {\n database.exec(\"BEGIN IMMEDIATE\");\n for (const row of pending) {\n if (legacyReadOnly) {\n const [version, runId, , ...rest] = row;\n insert.run(version, runId, ...rest);\n } else insert.run(...row);\n }\n database.exec(\"COMMIT\");\n pending.length = 0;\n } catch (error) {\n try {\n database.exec(\"ROLLBACK\");\n } catch {}\n exportError = error instanceof Error ? error : new Error(String(error));\n throw exportError;\n }\n }\n\n return {\n export(event) {\n if (closed) throw new Error(\"Cannot append to a closed pipeline run store.\");\n if (exportError) throw exportError;\n try {\n pending.push(eventRow(event));\n if (pending.length >= EXPORT_BATCH_SIZE) drain();\n } catch (error) {\n exportError = error instanceof Error ? error : new Error(String(error));\n throw exportError;\n }\n },\n flush() {\n if (exportError) throw exportError;\n drain();\n },\n async listEvents(query: PipelineRunEventQuery = {}) {\n if (closed) throw new Error(\"Cannot query a closed pipeline run store.\");\n drain();\n if (readOnly && resolvedFilename !== \":memory:\") {\n await sqliteAssertImmutableInspect(resolvedFilename);\n }\n const predicates: string[] = [];\n const params: unknown[] = [];\n if (query.afterId !== undefined) {\n predicates.push(\"id > ?\");\n params.push(query.afterId);\n }\n if (query.pipelineId !== undefined) {\n predicates.push(\"pipeline_id = ?\");\n params.push(query.pipelineId);\n }\n if (query.runId !== undefined) {\n predicates.push(\"run_id = ?\");\n params.push(query.runId);\n }\n const limit = Math.max(1, Math.min(100_000, Math.floor(query.limit ?? 20_000)));\n params.push(limit);\n const where = predicates.length > 0 ? `WHERE ${predicates.join(\" AND \")}` : \"\";\n // SAFETY: The SELECT * columns match the StoredEventRow interface exactly\n // (the table schema is owned by this module), so each result row is one.\n const rows = statement(\n database,\n `SELECT * FROM pipeline_run_events ${where} ORDER BY id ASC LIMIT ?`\n ).all(...params) as StoredEventRow[];\n if (readOnly && resolvedFilename !== \":memory:\") {\n await sqliteAssertImmutableInspect(resolvedFilename);\n }\n return rows.map(mapRow);\n },\n clearHistory() {\n if (closed) throw new Error(\"Cannot clear a closed pipeline run store.\");\n drain();\n try {\n database.exec(`\n BEGIN IMMEDIATE;\n DROP TRIGGER IF EXISTS pipeline_run_events_no_update;\n DROP TRIGGER IF EXISTS pipeline_run_events_no_delete;\n DELETE FROM pipeline_run_events;\n ${RUN_EVENT_STORE_APPEND_ONLY_TRIGGERS}\n COMMIT;\n `);\n } catch (error) {\n try {\n database.exec(\"ROLLBACK\");\n } catch {}\n throw error;\n }\n database.exec(\"VACUUM; PRAGMA wal_checkpoint(TRUNCATE);\");\n },\n close() {\n if (closed) return;\n closed = true;\n try {\n if (!exportError) drain();\n } catch {\n // exportError is recorded by drain; close still releases the handle.\n }\n database.close();\n if (exportError) throw exportError;\n },\n };\n}\n"]}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { RUN_MODEL_VERSION, type PipelineRunStatus, type PipelineStepLifecycleStatus, type PipelineStepProgressDetail } from "../core/pipeline.js";
|
|
2
2
|
import type { PipelineTraceError, PipelineTraceEvent, PipelineTraceExporter } from "../tracing/tracing.js";
|
|
3
3
|
/** One trace event after it has been appended to a durable local store. */
|
|
4
|
-
export
|
|
4
|
+
export type StoredPipelineEvent = PipelineTraceEvent & {
|
|
5
5
|
/** Store-local, monotonically increasing sequence. `0` is a valid first id. */
|
|
6
6
|
id: number;
|
|
7
|
-
}
|
|
7
|
+
};
|
|
8
8
|
export interface PipelineRunEventQuery {
|
|
9
9
|
/** Return events strictly after this store-local sequence. */
|
|
10
10
|
afterId?: number;
|
|
@@ -75,6 +75,7 @@ export interface StoredPipelineStep {
|
|
|
75
75
|
status: PipelineStepLifecycleStatus;
|
|
76
76
|
}
|
|
77
77
|
export interface StoredPipelineRun {
|
|
78
|
+
correlationId?: string;
|
|
78
79
|
dryRun: boolean;
|
|
79
80
|
durationMs?: number;
|
|
80
81
|
error?: PipelineTraceError;
|
|
@@ -1,153 +1,5 @@
|
|
|
1
1
|
import { RUN_MODEL_VERSION, } from "../core/pipeline.js";
|
|
2
2
|
import { hasVisibleStepProgress } from "../core/progress.js";
|
|
3
|
-
function isStringValue(value) {
|
|
4
|
-
return typeof value === "string";
|
|
5
|
-
}
|
|
6
|
-
function isNumberValue(value) {
|
|
7
|
-
return typeof value === "number";
|
|
8
|
-
}
|
|
9
|
-
function isBooleanValue(value) {
|
|
10
|
-
return typeof value === "boolean";
|
|
11
|
-
}
|
|
12
|
-
function stringAttribute(attributes, key) {
|
|
13
|
-
const value = attributes[key];
|
|
14
|
-
return isStringValue(value) ? value : undefined;
|
|
15
|
-
}
|
|
16
|
-
function numberAttribute(attributes, key) {
|
|
17
|
-
const value = attributes[key];
|
|
18
|
-
return isNumberValue(value) ? value : undefined;
|
|
19
|
-
}
|
|
20
|
-
function booleanAttribute(attributes, key) {
|
|
21
|
-
const value = attributes[key];
|
|
22
|
-
return isBooleanValue(value) ? value : undefined;
|
|
23
|
-
}
|
|
24
|
-
function stringArrayAttribute(attributes, key) {
|
|
25
|
-
const value = stringAttribute(attributes, key);
|
|
26
|
-
if (!value)
|
|
27
|
-
return [];
|
|
28
|
-
try {
|
|
29
|
-
const parsed = JSON.parse(value);
|
|
30
|
-
return Array.isArray(parsed)
|
|
31
|
-
? parsed.filter((item) => typeof item === "string")
|
|
32
|
-
: [];
|
|
33
|
-
}
|
|
34
|
-
catch {
|
|
35
|
-
return [];
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
function parseProgressDetails(attributes) {
|
|
39
|
-
const value = stringAttribute(attributes, "details");
|
|
40
|
-
if (!value)
|
|
41
|
-
return undefined;
|
|
42
|
-
try {
|
|
43
|
-
const parsed = JSON.parse(value);
|
|
44
|
-
if (!Array.isArray(parsed))
|
|
45
|
-
return undefined;
|
|
46
|
-
const details = parsed.flatMap((item) => {
|
|
47
|
-
if (item === null || Array.isArray(item) || !(item instanceof Object))
|
|
48
|
-
return [];
|
|
49
|
-
// SAFETY: JSON.parse leaves object fields untyped; isStringValue keeps strings only.
|
|
50
|
-
const id = item.id;
|
|
51
|
-
if (!("id" in item) || !isStringValue(id) || id.length === 0)
|
|
52
|
-
return [];
|
|
53
|
-
const detail = { id: id.slice(0, 4_096) };
|
|
54
|
-
// SAFETY: parsed fields are checked by the same guards as other trace attributes.
|
|
55
|
-
const fields = item;
|
|
56
|
-
const name = fields.name;
|
|
57
|
-
if (isStringValue(name) && name)
|
|
58
|
-
detail.name = name.slice(0, 4_096);
|
|
59
|
-
for (const key of ["depth", "completed", "total"]) {
|
|
60
|
-
const number = fields[key];
|
|
61
|
-
if (isNumberValue(number) && Number.isFinite(number))
|
|
62
|
-
detail[key] = number;
|
|
63
|
-
}
|
|
64
|
-
// SAFETY: JSON.parse leaves object fields untyped; isStringValue keeps strings only.
|
|
65
|
-
const label = ("label" in item ? item.label : undefined);
|
|
66
|
-
if (isStringValue(label) && label) {
|
|
67
|
-
detail.label = label.slice(0, 4_096);
|
|
68
|
-
}
|
|
69
|
-
// SAFETY: JSON.parse leaves object fields untyped; isStringValue keeps strings only.
|
|
70
|
-
const status = ("status" in item ? item.status : undefined);
|
|
71
|
-
if (isStringValue(status) &&
|
|
72
|
-
(status === "cancelled" ||
|
|
73
|
-
status === "completed" ||
|
|
74
|
-
status === "failed" ||
|
|
75
|
-
status === "pending" ||
|
|
76
|
-
status === "running" ||
|
|
77
|
-
status === "skipped")) {
|
|
78
|
-
detail.status = status;
|
|
79
|
-
}
|
|
80
|
-
return [detail];
|
|
81
|
-
});
|
|
82
|
-
return details.length > 0 ? details.slice(0, 128) : undefined;
|
|
83
|
-
}
|
|
84
|
-
catch {
|
|
85
|
-
return undefined;
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
function parseNestedPipeline(attributes) {
|
|
89
|
-
const value = stringAttribute(attributes, "nested_pipeline");
|
|
90
|
-
if (!value)
|
|
91
|
-
return undefined;
|
|
92
|
-
try {
|
|
93
|
-
const parsed = JSON.parse(value);
|
|
94
|
-
if (parsed === null || Array.isArray(parsed) || !(parsed instanceof Object))
|
|
95
|
-
return undefined;
|
|
96
|
-
if (!("mode" in parsed) || !("pipelineId" in parsed) || !("stepIds" in parsed))
|
|
97
|
-
return undefined;
|
|
98
|
-
if (parsed.mode !== "for-each" && parsed.mode !== "single")
|
|
99
|
-
return undefined;
|
|
100
|
-
// SAFETY: JSON.parse leaves object fields untyped; isStringValue keeps strings only.
|
|
101
|
-
const pipelineId = parsed.pipelineId;
|
|
102
|
-
if (!isStringValue(pipelineId) || pipelineId.length === 0)
|
|
103
|
-
return undefined;
|
|
104
|
-
if (!Array.isArray(parsed.stepIds))
|
|
105
|
-
return undefined;
|
|
106
|
-
const stepIds = parsed.stepIds
|
|
107
|
-
.filter(isStringValue)
|
|
108
|
-
.slice(0, 128)
|
|
109
|
-
.map((item) => item.slice(0, 4_096));
|
|
110
|
-
// SAFETY: JSON.parse leaves object fields untyped; isNumberValue keeps numbers only.
|
|
111
|
-
const recorded = ("step_count" in parsed ? parsed.step_count : undefined);
|
|
112
|
-
const recordedCount = isNumberValue(recorded) && Number.isFinite(recorded) ? Math.floor(recorded) : stepIds.length;
|
|
113
|
-
return {
|
|
114
|
-
mode: parsed.mode,
|
|
115
|
-
pipelineId: pipelineId.slice(0, 4_096),
|
|
116
|
-
stepCount: Math.max(stepIds.length, recordedCount),
|
|
117
|
-
stepIds,
|
|
118
|
-
};
|
|
119
|
-
}
|
|
120
|
-
catch {
|
|
121
|
-
return undefined;
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
function parseRemote(attributes) {
|
|
125
|
-
const value = stringAttribute(attributes, "remote");
|
|
126
|
-
if (!value)
|
|
127
|
-
return undefined;
|
|
128
|
-
try {
|
|
129
|
-
const parsed = JSON.parse(value);
|
|
130
|
-
if (parsed === null || Array.isArray(parsed) || !(parsed instanceof Object))
|
|
131
|
-
return undefined;
|
|
132
|
-
if (!("engine" in parsed))
|
|
133
|
-
return undefined;
|
|
134
|
-
// SAFETY: JSON.parse returned a plain object and we confirmed an engine key exists.
|
|
135
|
-
const engine = parsed.engine;
|
|
136
|
-
if (!isStringValue(engine) || engine.length === 0)
|
|
137
|
-
return undefined;
|
|
138
|
-
const remote = { engine: engine.slice(0, 4_096) };
|
|
139
|
-
if ("target" in parsed) {
|
|
140
|
-
// SAFETY: target is optional metadata on the same parsed remote object.
|
|
141
|
-
const target = parsed.target;
|
|
142
|
-
if (isStringValue(target) && target.length > 0)
|
|
143
|
-
remote.target = target.slice(0, 4_096);
|
|
144
|
-
}
|
|
145
|
-
return remote;
|
|
146
|
-
}
|
|
147
|
-
catch {
|
|
148
|
-
return undefined;
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
3
|
function terminalStepStatus(event) {
|
|
152
4
|
switch (event.name) {
|
|
153
5
|
case "step.cancelled":
|
|
@@ -177,11 +29,10 @@ function applyRunEvent(projection, event) {
|
|
|
177
29
|
projection.logCount += 1;
|
|
178
30
|
if (!projection.retainLogs)
|
|
179
31
|
return;
|
|
180
|
-
const level = stringAttribute(event.attributes, "level");
|
|
181
32
|
const log = {
|
|
182
33
|
id: event.id,
|
|
183
|
-
level: level
|
|
184
|
-
message:
|
|
34
|
+
level: event.payload.level,
|
|
35
|
+
message: event.payload.message,
|
|
185
36
|
timestampMs: event.timestampMs,
|
|
186
37
|
};
|
|
187
38
|
if (event.attemptId)
|
|
@@ -200,14 +51,16 @@ function applyRunEvent(projection, event) {
|
|
|
200
51
|
projection.stepOrder.push(event.stepId);
|
|
201
52
|
}
|
|
202
53
|
if (event.name === "step.planned") {
|
|
203
|
-
step.name =
|
|
204
|
-
step.description =
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
54
|
+
step.name = event.payload.name;
|
|
55
|
+
step.description = event.payload.description;
|
|
56
|
+
if (event.payload.nestedPipeline) {
|
|
57
|
+
step.nestedPipeline = {
|
|
58
|
+
...event.payload.nestedPipeline,
|
|
59
|
+
stepIds: [...event.payload.nestedPipeline.stepIds],
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
if (event.payload.remote)
|
|
63
|
+
step.remote = { ...event.payload.remote };
|
|
211
64
|
return;
|
|
212
65
|
}
|
|
213
66
|
if (event.attemptId) {
|
|
@@ -222,9 +75,7 @@ function applyRunEvent(projection, event) {
|
|
|
222
75
|
step.attempt = attempt;
|
|
223
76
|
}
|
|
224
77
|
if (event.name === "step.attempted") {
|
|
225
|
-
|
|
226
|
-
if (retry !== undefined)
|
|
227
|
-
attempt.retries.push(retry);
|
|
78
|
+
attempt.retries.push(event.payload.attempt);
|
|
228
79
|
}
|
|
229
80
|
const terminal = terminalStepStatus(event);
|
|
230
81
|
if (terminal) {
|
|
@@ -236,23 +87,11 @@ function applyRunEvent(projection, event) {
|
|
|
236
87
|
if (event.name === "step.running") {
|
|
237
88
|
step.status = "running";
|
|
238
89
|
step.startedAtMs ??= event.timestampMs;
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
progress.message = message;
|
|
245
|
-
const total = numberAttribute(event.attributes, "total");
|
|
246
|
-
if (total !== undefined)
|
|
247
|
-
progress.total = total;
|
|
248
|
-
const details = parseProgressDetails(event.attributes);
|
|
249
|
-
if (details)
|
|
250
|
-
progress.details = details;
|
|
251
|
-
const detailCount = numberAttribute(event.attributes, "detail_count");
|
|
252
|
-
if (detailCount !== undefined)
|
|
253
|
-
progress.detailCount = detailCount;
|
|
254
|
-
else if (details)
|
|
255
|
-
progress.detailCount = details.length;
|
|
90
|
+
if (event.payload.progress) {
|
|
91
|
+
const progress = {
|
|
92
|
+
...event.payload.progress,
|
|
93
|
+
details: event.payload.progress.details?.map((detail) => ({ ...detail })),
|
|
94
|
+
};
|
|
256
95
|
if (!step.progress || hasVisibleStepProgress(progress))
|
|
257
96
|
step.progress = progress;
|
|
258
97
|
}
|
|
@@ -284,12 +123,12 @@ function createRunProjection(event, retainLogs = true) {
|
|
|
284
123
|
}
|
|
285
124
|
function materializeRun(projection) {
|
|
286
125
|
const { completed, eventCount, first, logs, started, stepOrder, steps } = projection;
|
|
287
|
-
const statusValue = completed
|
|
126
|
+
const statusValue = completed?.name === "pipeline.completed" ? completed.payload.status : undefined;
|
|
288
127
|
const status = statusValue === "cancelled" || statusValue === "completed" || statusValue === "failed"
|
|
289
128
|
? statusValue
|
|
290
129
|
: "running";
|
|
291
130
|
const run = {
|
|
292
|
-
dryRun:
|
|
131
|
+
dryRun: started.name === "pipeline.started" ? started.payload.dryRun : false,
|
|
293
132
|
eventCount,
|
|
294
133
|
logCount: projection.logCount,
|
|
295
134
|
logs: projection.retainLogs ? logs.map((log) => ({ ...log })) : [],
|
|
@@ -300,6 +139,8 @@ function materializeRun(projection) {
|
|
|
300
139
|
steps: stepOrder.map((stepId) => structuredClone(steps.get(stepId))),
|
|
301
140
|
version: RUN_MODEL_VERSION,
|
|
302
141
|
};
|
|
142
|
+
if (first.correlationId !== undefined)
|
|
143
|
+
run.correlationId = first.correlationId;
|
|
303
144
|
if (completed?.durationMs !== undefined)
|
|
304
145
|
run.durationMs = completed.durationMs;
|
|
305
146
|
if (completed?.error)
|
|
@@ -322,25 +163,27 @@ export function projectPipelineRun(events) {
|
|
|
322
163
|
}
|
|
323
164
|
function definitionStep(event) {
|
|
324
165
|
const step = {
|
|
325
|
-
dependencies:
|
|
326
|
-
dryRun:
|
|
166
|
+
dependencies: [...event.payload.dependencies],
|
|
167
|
+
dryRun: event.payload.dryRun,
|
|
327
168
|
id: event.stepId,
|
|
328
|
-
optionalDependencies:
|
|
329
|
-
runtimeSkipPossible:
|
|
330
|
-
skipAfterFailureOf:
|
|
169
|
+
optionalDependencies: [...event.payload.optionalDependencies],
|
|
170
|
+
runtimeSkipPossible: event.payload.runtimeSkipPossible,
|
|
171
|
+
skipAfterFailureOf: [...event.payload.skipAfterFailureOf],
|
|
331
172
|
};
|
|
332
|
-
const description =
|
|
173
|
+
const description = event.payload.description;
|
|
333
174
|
if (description)
|
|
334
175
|
step.description = description;
|
|
335
|
-
const name =
|
|
176
|
+
const name = event.payload.name;
|
|
336
177
|
if (name)
|
|
337
178
|
step.name = name;
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
179
|
+
if (event.payload.nestedPipeline) {
|
|
180
|
+
step.nestedPipeline = {
|
|
181
|
+
...event.payload.nestedPipeline,
|
|
182
|
+
stepIds: [...event.payload.nestedPipeline.stepIds],
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
if (event.payload.remote)
|
|
186
|
+
step.remote = { ...event.payload.remote };
|
|
344
187
|
return step;
|
|
345
188
|
}
|
|
346
189
|
function createPipelineProjection(event) {
|
|
@@ -370,7 +213,7 @@ function applyPipelineEvent(projection, event) {
|
|
|
370
213
|
if (event.name === "pipeline.started") {
|
|
371
214
|
projection.runStartedAtMs.set(event.runId, event.timestampMs);
|
|
372
215
|
projection.runStartedEventIds.set(event.runId, event.id);
|
|
373
|
-
projection.runTargetIds.set(event.runId,
|
|
216
|
+
projection.runTargetIds.set(event.runId, [...event.payload.targetIds]);
|
|
374
217
|
}
|
|
375
218
|
if (event.name !== "step.planned" || !event.stepId)
|
|
376
219
|
return;
|