sim 2.1.17-preview.127.1 → 2.1.18-dev.129.1
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/auth/device-flow.d.ts +39 -0
- package/dist/auth/oauth-flow.d.ts +119 -0
- package/dist/auth/refresh.d.ts +16 -0
- package/dist/commands/auth.d.ts +5 -0
- package/dist/commands/configure.d.ts +2 -0
- package/dist/commands/credentials.d.ts +3 -0
- package/dist/commands/protocol/chat.d.ts +11 -0
- package/dist/commands/protocol/files-get.d.ts +25 -0
- package/dist/commands/protocol/files-upload.d.ts +2 -0
- package/dist/commands/protocol/index.d.ts +3 -0
- package/dist/commands/protocol/knowledge-document-upload.d.ts +2 -0
- package/dist/commands/protocol/knowledge-export.d.ts +14 -0
- package/dist/commands/protocol/logs-follow.d.ts +39 -0
- package/dist/commands/protocol/resource-directory.d.ts +24 -0
- package/dist/commands/protocol/result.d.ts +2 -0
- package/dist/commands/protocol/tables-import.d.ts +2 -0
- package/dist/commands/protocol/workflow-run-follow.d.ts +56 -0
- package/dist/commands/protocol/workflow-run-get.d.ts +15 -0
- package/dist/commands/protocol/workflow-run-wait.d.ts +3 -0
- package/dist/commands/protocol/workspace-operation-wait.d.ts +14 -0
- package/dist/commands/secrets.d.ts +3 -0
- package/dist/commands/telemetry.d.ts +2 -0
- package/dist/commands/update.d.ts +2 -0
- package/dist/config/index.d.ts +2 -0
- package/dist/config/ini.d.ts +111 -0
- package/dist/config/json-file.d.ts +18 -0
- package/dist/config/paths.d.ts +29 -0
- package/dist/config/profile.d.ts +210 -0
- package/dist/context.d.ts +21 -0
- package/dist/contract/commands.d.ts +14 -0
- package/dist/contract/types.d.ts +306 -0
- package/dist/embed-context.d.ts +77 -0
- package/dist/embed-output.d.ts +15 -0
- package/dist/embed.d.ts +39 -0
- package/dist/environment.d.ts +22 -0
- package/dist/generated/v2-api.d.ts +15057 -0
- package/dist/helpers.d.ts +9 -0
- package/dist/http/client.d.ts +173 -0
- package/dist/http/environment.d.ts +24 -0
- package/dist/http/ndjson.d.ts +5 -0
- package/dist/index.js +809 -327
- package/dist/output/io.d.ts +5 -0
- package/dist/output/presentation.d.ts +4 -0
- package/dist/output/render.d.ts +60 -0
- package/dist/output/terminal-text.d.ts +17 -0
- package/dist/output/trace.d.ts +3 -0
- package/dist/output/truncation.d.ts +3 -0
- package/dist/program.d.ts +21 -0
- package/dist/runtime/build.d.ts +38 -0
- package/dist/runtime/derive.d.ts +20 -0
- package/dist/runtime/execute.d.ts +32 -0
- package/dist/runtime/naming.d.ts +25 -0
- package/dist/runtime/options.d.ts +9 -0
- package/dist/runtime/renamed.d.ts +6 -0
- package/dist/runtime/request.d.ts +110 -0
- package/dist/runtime/result.d.ts +41 -0
- package/dist/runtime/types.d.ts +23 -0
- package/dist/runtime.d.ts +5 -0
- package/dist/runtime.js +21854 -0
- package/dist/telemetry/client-info.d.ts +20 -0
- package/dist/telemetry/coding-agent.d.ts +31 -0
- package/dist/telemetry/index.d.ts +4 -0
- package/dist/telemetry/invocation.d.ts +98 -0
- package/dist/telemetry/policy.d.ts +38 -0
- package/dist/telemetry/state.d.ts +47 -0
- package/dist/telemetry/transport.d.ts +47 -0
- package/dist/terminal/secret-input.d.ts +15 -0
- package/dist/terminal.d.ts +7 -0
- package/dist/transfer/local-file.d.ts +16 -0
- package/dist/transfer/streaming-upload.d.ts +16 -0
- package/dist/transfer/upload-session.d.ts +18 -0
- package/dist/update/check.d.ts +53 -0
- package/dist/update/install.d.ts +20 -0
- package/dist/version.d.ts +10 -0
- package/package.json +12 -2
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
type CliAuthScope = 'copilot' | 'platform';
|
|
2
|
+
export interface AuthRequest {
|
|
3
|
+
/** Semi-public rendezvous handle; travels in the browser URL. */
|
|
4
|
+
request: string;
|
|
5
|
+
/** Never leaves this process until the poll redeems it. */
|
|
6
|
+
pollSecret: string;
|
|
7
|
+
/** BASE64URL(SHA256(pollSecret)), registered when the user approves. */
|
|
8
|
+
challenge: string;
|
|
9
|
+
/** Printed for the user to compare against the browser. Never sent to the API. */
|
|
10
|
+
pairing: string;
|
|
11
|
+
}
|
|
12
|
+
export interface MintedKey {
|
|
13
|
+
id: string;
|
|
14
|
+
apiKey: string;
|
|
15
|
+
scope: CliAuthScope;
|
|
16
|
+
/** The workspace picked in the browser — the profile's default target. */
|
|
17
|
+
workspaceId: string | null;
|
|
18
|
+
/** Whether the key can *only* reach that workspace. */
|
|
19
|
+
workspaceBound: boolean;
|
|
20
|
+
}
|
|
21
|
+
export declare function createAuthRequest(): AuthRequest;
|
|
22
|
+
export declare function buildApprovalUrl(endpoint: string, auth: AuthRequest, workspaceId?: string): string;
|
|
23
|
+
/**
|
|
24
|
+
* Polls until the user approves in the browser.
|
|
25
|
+
*
|
|
26
|
+
* Transport failures are swallowed and retried rather than aborting the login:
|
|
27
|
+
* a laptop that slept, a VPN reconnecting, or a deploy rolling the server mid-
|
|
28
|
+
* wait are all recoverable, and the approval sits in Redis with its own TTL. A
|
|
29
|
+
* non-2xx *response*, by contrast, is the server refusing on purpose and is
|
|
30
|
+
* surfaced immediately.
|
|
31
|
+
*
|
|
32
|
+
* Retried is not the same as unreported: once
|
|
33
|
+
* {@link TRANSPORT_FAILURES_BEFORE_WARNING} attempts in a row fail to reach the
|
|
34
|
+
* endpoint at all, the reason is printed once to stderr and the poll carries on.
|
|
35
|
+
* Without it a typo'd endpoint was indistinguishable from a slow approval for
|
|
36
|
+
* the entire 15-minute timeout.
|
|
37
|
+
*/
|
|
38
|
+
export declare function pollForKey(endpoint: string, auth: AuthRequest, signal?: AbortSignal): Promise<MintedKey>;
|
|
39
|
+
export {};
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { SimApiError } from '../http/client';
|
|
2
|
+
/**
|
|
3
|
+
* The OAuth half of `sim login`: authorization code + PKCE with a loopback
|
|
4
|
+
* redirect (RFC 8252), the flow gcloud, the AWS CLI, Wrangler and Railway use.
|
|
5
|
+
*
|
|
6
|
+
* The CLI is a public client — there is no secret to keep — so PKCE is what
|
|
7
|
+
* binds the code to this process: the browser carries only the SHA-256 of a
|
|
8
|
+
* verifier that never leaves memory, and the token endpoint refuses a code
|
|
9
|
+
* presented without it. `state` guards the loopback listener against a stray
|
|
10
|
+
* or forged redirect, and the listener binds the loopback interface only, for
|
|
11
|
+
* the life of one login.
|
|
12
|
+
*
|
|
13
|
+
* The result is a short-lived access token and a rotating refresh token, both
|
|
14
|
+
* revocable from Settings → General → Authorized apps, instead of the permanent API key
|
|
15
|
+
* the pairing-code handoff in `device-flow.ts` mints. That handoff remains the
|
|
16
|
+
* path for a terminal whose browser cannot reach it (SSH, containers).
|
|
17
|
+
*/
|
|
18
|
+
/** The client id migration `0323_oauth_provider` seeds; a public client, no secret. */
|
|
19
|
+
export declare const OAUTH_CLIENT_ID = "sim-cli";
|
|
20
|
+
/**
|
|
21
|
+
* Everything the CLI does, and nothing more: renew itself, and read and change
|
|
22
|
+
* workspace resources.
|
|
23
|
+
*
|
|
24
|
+
* Sim's provider deliberately exposes OAuth API authorization rather than an
|
|
25
|
+
* OpenID Connect identity surface, so the CLI requests no identity claims.
|
|
26
|
+
*/
|
|
27
|
+
export declare const OAUTH_SCOPES_FULL: readonly ['offline_access', 'api:read', 'api:write'];
|
|
28
|
+
/** `--read-only`: a token that can inspect but never change anything. */
|
|
29
|
+
export declare const OAUTH_SCOPES_READ_ONLY: readonly ['offline_access', 'api:read'];
|
|
30
|
+
/**
|
|
31
|
+
* Refuses to run the OAuth flow over cleartext.
|
|
32
|
+
*
|
|
33
|
+
* The code, the verifier, and both tokens cross this connection. An API key
|
|
34
|
+
* over `http` earns a warning because the user typed the endpoint and may know
|
|
35
|
+
* something we do not; a login is different, because the flow itself is what
|
|
36
|
+
* would leak, and because a tampered discovery response silently downgrades
|
|
37
|
+
* `sim login` to the pairing-code handoff — which mints a permanent key.
|
|
38
|
+
* Loopback is exempt: it never leaves the machine.
|
|
39
|
+
*/
|
|
40
|
+
export declare function requireSecureEndpoint(endpoint: string): void;
|
|
41
|
+
export interface OAuthTokens {
|
|
42
|
+
accessToken: string;
|
|
43
|
+
refreshToken: string;
|
|
44
|
+
/** Epoch milliseconds at which `accessToken` stops working. */
|
|
45
|
+
expiresAt: number;
|
|
46
|
+
scope: string;
|
|
47
|
+
}
|
|
48
|
+
/** A refusal from the token endpoint, carrying the RFC 6749 error code. */
|
|
49
|
+
export declare class OAuthTokenError extends SimApiError {
|
|
50
|
+
readonly oauthError: string;
|
|
51
|
+
constructor(oauthError: string, description: string | undefined, status: number);
|
|
52
|
+
}
|
|
53
|
+
export interface Pkce {
|
|
54
|
+
verifier: string;
|
|
55
|
+
challenge: string;
|
|
56
|
+
state: string;
|
|
57
|
+
}
|
|
58
|
+
/** A fresh verifier (43 chars, 256 bits), its S256 challenge, and a `state` nonce. */
|
|
59
|
+
export declare function createPkce(): Pkce;
|
|
60
|
+
export declare function buildRedirectUri(port: number): string;
|
|
61
|
+
export declare function buildAuthorizeUrl(endpoint: string, args: {
|
|
62
|
+
redirectUri: string;
|
|
63
|
+
scopes: readonly string[];
|
|
64
|
+
pkce: Pkce;
|
|
65
|
+
}): string;
|
|
66
|
+
export type OAuthProviderStatus = 'available' | 'unavailable' | 'unreachable';
|
|
67
|
+
/**
|
|
68
|
+
* Whether the endpoint is an OAuth authorization server, from the RFC 8414
|
|
69
|
+
* discovery document. A 404 is a definite "no" — an older Sim, or one with the
|
|
70
|
+
* provider switched off — and sends login to the pairing-code handoff; a
|
|
71
|
+
* transport failure is reported as such so a typo'd endpoint is not mistaken
|
|
72
|
+
* for a server that lacks the feature.
|
|
73
|
+
*/
|
|
74
|
+
export declare function discoverOAuthProvider(endpoint: string): Promise<OAuthProviderStatus>;
|
|
75
|
+
export declare function grantsWriteAccess(scope: string): boolean;
|
|
76
|
+
/** Redeems an authorization code with its PKCE verifier. */
|
|
77
|
+
export declare function exchangeCode(endpoint: string, args: {
|
|
78
|
+
code: string;
|
|
79
|
+
redirectUri: string;
|
|
80
|
+
verifier: string;
|
|
81
|
+
requestedScopes: readonly string[];
|
|
82
|
+
}, signal?: AbortSignal): Promise<OAuthTokens>;
|
|
83
|
+
/**
|
|
84
|
+
* Trades a refresh token for a new pair. The server rotates: the token used
|
|
85
|
+
* here is dead afterwards, and presenting it again invalidates every access
|
|
86
|
+
* and refresh token from this login. Other independently authorized CLI
|
|
87
|
+
* logins remain active. Callers serialize local refreshes through the
|
|
88
|
+
* credentials lock before reaching this.
|
|
89
|
+
*/
|
|
90
|
+
export declare function refreshTokens(endpoint: string, refreshToken: string, expectedScopes?: readonly string[], signal?: AbortSignal): Promise<OAuthTokens>;
|
|
91
|
+
/**
|
|
92
|
+
* Revokes a refresh token server-side, which also kills every access and
|
|
93
|
+
* refresh token in that login family. RFC 7009 answers 200 for an unknown
|
|
94
|
+
* token, so this only fails when the server cannot be reached or refuses the
|
|
95
|
+
* client.
|
|
96
|
+
*/
|
|
97
|
+
export declare function revokeToken(endpoint: string, token: string): Promise<void>;
|
|
98
|
+
export interface BrowserLoginOptions {
|
|
99
|
+
scopes: readonly string[];
|
|
100
|
+
/** Pin the loopback port when an SSH tunnel forwards that same port. */
|
|
101
|
+
callbackPort?: number;
|
|
102
|
+
/** Called with the authorize URL once the listener is up, before waiting. */
|
|
103
|
+
onAuthorizeUrl: (url: string) => void;
|
|
104
|
+
signal?: AbortSignal;
|
|
105
|
+
timeoutMs?: number;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Runs the whole browser login: listener, authorize URL, callback, exchange.
|
|
109
|
+
* Resolves with tokens only after the code has been redeemed, so a caller that
|
|
110
|
+
* gets a result holds a working credential.
|
|
111
|
+
*/
|
|
112
|
+
export declare function loginWithBrowser(endpoint: string, options: BrowserLoginOptions): Promise<OAuthTokens>;
|
|
113
|
+
/**
|
|
114
|
+
* Whether this terminal's browser is unlikely to reach a loopback listener on
|
|
115
|
+
* this machine: an SSH session, or a Linux box with no display. An explicit
|
|
116
|
+
* `--method` selects the flow without this guess; `--callback-port` opts into
|
|
117
|
+
* OAuth when a forwarded port makes the loopback listener reachable.
|
|
118
|
+
*/
|
|
119
|
+
export declare function isLikelyRemoteSession(env?: NodeJS.ProcessEnv, platform?: NodeJS.Platform): boolean;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { type ResolvedProfile, type StoredOAuthCredential } from '../config/index';
|
|
2
|
+
/**
|
|
3
|
+
* Renews a stored OAuth login and persists the rotated pair.
|
|
4
|
+
*
|
|
5
|
+
* Under the credentials lock because the refresh token is single-use and two
|
|
6
|
+
* local processes must not race it. After taking the lock the file is read
|
|
7
|
+
* again: if another process already rotated the token, its result is adopted
|
|
8
|
+
* and no request is made. This coordinates trusted local processes; detecting
|
|
9
|
+
* and containing a copied token remains the authorization server's job.
|
|
10
|
+
*
|
|
11
|
+
* `invalid_grant` means the server no longer honours the refresh token — it
|
|
12
|
+
* was revoked from Settings → General → Authorized apps, expired, or was already rotated
|
|
13
|
+
* by a process this one could not see — and the remedy is logout followed by a
|
|
14
|
+
* new login.
|
|
15
|
+
*/
|
|
16
|
+
export declare function refreshStoredOAuth(profile: Pick<ResolvedProfile, 'name' | 'endpoint' | 'authProfile'>, current: StoredOAuthCredential): Promise<StoredOAuthCredential>;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { Command } from 'commander';
|
|
2
|
+
/**
|
|
3
|
+
* Adds `sim chat`.
|
|
4
|
+
*
|
|
5
|
+
* A protocol command rather than a generated one: the generated pass can only
|
|
6
|
+
* make one JSON request, while a chat turn can run for minutes and is consumed
|
|
7
|
+
* as an NDJSON stream so the reply prints as it generates and heartbeats keep
|
|
8
|
+
* proxies from idling the connection out. The generated `chat` operation is
|
|
9
|
+
* hidden in the CLI contract in favour of this command.
|
|
10
|
+
*/
|
|
11
|
+
export declare function attachChat(program: Command): void;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { type WriteStream } from 'node:fs';
|
|
2
|
+
import { type Writable } from 'node:stream';
|
|
3
|
+
import type { Command } from 'commander';
|
|
4
|
+
/** Streams a fetch body to disk while honoring write-stream backpressure. */
|
|
5
|
+
export declare function streamToFile(body: ReadableStream<Uint8Array>, file: Writable & Pick<WriteStream, 'path'>, reportedPath?: WriteStream['path']): Promise<void>;
|
|
6
|
+
/**
|
|
7
|
+
* Removes the staging directory when a signal ends the process.
|
|
8
|
+
*
|
|
9
|
+
* `saveStagedFile` cleans up in normal control flow, which a signal never
|
|
10
|
+
* reaches: the process is torn down mid-`pipeline`, so every Ctrl-C left
|
|
11
|
+
* another `.sim-download-*` holding a partial payload beside the destination.
|
|
12
|
+
* The removal is synchronous because the termination that follows gives an
|
|
13
|
+
* async `rm` no turn to run.
|
|
14
|
+
*
|
|
15
|
+
* Exported for its own test: driving it through a real interrupt would take the
|
|
16
|
+
* test runner down with it.
|
|
17
|
+
*/
|
|
18
|
+
export declare function removeStagingOnSignal(stagingDirectory: () => string | null, terminate?: (signal: NodeJS.Signals) => void): () => void;
|
|
19
|
+
/** Publishes a complete staged body atomically, with overwrite requiring explicit force. */
|
|
20
|
+
export declare function saveToFile(body: ReadableStream<Uint8Array>, target: string, force: boolean): Promise<void>;
|
|
21
|
+
/** Streams a fetch body to stdout without closing the process-wide stream. */
|
|
22
|
+
export declare function streamToStdout(body: ReadableStream<Uint8Array>, output?: NodeJS.WriteStream): Promise<void>;
|
|
23
|
+
/** Returns whether content can be written directly to an interactive terminal. */
|
|
24
|
+
export declare function isTerminalSafeContentType(contentType: string | null): boolean;
|
|
25
|
+
export declare function attachFileGet(files: Command): void;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { Command } from 'commander';
|
|
2
|
+
/**
|
|
3
|
+
* The file name a `Content-Disposition: attachment` header carries, or `null`
|
|
4
|
+
* when it names none.
|
|
5
|
+
*
|
|
6
|
+
* The RFC 5987 `filename*` form is read first, because the server only emits it
|
|
7
|
+
* when the real name is not printable ASCII — and in exactly that case the
|
|
8
|
+
* quoted form beside it has had every such character replaced, so reading the
|
|
9
|
+
* quoted form alone would save a knowledge base named "Suporte técnico" as
|
|
10
|
+
* `Suporte t_cnico`. Only the base name is kept, so a directory in the header
|
|
11
|
+
* can never decide where the archive lands on the caller's disk.
|
|
12
|
+
*/
|
|
13
|
+
export declare function attachmentFileName(contentDisposition: string | null): string | null;
|
|
14
|
+
export declare function attachKnowledgeExport(knowledge: Command): void;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { type Command } from 'commander';
|
|
2
|
+
import { type ListLogsResponse } from '../../generated/v2-api';
|
|
3
|
+
/** One run, as `GET /api/v2/logs` returns it. */
|
|
4
|
+
export type LogRow = ListLogsResponse['data'][number];
|
|
5
|
+
/** Widest a table column renders, matching the `logs list` table. */
|
|
6
|
+
export declare const MAX_CELL_WIDTH = 60;
|
|
7
|
+
export interface FollowStatus {
|
|
8
|
+
/** Replaces the status line, if there is a terminal to draw it on. */
|
|
9
|
+
note: (message: string) => void;
|
|
10
|
+
/**
|
|
11
|
+
* Reports something the reader has to know, on its own line.
|
|
12
|
+
*
|
|
13
|
+
* Unlike {@link note} this is not progress and is never erased: it records
|
|
14
|
+
* that rows are missing, which stays true after the follow moves on. It is
|
|
15
|
+
* written even when stderr is not a terminal, because a piped log is exactly
|
|
16
|
+
* where an unexplained hole is hardest to spot.
|
|
17
|
+
*/
|
|
18
|
+
warn: (message: string) => void;
|
|
19
|
+
/** Erases the line, if anything was ever written to it. */
|
|
20
|
+
clear: () => void;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Reports what the follow is doing, on stderr.
|
|
24
|
+
*
|
|
25
|
+
* The rule `pageProgress` follows: stdout is the stream of rows and gets piped,
|
|
26
|
+
* so anything that is not a row goes to stderr, and only to a terminal.
|
|
27
|
+
*/
|
|
28
|
+
export declare function followStatus(): FollowStatus;
|
|
29
|
+
/**
|
|
30
|
+
* Adds `sim logs follow`.
|
|
31
|
+
*
|
|
32
|
+
* A sibling command rather than `logs list --follow`, because `logs list` is
|
|
33
|
+
* generated from the CLI contract, which describes the HTTP surface: `--follow`
|
|
34
|
+
* has no wire counterpart, and its paging is the inverse of the contract's —
|
|
35
|
+
* re-reading the newest page forever, rather than walking a cursor to the end
|
|
36
|
+
* once. The filters are the same ones `logs list` exposes, so the two commands
|
|
37
|
+
* take the same arguments and render the same columns.
|
|
38
|
+
*/
|
|
39
|
+
export declare function attachLogsFollow(logs: Command): void;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { type Command } from 'commander';
|
|
2
|
+
type ResourceDirectoryConfig = {
|
|
3
|
+
kind: 'file';
|
|
4
|
+
resources: 'listFiles';
|
|
5
|
+
folders: 'listFileFolders';
|
|
6
|
+
createFolder: 'createFileFolder';
|
|
7
|
+
} | {
|
|
8
|
+
kind: 'knowledge';
|
|
9
|
+
resources: 'listKnowledgeBases';
|
|
10
|
+
folders: 'listKnowledgeFolders';
|
|
11
|
+
createFolder: 'createKnowledgeFolder';
|
|
12
|
+
} | {
|
|
13
|
+
kind: 'table';
|
|
14
|
+
resources: 'listTables';
|
|
15
|
+
folders: 'listTableFolders';
|
|
16
|
+
createFolder: 'createTableFolder';
|
|
17
|
+
} | {
|
|
18
|
+
kind: 'workflow';
|
|
19
|
+
resources: 'listWorkflows';
|
|
20
|
+
folders: 'listWorkflowFolders';
|
|
21
|
+
createFolder: 'createWorkflowFolder';
|
|
22
|
+
};
|
|
23
|
+
export declare function attachResourceDirectoryCommands(group: Command, config: ResourceDirectoryConfig): void;
|
|
24
|
+
export {};
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import type { Command } from 'commander';
|
|
2
|
+
/** The sink live commentary is written to; `process.stderr` satisfies it. */
|
|
3
|
+
export interface CommentaryWriter {
|
|
4
|
+
write(text: string): unknown;
|
|
5
|
+
}
|
|
6
|
+
export interface FollowOptions {
|
|
7
|
+
includeThinking: boolean;
|
|
8
|
+
includeToolCalls: boolean;
|
|
9
|
+
stderr: CommentaryWriter;
|
|
10
|
+
}
|
|
11
|
+
type WorkflowRunSelection = {
|
|
12
|
+
source: 'manual';
|
|
13
|
+
} | {
|
|
14
|
+
source: 'manual';
|
|
15
|
+
entry: {
|
|
16
|
+
type: 'trigger';
|
|
17
|
+
blockId?: string;
|
|
18
|
+
useMockPayload?: boolean;
|
|
19
|
+
};
|
|
20
|
+
} | {
|
|
21
|
+
source: 'manual';
|
|
22
|
+
entry: {
|
|
23
|
+
type: 'block';
|
|
24
|
+
blockId: string;
|
|
25
|
+
sourceRunId: string;
|
|
26
|
+
};
|
|
27
|
+
};
|
|
28
|
+
/** Projects friendly CLI flags into the API's strict nested run selector. */
|
|
29
|
+
export declare function resolveWorkflowRunSelection(flags: Record<string, unknown>): WorkflowRunSelection | undefined;
|
|
30
|
+
/**
|
|
31
|
+
* Renders one execute stream, returning the `final` envelope.
|
|
32
|
+
*
|
|
33
|
+
* Everything rendered here is commentary and goes to `stderr`: the payload a
|
|
34
|
+
* script captures is the final envelope, which the caller prints to stdout in
|
|
35
|
+
* the profile's output format. Streaming the answer text to stdout as well
|
|
36
|
+
* would put the same content in the redirect twice, once unparseable.
|
|
37
|
+
*
|
|
38
|
+
* Throws on a terminal `error` frame and on a stream that stops before either
|
|
39
|
+
* terminal frame arrives — a truncated stream is a failed run, and reporting it
|
|
40
|
+
* as an empty success is the one outcome a caller cannot detect afterwards.
|
|
41
|
+
*/
|
|
42
|
+
export declare function renderRunStream(body: ReadableStream<Uint8Array>, options: FollowOptions): Promise<Record<string, unknown>>;
|
|
43
|
+
/**
|
|
44
|
+
* Teaches the generated `workflows run` leaf to stream.
|
|
45
|
+
*
|
|
46
|
+
* `--follow` rides on `run` rather than standing up a sibling command because
|
|
47
|
+
* it is the same operation with a different response encoding: the input,
|
|
48
|
+
* output-selection, and `--async` flags all still apply, and a second command
|
|
49
|
+
* would have to restate every one of them and then drift.
|
|
50
|
+
*
|
|
51
|
+
* Commander offers no way to read the action it already holds, so the existing
|
|
52
|
+
* handler is captured for async execution. Synchronous execution uses the same
|
|
53
|
+
* generated request and result builders with a heartbeat-capable response.
|
|
54
|
+
*/
|
|
55
|
+
export declare function attachWorkflowRunFollow(workflows: Command): void;
|
|
56
|
+
export {};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { Command } from 'commander';
|
|
2
|
+
/**
|
|
3
|
+
* Teaches the generated `workflows runs get` leaf the block names
|
|
4
|
+
* `workflows run --select-output` already takes.
|
|
5
|
+
*
|
|
6
|
+
* The run resource matches recorded block ids only — it never loads the
|
|
7
|
+
* workflow — so `--select-output summarize.result`, the spelling the run was
|
|
8
|
+
* started with, came back `400` and the fix was to go and look up an id. The
|
|
9
|
+
* lookup is done here instead: a selection with any name-headed selector reads
|
|
10
|
+
* the workflow's blocks once, rewrites names onto ids, and reads the run keyed
|
|
11
|
+
* the way it was asked. A selection of ids alone, or no selection, still runs
|
|
12
|
+
* the generated handler byte for byte. Commander offers no way to read the
|
|
13
|
+
* action it holds, so it is captured and delegated to, as `--follow` does.
|
|
14
|
+
*/
|
|
15
|
+
export declare function attachWorkflowRunGet(runs: Command): void;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { Command } from 'commander';
|
|
2
|
+
import { type GetWorkspaceOperationResponse } from '../../generated/v2-api';
|
|
3
|
+
import { type SimClient } from '../../http/client';
|
|
4
|
+
type WorkspaceOperation = GetWorkspaceOperationResponse['data'];
|
|
5
|
+
export declare function readWorkspaceOperation(raw: unknown): WorkspaceOperation;
|
|
6
|
+
export declare function workspaceWaitTimeout(raw: unknown): number;
|
|
7
|
+
export declare function assertWorkspaceOperationOutcome(report: WorkspaceOperation, timedOut?: boolean): void;
|
|
8
|
+
/** Polls only the existing operation; uncertain mutations are never retried with a new ID. */
|
|
9
|
+
export declare function waitWorkspaceOperation(client: SimClient, workspaceId: string, operationId: string, timeoutSeconds: number, initial?: WorkspaceOperation): Promise<{
|
|
10
|
+
report: WorkspaceOperation;
|
|
11
|
+
timedOut: boolean;
|
|
12
|
+
}>;
|
|
13
|
+
export declare function attachWorkspaceOperationWait(operations: Command): void;
|
|
14
|
+
export {};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export { configDir, configPath, credentialsPath, telemetryStatePath } from './paths';
|
|
2
|
+
export { DEFAULT_ENDPOINT, DEFAULT_PROFILE, deleteProfile, FORBIDDEN_IN_VALUE, listAuthenticationDependents, listProfiles, normalizeEndpoint, normalizeWorkspaceId, OUTPUT_FORMATS, type OutputFormat, oauthIssuerForEndpoint, PROFILE_NAME_PATTERN, ProfileConfigError, type ProfileOverrides, type ResolvedProfile, readConfigProfile, readCredentialsProfile, readStoredCredential, readStoredOAuth, resolveAuthenticationProfileName, resolveProfile, type SettingSource, type StoredCredential, type StoredOAuthCredential, validateProfileName, withCredentialsLock, withProfileLoginLease, writeConfigProfile, writeCredentialsProfile, } from './profile';
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A minimal INI reader/writer for the AWS-style `~/.sim/config` and
|
|
3
|
+
* `~/.sim/credentials` files.
|
|
4
|
+
*
|
|
5
|
+
* Parsing keeps every line it did not understand — comments, blank lines,
|
|
6
|
+
* unrecognized keys — and writing re-emits them in place. These are files people
|
|
7
|
+
* hand-edit, so a round trip through `sim login` must not silently delete the
|
|
8
|
+
* comment above someone's staging endpoint.
|
|
9
|
+
*
|
|
10
|
+
* Deliberately not a general INI implementation: no nested sections, no `[a.b]`
|
|
11
|
+
* paths, no quoting rules beyond trimming. The format only has to carry a
|
|
12
|
+
* handful of flat string settings.
|
|
13
|
+
*/
|
|
14
|
+
/**
|
|
15
|
+
* An invalid stored setting, or a value the config files cannot represent.
|
|
16
|
+
*
|
|
17
|
+
* Defined here rather than in `profile.ts` because the writer below is the
|
|
18
|
+
* lowest layer that rejects input, and `profile.ts` already imports this module.
|
|
19
|
+
* `profile.ts` re-exports it, so callers keep seeing one error type — the one
|
|
20
|
+
* the entrypoint renders as a message instead of a stack trace.
|
|
21
|
+
*/
|
|
22
|
+
export declare class ProfileConfigError extends Error {
|
|
23
|
+
constructor(message: string);
|
|
24
|
+
}
|
|
25
|
+
type Entry = {
|
|
26
|
+
kind: 'kv';
|
|
27
|
+
key: string;
|
|
28
|
+
value: string;
|
|
29
|
+
} | {
|
|
30
|
+
kind: 'raw';
|
|
31
|
+
text: string;
|
|
32
|
+
};
|
|
33
|
+
interface Section {
|
|
34
|
+
name: string;
|
|
35
|
+
/**
|
|
36
|
+
* The header line exactly as it was read, re-emitted verbatim.
|
|
37
|
+
*
|
|
38
|
+
* {@link parseIni} trims the bracketed text to get {@link name}, so writing
|
|
39
|
+
* `[${name}]` back rewrote the header of every section in the file — a
|
|
40
|
+
* `configure --set-output` on `default` silently reformatted a hand-written
|
|
41
|
+
* `[profile padded ]` it was never asked to touch. Absent only on a
|
|
42
|
+
* section {@link setSectionValues} created, which has no original line.
|
|
43
|
+
*/
|
|
44
|
+
header?: string;
|
|
45
|
+
entries: Entry[];
|
|
46
|
+
}
|
|
47
|
+
export interface IniDocument {
|
|
48
|
+
/** Lines before the first section header. */
|
|
49
|
+
preamble: string[];
|
|
50
|
+
sections: Section[];
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Characters a stored value may not contain.
|
|
54
|
+
*
|
|
55
|
+
* The format has no escape syntax (see the module note), so text that can end a
|
|
56
|
+
* line is structure, not data: a value carrying a line break was written
|
|
57
|
+
* verbatim and read back on the next load as a *second* setting in the same
|
|
58
|
+
* section. That is the class of bug this closes — untrusted text reaching the
|
|
59
|
+
* serializer could add settings nobody typed.
|
|
60
|
+
*
|
|
61
|
+
* The set is every C0 and C1 control character plus U+2028 and U+2029, the two
|
|
62
|
+
* Unicode line separators. The separators matter for a second reason: they are
|
|
63
|
+
* not line breaks to the reader below, so {@link KV_PATTERN} (whose `.` never
|
|
64
|
+
* matches them) fails and the line is kept as opaque `raw` text — the key
|
|
65
|
+
* silently vanishes on the next read although the write reported success, and
|
|
66
|
+
* because the dead line no longer matches the key, the write after that appends
|
|
67
|
+
* a duplicate.
|
|
68
|
+
*
|
|
69
|
+
* Exported because callers that refuse untrusted text *before* writing — so they
|
|
70
|
+
* can say which side produced it — have to refuse exactly this set. A second
|
|
71
|
+
* hand-kept copy drifted from this one once already, and the gap let a rejected
|
|
72
|
+
* write land after an accepted one.
|
|
73
|
+
*/
|
|
74
|
+
export declare const FORBIDDEN_IN_VALUE: RegExp;
|
|
75
|
+
export declare function parseIni(text: string): IniDocument;
|
|
76
|
+
export declare function serializeIni(doc: IniDocument): string;
|
|
77
|
+
/**
|
|
78
|
+
* Reads a section's keys, merging every block that repeats its name.
|
|
79
|
+
*
|
|
80
|
+
* A hand-edited file can carry two `[default]` blocks; reading only the first
|
|
81
|
+
* silently dropped the second's keys and reported them as unset. The merge is
|
|
82
|
+
* **first wins** per key, matching {@link setSectionValues}, which upserts into
|
|
83
|
+
* the first block — so a value written through this module is the one read back.
|
|
84
|
+
*/
|
|
85
|
+
export declare function getSection(doc: IniDocument, name: string): Record<string, string> | null;
|
|
86
|
+
export declare function listSections(doc: IniDocument): string[];
|
|
87
|
+
/**
|
|
88
|
+
* Upserts values into a section, creating it when absent. A `null` value removes
|
|
89
|
+
* the key. Existing keys are updated where they sit so surrounding comments keep
|
|
90
|
+
* describing the line they were written above.
|
|
91
|
+
*
|
|
92
|
+
* A write targets the first block of that name, matching the first-wins read in
|
|
93
|
+
* {@link getSection}. A removal instead has to clear every block and every
|
|
94
|
+
* repeat of the key within one: deleting only the first left a later duplicate
|
|
95
|
+
* to win the merged read, so `--unset` reported success while the value stayed
|
|
96
|
+
* in force. A removal against a section that is not there writes nothing at all.
|
|
97
|
+
*
|
|
98
|
+
* This is the one place untrusted text enters the document, so it is where the
|
|
99
|
+
* write is refused: see {@link FORBIDDEN_IN_VALUE} for what cannot be stored
|
|
100
|
+
* and why the answer is a refusal rather than an escape.
|
|
101
|
+
*/
|
|
102
|
+
export declare function setSectionValues(doc: IniDocument, name: string, values: Record<string, string | null>): void;
|
|
103
|
+
/**
|
|
104
|
+
* Drops every block carrying the name, and reports whether one was there.
|
|
105
|
+
*
|
|
106
|
+
* A hand-edited file can repeat a section, and {@link getSection} merges them
|
|
107
|
+
* all — so removing only the first left `sim logout` reporting a profile gone
|
|
108
|
+
* while its later block still answered every read.
|
|
109
|
+
*/
|
|
110
|
+
export declare function removeSection(doc: IniDocument, name: string): boolean;
|
|
111
|
+
export {};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reads and parses a JSON file, or returns `null` for anything at all wrong.
|
|
3
|
+
*
|
|
4
|
+
* Follows no symlink and reads no more than `maxBytes`: the file lives where
|
|
5
|
+
* the user, or anything running as the user, can replace it, and the caller's
|
|
6
|
+
* only interest is in a small document it wrote itself. Shape validation is
|
|
7
|
+
* the caller's — this returns whatever JSON was there.
|
|
8
|
+
*/
|
|
9
|
+
export declare function readJsonFile(path: string, maxBytes: number): unknown;
|
|
10
|
+
/**
|
|
11
|
+
* Replaces a JSON file atomically, creating its directory if needed.
|
|
12
|
+
*
|
|
13
|
+
* An exclusive adjacent temporary file renamed into place means a reader never
|
|
14
|
+
* sees a partial document and a linked target is never modified through the
|
|
15
|
+
* link. Failures are swallowed: the callers are caches and preferences whose
|
|
16
|
+
* loss costs one extra request or one repeated notice.
|
|
17
|
+
*/
|
|
18
|
+
export declare function writeJsonFile(path: string, value: unknown, mode?: number): void;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Where the CLI keeps its state. `SIM_CONFIG_DIR` overrides the location
|
|
3
|
+
* wholesale, which is what lets tests and CI point at a scratch directory
|
|
4
|
+
* instead of the invoking user's real credentials.
|
|
5
|
+
*/
|
|
6
|
+
export declare function configDir(): string;
|
|
7
|
+
/** Non-secret per-profile settings. Safe to commit to a dotfiles repo. */
|
|
8
|
+
export declare function configPath(): string;
|
|
9
|
+
/** API keys, written 0600. Kept apart from `config` so the two can be handled differently. */
|
|
10
|
+
export declare function credentialsPath(): string;
|
|
11
|
+
/**
|
|
12
|
+
* Where the once-a-day update check remembers that it ran.
|
|
13
|
+
*
|
|
14
|
+
* Cache, not configuration, so it is safe to delete at any time and gets no
|
|
15
|
+
* `SIM_*` override of its own: nobody relocates a cache deliberately, and
|
|
16
|
+
* `SIM_CONFIG_DIR` already moves it for the two callers that matter — the test
|
|
17
|
+
* harness and anyone keeping `~/.sim` somewhere else. It is kept out of the
|
|
18
|
+
* config file because that file is INI the user edits, and a timestamp inside a
|
|
19
|
+
* `[profile x]` section would surface in `sim configure` and `sim whoami`.
|
|
20
|
+
*/
|
|
21
|
+
export declare function updateCachePath(): string;
|
|
22
|
+
/**
|
|
23
|
+
* Where usage telemetry keeps its device id, session, and on/off setting.
|
|
24
|
+
*
|
|
25
|
+
* State rather than configuration, so it follows `SIM_CONFIG_DIR` the way the
|
|
26
|
+
* update cache does and gets no override of its own. Deleting it forgets the
|
|
27
|
+
* device id and shows the first-run notice again; nothing else is lost.
|
|
28
|
+
*/
|
|
29
|
+
export declare function telemetryStatePath(): string;
|