bitfab-cli 0.2.417 → 0.2.419

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.
Files changed (2) hide show
  1. package/dist/index.js +36 -12
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -28875,7 +28875,7 @@ var deleteAssertionCategory = {
28875
28875
  var generateTraceAssertions = {
28876
28876
  name: "generate_trace_assertions",
28877
28877
  title: "Generate Trace Assertions",
28878
- description: "Generate review-ready assertion drafts from what one original trace actually did. Call this when the user asks Bitfab to generate assertions, infer expected behavior from a trace, or turn a known root cause into regression checks. Bitfab reads the organization's existing assertion categories, selects the categories supported by trace evidence, and generates assertions one category at a time. The generated assertions are saved awaiting human review, so they are not checked on replays until a person approves them. Generation runs on Bitfab and this call waits up to four minutes for it. If it is still running after that, the result says so, and calling again with the same traceId and without regenerate checks on it. A trace has one generation at a time, so a repeat call joins the running or finished generation instead of spending model calls again, and regenerate while one is running joins that one too. Set regenerate to true after it finishes to archive the prior generated drafts and replace them. A failed generation is returned as an error with its reason. Human-authored assertions are never replaced. Pass guidance when the user knows what the assertions should be about, most often a root cause analysis of why the trace was wrong; it narrows the evidence and produces smaller assertions. Pass categoryIds to limit generation to those assertion categories. A replay trace id is refused because assertions belong to the original trace.",
28878
+ description: 'Generate review-ready assertion drafts from what one original trace actually did. Call this when the user asks Bitfab to generate assertions, infer expected behavior from a trace, or turn a known root cause into regression checks. Bitfab reads the organization\'s existing assertion categories, selects the categories supported by trace evidence, and generates assertions one category at a time. The generated assertions are saved awaiting human review, so they are not checked on replays until a person approves them. Read them back with get_trace_assertions and `approvalStates: ["pending"]`. Generation runs on Bitfab and this call waits up to four minutes for it. If it is still running after that, the result says so, and calling again with the same traceId and without regenerate checks on it. A trace has one generation at a time, so a repeat call joins the running or finished generation instead of spending model calls again, and regenerate while one is running joins that one too. Set regenerate to true after it finishes to archive the prior generated drafts and replace them. A failed generation is returned as an error with its reason. Human-authored assertions are never replaced. Pass guidance when the user knows what the assertions should be about, most often a root cause analysis of why the trace was wrong; it narrows the evidence and produces smaller assertions. Pass categoryIds to limit generation to those assertion categories. A replay trace id is refused because assertions belong to the original trace.',
28879
28879
  inputSchema: {
28880
28880
  traceId: external_exports.uuid().describe("The ORIGINAL trace to generate assertions for. A replay trace id is refused, and the error names the original to retry with."),
28881
28881
  guidance: external_exports.string().trim().min(1).max(1e4).optional().describe("Optional assertion guidance, such as a root cause analysis of why the trace went wrong. Use it to focus generation on the smallest assertions that would catch this failure."),
@@ -28886,7 +28886,7 @@ var generateTraceAssertions = {
28886
28886
  var saveTraceAssertions = {
28887
28887
  name: "save_trace_assertions",
28888
28888
  title: "Save Trace Assertions",
28889
- description: `Record what SHOULD happen when this trace is replayed. Bitfab stores two kinds of label on a trace. A VERDICT says how a run that already happened turned out, and that is save_agent_labels / save_human_labels. An ASSERTION, which is what this tool writes, says what a correct run looks like for THIS specific input, carries no pass/fail of its own, and is checked against a later replay once a reviewer approves it. A trace holds at most one verdict per author and any number of assertions. Call it when the user describes the right answer for a particular case, for example "this booking should have picked the 6am flight, not the 9am". This is not a verdict on a run that already happened, which is save_agent_labels, and it is not a check that applies to every trace of a function, which is save_grader. Pass \`assertion\` plus optional \`passCriteria\` / \`failCriteria\`, the same trio save_grader takes, so an assertion that proves out across many traces can later be promoted into a grader with no rewriting. \`humanNote\` stores people-only context on the assertion; preserve and return it, but never use it to judge whether a replay passed. \`assigneeEmail\` names the member who should review it, which routes the assertion to that person without deciding anything, so it never changes the approval state. Pass an entry's \`id\` to edit an existing assertion, or omit it to add a new one, so two callers adding different assertions to one trace never overwrite each other. What this tool writes is saved awaiting review, so nothing checks it yet; a reviewer approves it, in Bitfab or with \`approvalState\` on a later call here, and from then on every replay of the trace is judged against it. \`approvalState\` decides an assertion that already exists, so deciding one is \`{ id, approvalState }\` with nothing else: an omitted \`assertion\` keeps the current wording. It is refused on a new assertion, so the call that invents a claim is never the call that puts it into force. One decision covers the assertion and the category it is filed under, so set \`category_assertion_id\` and \`approvalState\` in the same entry when you are deciding both; recategorizing on a later call without deciding returns it to not reviewed, since the approval covered the old category. What it gates is whether replays check the assertion at all, so decide from the assertion and the spans it cites rather than from memory of having written it. Rewording an assertion, or changing its criteria, target, or category, returns it to not reviewed unless the same call says otherwise. Call get_trace_assertions first to find the assertion to edit and to avoid creating a duplicate, and read them back before judging a replay, where it lists the approved ones only. Up to ${MAX_ASSERTIONS_PER_REQUEST} per call.`,
28889
+ description: `Record what SHOULD happen when this trace is replayed. Bitfab stores two kinds of label on a trace. A VERDICT says how a run that already happened turned out, and that is save_agent_labels / save_human_labels. An ASSERTION, which is what this tool writes, says what a correct run looks like for THIS specific input, carries no pass/fail of its own, and is checked against a later replay once a reviewer approves it. A trace holds at most one verdict per author and any number of assertions. Call it when the user describes the right answer for a particular case, for example "this booking should have picked the 6am flight, not the 9am". This is not a verdict on a run that already happened, which is save_agent_labels, and it is not a check that applies to every trace of a function, which is save_grader. Pass \`assertion\` plus optional \`passCriteria\` / \`failCriteria\`, the same trio save_grader takes, so an assertion that proves out across many traces can later be promoted into a grader with no rewriting. \`humanNote\` stores people-only context on the assertion; preserve and return it, but never use it to judge whether a replay passed. \`assigneeEmail\` names the member who should review it, which routes the assertion to that person without deciding anything, so it never changes the approval state. Pass an entry's \`id\` to edit an existing assertion, or omit it to add a new one, so two callers adding different assertions to one trace never overwrite each other. What this tool writes is saved awaiting review, so nothing checks it yet; a reviewer approves it, in Bitfab or with \`approvalState\` on a later call here, and from then on every replay of the trace is judged against it. \`approvalState\` decides an assertion that already exists, so deciding one is \`{ id, approvalState }\` with nothing else: an omitted \`assertion\` keeps the current wording. It is refused on a new assertion, so the call that invents a claim is never the call that puts it into force. One decision covers the assertion and the category it is filed under, so set \`category_assertion_id\` and \`approvalState\` in the same entry when you are deciding both; recategorizing on a later call without deciding returns it to not reviewed, since the approval covered the old category. What it gates is whether replays check the assertion at all, so decide from the assertion and the spans it cites rather than from memory of having written it. Rewording an assertion, or changing its criteria, target, or category, returns it to not reviewed unless the same call says otherwise. Call get_trace_assertions first to find the assertion to edit and to avoid creating a duplicate, and read them back before judging a replay, where it lists the approved ones by default. Pass it \`approvalStates: ["pending"]\` to read back drafts awaiting review, including the ones you just wrote. Up to ${MAX_ASSERTIONS_PER_REQUEST} per call.`,
28890
28890
  inputSchema: {
28891
28891
  traceId: external_exports.uuid().describe("The ORIGINAL trace to attach assertions to. A replay trace id is refused, and the error names the original to retry with, because a replay reads its original's assertions automatically."),
28892
28892
  assertions: external_exports.preprocess(parseJsonString, external_exports.array(external_exports.object({
@@ -28907,9 +28907,22 @@ var saveTraceAssertions = {
28907
28907
  var getTraceAssertions = {
28908
28908
  name: "get_trace_assertions",
28909
28909
  title: "Get Trace Assertions",
28910
- description: `Read what SHOULD happen when one or more traces are replayed: each trace's approved assertions, their pass/fail criteria, people-only human note, who is assigned to review each one, and what part of the evaluated trace each one checks. Only assertions a person has approved are returned, because only those are checked on a replay; a trace whose assertions are all still awaiting review reads the same as one with none. Each trace also reports its assertion generation, if one ran: running, completed with how many drafts it saved for review, or failed with the reason. Categorized assertions include category_assertion_id and the category's id, title, and description. A human note is returned so it can be read and edited, but it is never assessment evidence: judge only from the assertion, pass/fail criteria, and evaluated trace. Call this before judging a replay so the verdict is measured against what the user actually asked for rather than a guess, and before save_trace_assertions to find the assertion to edit or to avoid creating a duplicate. No span content is loaded, so one call accepts up to ${GET_TRACE_ASSERTIONS_MAX_IDS} ids. Accepts original trace ids and replay trace ids alike: a replay with no assertions of its own reads its original's, and the response says which original they came from. An assertion whose target cannot be found on the trace being evaluated is errored, never passed, so record it with save_agent_labels \`skip\` rather than a FAIL.`,
28910
+ description: `Read what SHOULD happen when one or more traces are replayed: each trace's assertions, their review state, their pass/fail criteria, people-only human note, who is assigned to review each one, and what part of the evaluated trace each one checks. By default only assertions a person has approved are returned, because only those are checked on a replay; a trace whose assertions are all still awaiting review reads the same as one with none. Pass \`approvalStates\` to read other review states: \`["pending"]\` for the assertions still awaiting review, including the drafts generate_trace_assertions saved, so a batch of them can be reviewed and then decided with save_trace_assertions \`approvalState\`; add \`"rejected"\` to see the ones turned down. Judge a replay only against the approved ones. To find assertions without knowing which traces carry them, such as every draft awaiting review on a function, use list_trace_assertions. Each trace also reports its assertion generation, if one ran: running, completed with how many drafts it saved for review, or failed with the reason. Categorized assertions include category_assertion_id and the category's id, title, and description. A human note is returned so it can be read and edited, but it is never assessment evidence: judge only from the assertion, pass/fail criteria, and evaluated trace. Call this before judging a replay so the verdict is measured against what the user actually asked for rather than a guess, and before save_trace_assertions to find the assertion to edit or to avoid creating a duplicate. No span content is loaded, so one call accepts up to ${GET_TRACE_ASSERTIONS_MAX_IDS} ids. Accepts original trace ids and replay trace ids alike: a replay with no assertions of its own reads its original's, and the response says which original they came from. An assertion whose target cannot be found on the trace being evaluated is errored, never passed, so record it with save_agent_labels \`skip\` rather than a FAIL.`,
28911
28911
  inputSchema: {
28912
- traceIds: external_exports.preprocess(parseJsonString, external_exports.array(external_exports.uuid()).min(1).max(GET_TRACE_ASSERTIONS_MAX_IDS)).describe(`Original trace IDs to read assertions for (1-${GET_TRACE_ASSERTIONS_MAX_IDS})`)
28912
+ traceIds: external_exports.preprocess(parseJsonString, external_exports.array(external_exports.uuid()).min(1).max(GET_TRACE_ASSERTIONS_MAX_IDS)).describe(`Original trace IDs to read assertions for (1-${GET_TRACE_ASSERTIONS_MAX_IDS})`),
28913
+ approvalStates: external_exports.preprocess(parseJsonString, external_exports.array(external_exports.enum(["pending", "approved", "rejected"])).min(1).max(3)).optional().describe('Review states to include: "approved" (checked on every replay), "pending" (awaiting review, including generated drafts), "rejected" (turned down, never checked). Defaults to ["approved"], which is what a replay is judged against. Pass ["pending"] to review drafts, or all three to see everything.')
28914
+ }
28915
+ };
28916
+ var listTraceAssertions = {
28917
+ name: "list_trace_assertions",
28918
+ title: "List Trace Assertions",
28919
+ description: `Find assertions across traces by review state, without knowing which traces carry them: for example every assertion still awaiting review on one traced function, which is the review queue. Each result names the trace it belongs to and carries the same fields get_trace_assertions returns, including its \`[ID: ...]\`, criteria, category, assignee, and approval. Newest first, one page at a time; pass the cursor a page returns to read the next. The cursor holds its place, so approving or rejecting the assertions on a page with save_trace_assertions \`approvalState\` before reading the next page never skips any. The first page also reports how many assertions are in each review state under the same filters. Only an assertion a person has approved is checked on a replay, so never score a replay against a pending or rejected one listed here. To read the assertions of traces you already have, use get_trace_assertions.`,
28920
+ inputSchema: {
28921
+ approvalStates: external_exports.preprocess(parseJsonString, external_exports.array(external_exports.enum(["pending", "approved", "rejected"])).min(1).max(3)).describe('Review states to list: "pending" (awaiting review, including generated drafts), "approved" (checked on every replay), "rejected" (turned down, never checked). Pass ["pending"] for the review queue.'),
28922
+ traceFunctionKey: external_exports.string().min(1).optional().describe("Only assertions on traces of this traced function, from list_trace_functions. Omit to list across the whole organization."),
28923
+ categoryId: external_exports.union([external_exports.literal("unfiled"), external_exports.uuid()]).optional().describe('Only assertions filed under this category, from list_assertion_categories, or "unfiled" for assertions with no category. Omit for every category.'),
28924
+ limit: external_exports.preprocess(parseJsonString, external_exports.number().int().min(1).max(100)).optional().describe("Max assertions to return (default 25, max 100)"),
28925
+ cursor: external_exports.string().min(1).optional().describe("Opaque cursor from the previous page; reuse the same filters")
28913
28926
  }
28914
28927
  };
28915
28928
  var archiveTraceAssertions = {
@@ -29235,6 +29248,7 @@ var ALL_TOOL_CONTRACTS = [
29235
29248
  generateTraceAssertions,
29236
29249
  saveTraceAssertions,
29237
29250
  getTraceAssertions,
29251
+ listTraceAssertions,
29238
29252
  archiveTraceAssertions,
29239
29253
  listOrganizationMembers,
29240
29254
  saveGrader,
@@ -29868,10 +29882,10 @@ var semver3 = __toESM(require_semver2(), 1);
29868
29882
 
29869
29883
  // ../bitfab-plugin-lib/dist/bakedSdkVersions.js
29870
29884
  var BAKED_SDK_VERSIONS = {
29871
- typescript: "0.64.3",
29872
- python: "0.64.3",
29873
- ruby: "0.64.3",
29874
- go: "0.64.2"
29885
+ typescript: "0.64.4",
29886
+ python: "0.64.4",
29887
+ ruby: "0.64.4",
29888
+ go: "0.64.3"
29875
29889
  };
29876
29890
 
29877
29891
  // ../bitfab-plugin-lib/dist/installedSdk.js
@@ -30978,6 +30992,16 @@ import { createWriteStream, mkdirSync as mkdirSync4, rmSync as rmSync2 } from "f
30978
30992
  import { dirname as dirname3, resolve as resolve3 } from "path";
30979
30993
  import { createInterface } from "readline";
30980
30994
 
30995
+ // ../bitfab-plugin-lib/dist/replayCloudResult.js
30996
+ var cloudSummarySchema = external_exports.object({
30997
+ cloudSummary: external_exports.literal(true),
30998
+ experimentId: external_exports.string().optional(),
30999
+ experimentUrl: external_exports.string().optional(),
31000
+ testRunId: external_exports.string().optional(),
31001
+ testRunUrl: external_exports.string().optional(),
31002
+ counts: external_exports.record(external_exports.string(), external_exports.number()).optional()
31003
+ }).passthrough();
31004
+
30981
31005
  // ../bitfab-plugin-lib/dist/replayItemWriter.js
30982
31006
  import { existsSync as existsSync2, mkdirSync as mkdirSync3, renameSync, writeFileSync as writeFileSync3 } from "fs";
30983
31007
  import { join as join3 } from "path";
@@ -35415,7 +35439,7 @@ cd <project-dir> && {{command:replayProgress}} --label <pipeline-name> --run-dir
35415
35439
 
35416
35440
  For every item you can judge during the run, key the verdict by its **original trace id** (the \`originalTraceId\` field in each item file, the same \`item.originalTraceId\` on progress rows), the original trace the item was replayed from, which the server resolves to this run's replay trace, no local-to-server id mapping step. You need the run's \`experimentId\` to persist (enriched progress rows may carry \`event.experimentId\`; older scripts may only reveal it in the final \`ReplayResult\`). As soon as a small batch of judged items has its original trace ids and you know the \`experimentId\`, persist that batch with \`{{command:persistReplayLabels}}\`. Keep a set of original trace IDs already persisted so the final reconciliation never double-writes a verdict.
35417
35441
 
35418
- 4. **When the background command finishes, read the final \`type: "complete"\` row from this run's \`events.jsonl\`**. Its \`result\` carries run metadata (\`experimentId\`, \`experimentUrl\`, \`itemCount\`) and its \`items\` array carries item refs. Read each needed \`items[].itemPath\` for the full replay item (trace ID, duration, tokens, model, and full original/new outputs). Read from the **files**, not from the captured command output, which the harness truncates in the middle.
35442
+ 4. **When the background command finishes, read the final \`type: "complete"\` row from this run's \`events.jsonl\`**. Its \`result\` carries run metadata (\`experimentId\`, \`experimentUrl\`, \`itemCount\`) and its \`items\` array carries item refs. Read each needed \`items[].itemPath\` for the full replay item (trace ID, duration, tokens, model, and full original/new outputs). Read from the **files**, not from the captured command output, which the harness truncates in the middle. A \`--cloud\` replay leaves \`items\` empty and sets \`result.cloudSummary: true\`, with the counts and each errored trace in \`result.erroredItems\`: read its items from Bitfab instead, {{tool:listExperimentTraces}} with the \`experimentId\` for each replay trace ID and its original, then \`{{command:readTracesBatched}} <replay and original trace IDs...> --scope full\` for their inputs and outputs.
35419
35443
 
35420
35444
  **Before running: verify the installed replay command returns the full original and new output values AND at least one verdict persist key (\`item.originalTraceId\` or \`item.traceId\`) for every item** (not just lengths, counts, hashes, or truncated previews) so the run's \`items/*.json\` files carry them. Modern items may carry both: prefer lineage persistence by \`item.originalTraceId\` (older SDKs may print it under the deprecated \`sourceTraceId\` alias), and fall back to the server replay \`item.traceId\` only when original lineage is absent. After an item's replay trace is flushed, its \`item.traceId\` is available to lifecycle callbacks and in the final result. The oldest SDKs have no \`item.originalTraceId\` and persist by \`item.traceId\`. If the installed command returns neither, upgrade the SDK first; the Replay Output Contract and registry examples live in the SDK reference at \`https://docs.bitfab.ai/<language>-sdk.md\`. Subagents can't evaluate an improvement from \`5 \u2192 7 (+2)\`, and an item that carries no persist key blocks verdict persistence for that item.
35421
35445
 
@@ -36537,7 +36561,7 @@ If the block prints \`ERROR: Bitfab plugin not installed\`, the user hasn't inst
36537
36561
  inspect: "Diagnose (and offer to fix) your tracing setup: auth, what's instrumented, plugin/SDK freshness, replay coverage, trace arrival.",
36538
36562
  "switch-org": "Switch which Bitfab org the plugin reads and writes (replaces the local API key).",
36539
36563
  replay: "Create or update replay registry modules for instrumented workflows.",
36540
- cloud: "Run your normal replay on your own GitHub Actions by adding --cloud: same options, same output, same exit code. One workflow file in the repository; no Bitfab repository connection or GitHub CLI required.",
36564
+ cloud: "Run your normal replay on your own GitHub Actions by adding --cloud: same options and exit code, with a short summary of the result. One workflow file in the repository; no Bitfab repository connection or GitHub CLI required.",
36541
36565
  "db-snapshot": "Set up per-trace database snapshots so replay runs against the DB state at trace time (TypeScript, Python, Ruby).",
36542
36566
  templates: "Iterate on the span-rendering templates for one trace function.",
36543
36567
  "analyze-repo": "Read-only discovery: scan source, rank the top workflows to instrument, and report recommendations without creating artifacts or changing code."
@@ -36602,7 +36626,7 @@ Never modify existing code on a refactor path without completing this three-step
36602
36626
  kind: "action",
36603
36627
  title: "Inspect the replay environment",
36604
36628
  toolCalls: ["bash", "read", "glob", "grep", "ask"],
36605
- body: `Cloud replay is the user's normal replay plus --cloud: every replay option works the same, the runner replays a snapshot of their working tree (changed files, plus new files git does not ignore) from the same directory, and the command prints the replay's own output and exits with its exit code. The code ships inside the SDK, and the repository keeps one file: .github/workflows/bitfab-replay.yml, which holds only settings.
36629
+ body: `Cloud replay is the user's normal replay plus --cloud: every replay option works the same, the runner replays a snapshot of their working tree (changed files, plus new files git does not ignore) from the same directory, and the command prints the replay's progress and a short summary of its result (experiment ID and URL, replayed, same, changed, and errored counts, and each errored trace with its error), then exits with its exit code. Every trace's input and output are in the experiment in Bitfab, readable through the Bitfab MCP tools; --cloud-full-output prints the whole result instead. The code ships inside the SDK, and the repository keeps one file: .github/workflows/bitfab-replay.yml, which holds only settings.
36606
36630
 
36607
36631
  Run the installed SDK's bitfab-replay --cloud --help; if it does not list --cloud-preview, upgrade the SDK through bitfab:update first. Check that the git origin is github.com and that Python 3.10+ exists (macOS or Linux). GitHub access needs no GitHub CLI: the SDK uses gh when it is logged in, otherwise GH_TOKEN or GITHUB_TOKEN, otherwise the github.com credential git stores. When the repository still has .bitfab/cloud.json from an older SDK, the SDK says to delete it and the old workflow and run --cloud-init again; show the user the old file's settings first.
36608
36632
 
@@ -36636,7 +36660,7 @@ Each replay pushes a temporary bitfab-replay/<UUID> branch. For each push-trigge
36636
36660
 
36637
36661
  Verify with the replay command the user already runs. First add --cloud --cloud-preview, which pushes nothing and lists the changed and new files the snapshot would carry; review them for anything that should not leave the machine, since filename screening is not a secret scanner, and have the user gitignore it. Once the workflow is merged and secrets are set, and remote runs are authorized, run the same command with --cloud --dry-run: a real run that replays nothing but receives the secrets, stops on any empty secret, runs the --check command, and resolves the traces. Then, only when a replay is authorized, run with --cloud alone.
36638
36662
 
36639
- From an agent session always add --cloud-detach, since a replay can run for hours, and follow it with --cloud-watch <UUID> (prints the replay's output and exits with its code), --cloud-status, --cloud-cancel, or --cloud-cleanup. --cloud-timeout <minutes> stops one replay early and keeps finished traces. Report separately whether the workflow is written, secrets are set, the workflow is merged, the preview was reviewed, the dry run passed, and a real replay completed.`,
36663
+ From an agent session always add --cloud-detach, since a replay can run for hours, and follow it with --cloud-watch <UUID> (prints the replay's progress and result summary and exits with its code), --cloud-status, --cloud-cancel, or --cloud-cleanup. --cloud-timeout <minutes> stops one replay early and keeps finished traces. Report separately whether the workflow is written, secrets are set, the workflow is merged, the preview was reviewed, the dry run passed, and a real replay completed.`,
36640
36664
  next: "cleanup/finish"
36641
36665
  }
36642
36666
  ]
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bitfab-cli",
3
- "version": "0.2.417",
3
+ "version": "0.2.419",
4
4
  "description": "Install and configure the Bitfab plugin in Claude Code, Codex, or Cursor, or the Bitfab skill pack in Amp (Alpha).",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",