@on-par/factory-cli 0.0.0-stage → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +23 -2
- package/dist/cli/admission.d.ts +17 -0
- package/dist/cli/admission.d.ts.map +1 -0
- package/dist/cli/admission.js +37 -0
- package/dist/cli/admission.js.map +1 -0
- package/dist/cli/branch-prefix.d.ts +8 -0
- package/dist/cli/branch-prefix.d.ts.map +1 -0
- package/dist/cli/branch-prefix.js +16 -0
- package/dist/cli/branch-prefix.js.map +1 -0
- package/dist/cli/classifier-backtest.d.ts +50 -0
- package/dist/cli/classifier-backtest.d.ts.map +1 -0
- package/dist/cli/classifier-backtest.js +112 -0
- package/dist/cli/classifier-backtest.js.map +1 -0
- package/dist/cli/cost-json.d.ts +37 -0
- package/dist/cli/cost-json.d.ts.map +1 -0
- package/dist/cli/cost-json.js +48 -0
- package/dist/cli/cost-json.js.map +1 -0
- package/dist/cli/daemon.d.ts +113 -0
- package/dist/cli/daemon.d.ts.map +1 -0
- package/dist/cli/daemon.js +282 -0
- package/dist/cli/daemon.js.map +1 -0
- package/dist/cli/doctor.d.ts +127 -0
- package/dist/cli/doctor.d.ts.map +1 -0
- package/dist/cli/doctor.js +400 -0
- package/dist/cli/doctor.js.map +1 -0
- package/dist/cli/feedback.d.ts +74 -0
- package/dist/cli/feedback.d.ts.map +1 -0
- package/dist/cli/feedback.js +180 -0
- package/dist/cli/feedback.js.map +1 -0
- package/dist/cli/filing.d.ts +22 -0
- package/dist/cli/filing.d.ts.map +1 -0
- package/dist/cli/filing.js +53 -0
- package/dist/cli/filing.js.map +1 -0
- package/dist/cli/first-run.d.ts +9 -0
- package/dist/cli/first-run.d.ts.map +1 -0
- package/dist/cli/first-run.js +34 -0
- package/dist/cli/first-run.js.map +1 -0
- package/dist/cli/help-groups.d.ts +17 -0
- package/dist/cli/help-groups.d.ts.map +1 -0
- package/dist/cli/help-groups.js +50 -0
- package/dist/cli/help-groups.js.map +1 -0
- package/dist/cli/hosted-queue.d.ts +45 -0
- package/dist/cli/hosted-queue.d.ts.map +1 -0
- package/dist/cli/hosted-queue.js +74 -0
- package/dist/cli/hosted-queue.js.map +1 -0
- package/dist/cli/hosted-runner.d.ts +44 -0
- package/dist/cli/hosted-runner.d.ts.map +1 -0
- package/dist/cli/hosted-runner.js +68 -0
- package/dist/cli/hosted-runner.js.map +1 -0
- package/dist/cli/hosted.d.ts +38 -0
- package/dist/cli/hosted.d.ts.map +1 -0
- package/dist/cli/hosted.js +82 -0
- package/dist/cli/hosted.js.map +1 -0
- package/dist/cli/index.d.ts +656 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +4801 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/init-files.d.ts +8 -0
- package/dist/cli/init-files.d.ts.map +1 -0
- package/dist/cli/init-files.js +45 -0
- package/dist/cli/init-files.js.map +1 -0
- package/dist/cli/logs.d.ts +27 -0
- package/dist/cli/logs.d.ts.map +1 -0
- package/dist/cli/logs.js +52 -0
- package/dist/cli/logs.js.map +1 -0
- package/dist/cli/merge-scope.d.ts +7 -0
- package/dist/cli/merge-scope.d.ts.map +1 -0
- package/dist/cli/merge-scope.js +14 -0
- package/dist/cli/merge-scope.js.map +1 -0
- package/dist/cli/octokit.d.ts +43 -0
- package/dist/cli/octokit.d.ts.map +1 -0
- package/dist/cli/octokit.js +87 -0
- package/dist/cli/octokit.js.map +1 -0
- package/dist/cli/queue-add-json.d.ts +25 -0
- package/dist/cli/queue-add-json.d.ts.map +1 -0
- package/dist/cli/queue-add-json.js +24 -0
- package/dist/cli/queue-add-json.js.map +1 -0
- package/dist/cli/queue-clear.d.ts +15 -0
- package/dist/cli/queue-clear.d.ts.map +1 -0
- package/dist/cli/queue-clear.js +58 -0
- package/dist/cli/queue-clear.js.map +1 -0
- package/dist/cli/queue-list.d.ts +24 -0
- package/dist/cli/queue-list.d.ts.map +1 -0
- package/dist/cli/queue-list.js +25 -0
- package/dist/cli/queue-list.js.map +1 -0
- package/dist/cli/ready-check.d.ts +98 -0
- package/dist/cli/ready-check.d.ts.map +1 -0
- package/dist/cli/ready-check.js +169 -0
- package/dist/cli/ready-check.js.map +1 -0
- package/dist/cli/reset.d.ts +40 -0
- package/dist/cli/reset.d.ts.map +1 -0
- package/dist/cli/reset.js +215 -0
- package/dist/cli/reset.js.map +1 -0
- package/dist/cli/run-children.d.ts +24 -0
- package/dist/cli/run-children.d.ts.map +1 -0
- package/dist/cli/run-children.js +73 -0
- package/dist/cli/run-children.js.map +1 -0
- package/dist/cli/run-flags.d.ts +14 -0
- package/dist/cli/run-flags.d.ts.map +1 -0
- package/dist/cli/run-flags.js +43 -0
- package/dist/cli/run-flags.js.map +1 -0
- package/dist/cli/runs-diffstat.d.ts +43 -0
- package/dist/cli/runs-diffstat.d.ts.map +1 -0
- package/dist/cli/runs-diffstat.js +91 -0
- package/dist/cli/runs-diffstat.js.map +1 -0
- package/dist/cli/runs.d.ts +36 -0
- package/dist/cli/runs.d.ts.map +1 -0
- package/dist/cli/runs.js +102 -0
- package/dist/cli/runs.js.map +1 -0
- package/dist/cli/staleness.d.ts +30 -0
- package/dist/cli/staleness.d.ts.map +1 -0
- package/dist/cli/staleness.js +132 -0
- package/dist/cli/staleness.js.map +1 -0
- package/dist/cli/status-json.d.ts +45 -0
- package/dist/cli/status-json.d.ts.map +1 -0
- package/dist/cli/status-json.js +22 -0
- package/dist/cli/status-json.js.map +1 -0
- package/dist/cli/stop-resume-json.d.ts +18 -0
- package/dist/cli/stop-resume-json.d.ts.map +1 -0
- package/dist/cli/stop-resume-json.js +10 -0
- package/dist/cli/stop-resume-json.js.map +1 -0
- package/dist/cli/stop-sentinel.d.ts +23 -0
- package/dist/cli/stop-sentinel.d.ts.map +1 -0
- package/dist/cli/stop-sentinel.js +61 -0
- package/dist/cli/stop-sentinel.js.map +1 -0
- package/dist/cli/sweep-heartbeat.d.ts +33 -0
- package/dist/cli/sweep-heartbeat.d.ts.map +1 -0
- package/dist/cli/sweep-heartbeat.js +65 -0
- package/dist/cli/sweep-heartbeat.js.map +1 -0
- package/dist/cli/unpark.d.ts +28 -0
- package/dist/cli/unpark.d.ts.map +1 -0
- package/dist/cli/unpark.js +68 -0
- package/dist/cli/unpark.js.map +1 -0
- package/dist/cli/usage-json.d.ts +20 -0
- package/dist/cli/usage-json.d.ts.map +1 -0
- package/dist/cli/usage-json.js +36 -0
- package/dist/cli/usage-json.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +6 -0
- package/dist/cli.js.map +1 -0
- package/dist/entry.d.ts +6 -0
- package/dist/entry.d.ts.map +1 -0
- package/dist/entry.js +13 -0
- package/dist/entry.js.map +1 -0
- package/package.json +48 -4
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
// packages/cli/src/cli/hosted-runner.ts — `factory hosted runner` [--url <base>]
|
|
2
|
+
// [--runner-id <id>] [--capabilities <csv>] [--timeout <ms>] [--poll-interval <ms>]
|
|
3
|
+
//
|
|
4
|
+
// Phone-home runner slice (#929): connects to the local hosted-exec control
|
|
5
|
+
// plane, registers its capabilities, polls within a bounded wait window, and
|
|
6
|
+
// leases exactly one compatible job — then exits cleanly whether or not a
|
|
7
|
+
// compatible job appeared. Does not execute the leased job; that is a later
|
|
8
|
+
// ticket. Gated by FACTORY_HOSTED_EXEC=1, same as the rest of hosted-exec.
|
|
9
|
+
import { randomUUID } from 'node:crypto';
|
|
10
|
+
import { createHttpHostedControlPlaneClient, hostedExecEnabled, runOneJobRunner } from '@on-par/factory-core';
|
|
11
|
+
import { applyExitCode } from './hosted.js';
|
|
12
|
+
function parsePositiveInt(value, fallback) {
|
|
13
|
+
if (!value)
|
|
14
|
+
return fallback;
|
|
15
|
+
const parsed = Number.parseInt(value, 10);
|
|
16
|
+
return Number.isFinite(parsed) && parsed > 0 ? parsed : fallback;
|
|
17
|
+
}
|
|
18
|
+
/** Renders only OneJobRunnerOutcome fields — no secret material ever flows
|
|
19
|
+
* through this path (registration/lease payloads carry no credentials). */
|
|
20
|
+
export function formatHostedRunnerOutcome(outcome) {
|
|
21
|
+
if (!outcome.leased) {
|
|
22
|
+
return `${outcome.trace}\n`;
|
|
23
|
+
}
|
|
24
|
+
const lines = [
|
|
25
|
+
`job: ${outcome.jobId}`,
|
|
26
|
+
`runner: ${outcome.runner.runnerId}`,
|
|
27
|
+
`lease: ${outcome.lease?.leaseId ?? '(none)'}`,
|
|
28
|
+
`status: ${outcome.job?.status ?? '(unknown)'}`,
|
|
29
|
+
`trace: ${outcome.trace}`,
|
|
30
|
+
];
|
|
31
|
+
return lines.join('\n') + '\n';
|
|
32
|
+
}
|
|
33
|
+
/** Testable core of the command: gate on the flag, register + poll for one
|
|
34
|
+
* compatible job within the bounded wait window, print the result. Exits 0
|
|
35
|
+
* both when a job is leased and when the window elapses with no compatible
|
|
36
|
+
* work — the latter is a clean, expected outcome, not a failure. */
|
|
37
|
+
export async function runHostedRunnerCli(opts, deps = {}) {
|
|
38
|
+
const env = deps.env ?? process.env;
|
|
39
|
+
const out = deps.out ?? process.stdout;
|
|
40
|
+
if (!hostedExecEnabled(env)) {
|
|
41
|
+
out.write('hosted-exec runner refused: set FACTORY_HOSTED_EXEC=1 to enable — the local factory path is unchanged\n');
|
|
42
|
+
return { exitCode: 0 };
|
|
43
|
+
}
|
|
44
|
+
const client = deps.client ?? createHttpHostedControlPlaneClient({ baseUrl: opts.url ?? 'http://127.0.0.1:8799' });
|
|
45
|
+
const capabilities = (opts.capabilities ?? 'git,node')
|
|
46
|
+
.split(',')
|
|
47
|
+
.map((c) => c.trim())
|
|
48
|
+
.filter((c) => c.length > 0);
|
|
49
|
+
const outcome = await runOneJobRunner(client, {
|
|
50
|
+
runnerId: opts.runnerId ?? `runner-${process.pid}`,
|
|
51
|
+
capabilities,
|
|
52
|
+
leaseId: deps.generateLeaseId?.() ?? randomUUID(),
|
|
53
|
+
ttlMs: parsePositiveInt(opts.leaseTtl, 300_000),
|
|
54
|
+
heartbeatIntervalMs: parsePositiveInt(opts.heartbeatInterval, 30_000),
|
|
55
|
+
timeoutMs: parsePositiveInt(opts.timeout, 30_000),
|
|
56
|
+
pollIntervalMs: parsePositiveInt(opts.pollInterval, 2_000),
|
|
57
|
+
now: deps.now,
|
|
58
|
+
sleep: deps.sleep,
|
|
59
|
+
});
|
|
60
|
+
out.write(formatHostedRunnerOutcome(outcome));
|
|
61
|
+
return { exitCode: 0 };
|
|
62
|
+
}
|
|
63
|
+
/** Command entry point wired up to commander. */
|
|
64
|
+
export async function cmdHostedRunner(opts) {
|
|
65
|
+
const { exitCode } = await runHostedRunnerCli(opts);
|
|
66
|
+
applyExitCode(exitCode);
|
|
67
|
+
}
|
|
68
|
+
//# sourceMappingURL=hosted-runner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hosted-runner.js","sourceRoot":"","sources":["../../src/cli/hosted-runner.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { ContainerEngine, HostedClock, HostedSmokeOutcome } from '@on-par/factory-core';
|
|
2
|
+
export interface HostedSmokeCliOptions {
|
|
3
|
+
/** default 'on-par/software-factory' */
|
|
4
|
+
repo?: string;
|
|
5
|
+
/** default 'node:20-alpine' */
|
|
6
|
+
image?: string;
|
|
7
|
+
}
|
|
8
|
+
export interface HostedSmokeCliDeps {
|
|
9
|
+
out?: {
|
|
10
|
+
write(s: string): unknown;
|
|
11
|
+
};
|
|
12
|
+
env?: NodeJS.ProcessEnv;
|
|
13
|
+
/** default () => isCommandAvailable('docker') */
|
|
14
|
+
dockerAvailable?: () => boolean;
|
|
15
|
+
/** default createDockerEngine({}) */
|
|
16
|
+
engine?: ContainerEngine;
|
|
17
|
+
/** default () => Date.now() */
|
|
18
|
+
now?: HostedClock;
|
|
19
|
+
}
|
|
20
|
+
/** Renders only the secret-free HostedJobSummary fields — never any other field of the
|
|
21
|
+
* outcome — so no secret value from the underlying store/engine can reach output. */
|
|
22
|
+
export declare function formatHostedSmokeSummary(outcome: HostedSmokeOutcome): string;
|
|
23
|
+
/** Default docker-availability probe, injectable for tests. */
|
|
24
|
+
export declare function resolveDockerAvailable(deps: HostedSmokeCliDeps): () => boolean;
|
|
25
|
+
/** Default real docker-CLI engine, injectable for tests. */
|
|
26
|
+
export declare function resolveEngine(deps: HostedSmokeCliDeps): ContainerEngine;
|
|
27
|
+
/** Testable core of the command: gate on the flag, gate on docker availability, run the
|
|
28
|
+
* smoke, print the result. Returns the exit code the CLI wrapper should use. */
|
|
29
|
+
export declare function runHostedSmokeCli(opts: HostedSmokeCliOptions, deps?: HostedSmokeCliDeps): Promise<{
|
|
30
|
+
exitCode: number;
|
|
31
|
+
}>;
|
|
32
|
+
/** Testable seam for the process exit — defaults to the real process.exit. */
|
|
33
|
+
export declare function exitProcess(exitCode: number): void;
|
|
34
|
+
/** Applies the CLI exit code, calling `exit` only when it is non-zero. */
|
|
35
|
+
export declare function applyExitCode(exitCode: number, exit?: (code: number) => void): void;
|
|
36
|
+
/** Command entry point wired up to commander. */
|
|
37
|
+
export declare function cmdHostedSmoke(opts: HostedSmokeCliOptions): Promise<void>;
|
|
38
|
+
//# sourceMappingURL=hosted.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hosted.d.ts","sourceRoot":"","sources":["../../src/cli/hosted.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,eAAe,EAAE,WAAW,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAI7F,MAAM,WAAW,qBAAqB;IACpC,wCAAwC;IACxC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,+BAA+B;IAC/B,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,kBAAkB;IACjC,GAAG,CAAC,EAAE;QAAE,KAAK,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAA;KAAE,CAAC;IACpC,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,iDAAiD;IACjD,eAAe,CAAC,EAAE,MAAM,OAAO,CAAC;IAChC,qCAAqC;IACrC,MAAM,CAAC,EAAE,eAAe,CAAC;IACzB,+BAA+B;IAC/B,GAAG,CAAC,EAAE,WAAW,CAAC;CACnB;AAKD;qFACqF;AACrF,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,kBAAkB,GAAG,MAAM,CAyB5E;AAED,+DAA+D;AAC/D,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,kBAAkB,GAAG,MAAM,OAAO,CAE9E;AAED,4DAA4D;AAC5D,wBAAgB,aAAa,CAAC,IAAI,EAAE,kBAAkB,GAAG,eAAe,CAEvE;AAED;gFACgF;AAChF,wBAAsB,iBAAiB,CACrC,IAAI,EAAE,qBAAqB,EAC3B,IAAI,GAAE,kBAAuB,GAC5B,OAAO,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CA0B/B;AAED,8EAA8E;AAC9E,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAElD;AAED,0EAA0E;AAC1E,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,GAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAkB,GAAG,IAAI,CAEhG;AAED,iDAAiD;AACjD,wBAAsB,cAAc,CAAC,IAAI,EAAE,qBAAqB,GAAG,OAAO,CAAC,IAAI,CAAC,CAG/E"}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
// packages/cli/src/cli/hosted.ts — `factory hosted smoke` [--repo <slug>] [--image <image>]
|
|
2
|
+
//
|
|
3
|
+
// Local end-to-end hosted-exec smoke: create -> lease -> disposable Docker run
|
|
4
|
+
// against a fresh clone -> terminal result -> cleanup proof (#923). Gated by
|
|
5
|
+
// FACTORY_HOSTED_EXEC=1 — refuses to run and leaves the local factory path
|
|
6
|
+
// unchanged when the flag is off, and cleanly skips when Docker is unavailable.
|
|
7
|
+
import { hostedExecEnabled, isCommandAvailable, runHostedSmoke } from '@on-par/factory-core';
|
|
8
|
+
import { createDockerEngine } from '@on-par/factory-core/internal';
|
|
9
|
+
// Minimal, read-only, factory-safe command run against the fresh clone at /workspace/repo.
|
|
10
|
+
const DEFAULT_SMOKE_COMMAND = ['sh', '-c', 'ls -a /workspace/repo && echo hosted-exec-smoke-ok'];
|
|
11
|
+
/** Renders only the secret-free HostedJobSummary fields — never any other field of the
|
|
12
|
+
* outcome — so no secret value from the underlying store/engine can reach output. */
|
|
13
|
+
export function formatHostedSmokeSummary(outcome) {
|
|
14
|
+
if (!outcome.enabled) {
|
|
15
|
+
return `${outcome.trace}\n`;
|
|
16
|
+
}
|
|
17
|
+
const summary = outcome.summary;
|
|
18
|
+
if (!summary) {
|
|
19
|
+
return `${outcome.trace}\n`;
|
|
20
|
+
}
|
|
21
|
+
const lines = [
|
|
22
|
+
`job: ${outcome.jobId ?? summary.jobId}`,
|
|
23
|
+
`repo: ${summary.repoSlug}`,
|
|
24
|
+
`lease: ${outcome.leaseId ?? '(none)'}`,
|
|
25
|
+
`outcome: ${summary.outcome ?? summary.status}`,
|
|
26
|
+
`exit: ${summary.exitCode ?? '(none)'}`,
|
|
27
|
+
`logs: ${summary.logsTail ?? '(none)'}`,
|
|
28
|
+
`artifacts: ${summary.artifactCount === 0
|
|
29
|
+
? '(none)'
|
|
30
|
+
: summary.artifacts.map((a) => `${a.name} (${a.kind}): ${a.ref}`).join(', ')}`,
|
|
31
|
+
`cleanup: ${summary.cleanupProof ?? '(none)'}`,
|
|
32
|
+
];
|
|
33
|
+
return lines.join('\n') + '\n';
|
|
34
|
+
}
|
|
35
|
+
/** Default docker-availability probe, injectable for tests. */
|
|
36
|
+
export function resolveDockerAvailable(deps) {
|
|
37
|
+
return deps.dockerAvailable ?? (() => isCommandAvailable('docker'));
|
|
38
|
+
}
|
|
39
|
+
/** Default real docker-CLI engine, injectable for tests. */
|
|
40
|
+
export function resolveEngine(deps) {
|
|
41
|
+
return deps.engine ?? createDockerEngine({});
|
|
42
|
+
}
|
|
43
|
+
/** Testable core of the command: gate on the flag, gate on docker availability, run the
|
|
44
|
+
* smoke, print the result. Returns the exit code the CLI wrapper should use. */
|
|
45
|
+
export async function runHostedSmokeCli(opts, deps = {}) {
|
|
46
|
+
const env = deps.env ?? process.env;
|
|
47
|
+
const out = deps.out ?? process.stdout;
|
|
48
|
+
if (!hostedExecEnabled(env)) {
|
|
49
|
+
out.write('hosted-exec smoke refused: set FACTORY_HOSTED_EXEC=1 to enable — the local factory path is unchanged\n');
|
|
50
|
+
return { exitCode: 0 };
|
|
51
|
+
}
|
|
52
|
+
const dockerAvailable = resolveDockerAvailable(deps);
|
|
53
|
+
if (!dockerAvailable()) {
|
|
54
|
+
out.write('docker not available — skipping hosted-exec smoke\n');
|
|
55
|
+
return { exitCode: 0 };
|
|
56
|
+
}
|
|
57
|
+
const engine = resolveEngine(deps);
|
|
58
|
+
const outcome = await runHostedSmoke(engine, {
|
|
59
|
+
repoSlug: opts.repo ?? 'on-par/software-factory',
|
|
60
|
+
image: opts.image ?? 'node:20-alpine',
|
|
61
|
+
command: DEFAULT_SMOKE_COMMAND,
|
|
62
|
+
now: deps.now ?? (() => Date.now()),
|
|
63
|
+
env,
|
|
64
|
+
});
|
|
65
|
+
out.write(formatHostedSmokeSummary(outcome));
|
|
66
|
+
return { exitCode: outcome.summary?.outcome === 'completed' ? 0 : 1 };
|
|
67
|
+
}
|
|
68
|
+
/** Testable seam for the process exit — defaults to the real process.exit. */
|
|
69
|
+
export function exitProcess(exitCode) {
|
|
70
|
+
process.exit(exitCode);
|
|
71
|
+
}
|
|
72
|
+
/** Applies the CLI exit code, calling `exit` only when it is non-zero. */
|
|
73
|
+
export function applyExitCode(exitCode, exit = exitProcess) {
|
|
74
|
+
if (exitCode !== 0)
|
|
75
|
+
exit(exitCode);
|
|
76
|
+
}
|
|
77
|
+
/** Command entry point wired up to commander. */
|
|
78
|
+
export async function cmdHostedSmoke(opts) {
|
|
79
|
+
const { exitCode } = await runHostedSmokeCli(opts);
|
|
80
|
+
applyExitCode(exitCode);
|
|
81
|
+
}
|
|
82
|
+
//# sourceMappingURL=hosted.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hosted.js","sourceRoot":"","sources":["../../src/cli/hosted.ts"],"names":[],"mappings":"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"}
|