@shipfox/client-logs 12.0.1 → 13.0.0

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.
@@ -1,2 +1,2 @@
1
1
  $ shipfox-swc
2
- Successfully compiled: 13 files with swc (251.76ms)
2
+ Successfully compiled: 13 files with swc (231.07ms)
package/CHANGELOG.md CHANGED
@@ -1,5 +1,16 @@
1
1
  # @shipfox/client-logs
2
2
 
3
+ ## 13.0.0
4
+
5
+ ### Patch Changes
6
+
7
+ - f78740d: Remove Unicode dash punctuation from package prose and source comments.
8
+ - Updated dependencies [f78740d]
9
+ - Updated dependencies [9969937]
10
+ - Updated dependencies [6adc228]
11
+ - @shipfox/api-logs-dto@12.0.0
12
+ - @shipfox/react-ui@0.4.0
13
+
3
14
  ## 12.0.1
4
15
 
5
16
  ### Patch Changes
@@ -2,7 +2,7 @@ import type { LogRecord } from './log-model.js';
2
2
  /**
3
3
  * Pure render transform for the step-log read stream. The runner emits a flat,
4
4
  * ordered NDJSON record list; `group_start`/`group_end` form a tree that the
5
- * reader reconstructs here before rendering. No React, no state one function
5
+ * reader reconstructs here before rendering. No React, no state: one function
6
6
  * over the record array.
7
7
  *
8
8
  * records[] ──▶ buildLogTree ──▶ { nodes (forest), terminated, originTs, lineCount }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/core/log-tree.ts"],"sourcesContent":["import type {LogRecord} from './log-model.js';\n\n/**\n * Pure render transform for the step-log read stream. The runner emits a flat,\n * ordered NDJSON record list; `group_start`/`group_end` form a tree that the\n * reader reconstructs here before rendering. No React, no state — one function\n * over the record array.\n *\n * records[] ──▶ buildLogTree ──▶ { nodes (forest), terminated, originTs, lineCount }\n *\n * Group closing matches `group_id` (not a blind top-of-stack pop) so a stream that\n * drops a `group_start` under backlog/gap pressure but still delivers its\n * `group_end` does not mis-nest everything after it.\n */\n\nexport type OutputLogRecord = Extract<LogRecord, {type: 'output'}>;\nexport type GroupStartLogRecord = Extract<LogRecord, {type: 'group_start'}>;\nexport type EndLogRecord = Extract<LogRecord, {type: 'end'}>;\nexport type GapLogRecord = Extract<LogRecord, {type: 'gap'}>;\nexport type CappedLogRecord = Extract<LogRecord, {type: 'capped'}>;\nexport type RunnerLostLogRecord = Extract<LogRecord, {type: 'runner_lost'}>;\nexport type AgentSessionLogRecord = Extract<LogRecord, {type: 'agent_session'}>;\nexport type MarkerLogRecord = EndLogRecord | GapLogRecord | CappedLogRecord | RunnerLostLogRecord;\n\n/**\n * Stable, unique render key in creation order. A natural key is not enough: `group_id`\n * and a marker's `(type, ts)` can both repeat among siblings once a consumer feeds a\n * concatenated multi-step/retry stream (or two markers land in the same millisecond),\n * and the append-only build order keeps `seq` stable across re-renders.\n */\nexport interface LogNodeBase {\n seq: number;\n}\n\nexport interface OutputLogNode extends LogNodeBase {\n kind: 'output';\n lineNumber: number;\n record: OutputLogRecord;\n}\n\nexport interface MarkerLogNode extends LogNodeBase {\n kind: 'marker';\n record: MarkerLogRecord;\n}\n\nexport interface GroupLogNode extends LogNodeBase {\n kind: 'group';\n record: GroupStartLogRecord;\n /** False when no matching `group_end` arrived (still streaming, or truncated). */\n closed: boolean;\n /** `group_end` timestamp when closed by its matching end, else null. */\n endTs: number | null;\n /** Precomputed: subtree contains a `runner_lost` (a genuine failure). `stderr` is a channel, not an error, so it never sets this. */\n hasError: boolean;\n /** Precomputed output-line count in the subtree, for the collapsed summary. */\n lineCount: number;\n children: LogNode[];\n}\n\nexport interface SessionLogNode extends LogNodeBase {\n kind: 'session';\n record: AgentSessionLogRecord;\n}\n\nexport type LogNode = OutputLogNode | MarkerLogNode | GroupLogNode | SessionLogNode;\n\nexport interface LogTree {\n nodes: LogNode[];\n /** The stream is closed: the records contain an `end` or a `runner_lost`. */\n terminated: boolean;\n /** First record's timestamp; the baseline for relative timestamps. Null when empty. */\n originTs: number | null;\n /** Physical output lines (one per `output` record in v1); drives the end banner. */\n lineCount: number;\n}\n\nconst TRAILING_NEWLINE = /\\r?\\n$/;\n\n/** Strips a single trailing line ending (CRLF or LF) so a line-framed record renders without a blank continuation. */\nexport function stripTrailingNewline(data: string): string {\n return data.replace(TRAILING_NEWLINE, '');\n}\n\nexport function assertNever(value: never): never {\n throw new Error(`unexpected log record type: ${JSON.stringify(value)}`);\n}\n\nexport function buildLogTree(records: readonly LogRecord[]): LogTree {\n const nodes: LogNode[] = [];\n const stack: GroupLogNode[] = [];\n let seq = 0;\n let lineNumber = 0;\n let lineCount = 0;\n let terminated = false;\n let originTs: number | null = null;\n\n const childrenOf = (): LogNode[] => stack[stack.length - 1]?.children ?? nodes;\n\n // Bubble a failure signal (a runner_lost only) to every currently-open ancestor group\n // in one pass, so `hasError` is read in O(1) at render time instead of re-walking subtrees.\n const markOpenGroupsError = (): void => {\n for (const frame of stack) frame.hasError = true;\n };\n\n for (const record of records) {\n if (originTs === null) originTs = record.ts;\n switch (record.type) {\n case 'output': {\n lineNumber += 1;\n lineCount += 1;\n for (const frame of stack) frame.lineCount += 1;\n childrenOf().push({kind: 'output', seq: seq++, lineNumber, record});\n break;\n }\n case 'group_start': {\n // Reconcile the open stack to the declared parent before nesting. `parent_group_id`\n // is the runner's stack top at emit time (null at the root), so any reader frame\n // below that parent (or every open frame, when the parent is root) is a group whose\n // own `group_end` was dropped under backlog pressure. Orphan-close those frames so a\n // dropped end never mis-parents the groups that follow. A parent whose own start was\n // dropped is not on the stack: it falls through to best-effort root placement.\n const parentId = record.parentGroupId;\n let parentIndex = -1;\n if (parentId !== null) {\n for (let i = stack.length - 1; i >= 0; i -= 1) {\n if (stack[i]?.record.groupId === parentId) {\n parentIndex = i;\n break;\n }\n }\n }\n for (let i = stack.length - 1; i > parentIndex; i -= 1) {\n const frame = stack[i];\n if (frame) frame.closed = true;\n }\n stack.length = parentIndex + 1;\n\n const group: GroupLogNode = {\n kind: 'group',\n seq: seq++,\n record,\n closed: false,\n endTs: null,\n hasError: false,\n lineCount: 0,\n children: [],\n };\n childrenOf().push(group);\n stack.push(group);\n break;\n }\n case 'group_end': {\n // Close the matching open group_id; any inner frames orphaned by a dropped\n // group_end close with it. An end with no matching open start is ignored.\n let matchIndex = -1;\n for (let i = stack.length - 1; i >= 0; i -= 1) {\n if (stack[i]?.record.groupId === record.groupId) {\n matchIndex = i;\n break;\n }\n }\n if (matchIndex !== -1) {\n for (let i = stack.length - 1; i >= matchIndex; i -= 1) {\n const frame = stack[i];\n if (frame) frame.closed = true;\n }\n const matched = stack[matchIndex];\n if (matched) matched.endTs = record.ts;\n stack.length = matchIndex;\n }\n break;\n }\n case 'end':\n case 'gap':\n case 'capped': {\n if (record.type === 'end') terminated = true;\n childrenOf().push({kind: 'marker', seq: seq++, record});\n break;\n }\n case 'runner_lost': {\n terminated = true;\n childrenOf().push({kind: 'marker', seq: seq++, record});\n markOpenGroupsError();\n break;\n }\n case 'agent_session':\n childrenOf().push({kind: 'session', seq: seq++, record});\n break;\n default:\n assertNever(record);\n }\n }\n\n return {\n nodes,\n terminated,\n originTs,\n lineCount,\n };\n}\n"],"names":["TRAILING_NEWLINE","stripTrailingNewline","data","replace","assertNever","value","Error","JSON","stringify","buildLogTree","records","nodes","stack","seq","lineNumber","lineCount","terminated","originTs","childrenOf","length","children","markOpenGroupsError","frame","hasError","record","ts","type","push","kind","parentId","parentGroupId","parentIndex","i","groupId","closed","group","endTs","matchIndex","matched"],"mappings":"AA4EA,MAAMA,mBAAmB;AAEzB,oHAAoH,GACpH,OAAO,SAASC,qBAAqBC,IAAY;IAC/C,OAAOA,KAAKC,OAAO,CAACH,kBAAkB;AACxC;AAEA,OAAO,SAASI,YAAYC,KAAY;IACtC,MAAM,IAAIC,MAAM,CAAC,4BAA4B,EAAEC,KAAKC,SAAS,CAACH,QAAQ;AACxE;AAEA,OAAO,SAASI,aAAaC,OAA6B;IACxD,MAAMC,QAAmB,EAAE;IAC3B,MAAMC,QAAwB,EAAE;IAChC,IAAIC,MAAM;IACV,IAAIC,aAAa;IACjB,IAAIC,YAAY;IAChB,IAAIC,aAAa;IACjB,IAAIC,WAA0B;IAE9B,MAAMC,aAAa,IAAiBN,KAAK,CAACA,MAAMO,MAAM,GAAG,EAAE,EAAEC,YAAYT;IAEzE,sFAAsF;IACtF,4FAA4F;IAC5F,MAAMU,sBAAsB;QAC1B,KAAK,MAAMC,SAASV,MAAOU,MAAMC,QAAQ,GAAG;IAC9C;IAEA,KAAK,MAAMC,UAAUd,QAAS;QAC5B,IAAIO,aAAa,MAAMA,WAAWO,OAAOC,EAAE;QAC3C,OAAQD,OAAOE,IAAI;YACjB,KAAK;gBAAU;oBACbZ,cAAc;oBACdC,aAAa;oBACb,KAAK,MAAMO,SAASV,MAAOU,MAAMP,SAAS,IAAI;oBAC9CG,aAAaS,IAAI,CAAC;wBAACC,MAAM;wBAAUf,KAAKA;wBAAOC;wBAAYU;oBAAM;oBACjE;gBACF;YACA,KAAK;gBAAe;oBAClB,oFAAoF;oBACpF,iFAAiF;oBACjF,oFAAoF;oBACpF,qFAAqF;oBACrF,qFAAqF;oBACrF,+EAA+E;oBAC/E,MAAMK,WAAWL,OAAOM,aAAa;oBACrC,IAAIC,cAAc,CAAC;oBACnB,IAAIF,aAAa,MAAM;wBACrB,IAAK,IAAIG,IAAIpB,MAAMO,MAAM,GAAG,GAAGa,KAAK,GAAGA,KAAK,EAAG;4BAC7C,IAAIpB,KAAK,CAACoB,EAAE,EAAER,OAAOS,YAAYJ,UAAU;gCACzCE,cAAcC;gCACd;4BACF;wBACF;oBACF;oBACA,IAAK,IAAIA,IAAIpB,MAAMO,MAAM,GAAG,GAAGa,IAAID,aAAaC,KAAK,EAAG;wBACtD,MAAMV,QAAQV,KAAK,CAACoB,EAAE;wBACtB,IAAIV,OAAOA,MAAMY,MAAM,GAAG;oBAC5B;oBACAtB,MAAMO,MAAM,GAAGY,cAAc;oBAE7B,MAAMI,QAAsB;wBAC1BP,MAAM;wBACNf,KAAKA;wBACLW;wBACAU,QAAQ;wBACRE,OAAO;wBACPb,UAAU;wBACVR,WAAW;wBACXK,UAAU,EAAE;oBACd;oBACAF,aAAaS,IAAI,CAACQ;oBAClBvB,MAAMe,IAAI,CAACQ;oBACX;gBACF;YACA,KAAK;gBAAa;oBAChB,2EAA2E;oBAC3E,0EAA0E;oBAC1E,IAAIE,aAAa,CAAC;oBAClB,IAAK,IAAIL,IAAIpB,MAAMO,MAAM,GAAG,GAAGa,KAAK,GAAGA,KAAK,EAAG;wBAC7C,IAAIpB,KAAK,CAACoB,EAAE,EAAER,OAAOS,YAAYT,OAAOS,OAAO,EAAE;4BAC/CI,aAAaL;4BACb;wBACF;oBACF;oBACA,IAAIK,eAAe,CAAC,GAAG;wBACrB,IAAK,IAAIL,IAAIpB,MAAMO,MAAM,GAAG,GAAGa,KAAKK,YAAYL,KAAK,EAAG;4BACtD,MAAMV,QAAQV,KAAK,CAACoB,EAAE;4BACtB,IAAIV,OAAOA,MAAMY,MAAM,GAAG;wBAC5B;wBACA,MAAMI,UAAU1B,KAAK,CAACyB,WAAW;wBACjC,IAAIC,SAASA,QAAQF,KAAK,GAAGZ,OAAOC,EAAE;wBACtCb,MAAMO,MAAM,GAAGkB;oBACjB;oBACA;gBACF;YACA,KAAK;YACL,KAAK;YACL,KAAK;gBAAU;oBACb,IAAIb,OAAOE,IAAI,KAAK,OAAOV,aAAa;oBACxCE,aAAaS,IAAI,CAAC;wBAACC,MAAM;wBAAUf,KAAKA;wBAAOW;oBAAM;oBACrD;gBACF;YACA,KAAK;gBAAe;oBAClBR,aAAa;oBACbE,aAAaS,IAAI,CAAC;wBAACC,MAAM;wBAAUf,KAAKA;wBAAOW;oBAAM;oBACrDH;oBACA;gBACF;YACA,KAAK;gBACHH,aAAaS,IAAI,CAAC;oBAACC,MAAM;oBAAWf,KAAKA;oBAAOW;gBAAM;gBACtD;YACF;gBACEpB,YAAYoB;QAChB;IACF;IAEA,OAAO;QACLb;QACAK;QACAC;QACAF;IACF;AACF"}
1
+ {"version":3,"sources":["../../src/core/log-tree.ts"],"sourcesContent":["import type {LogRecord} from './log-model.js';\n\n/**\n * Pure render transform for the step-log read stream. The runner emits a flat,\n * ordered NDJSON record list; `group_start`/`group_end` form a tree that the\n * reader reconstructs here before rendering. No React, no state: one function\n * over the record array.\n *\n * records[] ──▶ buildLogTree ──▶ { nodes (forest), terminated, originTs, lineCount }\n *\n * Group closing matches `group_id` (not a blind top-of-stack pop) so a stream that\n * drops a `group_start` under backlog/gap pressure but still delivers its\n * `group_end` does not mis-nest everything after it.\n */\n\nexport type OutputLogRecord = Extract<LogRecord, {type: 'output'}>;\nexport type GroupStartLogRecord = Extract<LogRecord, {type: 'group_start'}>;\nexport type EndLogRecord = Extract<LogRecord, {type: 'end'}>;\nexport type GapLogRecord = Extract<LogRecord, {type: 'gap'}>;\nexport type CappedLogRecord = Extract<LogRecord, {type: 'capped'}>;\nexport type RunnerLostLogRecord = Extract<LogRecord, {type: 'runner_lost'}>;\nexport type AgentSessionLogRecord = Extract<LogRecord, {type: 'agent_session'}>;\nexport type MarkerLogRecord = EndLogRecord | GapLogRecord | CappedLogRecord | RunnerLostLogRecord;\n\n/**\n * Stable, unique render key in creation order. A natural key is not enough: `group_id`\n * and a marker's `(type, ts)` can both repeat among siblings once a consumer feeds a\n * concatenated multi-step/retry stream (or two markers land in the same millisecond),\n * and the append-only build order keeps `seq` stable across re-renders.\n */\nexport interface LogNodeBase {\n seq: number;\n}\n\nexport interface OutputLogNode extends LogNodeBase {\n kind: 'output';\n lineNumber: number;\n record: OutputLogRecord;\n}\n\nexport interface MarkerLogNode extends LogNodeBase {\n kind: 'marker';\n record: MarkerLogRecord;\n}\n\nexport interface GroupLogNode extends LogNodeBase {\n kind: 'group';\n record: GroupStartLogRecord;\n /** False when no matching `group_end` arrived (still streaming, or truncated). */\n closed: boolean;\n /** `group_end` timestamp when closed by its matching end, else null. */\n endTs: number | null;\n /** Precomputed: subtree contains a `runner_lost` (a genuine failure). `stderr` is a channel, not an error, so it never sets this. */\n hasError: boolean;\n /** Precomputed output-line count in the subtree, for the collapsed summary. */\n lineCount: number;\n children: LogNode[];\n}\n\nexport interface SessionLogNode extends LogNodeBase {\n kind: 'session';\n record: AgentSessionLogRecord;\n}\n\nexport type LogNode = OutputLogNode | MarkerLogNode | GroupLogNode | SessionLogNode;\n\nexport interface LogTree {\n nodes: LogNode[];\n /** The stream is closed: the records contain an `end` or a `runner_lost`. */\n terminated: boolean;\n /** First record's timestamp; the baseline for relative timestamps. Null when empty. */\n originTs: number | null;\n /** Physical output lines (one per `output` record in v1); drives the end banner. */\n lineCount: number;\n}\n\nconst TRAILING_NEWLINE = /\\r?\\n$/;\n\n/** Strips a single trailing line ending (CRLF or LF) so a line-framed record renders without a blank continuation. */\nexport function stripTrailingNewline(data: string): string {\n return data.replace(TRAILING_NEWLINE, '');\n}\n\nexport function assertNever(value: never): never {\n throw new Error(`unexpected log record type: ${JSON.stringify(value)}`);\n}\n\nexport function buildLogTree(records: readonly LogRecord[]): LogTree {\n const nodes: LogNode[] = [];\n const stack: GroupLogNode[] = [];\n let seq = 0;\n let lineNumber = 0;\n let lineCount = 0;\n let terminated = false;\n let originTs: number | null = null;\n\n const childrenOf = (): LogNode[] => stack[stack.length - 1]?.children ?? nodes;\n\n // Bubble a failure signal (a runner_lost only) to every currently-open ancestor group\n // in one pass, so `hasError` is read in O(1) at render time instead of re-walking subtrees.\n const markOpenGroupsError = (): void => {\n for (const frame of stack) frame.hasError = true;\n };\n\n for (const record of records) {\n if (originTs === null) originTs = record.ts;\n switch (record.type) {\n case 'output': {\n lineNumber += 1;\n lineCount += 1;\n for (const frame of stack) frame.lineCount += 1;\n childrenOf().push({kind: 'output', seq: seq++, lineNumber, record});\n break;\n }\n case 'group_start': {\n // Reconcile the open stack to the declared parent before nesting. `parent_group_id`\n // is the runner's stack top at emit time (null at the root), so any reader frame\n // below that parent (or every open frame, when the parent is root) is a group whose\n // own `group_end` was dropped under backlog pressure. Orphan-close those frames so a\n // dropped end never mis-parents the groups that follow. A parent whose own start was\n // dropped is not on the stack: it falls through to best-effort root placement.\n const parentId = record.parentGroupId;\n let parentIndex = -1;\n if (parentId !== null) {\n for (let i = stack.length - 1; i >= 0; i -= 1) {\n if (stack[i]?.record.groupId === parentId) {\n parentIndex = i;\n break;\n }\n }\n }\n for (let i = stack.length - 1; i > parentIndex; i -= 1) {\n const frame = stack[i];\n if (frame) frame.closed = true;\n }\n stack.length = parentIndex + 1;\n\n const group: GroupLogNode = {\n kind: 'group',\n seq: seq++,\n record,\n closed: false,\n endTs: null,\n hasError: false,\n lineCount: 0,\n children: [],\n };\n childrenOf().push(group);\n stack.push(group);\n break;\n }\n case 'group_end': {\n // Close the matching open group_id; any inner frames orphaned by a dropped\n // group_end close with it. An end with no matching open start is ignored.\n let matchIndex = -1;\n for (let i = stack.length - 1; i >= 0; i -= 1) {\n if (stack[i]?.record.groupId === record.groupId) {\n matchIndex = i;\n break;\n }\n }\n if (matchIndex !== -1) {\n for (let i = stack.length - 1; i >= matchIndex; i -= 1) {\n const frame = stack[i];\n if (frame) frame.closed = true;\n }\n const matched = stack[matchIndex];\n if (matched) matched.endTs = record.ts;\n stack.length = matchIndex;\n }\n break;\n }\n case 'end':\n case 'gap':\n case 'capped': {\n if (record.type === 'end') terminated = true;\n childrenOf().push({kind: 'marker', seq: seq++, record});\n break;\n }\n case 'runner_lost': {\n terminated = true;\n childrenOf().push({kind: 'marker', seq: seq++, record});\n markOpenGroupsError();\n break;\n }\n case 'agent_session':\n childrenOf().push({kind: 'session', seq: seq++, record});\n break;\n default:\n assertNever(record);\n }\n }\n\n return {\n nodes,\n terminated,\n originTs,\n lineCount,\n };\n}\n"],"names":["TRAILING_NEWLINE","stripTrailingNewline","data","replace","assertNever","value","Error","JSON","stringify","buildLogTree","records","nodes","stack","seq","lineNumber","lineCount","terminated","originTs","childrenOf","length","children","markOpenGroupsError","frame","hasError","record","ts","type","push","kind","parentId","parentGroupId","parentIndex","i","groupId","closed","group","endTs","matchIndex","matched"],"mappings":"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"}