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.
- package/dist/dataset-clone-workflow.d.ts +11 -0
- package/dist/dataset-clone-workflow.d.ts.map +1 -0
- package/dist/dataset-clone-workflow.js +100 -0
- package/dist/dataset-commands.d.ts.map +1 -1
- package/dist/dataset-commands.js +6 -29
- package/dist/dataset-transfer-upload.d.ts +2 -6
- package/dist/dataset-transfer-upload.d.ts.map +1 -1
- package/dist/dataset-transfer-upload.js +9 -2
- package/dist/dataset-upload-snapshot.d.ts.map +1 -1
- package/dist/dataset-upload-snapshot.js +7 -1
- package/dist/dataset-version-workflow.d.ts +24 -0
- package/dist/dataset-version-workflow.d.ts.map +1 -0
- package/dist/dataset-version-workflow.js +99 -0
- package/dist/feedback-cli.js +3 -3
- package/dist/hosted-harness-opencode.d.ts +1 -1
- package/dist/hosted-harness-opencode.js +7 -7
- package/dist/hosted-loop-lifecycle.d.ts +3 -2
- package/dist/hosted-loop-lifecycle.d.ts.map +1 -1
- package/dist/hosted-loop-lifecycle.js +3 -2
- package/dist/hosted-loop.d.ts +7 -0
- package/dist/hosted-loop.d.ts.map +1 -1
- package/dist/hosted-loop.js +14 -6
- package/dist/index.js +2 -2
- package/dist/last-error-record.d.ts +4 -2
- package/dist/last-error-record.d.ts.map +1 -1
- package/dist/last-error-record.js +10 -68
- package/dist/last-error-workflow.d.ts +4 -0
- package/dist/last-error-workflow.d.ts.map +1 -0
- package/dist/last-error-workflow.js +78 -0
- package/dist/task-commands.d.ts.map +1 -1
- package/dist/task-commands.js +9 -16
- package/dist/task-report-workflow.d.ts +47 -0
- package/dist/task-report-workflow.d.ts.map +1 -0
- package/dist/task-report-workflow.js +160 -0
- package/package.json +1 -1
- package/src/dataset-clone-workflow.ts +100 -0
- package/src/dataset-commands.ts +6 -53
- package/src/dataset-transfer-upload.ts +12 -5
- package/src/dataset-upload-snapshot.ts +8 -1
- package/src/dataset-version-workflow.ts +105 -0
- package/src/feedback-cli.ts +4 -4
- package/src/hosted-harness-opencode.ts +7 -7
- package/src/hosted-loop-lifecycle.ts +3 -2
- package/src/hosted-loop.ts +14 -6
- package/src/index.ts +2 -2
- package/src/last-error-record.ts +11 -85
- package/src/last-error-workflow.ts +121 -0
- package/src/task-commands.ts +9 -43
- 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":"
|
|
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"}
|
package/dist/dataset-commands.js
CHANGED
|
@@ -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
|
|
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
|
|
518
|
-
|
|
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
|
|
504
|
+
printJson({ dataset });
|
|
528
505
|
return;
|
|
529
506
|
}
|
|
530
|
-
printLine(`Cloned dataset ${sanitizeTerminalText(
|
|
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:
|
|
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":"
|
|
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 =>
|
|
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":"
|
|
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
|
-
|
|
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
|
+
}
|
package/dist/feedback-cli.js
CHANGED
|
@@ -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.
|
|
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
|
-
//
|
|
58
|
-
//
|
|
59
|
-
//
|
|
60
|
-
//
|
|
61
|
-
//
|
|
62
|
-
//
|
|
63
|
-
export const OPENCODE_PINNED_VERSION = '1.
|
|
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.
|
|
34
|
-
*
|
|
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":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAA;AACvD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAA;AAErE
|
|
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.
|
|
32
|
-
*
|
|
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.
|
package/dist/hosted-loop.d.ts
CHANGED
|
@@ -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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"}
|
package/dist/hosted-loop.js
CHANGED
|
@@ -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
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
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 {
|
|
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
|