orizu 0.5.23 → 0.5.24
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +18 -10
- package/dist/child-output-tee.d.ts +48 -0
- package/dist/child-output-tee.d.ts.map +1 -0
- package/dist/child-output-tee.js +512 -0
- package/dist/cli-auth-browser-page.d.ts +2 -0
- package/dist/cli-auth-browser-page.d.ts.map +1 -0
- package/dist/cli-auth-browser-page.js +107 -0
- package/dist/github-setup.js +8 -8
- package/dist/headless-login.d.ts +17 -0
- package/dist/headless-login.d.ts.map +1 -0
- package/dist/headless-login.js +105 -0
- package/dist/help.d.ts.map +1 -1
- package/dist/help.js +30 -22
- package/dist/hosted-boot.js +3 -3
- package/dist/hosted-bootstrap.js +2 -2
- package/dist/hosted-commands.d.ts +2 -0
- package/dist/hosted-commands.d.ts.map +1 -1
- package/dist/hosted-commands.js +11 -0
- package/dist/hosted-environment.d.ts +3 -0
- package/dist/hosted-environment.d.ts.map +1 -0
- package/dist/hosted-environment.js +2 -0
- package/dist/hosted-gepa-cli.d.ts +3 -0
- package/dist/hosted-gepa-cli.d.ts.map +1 -1
- package/dist/hosted-gepa-cli.js +92 -5
- package/dist/hosted-loop.d.ts +1 -1
- package/dist/hosted-loop.d.ts.map +1 -1
- package/dist/hosted-loop.js +2 -1
- package/dist/hosted-optimization-cli.d.ts +7 -0
- package/dist/hosted-optimization-cli.d.ts.map +1 -0
- package/dist/hosted-optimization-cli.js +218 -0
- package/dist/hosted-optimization-refusals.d.ts +88 -0
- package/dist/hosted-optimization-refusals.d.ts.map +1 -0
- package/dist/hosted-optimization-refusals.js +86 -0
- package/dist/hosted-optimization.d.ts +6 -0
- package/dist/hosted-optimization.d.ts.map +1 -0
- package/dist/hosted-optimization.js +436 -0
- package/dist/hosted-provider-settings.d.ts +3 -0
- package/dist/hosted-provider-settings.d.ts.map +1 -1
- package/dist/hosted-provider-settings.js +9 -0
- package/dist/hosted-session-cli.d.ts.map +1 -1
- package/dist/hosted-session-cli.js +6 -1
- package/dist/hosted-skill-staging.d.ts +9 -9
- package/dist/hosted-skill-staging.d.ts.map +1 -1
- package/dist/hosted-skill-staging.js +13 -10
- package/dist/index.d.ts +4 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +338 -368
- package/dist/report-comments-cli.d.ts +1 -0
- package/dist/report-comments-cli.d.ts.map +1 -1
- package/dist/report-comments-cli.js +70 -4
- package/dist/runner-dir-verify.d.ts +5 -0
- package/dist/runner-dir-verify.d.ts.map +1 -1
- package/dist/runner-dir-verify.js +41 -9
- package/dist/runner-version-materialization.d.ts +6 -0
- package/dist/runner-version-materialization.d.ts.map +1 -0
- package/dist/runner-version-materialization.js +64 -0
- package/dist/setup-onboarding.d.ts +16 -0
- package/dist/setup-onboarding.d.ts.map +1 -0
- package/dist/setup-onboarding.js +59 -0
- package/dist/skill-installer.d.ts +3 -3
- package/dist/skill-installer.d.ts.map +1 -1
- package/dist/skill-installer.js +39 -3
- package/dist/skilled-proposer-launch.d.ts +5 -1
- package/dist/skilled-proposer-launch.d.ts.map +1 -1
- package/dist/skilled-proposer-launch.js +27 -5
- package/dist/skilled-proposer-wire.d.ts +2 -0
- package/dist/skilled-proposer-wire.d.ts.map +1 -0
- package/dist/skilled-proposer-wire.js +25 -0
- package/dist/workspace.d.ts +14 -0
- package/dist/workspace.d.ts.map +1 -1
- package/dist/workspace.js +63 -4
- package/package.json +1 -1
- package/scripts/vendor-orizu-skill.mjs +3 -3
- package/src/child-output-tee.ts +587 -0
- package/src/cli-auth-browser-page.ts +108 -0
- package/src/github-setup.ts +8 -8
- package/src/headless-login.ts +178 -0
- package/src/help.ts +30 -22
- package/src/hosted-boot.ts +3 -3
- package/src/hosted-bootstrap.ts +2 -2
- package/src/hosted-commands.ts +16 -0
- package/src/hosted-environment.ts +2 -0
- package/src/hosted-gepa-cli.ts +112 -4
- package/src/hosted-loop.ts +2 -1
- package/src/hosted-optimization-cli.ts +215 -0
- package/src/hosted-optimization-refusals.ts +101 -0
- package/src/hosted-optimization.ts +483 -0
- package/src/hosted-provider-settings.ts +12 -0
- package/src/hosted-session-cli.ts +6 -1
- package/src/hosted-skill-staging.ts +17 -14
- package/src/index.ts +289 -290
- package/src/report-comments-cli.ts +83 -5
- package/src/runner-dir-verify.ts +74 -9
- package/src/runner-version-materialization.ts +56 -0
- package/src/setup-onboarding.ts +64 -0
- package/src/skill-installer.ts +39 -3
- package/src/skilled-proposer-launch.ts +36 -5
- package/src/skilled-proposer-wire.ts +22 -0
- package/src/workspace.ts +65 -4
- package/vendor/orizu-gepa/src/orizu_gepa_connector/runtime.py +56 -21
- package/vendor/orizu-gepa-python/src/orizu_gepa/client.py +76 -13
- package/vendor/orizu-gepa-python/src/orizu_gepa/optimizer.py +16 -2
- package/vendor/skills/{orizu-cli → orizu}/SKILL.md +7 -3
- package/vendor/skills/orizu/agents/openai.yaml +4 -0
- package/vendor/skills/{orizu-cli → orizu}/references/assess-and-plan.md +1 -1
- package/vendor/skills/{orizu-cli → orizu}/references/building-apps.md +1 -1
- package/vendor/skills/{orizu-cli → orizu}/references/cli-reference.md +4 -4
- package/vendor/skills/{orizu-cli → orizu}/references/migrate-existing-gepa-setup.md +1 -1
- package/vendor/skills/{orizu-cli → orizu}/references/optimization-with-gepa.md +17 -3
- package/vendor/skills/orizu-cli/agents/openai.yaml +0 -4
- /package/vendor/skills/{orizu-cli → orizu}/references/building-judges.md +0 -0
- /package/vendor/skills/{orizu-cli → orizu}/references/dataset-design.md +0 -0
- /package/vendor/skills/{orizu-cli → orizu}/references/eval-strategy.md +0 -0
- /package/vendor/skills/{orizu-cli → orizu}/references/instructions-after-prompts.md +0 -0
- /package/vendor/skills/{orizu-cli → orizu}/references/optimization-reports.md +0 -0
- /package/vendor/skills/{orizu-cli → orizu}/references/primer.md +0 -0
- /package/vendor/skills/{orizu-cli → orizu}/references/prompt-control-plane.md +0 -0
- /package/vendor/skills/{orizu-cli → orizu}/scripts/test-app.mjs +0 -0
package/README.md
CHANGED
|
@@ -86,12 +86,15 @@ Install the CLI globally with your package manager:
|
|
|
86
86
|
| pnpm | `pnpm add -g orizu` |
|
|
87
87
|
| Bun | `bun add -g orizu` |
|
|
88
88
|
|
|
89
|
-
Then run the guided setup — it signs you in,
|
|
90
|
-
|
|
91
|
-
|
|
89
|
+
Then run the guided setup — it signs you in, asks you to choose or create a
|
|
90
|
+
team and project, initializes the local workspace contract, installs the shared
|
|
91
|
+
`~/.agents/skills/orizu` skill plus selected native targets, and optionally
|
|
92
|
+
launches Claude, Codex, or Pi:
|
|
92
93
|
|
|
93
94
|
```bash
|
|
94
95
|
orizu setup
|
|
96
|
+
# Scripts use explicit choices after `orizu login --headless`:
|
|
97
|
+
orizu setup --team acme --project support-agent --agent codex --non-interactive
|
|
95
98
|
```
|
|
96
99
|
|
|
97
100
|
To repair or customize skill installs later, run the companion skill installer
|
|
@@ -137,9 +140,8 @@ Agents are first-class users of this CLI: **every command supports `--json`**
|
|
|
137
140
|
(as a prefix, `orizu --json teams list`, or a trailing flag) and emits a single
|
|
138
141
|
machine-readable JSON document instead of formatted text. Discover the full
|
|
139
142
|
command surface, including global options, with `orizu capabilities --json`.
|
|
140
|
-
Hosted agents may read and sync instruction sets and prepare complete manifests. A local coding agent using the user's token runs instruction create, push, shape,
|
|
141
|
-
|
|
142
|
-
In a hosted session, a human curator using the local CLI must run both categories.
|
|
143
|
+
Hosted agents may read and sync instruction sets, create profile seeds, run shape add/remove with team-scoped curator authority, and prepare complete manifests. A local coding agent using the user's token runs instruction create, push, shape add/remove, archive, and restore itself after plan ratification. It gathers only read-only pointer-resolution and binding evidence; a human curator executes every production/default pointer command on every surface.
|
|
144
|
+
In a hosted session, a human curator using the local CLI must run create/push, archive/restore, and every pointer command; shape add/remove stays agent-runnable because it creates unpromoted heads only.
|
|
143
145
|
|
|
144
146
|
## Authentication
|
|
145
147
|
|
|
@@ -152,6 +154,12 @@ orizu login
|
|
|
152
154
|
This will open a browser tab for you to login with. You must either have an account on the [Orizu platform](https://orizu.ai) or it will help you create one.
|
|
153
155
|
Approving the login creates a personal access token for the CLI and stores it in your local Orizu credentials file. You can revoke CLI tokens from the Personal Tokens page in Orizu.
|
|
154
156
|
|
|
157
|
+
In an SSH or display-less Linux session, the CLI automatically prints an approval URL and polls for completion instead of opening a local browser. Force this mode when needed with:
|
|
158
|
+
|
|
159
|
+
```bash
|
|
160
|
+
orizu login --headless
|
|
161
|
+
```
|
|
162
|
+
|
|
155
163
|
**Check the signed-in user**
|
|
156
164
|
|
|
157
165
|
```bash
|
|
@@ -239,12 +247,12 @@ orizu logout
|
|
|
239
247
|
<td colspan="2"><strong>Report comments</strong></td>
|
|
240
248
|
</tr>
|
|
241
249
|
<tr>
|
|
242
|
-
<td>List report comments</td>
|
|
243
|
-
<td><code>orizu comments list --prompt <promptIdOrName> --project ops-eval/support-qa</code><br><code>orizu comments list --run <runId></code><br><code>orizu comments list --task <taskId></code></td>
|
|
250
|
+
<td>List report or README comments</td>
|
|
251
|
+
<td><code>orizu comments list --prompt <promptIdOrName> --project ops-eval/support-qa</code><br><code>orizu comments list --run <runId></code><br><code>orizu comments list --task <taskId></code><br><code>orizu comments list --dataset <datasetIdOrName> --project ops-eval/support-qa</code></td>
|
|
244
252
|
</tr>
|
|
245
253
|
<tr>
|
|
246
254
|
<td>Add or update comments</td>
|
|
247
|
-
<td><code>orizu comments add --run <runId> --body @comment.md --anchor "Summary" --lines 4:6</code><br><code>orizu comments reply <commentId> --body "Fixed"</code><br><code>orizu comments resolve <commentId></code></td>
|
|
255
|
+
<td><code>orizu comments add --run <runId> --body @comment.md --anchor "Summary" --lines 4:6</code><br><code>orizu comments add --dataset <datasetIdOrName> --project ops-eval/support-qa --body "Clarify this README" --anchor "Summary" --lines 4:6</code><br><code>orizu comments reply <commentId> --body "Fixed"</code><br><code>orizu comments resolve <commentId></code></td>
|
|
248
256
|
</tr>
|
|
249
257
|
<tr>
|
|
250
258
|
<td colspan="2"><strong>Diff comments</strong></td>
|
|
@@ -412,4 +420,4 @@ Use `--json` on supported task and app commands when automation needs structured
|
|
|
412
420
|
## More Documentation
|
|
413
421
|
|
|
414
422
|
- [docs/cli.md](docs/cli.md): complete CLI guide and command reference
|
|
415
|
-
- [skills/orizu
|
|
423
|
+
- [skills/orizu/references/cli-reference.md](skills/orizu/references/cli-reference.md): compact command matrix and end-to-end flows
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { Readable, Writable } from 'node:stream';
|
|
2
|
+
declare class FileDescriptorSink extends Writable {
|
|
3
|
+
private readonly descriptor;
|
|
4
|
+
private readonly activeWriteCancellations;
|
|
5
|
+
private isLiveOutputAvailable;
|
|
6
|
+
private relay;
|
|
7
|
+
constructor(descriptor: number);
|
|
8
|
+
_write(chunk: Buffer, _encoding: BufferEncoding, callback: (error?: Error | null) => void): void;
|
|
9
|
+
prepare(): Promise<void>;
|
|
10
|
+
cancelPendingWrites(): void;
|
|
11
|
+
private relayProcess;
|
|
12
|
+
}
|
|
13
|
+
export declare const childOutputSinks: {
|
|
14
|
+
stdout: FileDescriptorSink;
|
|
15
|
+
stderr: FileDescriptorSink;
|
|
16
|
+
};
|
|
17
|
+
export interface PipedChild {
|
|
18
|
+
stdout: Readable;
|
|
19
|
+
stderr: Readable;
|
|
20
|
+
exited: Promise<number | null>;
|
|
21
|
+
signalCode: NodeJS.Signals | null;
|
|
22
|
+
kill(signal?: number | NodeJS.Signals): void;
|
|
23
|
+
}
|
|
24
|
+
export declare function spawnPipedChild(command: string, args: string[], environment: NodeJS.ProcessEnv): Promise<PipedChild>;
|
|
25
|
+
export declare function writeChildStderr(text: string): Promise<void>;
|
|
26
|
+
export interface ChildOutputForwarding {
|
|
27
|
+
completed: Promise<void>;
|
|
28
|
+
failure: Promise<Error>;
|
|
29
|
+
failureReason(): Error | undefined;
|
|
30
|
+
expectSourceClose(): void;
|
|
31
|
+
stopLiveOutput(): void;
|
|
32
|
+
}
|
|
33
|
+
export interface ChildOutputCapture {
|
|
34
|
+
stdout(chunk: string): void;
|
|
35
|
+
stderr(chunk: string): void;
|
|
36
|
+
}
|
|
37
|
+
export declare function completePipedChild(child: PipedChild, forwarding: readonly ChildOutputForwarding[]): Promise<number | null>;
|
|
38
|
+
export declare function runPipedChild(command: string, args: string[], environment: NodeJS.ProcessEnv, onSpawn: () => Promise<void>, capture: ChildOutputCapture, observeChild?: (child: PipedChild) => void): Promise<{
|
|
39
|
+
status: number | null;
|
|
40
|
+
error?: Error;
|
|
41
|
+
}>;
|
|
42
|
+
/**
|
|
43
|
+
* Forward a child stream live while retaining a bounded caller-owned copy.
|
|
44
|
+
* Transient sink slowness pushes back; a stall degrades safely to capture-only.
|
|
45
|
+
*/
|
|
46
|
+
export declare function teeChildOutput(source: Readable, destination: Writable, capture: (chunk: string) => void): ChildOutputForwarding;
|
|
47
|
+
export {};
|
|
48
|
+
//# sourceMappingURL=child-output-tee.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"child-output-tee.d.ts","sourceRoot":"","sources":["../src/child-output-tee.ts"],"names":[],"mappings":"AAWA,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;AAsHhD,cAAM,kBAAmB,SAAQ,QAAQ;IAK3B,OAAO,CAAC,QAAQ,CAAC,UAAU;IAJvC,OAAO,CAAC,QAAQ,CAAC,wBAAwB,CAAwB;IACjE,OAAO,CAAC,qBAAqB,CAAO;IACpC,OAAO,CAAC,KAAK,CAA6B;gBAEb,UAAU,EAAE,MAAM;IAItC,MAAM,CACb,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,cAAc,EACzB,QAAQ,EAAE,CAAC,KAAK,CAAC,EAAE,KAAK,GAAG,IAAI,KAAK,IAAI,GACvC,IAAI;IAgCD,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAK9B,mBAAmB,IAAI,IAAI;IAS3B,OAAO,CAAC,YAAY;CAiCrB;AAED,eAAO,MAAM,gBAAgB;;;CAG5B,CAAA;AAED,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,QAAQ,CAAA;IAChB,MAAM,EAAE,QAAQ,CAAA;IAChB,MAAM,EAAE,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAA;IAC9B,UAAU,EAAE,MAAM,CAAC,OAAO,GAAG,IAAI,CAAA;IACjC,IAAI,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC,OAAO,GAAG,IAAI,CAAA;CAC7C;AAqDD,wBAAsB,eAAe,CACnC,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EAAE,EACd,WAAW,EAAE,MAAM,CAAC,UAAU,GAC7B,OAAO,CAAC,UAAU,CAAC,CAiDrB;AAoCD,wBAAsB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAWlE;AAED,MAAM,WAAW,qBAAqB;IACpC,SAAS,EAAE,OAAO,CAAC,IAAI,CAAC,CAAA;IACxB,OAAO,EAAE,OAAO,CAAC,KAAK,CAAC,CAAA;IACvB,aAAa,IAAI,KAAK,GAAG,SAAS,CAAA;IAClC,iBAAiB,IAAI,IAAI,CAAA;IACzB,cAAc,IAAI,IAAI,CAAA;CACvB;AAED,MAAM,WAAW,kBAAkB;IACjC,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IAC3B,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;CAC5B;AAuCD,wBAAsB,kBAAkB,CACtC,KAAK,EAAE,UAAU,EACjB,UAAU,EAAE,SAAS,qBAAqB,EAAE,GAC3C,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CA6CxB;AAED,wBAAsB,aAAa,CACjC,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EAAE,EACd,WAAW,EAAE,MAAM,CAAC,UAAU,EAC9B,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,EAC5B,OAAO,EAAE,kBAAkB,EAC3B,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,GACzC,OAAO,CAAC;IAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,KAAK,CAAC,EAAE,KAAK,CAAA;CAAE,CAAC,CAqBnD;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAC5B,MAAM,EAAE,QAAQ,EAChB,WAAW,EAAE,QAAQ,EACrB,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,GAC/B,qBAAqB,CA2DvB"}
|
|
@@ -0,0 +1,512 @@
|
|
|
1
|
+
import { spawn, spawnSync } from 'node:child_process';
|
|
2
|
+
import { closeSync, constants, mkdtempSync, openSync, read as readFileDescriptor, rmSync, } from 'node:fs';
|
|
3
|
+
import { tmpdir } from 'node:os';
|
|
4
|
+
import { join } from 'node:path';
|
|
5
|
+
import { Readable, Writable } from 'node:stream';
|
|
6
|
+
const CHILD_OUTPUT_PREFETCH_MAX_BYTES = 64 * 1024;
|
|
7
|
+
const CHILD_OUTPUT_READ_BUFFER_BYTES = 16 * 1024;
|
|
8
|
+
const EMPTY_FIFO_INITIAL_RETRY_MS = 4;
|
|
9
|
+
const EMPTY_FIFO_MAX_RETRY_MS = 64;
|
|
10
|
+
const FORWARDING_FAILURE_TERMINATION_TIMEOUT_MS = 250, LIVE_OUTPUT_STALL_TIMEOUT_MS = 1_500;
|
|
11
|
+
const LIVE_OUTPUT_RELAY_SCRIPT = [
|
|
12
|
+
"const { writeSync } = require('node:fs')",
|
|
13
|
+
'process.stdout._handle?.setBlocking(true)',
|
|
14
|
+
'let buffered = Buffer.alloc(0)',
|
|
15
|
+
'process.stdin.on(\'data\', chunk => {',
|
|
16
|
+
' buffered = Buffer.concat([buffered, chunk])',
|
|
17
|
+
' while (buffered.length >= 4) {',
|
|
18
|
+
' const length = buffered.readUInt32BE(0)',
|
|
19
|
+
' if (buffered.length < length + 4) return',
|
|
20
|
+
' const payload = buffered.subarray(4, length + 4)',
|
|
21
|
+
' buffered = buffered.subarray(length + 4)',
|
|
22
|
+
' for (let offset = 0; offset < payload.length; )',
|
|
23
|
+
' offset += writeSync(1, payload, offset, payload.length - offset)',
|
|
24
|
+
" writeSync(3, '1')",
|
|
25
|
+
' }',
|
|
26
|
+
'})',
|
|
27
|
+
"writeSync(3, 'R')",
|
|
28
|
+
].join('\n');
|
|
29
|
+
class FileDescriptorSource extends Readable {
|
|
30
|
+
descriptor;
|
|
31
|
+
readBuffer = Buffer.allocUnsafe(CHILD_OUTPUT_READ_BUFFER_BYTES);
|
|
32
|
+
emptyRetryMilliseconds = EMPTY_FIFO_INITIAL_RETRY_MS;
|
|
33
|
+
isReadPending = false;
|
|
34
|
+
retryTimer;
|
|
35
|
+
pendingDestroy;
|
|
36
|
+
constructor(descriptor) {
|
|
37
|
+
super({ highWaterMark: CHILD_OUTPUT_PREFETCH_MAX_BYTES });
|
|
38
|
+
this.descriptor = descriptor;
|
|
39
|
+
}
|
|
40
|
+
_read() {
|
|
41
|
+
if (this.isReadPending || this.retryTimer || this.descriptor === undefined)
|
|
42
|
+
return;
|
|
43
|
+
this.isReadPending = true;
|
|
44
|
+
readFileDescriptor(this.descriptor, this.readBuffer, 0, this.readBuffer.byteLength, null, (error, bytesRead) => {
|
|
45
|
+
this.isReadPending = false;
|
|
46
|
+
if (this.pendingDestroy) {
|
|
47
|
+
this.finishDestroy();
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
if (error) {
|
|
51
|
+
if (error.code === 'EINTR') {
|
|
52
|
+
this._read();
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
if (['EAGAIN', 'EWOULDBLOCK'].includes(error.code ?? '')) {
|
|
56
|
+
const delay = this.emptyRetryMilliseconds;
|
|
57
|
+
this.emptyRetryMilliseconds = Math.min(EMPTY_FIFO_MAX_RETRY_MS, this.emptyRetryMilliseconds * 2);
|
|
58
|
+
this.retryTimer = setTimeout(() => {
|
|
59
|
+
this.retryTimer = undefined;
|
|
60
|
+
this._read();
|
|
61
|
+
}, delay);
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
this.destroy(error);
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
if (bytesRead === 0) {
|
|
68
|
+
this.push(null);
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
this.emptyRetryMilliseconds = EMPTY_FIFO_INITIAL_RETRY_MS;
|
|
72
|
+
this.push(Buffer.from(this.readBuffer.subarray(0, bytesRead)));
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
_destroy(error, callback) {
|
|
76
|
+
if (this.retryTimer)
|
|
77
|
+
clearTimeout(this.retryTimer);
|
|
78
|
+
this.retryTimer = undefined;
|
|
79
|
+
this.pendingDestroy = { error, callback };
|
|
80
|
+
if (!this.isReadPending)
|
|
81
|
+
this.finishDestroy();
|
|
82
|
+
}
|
|
83
|
+
finishDestroy() {
|
|
84
|
+
const pendingDestroy = this.pendingDestroy;
|
|
85
|
+
if (!pendingDestroy)
|
|
86
|
+
return;
|
|
87
|
+
this.pendingDestroy = undefined;
|
|
88
|
+
const descriptor = this.descriptor;
|
|
89
|
+
this.descriptor = undefined;
|
|
90
|
+
try {
|
|
91
|
+
if (descriptor !== undefined)
|
|
92
|
+
closeSync(descriptor);
|
|
93
|
+
pendingDestroy.callback(pendingDestroy.error);
|
|
94
|
+
}
|
|
95
|
+
catch (error) {
|
|
96
|
+
pendingDestroy.callback(error instanceof Error ? error : new Error(String(error)));
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
class FileDescriptorSink extends Writable {
|
|
101
|
+
descriptor;
|
|
102
|
+
activeWriteCancellations = new Set();
|
|
103
|
+
isLiveOutputAvailable = true;
|
|
104
|
+
relay;
|
|
105
|
+
constructor(descriptor) {
|
|
106
|
+
super({ highWaterMark: 16 * 1024 });
|
|
107
|
+
this.descriptor = descriptor;
|
|
108
|
+
}
|
|
109
|
+
_write(chunk, _encoding, callback) {
|
|
110
|
+
if (!this.isLiveOutputAvailable) {
|
|
111
|
+
callback();
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
let relay;
|
|
115
|
+
let hasSettled = false;
|
|
116
|
+
const settle = (error) => {
|
|
117
|
+
if (hasSettled)
|
|
118
|
+
return;
|
|
119
|
+
hasSettled = true;
|
|
120
|
+
if (error)
|
|
121
|
+
this.isLiveOutputAvailable = false;
|
|
122
|
+
this.activeWriteCancellations.delete(cancel);
|
|
123
|
+
relay?.acknowledgements.off('data', acknowledge);
|
|
124
|
+
relay?.child.off('exit', relayExited);
|
|
125
|
+
callback(error);
|
|
126
|
+
};
|
|
127
|
+
const acknowledge = () => settle();
|
|
128
|
+
const relayExited = () => settle(new Error('live output relay exited before write acknowledgement'));
|
|
129
|
+
const cancel = () => settle();
|
|
130
|
+
this.activeWriteCancellations.add(cancel);
|
|
131
|
+
try {
|
|
132
|
+
relay = this.relayProcess();
|
|
133
|
+
}
|
|
134
|
+
catch (error) {
|
|
135
|
+
settle(errorFromUnknown(error));
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
void relay.ready.then(() => {
|
|
139
|
+
if (hasSettled)
|
|
140
|
+
return;
|
|
141
|
+
relay.acknowledgements.once('data', acknowledge);
|
|
142
|
+
relay.child.once('exit', relayExited);
|
|
143
|
+
const frame = Buffer.allocUnsafe(chunk.byteLength + 4);
|
|
144
|
+
frame.writeUInt32BE(chunk.byteLength);
|
|
145
|
+
chunk.copy(frame, 4);
|
|
146
|
+
relay.input.write(frame, error => { if (error)
|
|
147
|
+
settle(error); });
|
|
148
|
+
}).catch(error => settle(errorFromUnknown(error)));
|
|
149
|
+
}
|
|
150
|
+
async prepare() {
|
|
151
|
+
if (!this.isLiveOutputAvailable)
|
|
152
|
+
return;
|
|
153
|
+
await this.relayProcess().ready;
|
|
154
|
+
}
|
|
155
|
+
cancelPendingWrites() {
|
|
156
|
+
this.isLiveOutputAvailable = false;
|
|
157
|
+
const relay = this.relay;
|
|
158
|
+
this.relay = undefined;
|
|
159
|
+
relay?.input.destroy();
|
|
160
|
+
relay?.child.kill('SIGKILL');
|
|
161
|
+
for (const cancel of [...this.activeWriteCancellations])
|
|
162
|
+
cancel();
|
|
163
|
+
}
|
|
164
|
+
relayProcess() {
|
|
165
|
+
if (this.relay)
|
|
166
|
+
return this.relay;
|
|
167
|
+
const child = spawn('node', ['-e', LIVE_OUTPUT_RELAY_SCRIPT], {
|
|
168
|
+
stdio: ['pipe', this.descriptor, 'ignore', 'pipe'],
|
|
169
|
+
});
|
|
170
|
+
const input = child.stdin;
|
|
171
|
+
const acknowledgements = child.stdio[3];
|
|
172
|
+
if (!input || !acknowledgements)
|
|
173
|
+
throw new Error('live output relay has no control pipes');
|
|
174
|
+
child.on('error', () => { });
|
|
175
|
+
input.on('error', () => { });
|
|
176
|
+
acknowledgements.on('error', () => { });
|
|
177
|
+
const ready = new Promise((resolve, reject) => {
|
|
178
|
+
acknowledgements.once('data', chunk => {
|
|
179
|
+
if (chunk.includes('R'.charCodeAt(0)))
|
|
180
|
+
resolve();
|
|
181
|
+
else
|
|
182
|
+
reject(new Error('live output relay sent an invalid readiness acknowledgement'));
|
|
183
|
+
});
|
|
184
|
+
child.once('exit', () => reject(new Error('live output relay exited before readiness')));
|
|
185
|
+
child.once('error', reject);
|
|
186
|
+
});
|
|
187
|
+
void ready.catch(() => { });
|
|
188
|
+
child.unref();
|
|
189
|
+
void ready.then(() => {
|
|
190
|
+
input.unref?.();
|
|
191
|
+
acknowledgements.unref?.();
|
|
192
|
+
}, () => { });
|
|
193
|
+
const relay = { child, input, acknowledgements, ready };
|
|
194
|
+
child.once('exit', () => {
|
|
195
|
+
if (this.relay?.child !== child)
|
|
196
|
+
return;
|
|
197
|
+
this.relay = undefined;
|
|
198
|
+
});
|
|
199
|
+
this.relay = relay;
|
|
200
|
+
return relay;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
export const childOutputSinks = {
|
|
204
|
+
stdout: new FileDescriptorSink(1),
|
|
205
|
+
stderr: new FileDescriptorSink(2),
|
|
206
|
+
};
|
|
207
|
+
const POST_LEADER_CAPTURE_DRAIN_TIMEOUT_MS = 250;
|
|
208
|
+
function closeDescriptor(descriptor) {
|
|
209
|
+
if (descriptor === undefined)
|
|
210
|
+
return;
|
|
211
|
+
try {
|
|
212
|
+
closeSync(descriptor);
|
|
213
|
+
}
|
|
214
|
+
catch {
|
|
215
|
+
// Best-effort cleanup after another operation has already failed.
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
function createOutputFifo(name) {
|
|
219
|
+
const root = mkdtempSync(join(tmpdir(), 'orizu-child-output-'));
|
|
220
|
+
const fifoPath = join(root, name);
|
|
221
|
+
let anchorDescriptor;
|
|
222
|
+
let readDescriptor;
|
|
223
|
+
let writeDescriptor;
|
|
224
|
+
try {
|
|
225
|
+
const creation = spawnSync('mkfifo', [fifoPath], { stdio: 'ignore' });
|
|
226
|
+
if (creation.error)
|
|
227
|
+
throw creation.error;
|
|
228
|
+
if (creation.status !== 0) {
|
|
229
|
+
throw new Error(`mkfifo exited with status ${creation.status ?? 'unknown'}`);
|
|
230
|
+
}
|
|
231
|
+
// The temporary read/write anchor prevents either open from waiting for
|
|
232
|
+
// its peer. The child inherits the blocking write end; the parent polls a
|
|
233
|
+
// nonblocking read end so descendant-held descriptors remain cancellable.
|
|
234
|
+
anchorDescriptor = openSync(fifoPath, constants.O_RDWR | constants.O_NONBLOCK);
|
|
235
|
+
readDescriptor = openSync(fifoPath, constants.O_RDONLY | constants.O_NONBLOCK);
|
|
236
|
+
writeDescriptor = openSync(fifoPath, constants.O_WRONLY);
|
|
237
|
+
closeDescriptor(anchorDescriptor);
|
|
238
|
+
anchorDescriptor = undefined;
|
|
239
|
+
const source = new FileDescriptorSource(readDescriptor);
|
|
240
|
+
readDescriptor = undefined;
|
|
241
|
+
rmSync(root, { force: true, recursive: true });
|
|
242
|
+
return { source, writeDescriptor };
|
|
243
|
+
}
|
|
244
|
+
catch (error) {
|
|
245
|
+
closeDescriptor(writeDescriptor);
|
|
246
|
+
closeDescriptor(readDescriptor);
|
|
247
|
+
closeDescriptor(anchorDescriptor);
|
|
248
|
+
rmSync(root, { force: true, recursive: true });
|
|
249
|
+
throw error;
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
export async function spawnPipedChild(command, args, environment) {
|
|
253
|
+
const stdout = createOutputFifo('stdout');
|
|
254
|
+
let stderr;
|
|
255
|
+
try {
|
|
256
|
+
stderr = createOutputFifo('stderr');
|
|
257
|
+
}
|
|
258
|
+
catch (error) {
|
|
259
|
+
stdout.source.destroy();
|
|
260
|
+
closeDescriptor(stdout.writeDescriptor);
|
|
261
|
+
throw error;
|
|
262
|
+
}
|
|
263
|
+
let child;
|
|
264
|
+
try {
|
|
265
|
+
// Begin the bounded parent-side drain before an immediate child crash can
|
|
266
|
+
// strand bytes in the child's userland stdout/stderr buffers.
|
|
267
|
+
stdout.source.read(0);
|
|
268
|
+
stderr.source.read(0);
|
|
269
|
+
child = spawn(command, args, {
|
|
270
|
+
env: environment,
|
|
271
|
+
stdio: ['inherit', stdout.writeDescriptor, stderr.writeDescriptor],
|
|
272
|
+
});
|
|
273
|
+
}
|
|
274
|
+
catch (error) {
|
|
275
|
+
stdout.source.destroy();
|
|
276
|
+
stderr.source.destroy();
|
|
277
|
+
throw error;
|
|
278
|
+
}
|
|
279
|
+
finally {
|
|
280
|
+
closeDescriptor(stdout.writeDescriptor);
|
|
281
|
+
closeDescriptor(stderr.writeDescriptor);
|
|
282
|
+
}
|
|
283
|
+
// `close` also waits for descendant-held stdio descriptors. Observe the
|
|
284
|
+
// leader's exit so completePipedChild can enforce its bounded EOF grace.
|
|
285
|
+
const exited = new Promise(resolve => child.once('exit', resolve));
|
|
286
|
+
try {
|
|
287
|
+
await new Promise((resolve, reject) => {
|
|
288
|
+
child.once('spawn', resolve);
|
|
289
|
+
child.once('error', reject);
|
|
290
|
+
});
|
|
291
|
+
}
|
|
292
|
+
catch (error) {
|
|
293
|
+
stdout.source.destroy();
|
|
294
|
+
stderr.source.destroy();
|
|
295
|
+
throw error;
|
|
296
|
+
}
|
|
297
|
+
return {
|
|
298
|
+
stdout: stdout.source,
|
|
299
|
+
stderr: stderr.source,
|
|
300
|
+
exited,
|
|
301
|
+
get signalCode() { return child.signalCode; },
|
|
302
|
+
kill: signal => { child.kill(signal); },
|
|
303
|
+
};
|
|
304
|
+
}
|
|
305
|
+
const liveSinkStates = new WeakMap();
|
|
306
|
+
function liveSinkState(destination) {
|
|
307
|
+
const existing = liveSinkStates.get(destination);
|
|
308
|
+
if (existing)
|
|
309
|
+
return existing;
|
|
310
|
+
const state = { hasFailed: false };
|
|
311
|
+
destination.on('error', () => { state.hasFailed = true; });
|
|
312
|
+
liveSinkStates.set(destination, state);
|
|
313
|
+
return state;
|
|
314
|
+
}
|
|
315
|
+
async function writeLiveOutput(destination, state, text) {
|
|
316
|
+
if (state.hasFailed)
|
|
317
|
+
return;
|
|
318
|
+
await new Promise(resolve => {
|
|
319
|
+
try {
|
|
320
|
+
destination.write(text, error => {
|
|
321
|
+
if (error)
|
|
322
|
+
state.hasFailed = true;
|
|
323
|
+
resolve();
|
|
324
|
+
});
|
|
325
|
+
}
|
|
326
|
+
catch {
|
|
327
|
+
state.hasFailed = true;
|
|
328
|
+
resolve();
|
|
329
|
+
}
|
|
330
|
+
});
|
|
331
|
+
}
|
|
332
|
+
export async function writeChildStderr(text) {
|
|
333
|
+
const sink = childOutputSinks.stderr;
|
|
334
|
+
let timer;
|
|
335
|
+
const didForward = await Promise.race([
|
|
336
|
+
writeLiveOutput(sink, liveSinkState(sink), `${text}\n`).then(() => true),
|
|
337
|
+
new Promise(resolve => {
|
|
338
|
+
timer = setTimeout(() => resolve(false), LIVE_OUTPUT_STALL_TIMEOUT_MS);
|
|
339
|
+
}),
|
|
340
|
+
]);
|
|
341
|
+
if (timer)
|
|
342
|
+
clearTimeout(timer);
|
|
343
|
+
if (!didForward)
|
|
344
|
+
sink.cancelPendingWrites();
|
|
345
|
+
}
|
|
346
|
+
function errorFromUnknown(cause) {
|
|
347
|
+
return cause instanceof Error ? cause : new Error(String(cause));
|
|
348
|
+
}
|
|
349
|
+
async function waitForChildExit(child, timeoutMilliseconds) {
|
|
350
|
+
let timer;
|
|
351
|
+
const didExit = await Promise.race([
|
|
352
|
+
child.exited.then(() => true),
|
|
353
|
+
new Promise(resolve => {
|
|
354
|
+
timer = setTimeout(() => resolve(false), timeoutMilliseconds);
|
|
355
|
+
}),
|
|
356
|
+
]);
|
|
357
|
+
if (timer)
|
|
358
|
+
clearTimeout(timer);
|
|
359
|
+
return didExit;
|
|
360
|
+
}
|
|
361
|
+
async function terminateAfterForwardingFailure(child, forwarding, captureDrain, error) {
|
|
362
|
+
child.kill('SIGTERM');
|
|
363
|
+
for (const stream of forwarding)
|
|
364
|
+
stream.stopLiveOutput();
|
|
365
|
+
child.stdout.destroy();
|
|
366
|
+
child.stderr.destroy();
|
|
367
|
+
await captureDrain;
|
|
368
|
+
if (!await waitForChildExit(child, FORWARDING_FAILURE_TERMINATION_TIMEOUT_MS)) {
|
|
369
|
+
child.kill('SIGKILL');
|
|
370
|
+
await waitForChildExit(child, FORWARDING_FAILURE_TERMINATION_TIMEOUT_MS);
|
|
371
|
+
}
|
|
372
|
+
throw error;
|
|
373
|
+
}
|
|
374
|
+
export async function completePipedChild(child, forwarding) {
|
|
375
|
+
const captureDrain = Promise.allSettled(forwarding.map(stream => stream.completed));
|
|
376
|
+
const firstFailure = Promise.race(forwarding.map(stream => stream.failure));
|
|
377
|
+
const firstOutcome = await Promise.race([
|
|
378
|
+
child.exited.then(status => ({ kind: 'exit', status })),
|
|
379
|
+
firstFailure.then(error => ({ kind: 'failure', error })),
|
|
380
|
+
]);
|
|
381
|
+
if (firstOutcome.kind === 'failure') {
|
|
382
|
+
return terminateAfterForwardingFailure(child, forwarding, captureDrain, firstOutcome.error);
|
|
383
|
+
}
|
|
384
|
+
const status = firstOutcome.status;
|
|
385
|
+
const waitForCaptureDrain = async () => {
|
|
386
|
+
let timer;
|
|
387
|
+
const didDrain = await Promise.race([
|
|
388
|
+
captureDrain.then(() => true),
|
|
389
|
+
new Promise(resolve => {
|
|
390
|
+
timer = setTimeout(() => resolve(false), POST_LEADER_CAPTURE_DRAIN_TIMEOUT_MS);
|
|
391
|
+
}),
|
|
392
|
+
]);
|
|
393
|
+
if (timer)
|
|
394
|
+
clearTimeout(timer);
|
|
395
|
+
return didDrain;
|
|
396
|
+
};
|
|
397
|
+
const throwIfCaptureFailed = async () => {
|
|
398
|
+
await captureDrain;
|
|
399
|
+
const failure = forwarding.map(stream => stream.failureReason()).find(Boolean);
|
|
400
|
+
if (failure)
|
|
401
|
+
throw failure;
|
|
402
|
+
};
|
|
403
|
+
// Preserve ordinary live forwarding when EOF is already on its way. If a
|
|
404
|
+
// blocked sink or descendant-held descriptor prevents that bounded drain,
|
|
405
|
+
// switch to capture-only before enforcing the same bounded EOF grace.
|
|
406
|
+
if (await waitForCaptureDrain()) {
|
|
407
|
+
await throwIfCaptureFailed();
|
|
408
|
+
return status;
|
|
409
|
+
}
|
|
410
|
+
for (const stream of forwarding)
|
|
411
|
+
stream.stopLiveOutput();
|
|
412
|
+
if (await waitForCaptureDrain()) {
|
|
413
|
+
await throwIfCaptureFailed();
|
|
414
|
+
return status;
|
|
415
|
+
}
|
|
416
|
+
for (const stream of forwarding)
|
|
417
|
+
stream.expectSourceClose();
|
|
418
|
+
child.stdout.destroy();
|
|
419
|
+
child.stderr.destroy();
|
|
420
|
+
await throwIfCaptureFailed();
|
|
421
|
+
return status;
|
|
422
|
+
}
|
|
423
|
+
export async function runPipedChild(command, args, environment, onSpawn, capture, observeChild) {
|
|
424
|
+
await Promise.all([childOutputSinks.stdout.prepare(), childOutputSinks.stderr.prepare()]);
|
|
425
|
+
const child = await spawnPipedChild(command, args, environment);
|
|
426
|
+
observeChild?.(child);
|
|
427
|
+
const forwarding = [
|
|
428
|
+
teeChildOutput(child.stdout, childOutputSinks.stdout, capture.stdout),
|
|
429
|
+
teeChildOutput(child.stderr, childOutputSinks.stderr, capture.stderr),
|
|
430
|
+
];
|
|
431
|
+
const completion = completePipedChild(child, forwarding);
|
|
432
|
+
const firstForwardingFailure = Promise.race(forwarding.map(stream => stream.failure)).then(error => { throw error; });
|
|
433
|
+
try {
|
|
434
|
+
await Promise.race([onSpawn(), firstForwardingFailure]);
|
|
435
|
+
const exitCode = await completion;
|
|
436
|
+
return { status: child.signalCode ? null : exitCode };
|
|
437
|
+
}
|
|
438
|
+
catch (cause) {
|
|
439
|
+
child.kill('SIGTERM');
|
|
440
|
+
await completion.catch(() => undefined);
|
|
441
|
+
throw cause;
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
/**
|
|
445
|
+
* Forward a child stream live while retaining a bounded caller-owned copy.
|
|
446
|
+
* Transient sink slowness pushes back; a stall degrades safely to capture-only.
|
|
447
|
+
*/
|
|
448
|
+
export function teeChildOutput(source, destination, capture) {
|
|
449
|
+
let isLiveOutputEnabled = true;
|
|
450
|
+
let isSourceCloseExpected = false;
|
|
451
|
+
let unexpectedFailure;
|
|
452
|
+
let remainingLiveOutputWaitMilliseconds = LIVE_OUTPUT_STALL_TIMEOUT_MS;
|
|
453
|
+
let liveOutputWaitFinishedAt = performance.now();
|
|
454
|
+
let resolveLiveOutputStopped = () => { };
|
|
455
|
+
const liveOutputStopped = new Promise(resolve => { resolveLiveOutputStopped = resolve; });
|
|
456
|
+
const stopLiveOutput = () => {
|
|
457
|
+
if (!isLiveOutputEnabled)
|
|
458
|
+
return;
|
|
459
|
+
isLiveOutputEnabled = false;
|
|
460
|
+
if (destination instanceof FileDescriptorSink)
|
|
461
|
+
destination.cancelPendingWrites();
|
|
462
|
+
resolveLiveOutputStopped();
|
|
463
|
+
};
|
|
464
|
+
const sinkState = liveSinkState(destination);
|
|
465
|
+
const forward = async (text) => {
|
|
466
|
+
capture(text);
|
|
467
|
+
if (!isLiveOutputEnabled)
|
|
468
|
+
return;
|
|
469
|
+
const waitStartedAt = performance.now();
|
|
470
|
+
remainingLiveOutputWaitMilliseconds = Math.min(LIVE_OUTPUT_STALL_TIMEOUT_MS, remainingLiveOutputWaitMilliseconds + waitStartedAt - liveOutputWaitFinishedAt);
|
|
471
|
+
let stallTimer;
|
|
472
|
+
const wasForwarded = await Promise.race([
|
|
473
|
+
writeLiveOutput(destination, sinkState, text).then(() => true),
|
|
474
|
+
liveOutputStopped.then(() => false),
|
|
475
|
+
new Promise(resolve => {
|
|
476
|
+
stallTimer = setTimeout(() => resolve(false), remainingLiveOutputWaitMilliseconds);
|
|
477
|
+
}),
|
|
478
|
+
]);
|
|
479
|
+
if (stallTimer)
|
|
480
|
+
clearTimeout(stallTimer);
|
|
481
|
+
liveOutputWaitFinishedAt = performance.now();
|
|
482
|
+
remainingLiveOutputWaitMilliseconds -= liveOutputWaitFinishedAt - waitStartedAt;
|
|
483
|
+
if (!wasForwarded || remainingLiveOutputWaitMilliseconds <= 0)
|
|
484
|
+
stopLiveOutput();
|
|
485
|
+
};
|
|
486
|
+
const completed = (async () => {
|
|
487
|
+
const decoder = new TextDecoder();
|
|
488
|
+
for await (const chunk of source) {
|
|
489
|
+
const text = decoder.decode(chunk, { stream: true });
|
|
490
|
+
if (text)
|
|
491
|
+
await forward(text);
|
|
492
|
+
}
|
|
493
|
+
const remainder = decoder.decode();
|
|
494
|
+
if (remainder)
|
|
495
|
+
await forward(remainder);
|
|
496
|
+
})();
|
|
497
|
+
let resolveFailure = () => { };
|
|
498
|
+
const failure = new Promise(resolve => { resolveFailure = resolve; });
|
|
499
|
+
void completed.catch(cause => {
|
|
500
|
+
if (isSourceCloseExpected)
|
|
501
|
+
return;
|
|
502
|
+
unexpectedFailure = errorFromUnknown(cause);
|
|
503
|
+
resolveFailure(unexpectedFailure);
|
|
504
|
+
});
|
|
505
|
+
return {
|
|
506
|
+
completed,
|
|
507
|
+
failure,
|
|
508
|
+
failureReason: () => unexpectedFailure,
|
|
509
|
+
expectSourceClose: () => { isSourceCloseExpected = true; },
|
|
510
|
+
stopLiveOutput,
|
|
511
|
+
};
|
|
512
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli-auth-browser-page.d.ts","sourceRoot":"","sources":["../src/cli-auth-browser-page.ts"],"names":[],"mappings":"AAAA,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,SAAS,GAAG,OAAO,GAAG,MAAM,CA2G5E"}
|