orizu 0.5.40 → 0.5.41

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 (49) hide show
  1. package/dist/dataset-clone-workflow.d.ts +11 -0
  2. package/dist/dataset-clone-workflow.d.ts.map +1 -0
  3. package/dist/dataset-clone-workflow.js +100 -0
  4. package/dist/dataset-commands.d.ts.map +1 -1
  5. package/dist/dataset-commands.js +6 -29
  6. package/dist/dataset-transfer-upload.d.ts +2 -6
  7. package/dist/dataset-transfer-upload.d.ts.map +1 -1
  8. package/dist/dataset-transfer-upload.js +9 -2
  9. package/dist/dataset-upload-snapshot.d.ts.map +1 -1
  10. package/dist/dataset-upload-snapshot.js +7 -1
  11. package/dist/dataset-version-workflow.d.ts +24 -0
  12. package/dist/dataset-version-workflow.d.ts.map +1 -0
  13. package/dist/dataset-version-workflow.js +99 -0
  14. package/dist/feedback-cli.js +3 -3
  15. package/dist/hosted-harness-opencode.d.ts +1 -1
  16. package/dist/hosted-harness-opencode.js +7 -7
  17. package/dist/hosted-loop-lifecycle.d.ts +3 -2
  18. package/dist/hosted-loop-lifecycle.d.ts.map +1 -1
  19. package/dist/hosted-loop-lifecycle.js +3 -2
  20. package/dist/hosted-loop.d.ts +7 -0
  21. package/dist/hosted-loop.d.ts.map +1 -1
  22. package/dist/hosted-loop.js +14 -6
  23. package/dist/index.js +2 -2
  24. package/dist/last-error-record.d.ts +4 -2
  25. package/dist/last-error-record.d.ts.map +1 -1
  26. package/dist/last-error-record.js +10 -68
  27. package/dist/last-error-workflow.d.ts +4 -0
  28. package/dist/last-error-workflow.d.ts.map +1 -0
  29. package/dist/last-error-workflow.js +78 -0
  30. package/dist/task-commands.d.ts.map +1 -1
  31. package/dist/task-commands.js +9 -16
  32. package/dist/task-report-workflow.d.ts +47 -0
  33. package/dist/task-report-workflow.d.ts.map +1 -0
  34. package/dist/task-report-workflow.js +160 -0
  35. package/package.json +1 -1
  36. package/src/dataset-clone-workflow.ts +100 -0
  37. package/src/dataset-commands.ts +6 -53
  38. package/src/dataset-transfer-upload.ts +12 -5
  39. package/src/dataset-upload-snapshot.ts +8 -1
  40. package/src/dataset-version-workflow.ts +105 -0
  41. package/src/feedback-cli.ts +4 -4
  42. package/src/hosted-harness-opencode.ts +7 -7
  43. package/src/hosted-loop-lifecycle.ts +3 -2
  44. package/src/hosted-loop.ts +14 -6
  45. package/src/index.ts +2 -2
  46. package/src/last-error-record.ts +11 -85
  47. package/src/last-error-workflow.ts +121 -0
  48. package/src/task-commands.ts +9 -43
  49. package/src/task-report-workflow.ts +179 -0
@@ -0,0 +1,11 @@
1
+ import { Schema } from 'effect';
2
+ declare const ClonedDataset: Schema.Struct<{
3
+ readonly id: Schema.String;
4
+ readonly name: Schema.String;
5
+ readonly rowCount: Schema.Number;
6
+ readonly parentDatasetId: Schema.String;
7
+ }>;
8
+ export type ClonedDataset = typeof ClonedDataset.Type;
9
+ export declare function cloneDataset(datasetId: string, name: string | null): Promise<ClonedDataset>;
10
+ export {};
11
+ //# sourceMappingURL=dataset-clone-workflow.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dataset-clone-workflow.d.ts","sourceRoot":"","sources":["../src/dataset-clone-workflow.ts"],"names":[],"mappings":"AAAA,OAAO,EAA+B,MAAM,EAAE,MAAM,QAAQ,CAAA;AAU5D,QAAA,MAAM,aAAa;;;;;EAKjB,CAAA;AAGF,MAAM,MAAM,aAAa,GAAG,OAAO,aAAa,CAAC,IAAI,CAAA;AA6ErD,wBAAsB,YAAY,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,aAAa,CAAC,CAIjG"}
@@ -0,0 +1,100 @@
1
+ import { Cause, Effect, Exit, Result, Schema } from 'effect';
2
+ import { datasetTransferTimeoutMs } from './dataset-transfer-policy.js';
3
+ import { authedFetch } from './http.js';
4
+ import { parseJsonResponse } from './json-response.js';
5
+ // Loaded only through `await import(...)` from dataset-commands, like lock.
6
+ const SERVER_MAY_BE_CREATED = 'Dataset clone may already be created';
7
+ const ClonedDataset = Schema.Struct({
8
+ id: Schema.String,
9
+ name: Schema.String,
10
+ rowCount: Schema.Number,
11
+ parentDatasetId: Schema.String,
12
+ });
13
+ const CloneReply = Schema.Struct({ dataset: ClonedDataset });
14
+ const ErrorReply = Schema.Struct({ error: Schema.String });
15
+ // A refusal means nothing was cloned. After any other failure once the request
16
+ // was sent, the clone may exist. Unlike lock, cloning again is not harmless: it
17
+ // makes another copy, so the clone is never retried and the user is told to look.
18
+ class CloneFailure extends Error {
19
+ mayBeCreated;
20
+ constructor(message, mayBeCreated) {
21
+ super(message);
22
+ this.mayBeCreated = mayBeCreated;
23
+ }
24
+ }
25
+ function mayBeCreatedGuidance(name) {
26
+ const target = name ? `a dataset named ${JSON.stringify(name)}` : 'a new dataset named after the source with " Copy" at the end';
27
+ return `The clone may already have been created. Run \`orizu datasets list\` and look for ${target} before cloning again: running clone again makes another copy.`;
28
+ }
29
+ // authedFetch raises this code only when it sent nothing, or when the server
30
+ // answered 401 and the changed credentials stopped a replay. Nothing was cloned.
31
+ function isAuthContextChange(cause) {
32
+ return cause instanceof Error && cause.message.startsWith('ORIZU_AUTH_CONTEXT_CHANGED:');
33
+ }
34
+ function serverError(text) {
35
+ try {
36
+ const decoded = Schema.decodeUnknownResult(ErrorReply)(JSON.parse(text));
37
+ return Result.isSuccess(decoded) ? decoded.success.error : null;
38
+ }
39
+ catch {
40
+ return null;
41
+ }
42
+ }
43
+ function cloneRequest(datasetId, name, timeoutMs) {
44
+ return Effect.suspend(() => {
45
+ let sent = false;
46
+ let timedOut = false;
47
+ return Effect.tryPromise({
48
+ try: async (signal) => {
49
+ const request = new AbortController();
50
+ const abort = () => request.abort();
51
+ const timer = setTimeout(() => { timedOut = true; request.abort(); }, timeoutMs);
52
+ if (signal.aborted)
53
+ abort();
54
+ else
55
+ signal.addEventListener('abort', abort, { once: true });
56
+ try {
57
+ const response = await authedFetch(`/api/cli/datasets/${encodeURIComponent(datasetId)}/clone`, {
58
+ method: 'POST',
59
+ headers: { 'Content-Type': 'application/json' },
60
+ body: JSON.stringify(name ? { name } : {}),
61
+ signal: request.signal,
62
+ }, () => { sent = true; });
63
+ if (!response.ok) {
64
+ const text = await response.text();
65
+ const error = serverError(text);
66
+ // The app's own 5xx bodies name what happened; anything else at 5xx
67
+ // (a gateway page, an empty body) says nothing about the clone.
68
+ const mayBeCreated = response.status < 400 || error === SERVER_MAY_BE_CREATED || (response.status >= 500 && error === null);
69
+ throw new CloneFailure(`Clone failed: ${text}`, mayBeCreated);
70
+ }
71
+ const data = await parseJsonResponse(response, 'Dataset clone');
72
+ const decoded = Schema.decodeUnknownResult(CloneReply)(data);
73
+ if (Result.isFailure(decoded)) {
74
+ throw new CloneFailure(`Dataset clone returned an unexpected response (status ${response.status}).`, true);
75
+ }
76
+ return decoded.success.dataset;
77
+ }
78
+ finally {
79
+ clearTimeout(timer);
80
+ signal.removeEventListener('abort', abort);
81
+ request.abort();
82
+ }
83
+ },
84
+ catch: cause => {
85
+ if (timedOut)
86
+ return new CloneFailure('DATASET_TRANSFER_TIMEOUT: Dataset clone exceeded its deadline', true);
87
+ if (cause instanceof CloneFailure)
88
+ return cause;
89
+ return new CloneFailure(cause instanceof Error ? cause.message : String(cause), sent && !isAuthContextChange(cause));
90
+ },
91
+ });
92
+ }).pipe(Effect.mapError(failure => new Error(failure.mayBeCreated ? `${failure.message}\n${mayBeCreatedGuidance(name)}` : failure.message)));
93
+ }
94
+ // Nothing to clean up, so signals keep Node's default handling.
95
+ export async function cloneDataset(datasetId, name) {
96
+ const exit = await Effect.runPromiseExit(cloneRequest(datasetId, name, datasetTransferTimeoutMs()));
97
+ if (Exit.isSuccess(exit))
98
+ return exit.value;
99
+ throw Cause.squash(exit.cause);
100
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"dataset-commands.d.ts","sourceRoot":"","sources":["../src/dataset-commands.ts"],"names":[],"mappings":"AAuJA,iBAAe,oBAAoB,kBAiClC;AAED,iBAAe,oBAAoB,kBAYlC;AAED,iBAAe,mBAAmB,kBAcjC;AAED,iBAAe,qBAAqB,kBAkDnC;AAED,iBAAe,YAAY,kBAW1B;AAsBD,iBAAe,aAAa,kBAiC3B;AAED,iBAAe,WAAW,kBAwCzB;AAED,iBAAe,gBAAgB,kBA+B9B;AAgBD,iBAAe,eAAe,kBA6C7B;AAED,iBAAe,iBAAiB,kBAU/B;AAED,iBAAe,eAAe,kBA2B7B;AAED,iBAAe,iBAAiB,kBA2B/B;AA0BD,iBAAe,aAAa,kBAuB3B;AAED,iBAAe,WAAW,kBAuBzB;AAED,iBAAe,YAAY,kBAuC1B;AAED,iBAAe,mBAAmB,kBA0BjC;AAED,OAAO,EACL,aAAa,EACb,YAAY,EACZ,WAAW,EACX,eAAe,EACf,iBAAiB,EACjB,gBAAgB,EAChB,oBAAoB,EACpB,qBAAqB,EACrB,oBAAoB,EACpB,mBAAmB,EACnB,eAAe,EACf,iBAAiB,EACjB,aAAa,EACb,WAAW,EACX,YAAY,EACZ,mBAAmB,GACpB,CAAA"}
1
+ {"version":3,"file":"dataset-commands.d.ts","sourceRoot":"","sources":["../src/dataset-commands.ts"],"names":[],"mappings":"AAuHA,iBAAe,oBAAoB,kBAkClC;AAED,iBAAe,oBAAoB,kBAYlC;AAED,iBAAe,mBAAmB,kBAcjC;AAED,iBAAe,qBAAqB,kBAkDnC;AAED,iBAAe,YAAY,kBAW1B;AAsBD,iBAAe,aAAa,kBAiC3B;AAED,iBAAe,WAAW,kBAwCzB;AAED,iBAAe,gBAAgB,kBA+B9B;AAgBD,iBAAe,eAAe,kBA6C7B;AAED,iBAAe,iBAAiB,kBAU/B;AAED,iBAAe,eAAe,kBA2B7B;AAED,iBAAe,iBAAiB,kBA2B/B;AA0BD,iBAAe,aAAa,kBAuB3B;AAED,iBAAe,WAAW,kBAuBzB;AAED,iBAAe,YAAY,kBAuB1B;AAED,iBAAe,mBAAmB,kBA0BjC;AAED,OAAO,EACL,aAAa,EACb,YAAY,EACZ,WAAW,EACX,eAAe,EACf,iBAAiB,EACjB,gBAAgB,EAChB,oBAAoB,EACpB,qBAAqB,EACrB,oBAAoB,EACpB,mBAAmB,EACnB,eAAe,EACf,iBAAiB,EACjB,aAAa,EACb,WAAW,EACX,YAAY,EACZ,mBAAmB,GACpB,CAAA"}
@@ -7,7 +7,6 @@ import { getArg, hasArg, expandHomePath, getPositionalArg, hasJsonFlag, getArchi
7
7
  import { resolveProjectSlug, fetchDatasets, selectDatasetInteractively, selectTaskIdInteractively, } from './account-directory.js';
8
8
  import { sanitizeTerminalText, parseJsonResponse } from './json-response.js';
9
9
  import { authedFetch } from './http.js';
10
- import { extractErrorMessage } from './error-response.js';
11
10
  import { printJson, printLine } from './cli-console-output.js';
12
11
  import { readJsonFile } from './app-commands.js';
13
12
  import { printDatasetSummaries } from './archive-artifacts-cli.js';
@@ -81,22 +80,6 @@ async function resolveDatasetIdForProject(datasetRef, projectArg) {
81
80
  }
82
81
  return matches[0].id;
83
82
  }
84
- async function requestDatasetVersionSnapshot(datasetId, options = {}) {
85
- const response = await authedFetch(`/api/cli/datasets/${encodeURIComponent(datasetId)}/versions`, {
86
- method: 'POST',
87
- headers: { 'Content-Type': 'application/json' },
88
- body: JSON.stringify({
89
- ...(options.versionLabel ? { versionLabel: options.versionLabel } : {}),
90
- ...(options.readmeMarkdown !== undefined && options.readmeMarkdown !== null
91
- ? { readmeMarkdown: options.readmeMarkdown }
92
- : {}),
93
- }),
94
- });
95
- if (!response.ok) {
96
- throw new Error(`Failed to create dataset version: ${await extractErrorMessage(response)}`);
97
- }
98
- return parseJsonResponse(response, 'Dataset version create');
99
- }
100
83
  async function createDatasetVersion() {
101
84
  const datasetId = getPositionalArg(3) || getArg('--dataset');
102
85
  const versionLabel = getArg('--label') || getArg('--version-label') || null;
@@ -107,7 +90,8 @@ async function createDatasetVersion() {
107
90
  }
108
91
  const readmeMarkdown = readReadmeMarkdownFromArgs(usage);
109
92
  const resolvedDatasetId = await resolveDatasetIdForProject(datasetId, project);
110
- const data = await requestDatasetVersionSnapshot(resolvedDatasetId, {
93
+ const { createDatasetVersionSnapshot } = await import('./dataset-version-workflow.js');
94
+ const data = await createDatasetVersionSnapshot(resolvedDatasetId, {
111
95
  versionLabel,
112
96
  readmeMarkdown,
113
97
  });
@@ -514,20 +498,13 @@ async function cloneDataset() {
514
498
  const selected = await selectDatasetInteractively(projectArg);
515
499
  datasetId = selected.datasetId;
516
500
  }
517
- const response = await authedFetch(`/api/cli/datasets/${encodeURIComponent(datasetId)}/clone`, {
518
- method: 'POST',
519
- headers: { 'Content-Type': 'application/json' },
520
- body: JSON.stringify(name ? { name } : {}),
521
- });
522
- if (!response.ok) {
523
- throw new Error(`Clone failed: ${await response.text()}`);
524
- }
525
- const data = await parseJsonResponse(response, 'Dataset clone');
501
+ const { cloneDataset: requestClone } = await import('./dataset-clone-workflow.js');
502
+ const dataset = await requestClone(datasetId, name ?? null);
526
503
  if (hasJsonFlag()) {
527
- printJson({ dataset: data.dataset });
504
+ printJson({ dataset });
528
505
  return;
529
506
  }
530
- printLine(`Cloned dataset ${sanitizeTerminalText(data.dataset.parentDatasetId)} -> ${sanitizeTerminalText(data.dataset.name)} (${sanitizeTerminalText(data.dataset.id)}). Row count: ${data.dataset.rowCount}`);
507
+ printLine(`Cloned dataset ${sanitizeTerminalText(dataset.parentDatasetId)} -> ${sanitizeTerminalText(dataset.name)} (${sanitizeTerminalText(dataset.id)}). Row count: ${dataset.rowCount}`);
531
508
  }
532
509
  async function downloadAnnotations() {
533
510
  let taskId = getArg('--task');
@@ -1,3 +1,4 @@
1
+ import { type DatasetVersionResponse } from './dataset-version-workflow.js';
1
2
  export interface DatasetUploadResponse {
2
3
  dataset: {
3
4
  id: string;
@@ -12,11 +13,6 @@ export interface DatasetUploadResponse {
12
13
  created_at: string;
13
14
  } | null;
14
15
  }
15
- interface DatasetSnapshot {
16
- datasetVersion: {
17
- id: string;
18
- };
19
- }
20
16
  type UploadRows = Array<Record<string, unknown>>;
21
17
  type UploadSource = {
22
18
  kind: 'jsonl';
@@ -36,7 +32,7 @@ export interface DatasetUploadOptions {
36
32
  }
37
33
  export declare function transferDatasetUpload(options: DatasetUploadOptions): Promise<{
38
34
  data: DatasetUploadResponse;
39
- version: DatasetSnapshot;
35
+ version: DatasetVersionResponse;
40
36
  }>;
41
37
  export {};
42
38
  //# sourceMappingURL=dataset-transfer-upload.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"dataset-transfer-upload.d.ts","sourceRoot":"","sources":["../src/dataset-transfer-upload.ts"],"names":[],"mappings":"AASA,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,GAAG,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;IACzF,aAAa,CAAC,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAA;CAC/E;AAED,UAAU,eAAe;IAAG,cAAc,EAAE;QAAE,EAAE,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE;AAE5D,KAAK,UAAU,GAAG,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAA;AAChD,KAAK,YAAY,GAAG;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,UAAU,CAAC;IAAC,UAAU,EAAE,KAAK,GAAG,MAAM,GAAG,OAAO,CAAA;CAAE,CAAA;AAE9H,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,MAAM,CAAA;IACf,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,YAAY,CAAA;IACpB,cAAc,EAAE,MAAM,GAAG,IAAI,CAAA;IAC7B,IAAI,EAAE,OAAO,CAAA;IACb,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAA;CACnD;AAoHD,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,oBAAoB,GAAG,OAAO,CAAC;IAAE,IAAI,EAAE,qBAAqB,CAAC;IAAC,OAAO,EAAE,eAAe,CAAA;CAAE,CAAC,CAEvI"}
1
+ {"version":3,"file":"dataset-transfer-upload.d.ts","sourceRoot":"","sources":["../src/dataset-transfer-upload.ts"],"names":[],"mappings":"AAIA,OAAO,EAAsD,KAAK,sBAAsB,EAAE,MAAM,+BAA+B,CAAA;AAM/H,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,GAAG,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;IACzF,aAAa,CAAC,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAA;CAC/E;AAGD,KAAK,UAAU,GAAG,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAA;AAChD,KAAK,YAAY,GAAG;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,UAAU,CAAC;IAAC,UAAU,EAAE,KAAK,GAAG,MAAM,GAAG,OAAO,CAAA;CAAE,CAAA;AAE9H,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,MAAM,CAAA;IACf,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,YAAY,CAAA;IACpB,cAAc,EAAE,MAAM,GAAG,IAAI,CAAA;IAC7B,IAAI,EAAE,OAAO,CAAA;IACb,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAA;CACnD;AA2HD,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,oBAAoB,GAAG,OAAO,CAAC;IAAE,IAAI,EAAE,qBAAqB,CAAC;IAAC,OAAO,EAAE,sBAAsB,CAAA;CAAE,CAAC,CAE9I"}
@@ -1,6 +1,7 @@
1
1
  import { Context, Effect, Layer, Result } from 'effect';
2
2
  import { ensureDatasetUploadSnapshot } from './dataset-upload-snapshot.js';
3
3
  import { datasetTransferTimeoutMs } from './dataset-transfer-policy.js';
4
+ import { datasetVersionSnapshot } from './dataset-version-workflow.js';
4
5
  import { extractErrorMessage } from './error-response.js';
5
6
  import { authedFetch } from './http.js';
6
7
  import { parseJsonResponse, sanitizeTerminalText } from './json-response.js';
@@ -18,6 +19,12 @@ class DatasetInputFailure extends Error {
18
19
  constructor(cause) { super(cause instanceof Error ? cause.message : String(cause), { cause }); }
19
20
  }
20
21
  const DatasetUploadApi = Context.Service('orizu/DatasetUploadApi');
22
+ // authedFetch raises this code only when it sent nothing, or after the server
23
+ // answered 401 (it writes nothing) and the stored credentials changed, so it
24
+ // refused to replay. Either way nothing was written (ORI-2431).
25
+ function isAuthContextChange(cause) {
26
+ return cause instanceof Error && cause.message.startsWith('ORIZU_AUTH_CONTEXT_CHANGED:');
27
+ }
21
28
  // Only the existing authentication client's rejected-token refresh may replay a
22
29
  // request. No transient/transport retries belong around these non-idempotent writes.
23
30
  function post(path, body, context, prefix, timeoutMs) {
@@ -34,7 +41,7 @@ function post(path, body, context, prefix, timeoutMs) {
34
41
  }
35
42
  return await parseJsonResponse(response, context);
36
43
  },
37
- catch: cause => cause instanceof DatasetWriteFailure ? cause : new DatasetWriteFailure(cause instanceof Error ? cause.message : String(cause), requestStarted ? 'unknown' : 'rejected', { cause }),
44
+ catch: cause => cause instanceof DatasetWriteFailure ? cause : new DatasetWriteFailure(cause instanceof Error ? cause.message : String(cause), requestStarted && !isAuthContextChange(cause) ? 'unknown' : 'rejected', { cause }),
38
45
  }).pipe(Effect.timeoutOrElse({
39
46
  duration: timeoutMs,
40
47
  orElse: () => Effect.fail(new DatasetWriteFailure(`DATASET_TRANSFER_TIMEOUT: ${context} exceeded its deadline`, requestStarted ? 'unknown' : 'rejected')),
@@ -49,7 +56,7 @@ function liveUploadApi(options) {
49
56
  ...(options.readmeMarkdown !== null ? { readmeMarkdown: options.readmeMarkdown } : {}),
50
57
  }, 'Dataset upload', 'Upload failed', timeoutMs),
51
58
  append: (id, rows) => post(`/api/cli/datasets/${encodeURIComponent(id)}/rows`, { rows }, 'Dataset append', 'Append failed', timeoutMs),
52
- snapshot: id => post(`/api/cli/datasets/${encodeURIComponent(id)}/versions`, {}, 'Dataset version create', 'Failed to create dataset version', timeoutMs),
59
+ snapshot: id => datasetVersionSnapshot(id, {}, timeoutMs),
53
60
  });
54
61
  }
55
62
  async function expectedPromise(program) {
@@ -1 +1 @@
1
- {"version":3,"file":"dataset-upload-snapshot.d.ts","sourceRoot":"","sources":["../src/dataset-upload-snapshot.ts"],"names":[],"mappings":"AAAA,UAAU,uBAAuB;IAC/B,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,MAAM,CAAA;CACjB;AAED,UAAU,sBAAsB;IAC9B,cAAc,EAAE;QACd,EAAE,EAAE,MAAM,CAAA;KACX,CAAA;CACF;AAED,wBAAsB,2BAA2B,CAAC,CAAC,SAAS,sBAAsB,EAChF,OAAO,EAAE,uBAAuB,EAChC,UAAU,EAAE,OAAO,EACnB,cAAc,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,OAAO,CAAC,CAAC,CAAC,GAChD,OAAO,CAAC,CAAC,CAAC,CAwBZ"}
1
+ {"version":3,"file":"dataset-upload-snapshot.d.ts","sourceRoot":"","sources":["../src/dataset-upload-snapshot.ts"],"names":[],"mappings":"AAEA,UAAU,uBAAuB;IAC/B,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,MAAM,CAAA;CACjB;AAED,UAAU,sBAAsB;IAC9B,cAAc,EAAE;QACd,EAAE,EAAE,MAAM,CAAA;KACX,CAAA;CACF;AAED,wBAAsB,2BAA2B,CAAC,CAAC,SAAS,sBAAsB,EAChF,OAAO,EAAE,uBAAuB,EAChC,UAAU,EAAE,OAAO,EACnB,cAAc,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,OAAO,CAAC,CAAC,CAAC,GAChD,OAAO,CAAC,CAAC,CAAC,CA6BZ"}
@@ -1,3 +1,4 @@
1
+ import { DatasetVersionFailure, VERSION_MAY_BE_CREATED } from './dataset-version-workflow.js';
1
2
  export async function ensureDatasetUploadSnapshot(dataset, jsonOutput, createSnapshot) {
2
3
  try {
3
4
  return await createSnapshot(dataset.id);
@@ -5,6 +6,8 @@ export async function ensureDatasetUploadSnapshot(dataset, jsonOutput, createSna
5
6
  catch (error) {
6
7
  const detail = error instanceof Error ? error.message : String(error);
7
8
  const retryCommand = `orizu datasets versions create --dataset ${dataset.id}`;
9
+ // After an unclear outcome the version may exist; check before retrying.
10
+ const mayBeCreated = error instanceof DatasetVersionFailure && error.mayBeCreated;
8
11
  if (jsonOutput) {
9
12
  throw new Error(JSON.stringify({
10
13
  error: 'Dataset upload completed but dataset version creation failed',
@@ -13,10 +16,13 @@ export async function ensureDatasetUploadSnapshot(dataset, jsonOutput, createSna
13
16
  dataset_id: dataset.id,
14
17
  dataset_version_id: null,
15
18
  retry_command: retryCommand,
19
+ ...(mayBeCreated ? { may_be_created: true } : {}),
16
20
  }));
17
21
  }
18
22
  throw new Error(`Dataset upload completed but dataset version creation failed: ${detail}\n` +
19
23
  `Dataset ${dataset.name} (${dataset.id}) was created with ${dataset.rowCount} rows. ` +
20
- `Retry only the snapshot step with: ${retryCommand}`);
24
+ (mayBeCreated
25
+ ? `${VERSION_MAY_BE_CREATED} If it is not there, create it with: ${retryCommand}`
26
+ : `Retry only the snapshot step with: ${retryCommand}`));
21
27
  }
22
28
  }
@@ -0,0 +1,24 @@
1
+ import { Effect, Schema } from 'effect';
2
+ export declare const VERSION_MAY_BE_CREATED = "The version may already be created: check the dataset's versions in the web app before creating it again.";
3
+ declare const CreateReply: Schema.Struct<{
4
+ readonly datasetVersion: Schema.Struct<{
5
+ readonly id: Schema.NonEmptyString;
6
+ readonly rowCount: Schema.Number;
7
+ readonly artifactFormat: Schema.optional<Schema.String>;
8
+ readonly artifactStoragePath: Schema.optional<Schema.String>;
9
+ }>;
10
+ }>;
11
+ export type DatasetVersionResponse = typeof CreateReply.Type;
12
+ export interface DatasetVersionRequest {
13
+ versionLabel?: string | null;
14
+ readmeMarkdown?: string | null;
15
+ }
16
+ export declare class DatasetVersionFailure extends Error {
17
+ readonly mayBeCreated: boolean;
18
+ readonly _tag = "DatasetVersionFailure";
19
+ constructor(message: string, mayBeCreated: boolean);
20
+ }
21
+ export declare function datasetVersionSnapshot(datasetId: string, options: DatasetVersionRequest, timeoutMs: number): Effect.Effect<DatasetVersionResponse, DatasetVersionFailure>;
22
+ export declare function createDatasetVersionSnapshot(datasetId: string, options: DatasetVersionRequest): Promise<DatasetVersionResponse>;
23
+ export {};
24
+ //# sourceMappingURL=dataset-version-workflow.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dataset-version-workflow.d.ts","sourceRoot":"","sources":["../src/dataset-version-workflow.ts"],"names":[],"mappings":"AAAA,OAAO,EAAS,MAAM,EAAgB,MAAM,EAAE,MAAM,QAAQ,CAAA;AAS5D,eAAO,MAAM,sBAAsB,8GAA8G,CAAA;AAIjJ,QAAA,MAAM,WAAW;;;;;;;EAOf,CAAA;AAEF,MAAM,MAAM,sBAAsB,GAAG,OAAO,WAAW,CAAC,IAAI,CAAA;AAE5D,MAAM,WAAW,qBAAqB;IACpC,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC5B,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAC/B;AAMD,qBAAa,qBAAsB,SAAQ,KAAK;IAEjB,QAAQ,CAAC,YAAY,EAAE,OAAO;IAD3D,QAAQ,CAAC,IAAI,2BAA0B;gBAC3B,OAAO,EAAE,MAAM,EAAW,YAAY,EAAE,OAAO;CAC5D;AAaD,wBAAgB,sBAAsB,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,qBAAqB,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,sBAAsB,EAAE,qBAAqB,CAAC,CA+CzK;AAED,wBAAsB,4BAA4B,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,qBAAqB,GAAG,OAAO,CAAC,sBAAsB,CAAC,CAMrI"}
@@ -0,0 +1,99 @@
1
+ import { Cause, Effect, Exit, Result, Schema } from 'effect';
2
+ import { datasetTransferTimeoutMs } from './dataset-transfer-policy.js';
3
+ import { extractErrorMessage, isJsonErrorResponsePayload } from './error-response.js';
4
+ import { authedFetch } from './http.js';
5
+ import { parseJsonResponse } from './json-response.js';
6
+ // Loaded only through `await import(...)`, like the README and delete workflows.
7
+ export const VERSION_MAY_BE_CREATED = "The version may already be created: check the dataset's versions in the web app before creating it again.";
8
+ // What the server says when it cannot tell whether the version was saved.
9
+ const SERVER_MAY_BE_CREATED = 'Dataset version may already be created';
10
+ const CreateReply = Schema.Struct({
11
+ datasetVersion: Schema.Struct({
12
+ id: Schema.NonEmptyString,
13
+ rowCount: Schema.Number,
14
+ artifactFormat: Schema.optional(Schema.String),
15
+ artifactStoragePath: Schema.optional(Schema.String),
16
+ }),
17
+ });
18
+ // The version may exist when the server says so, when the reply was lost or
19
+ // unreadable after the request was sent, or when a 5xx did not come from the
20
+ // app (a gateway giving up while the app kept working). Any other error reply
21
+ // is a clear refusal.
22
+ export class DatasetVersionFailure extends Error {
23
+ mayBeCreated;
24
+ _tag = 'DatasetVersionFailure';
25
+ constructor(message, mayBeCreated) {
26
+ super(message);
27
+ this.mayBeCreated = mayBeCreated;
28
+ }
29
+ }
30
+ async function appErrorOf(response) {
31
+ try {
32
+ const payload = await response.json();
33
+ return isJsonErrorResponsePayload(response, payload) ? payload.error : null;
34
+ }
35
+ catch {
36
+ return null;
37
+ }
38
+ }
39
+ // One request, never retried: a retry after an unknown outcome could add a
40
+ // second version.
41
+ export function datasetVersionSnapshot(datasetId, options, timeoutMs) {
42
+ return Effect.suspend(() => {
43
+ let sent = false;
44
+ let timedOut = false;
45
+ return Effect.tryPromise({
46
+ try: async (signal) => {
47
+ const request = new AbortController();
48
+ const abort = () => request.abort();
49
+ const timer = setTimeout(() => { timedOut = true; request.abort(); }, timeoutMs);
50
+ if (signal.aborted)
51
+ abort();
52
+ else
53
+ signal.addEventListener('abort', abort, { once: true });
54
+ try {
55
+ const response = await authedFetch(`/api/cli/datasets/${encodeURIComponent(datasetId)}/versions`, {
56
+ method: 'POST',
57
+ headers: { 'Content-Type': 'application/json' },
58
+ body: JSON.stringify({
59
+ ...(options.versionLabel ? { versionLabel: options.versionLabel } : {}),
60
+ ...(options.readmeMarkdown !== undefined && options.readmeMarkdown !== null
61
+ ? { readmeMarkdown: options.readmeMarkdown }
62
+ : {}),
63
+ }),
64
+ signal: request.signal,
65
+ }, () => { sent = true; });
66
+ if (!response.ok) {
67
+ const serverError = await appErrorOf(response.clone());
68
+ const message = `Failed to create dataset version: ${await extractErrorMessage(response)}`;
69
+ throw new DatasetVersionFailure(message, response.status < 400 || serverError === SERVER_MAY_BE_CREATED || (response.status >= 500 && serverError === null));
70
+ }
71
+ const data = await parseJsonResponse(response, 'Dataset version create');
72
+ const decoded = Schema.decodeUnknownResult(CreateReply)(data);
73
+ if (Result.isFailure(decoded)) {
74
+ throw new DatasetVersionFailure(`Dataset version create returned an unexpected response (status ${response.status}).`, true);
75
+ }
76
+ return decoded.success;
77
+ }
78
+ finally {
79
+ clearTimeout(timer);
80
+ signal.removeEventListener('abort', abort);
81
+ request.abort();
82
+ }
83
+ },
84
+ catch: cause => {
85
+ if (timedOut)
86
+ return new DatasetVersionFailure('DATASET_TRANSFER_TIMEOUT: Dataset version create exceeded its deadline', sent);
87
+ if (cause instanceof DatasetVersionFailure)
88
+ return cause;
89
+ return new DatasetVersionFailure(cause instanceof Error ? cause.message : String(cause), sent);
90
+ },
91
+ });
92
+ });
93
+ }
94
+ export async function createDatasetVersionSnapshot(datasetId, options) {
95
+ const exit = await Effect.runPromiseExit(datasetVersionSnapshot(datasetId, options, datasetTransferTimeoutMs()).pipe(Effect.mapError(failure => new Error(failure.mayBeCreated ? `${failure.message}\n${VERSION_MAY_BE_CREATED}` : failure.message))));
96
+ if (Exit.isSuccess(exit))
97
+ return exit.value;
98
+ throw Cause.squash(exit.cause);
99
+ }
@@ -307,8 +307,8 @@ function resolveProjectContext(explicitProject, workspaceRoot) {
307
307
  : existingWorkspaceTeamSlug(workspaceRoot);
308
308
  return { teamSlug: workspaceTeam, projectSlug: null };
309
309
  }
310
- function lastErrorForContext(configDirectory, serverBaseUrl, teamSlug, now, printErr, scrubNotice) {
311
- const record = readLastErrorRecord(configDirectory);
310
+ async function lastErrorForContext(configDirectory, serverBaseUrl, teamSlug, now, printErr, scrubNotice) {
311
+ const record = await readLastErrorRecord(configDirectory);
312
312
  if (!record || !isLastErrorRecordShape(record))
313
313
  return null;
314
314
  if (teamSlug === null) {
@@ -482,7 +482,7 @@ export async function feedbackCommand(args, io) {
482
482
  const values = { ...fromFile, ...parsed.values };
483
483
  const lastError = parsed.suppressLastError
484
484
  ? null
485
- : lastErrorForContext(configDirectory, baseUrl, projectContext.teamSlug, now(), io.printErr, scrubNotice);
485
+ : await lastErrorForContext(configDirectory, baseUrl, projectContext.teamSlug, now(), io.printErr, scrubNotice);
486
486
  const scrubOptions = { reporterEmail: null, homeDir: homeDirectory, secrets };
487
487
  const scrubbedFields = scrubFeedbackValue({
488
488
  category: values.category,
@@ -49,7 +49,7 @@
49
49
  * would break both ports and must be re-verified.
50
50
  */
51
51
  import type { AgentHarness } from './hosted-harness.js';
52
- export declare const OPENCODE_PINNED_VERSION = "1.14.41";
52
+ export declare const OPENCODE_PINNED_VERSION = "1.18.35";
53
53
  export declare const DEFAULT_PROMPT_MAX_DURATION_MS = 5400000;
54
54
  export type HarnessFetch = (url: string, init?: RequestInit) => Promise<Response>;
55
55
  export interface OpenCodeHarnessOptions {
@@ -54,13 +54,13 @@ import { HOSTED_AGENT_NAME, HOSTED_AGENT_PROMPT } from './hosted-agent-prompt.js
54
54
  import { parseModelIdentity } from './provider-registry.js';
55
55
  import { HARNESS_NAMES } from './hosted-harness.js';
56
56
  // OpenCode is HARD-PINNED to this version everywhere it is installed/launched.
57
- // AUDIT RISK #1 (SSE fragility): the entire event model rides OpenCode's
58
- // undocumented `/event` SSE part schema (`message.part.updated`, `session.idle`,
59
- // `session.error`, `session.updated`, ...). Versions newer than 1.14.41 broke
60
- // that stream upstream, so the pin is load-bearing and must be re-verified
61
- // before any bump. The AgentHarness seam is the mitigation of last resort: swap
62
- // to a Claude-Agent-SDK loop (ALI-929) rather than chase OpenCode's SSE.
63
- export const OPENCODE_PINNED_VERSION = '1.14.41';
57
+ // The event model rides OpenCode's undocumented `/event` SSE part schema
58
+ // (`message.part.updated`, `session.idle`, `session.error`, `session.updated`,
59
+ // ...), so every bump must pass test/cli/hosted-opencode-contract-real.test.ts
60
+ // against the real binary (the path-gated `opencode-real` CI job runs it when
61
+ // this pin changes). 1.14.41 → 1.18.35 was measured and checked that way
62
+ // (ORI-2523). The AgentHarness seam remains the mitigation of last resort.
63
+ export const OPENCODE_PINNED_VERSION = '1.18.35';
64
64
  const DEFAULT_OPENCODE_PORT = 4096;
65
65
  const DEFAULT_SSE_INACTIVITY_MS = 120_000;
66
66
  const DEFAULT_REQUEST_TIMEOUT_MS = 30_000;
@@ -30,8 +30,9 @@ import type { HostedSessionOrigin } from './hosted-runtime-assets.js';
30
30
  * re-inline it.
31
31
  *
32
32
  * PIN CONSTRAINT: the hosted OpenCode runtime is HARD-PINNED to
33
- * `opencode-ai@1.14.41` (`OPENCODE_PINNED_VERSION`, SSE-fragile — do not bump)
34
- * whose bundled catalog predates this model. Images bake a validated models.dev
33
+ * `OPENCODE_PINNED_VERSION` (opencode-ai@1.18.35, whose bundled catalog
34
+ * includes this model; bumps are checked by the real-binary contract test,
35
+ * ORI-2523). Images also bake a validated models.dev
35
36
  * list into the runtime user's cache. Orizu refreshes that cache before spawning
36
37
  * OpenCode, preserving baked models on failure; the native unchecked writer is
37
38
  * disabled (ORI-2513). Pre-prompt validation still checks the running server.
@@ -1 +1 @@
1
- {"version":3,"file":"hosted-loop-lifecycle.d.ts","sourceRoot":"","sources":["../src/hosted-loop-lifecycle.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"hosted-loop-lifecycle.d.ts","sourceRoot":"","sources":["../src/hosted-loop-lifecycle.ts"],"names":[],"mappings":"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"}
@@ -28,8 +28,9 @@
28
28
  * re-inline it.
29
29
  *
30
30
  * PIN CONSTRAINT: the hosted OpenCode runtime is HARD-PINNED to
31
- * `opencode-ai@1.14.41` (`OPENCODE_PINNED_VERSION`, SSE-fragile — do not bump)
32
- * whose bundled catalog predates this model. Images bake a validated models.dev
31
+ * `OPENCODE_PINNED_VERSION` (opencode-ai@1.18.35, whose bundled catalog
32
+ * includes this model; bumps are checked by the real-binary contract test,
33
+ * ORI-2523). Images also bake a validated models.dev
33
34
  * list into the runtime user's cache. Orizu refreshes that cache before spawning
34
35
  * OpenCode, preserving baked models on failure; the native unchecked writer is
35
36
  * disabled (ORI-2513). Pre-prompt validation still checks the running server.
@@ -192,6 +192,13 @@ export declare const TERMINAL_DELIVERY_RETRY_DELAYS_MS: readonly number[];
192
192
  * (model key + connector credentials) lands on the run-event redaction list.
193
193
  */
194
194
  export { INJECTED_ENV_VARS_ENV } from './hosted-environment.js';
195
+ /** Best-effort global install of the pinned opencode. Non-fatal: a failure is
196
+ * recorded and the run finishes cleanly when the subsequent connect fails.
197
+ * From 1.18 opencode's postinstall script writes the `opencode` command, and
198
+ * npm 12 blocks it unless allowed, leaving a placeholder that exits 1; so npm
199
+ * allows that one script and the result must print the pinned version
200
+ * (ORI-2523). `env` exists for tests. */
201
+ export declare function installOpenCodePinned(version: string, env?: NodeJS.ProcessEnv): InstallResult;
195
202
  export declare function runHostedLoop(opts: RunHostedLoopOptions): Promise<HostedLoopResult>;
196
203
  export declare function startHostedLoopSession(context: HostedLoopSessionContext): Promise<HostedLoopSessionHandle>;
197
204
  export declare function runHostedLoopTurn(session: HostedLoopSessionHandle, turn: HostedLoopTurnContext, options: Omit<RunHostedLoopOptions, 'context' | 'taskPrompt' | 'sharedRuntime'> & {
@@ -1 +1 @@
1
- {"version":3,"file":"hosted-loop.d.ts","sourceRoot":"","sources":["../src/hosted-loop.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"hosted-loop.d.ts","sourceRoot":"","sources":["../src/hosted-loop.ts"],"names":[],"mappings":"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"}
@@ -152,13 +152,21 @@ function detectLoopPrebaked(flag, markerPath) {
152
152
  return flag === true || hasValidPrebakedMarker(markerPath);
153
153
  }
154
154
  /** Best-effort global install of the pinned opencode. Non-fatal: a failure is
155
- * recorded and the run finishes cleanly when the subsequent connect fails. */
156
- function installOpenCodePinned(version) {
157
- const command = `bun add -g opencode-ai@${version} >/dev/null 2>&1 || ` +
158
- `npm install -g opencode-ai@${version} >/dev/null 2>&1`;
159
- const res = spawnSync('bash', ['-c', command], { encoding: 'utf8' });
155
+ * recorded and the run finishes cleanly when the subsequent connect fails.
156
+ * From 1.18 opencode's postinstall script writes the `opencode` command, and
157
+ * npm 12 blocks it unless allowed, leaving a placeholder that exits 1; so npm
158
+ * allows that one script and the result must print the pinned version
159
+ * (ORI-2523). `env` exists for tests. */
160
+ export function installOpenCodePinned(version, env) {
161
+ const command = `{ bun add -g opencode-ai@${version} >/dev/null 2>&1 || ` +
162
+ `npm install -g --allow-scripts=opencode-ai opencode-ai@${version} >/dev/null 2>&1; } && ` +
163
+ `v="$(opencode --version 2>/dev/null)" && [ "$v" = '${version}' ]`;
164
+ const res = spawnSync('bash', ['-c', command], { encoding: 'utf8', ...(env ? { env } : {}) });
160
165
  const ok = (res.status ?? 1) === 0;
161
- return { ok, detail: ok ? `installed opencode-ai@${version}` : `install exit ${res.status ?? 'unknown'}` };
166
+ return {
167
+ ok,
168
+ detail: ok ? `installed opencode-ai@${version}` : `install exit ${res.status ?? 'unknown'}, or opencode --version is not ${version}`,
169
+ };
162
170
  }
163
171
  /** Node child_process spawner for `opencode serve` (the sandbox runtime is
164
172
  * node24 — Bun.spawn is not guaranteed present, so spawnOpenCode is given this
package/dist/index.js CHANGED
@@ -1794,10 +1794,10 @@ function isCliEntrypoint() {
1794
1794
  }
1795
1795
  if (isCliEntrypoint()) {
1796
1796
  const rawArgs = process.argv.slice(2);
1797
- withPassiveUpdateNotice(rawArgs, getCliVersion, printError, args => main(args).catch(error => {
1797
+ withPassiveUpdateNotice(rawArgs, getCliVersion, printError, args => main(args).catch(async (error) => {
1798
1798
  const message = error instanceof Error ? error.message : 'Unknown error';
1799
1799
  // The reporter email is unknown on the failure path, so the record masks every address.
1800
- writeLastErrorRecord({
1800
+ await writeLastErrorRecord({
1801
1801
  argv: args,
1802
1802
  message,
1803
1803
  code: extractLastErrorCode(error),
@@ -30,8 +30,10 @@ export interface WriteLastErrorRecordOptions {
30
30
  configDir?: string;
31
31
  }
32
32
  export declare function extractLastErrorCode(error: unknown): string | null;
33
+ export declare function isStringWithinCap(value: unknown, maximumCharacters: number, wasTruncated: boolean): value is string;
34
+ export declare function boundedServerBaseUrl(value: string | null | undefined): string | null;
33
35
  export declare function buildLastErrorRecord(input: LastErrorRecordInput): LastErrorRecord;
34
36
  export declare function getLastErrorRecordPath(configDir?: string): string;
35
- export declare function writeLastErrorRecord(input: LastErrorRecordInput, options?: WriteLastErrorRecordOptions): void;
36
- export declare function readLastErrorRecord(configDir?: string): LastErrorRecord | null;
37
+ export declare function writeLastErrorRecord(input: LastErrorRecordInput, options?: WriteLastErrorRecordOptions): Promise<void>;
38
+ export declare function readLastErrorRecord(configDir?: string): Promise<LastErrorRecord | null>;
37
39
  //# sourceMappingURL=last-error-record.d.ts.map