@axtary/cli 0.0.1 → 0.2.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.
Files changed (49) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +140 -6
  3. package/dist/bin.js +10 -0
  4. package/dist/bin.js.map +1 -1
  5. package/dist/claude-code-hook.d.ts +65 -0
  6. package/dist/claude-code-hook.d.ts.map +1 -0
  7. package/dist/claude-code-hook.js +326 -0
  8. package/dist/claude-code-hook.js.map +1 -0
  9. package/dist/codex-hook.d.ts +48 -0
  10. package/dist/codex-hook.d.ts.map +1 -0
  11. package/dist/codex-hook.js +259 -0
  12. package/dist/codex-hook.js.map +1 -0
  13. package/dist/credentials.d.ts +101 -0
  14. package/dist/credentials.d.ts.map +1 -0
  15. package/dist/credentials.js +277 -0
  16. package/dist/credentials.js.map +1 -0
  17. package/dist/cursor-hook.d.ts +51 -0
  18. package/dist/cursor-hook.d.ts.map +1 -0
  19. package/dist/cursor-hook.js +214 -0
  20. package/dist/cursor-hook.js.map +1 -0
  21. package/dist/hook-install.d.ts +21 -0
  22. package/dist/hook-install.d.ts.map +1 -0
  23. package/dist/hook-install.js +179 -0
  24. package/dist/hook-install.js.map +1 -0
  25. package/dist/index.d.ts +897 -5
  26. package/dist/index.d.ts.map +1 -1
  27. package/dist/index.js +6750 -513
  28. package/dist/index.js.map +1 -1
  29. package/dist/mcp-fs-normalize.d.ts +18 -0
  30. package/dist/mcp-fs-normalize.d.ts.map +1 -0
  31. package/dist/mcp-fs-normalize.js +39 -0
  32. package/dist/mcp-fs-normalize.js.map +1 -0
  33. package/dist/mcp-oauth.d.ts +67 -0
  34. package/dist/mcp-oauth.d.ts.map +1 -0
  35. package/dist/mcp-oauth.js +242 -0
  36. package/dist/mcp-oauth.js.map +1 -0
  37. package/dist/oauth.d.ts +90 -0
  38. package/dist/oauth.d.ts.map +1 -0
  39. package/dist/oauth.js +339 -0
  40. package/dist/oauth.js.map +1 -0
  41. package/dist/render.d.ts +103 -0
  42. package/dist/render.d.ts.map +1 -0
  43. package/dist/render.js +172 -0
  44. package/dist/render.js.map +1 -0
  45. package/dist/shell-file-normalize.d.ts +21 -0
  46. package/dist/shell-file-normalize.d.ts.map +1 -0
  47. package/dist/shell-file-normalize.js +269 -0
  48. package/dist/shell-file-normalize.js.map +1 -0
  49. package/package.json +17 -13
package/dist/oauth.js ADDED
@@ -0,0 +1,339 @@
1
+ import { spawn } from "node:child_process";
2
+ import { createHash, randomBytes, timingSafeEqual } from "node:crypto";
3
+ import { createServer, } from "node:http";
4
+ import {} from "node:net";
5
+ // Local-loopback OAuth 2.0 Authorization Code flow (with PKCE when the provider
6
+ // supports it). This is the `gh auth login` model: the browser does the consent,
7
+ // the provider redirects to 127.0.0.1, the CLI captures the code and exchanges
8
+ // it locally. The resulting token never leaves the machine and is never pasted.
9
+ //
10
+ // Axtary never holds the customer's OAuth client secret: the user registers
11
+ // their own OAuth app (or GitHub App) and the secret is read from local env.
12
+ // That keeps the credential broker fully local, per PRD §10.1.
13
+ export const DEFAULT_OAUTH_REDIRECT_PORT = 7878;
14
+ export const DEFAULT_OAUTH_REDIRECT_PATH = "/callback";
15
+ export const OAUTH_PROVIDERS = {
16
+ slack: {
17
+ provider: "slack",
18
+ authorizeUrl: "https://slack.com/oauth/v2/authorize",
19
+ tokenUrl: "https://slack.com/api/oauth.v2.access",
20
+ scopes: ["chat:write"],
21
+ scopeSeparator: ",",
22
+ pkce: false,
23
+ requiresClientSecret: true,
24
+ requiresHttpsRedirect: true,
25
+ },
26
+ linear: {
27
+ provider: "linear",
28
+ authorizeUrl: "https://linear.app/oauth/authorize",
29
+ tokenUrl: "https://api.linear.app/oauth/token",
30
+ scopes: ["read", "write"],
31
+ scopeSeparator: ",",
32
+ pkce: false,
33
+ requiresClientSecret: true,
34
+ requiresHttpsRedirect: false,
35
+ extraAuthParams: { prompt: "consent" },
36
+ },
37
+ jira: {
38
+ provider: "jira",
39
+ authorizeUrl: "https://auth.atlassian.com/authorize",
40
+ tokenUrl: "https://auth.atlassian.com/oauth/token",
41
+ scopes: ["read:jira-work", "write:jira-work", "read:me", "offline_access"],
42
+ scopeSeparator: " ",
43
+ pkce: false,
44
+ requiresClientSecret: true,
45
+ tokenRequestFormat: "json",
46
+ requiresHttpsRedirect: true,
47
+ extraAuthParams: {
48
+ audience: "api.atlassian.com",
49
+ prompt: "consent",
50
+ },
51
+ },
52
+ drive: {
53
+ provider: "drive",
54
+ authorizeUrl: "https://accounts.google.com/o/oauth2/v2/auth",
55
+ tokenUrl: "https://oauth2.googleapis.com/token",
56
+ scopes: ["https://www.googleapis.com/auth/drive.file"],
57
+ scopeSeparator: " ",
58
+ pkce: true,
59
+ // Google's `trigger_onepick` Picker flow requires a custom HTTPS redirect,
60
+ // which only a Google **Web application** OAuth client can register — and a
61
+ // Web client is confidential, so Google's token endpoint requires the client
62
+ // secret at exchange (alongside PKCE). A Desktop/public client (no secret)
63
+ // cannot register a non-loopback redirect, so the secret is required here.
64
+ requiresClientSecret: true,
65
+ requiresHttpsRedirect: true,
66
+ extraAuthParams: {
67
+ access_type: "offline",
68
+ prompt: "consent",
69
+ trigger_onepick: "true",
70
+ allow_multiple: "false",
71
+ mimetypes: "application/vnd.google-apps.document,text/plain,text/markdown,text/html,text/csv,application/json,application/xml",
72
+ },
73
+ },
74
+ };
75
+ function base64Url(buffer) {
76
+ return buffer.toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
77
+ }
78
+ export async function runLoopbackOAuth(input) {
79
+ const fetchImpl = input.fetch ?? fetch;
80
+ const now = input.now ?? (() => Date.now());
81
+ const redirectPath = input.redirectPath ?? DEFAULT_OAUTH_REDIRECT_PATH;
82
+ const state = (input.randomState ?? (() => base64Url(randomBytes(24))))();
83
+ const verifier = input.descriptor.pkce
84
+ ? (input.pkceVerifier ?? (() => base64Url(randomBytes(32))))()
85
+ : null;
86
+ const challenge = verifier ? base64Url(createHash("sha256").update(verifier).digest()) : null;
87
+ const { server, port } = await listen(input.redirectPort ?? DEFAULT_OAUTH_REDIRECT_PORT);
88
+ input.onListening?.(port);
89
+ // The advertised redirect (sent to the provider and used in the exchange) may
90
+ // be a tunnel HTTPS URL; the local server matches on its path either way.
91
+ const redirectUri = input.redirectUri ?? `http://127.0.0.1:${port}${redirectPath}`;
92
+ const matchPath = new URL(redirectUri).pathname;
93
+ try {
94
+ const authorization = await captureAuthorizationCode({
95
+ server,
96
+ redirectPath: matchPath,
97
+ state,
98
+ timeoutMs: input.timeoutMs ?? 300_000,
99
+ start: async () => {
100
+ const authorizeUrl = buildAuthorizeUrl({
101
+ descriptor: input.descriptor,
102
+ clientId: input.clientId,
103
+ redirectUri,
104
+ state,
105
+ challenge,
106
+ });
107
+ await input.openBrowser(authorizeUrl);
108
+ },
109
+ });
110
+ const json = await exchangeCode({
111
+ descriptor: input.descriptor,
112
+ clientId: input.clientId,
113
+ clientSecret: input.clientSecret,
114
+ code: authorization.code,
115
+ redirectUri,
116
+ verifier,
117
+ fetchImpl,
118
+ });
119
+ return mapTokenResponse(input.descriptor, json, now(), authorization.selectedResourceIds);
120
+ }
121
+ finally {
122
+ server.close();
123
+ }
124
+ }
125
+ function buildAuthorizeUrl(input) {
126
+ const url = new URL(input.descriptor.authorizeUrl);
127
+ url.searchParams.set("response_type", "code");
128
+ url.searchParams.set("client_id", input.clientId);
129
+ url.searchParams.set("redirect_uri", input.redirectUri);
130
+ url.searchParams.set("scope", input.descriptor.scopes.join(input.descriptor.scopeSeparator));
131
+ url.searchParams.set("state", input.state);
132
+ if (input.challenge) {
133
+ url.searchParams.set("code_challenge", input.challenge);
134
+ url.searchParams.set("code_challenge_method", "S256");
135
+ }
136
+ for (const [key, value] of Object.entries(input.descriptor.extraAuthParams ?? {})) {
137
+ url.searchParams.set(key, value);
138
+ }
139
+ return url.toString();
140
+ }
141
+ async function exchangeCode(input) {
142
+ const values = {
143
+ grant_type: "authorization_code",
144
+ code: input.code,
145
+ redirect_uri: input.redirectUri,
146
+ client_id: input.clientId,
147
+ ...(input.clientSecret ? { client_secret: input.clientSecret } : {}),
148
+ ...(input.verifier ? { code_verifier: input.verifier } : {}),
149
+ };
150
+ const json = input.descriptor.tokenRequestFormat === "json";
151
+ const body = json
152
+ ? JSON.stringify(values)
153
+ : new URLSearchParams(values).toString();
154
+ const response = await input.fetchImpl(input.descriptor.tokenUrl, {
155
+ method: "POST",
156
+ headers: {
157
+ "content-type": json
158
+ ? "application/json"
159
+ : "application/x-www-form-urlencoded",
160
+ accept: "application/json",
161
+ },
162
+ body,
163
+ });
164
+ if (!response.ok) {
165
+ throw new Error(`oauth_token_exchange_failed:${response.status}`);
166
+ }
167
+ return (await response.json());
168
+ }
169
+ export async function discoverAtlassianAccessibleResources(accessToken, fetchImpl = fetch) {
170
+ const response = await fetchImpl("https://api.atlassian.com/oauth/token/accessible-resources", {
171
+ headers: {
172
+ authorization: `Bearer ${accessToken}`,
173
+ accept: "application/json",
174
+ },
175
+ });
176
+ if (!response.ok) {
177
+ throw new Error(`jira_accessible_resources_failed:${response.status}`);
178
+ }
179
+ const resources = (await response.json());
180
+ return resources.filter((resource) => typeof resource.id === "string" &&
181
+ typeof resource.url === "string" &&
182
+ typeof resource.name === "string");
183
+ }
184
+ export async function refreshOAuthAccessToken(input) {
185
+ const fetchImpl = input.fetch ?? fetch;
186
+ const values = {
187
+ grant_type: "refresh_token",
188
+ client_id: input.clientId,
189
+ refresh_token: input.refreshToken,
190
+ ...(input.clientSecret ? { client_secret: input.clientSecret } : {}),
191
+ };
192
+ const json = input.descriptor.tokenRequestFormat === "json";
193
+ const response = await fetchImpl(input.descriptor.tokenUrl, {
194
+ method: "POST",
195
+ headers: {
196
+ "content-type": json
197
+ ? "application/json"
198
+ : "application/x-www-form-urlencoded",
199
+ accept: "application/json",
200
+ },
201
+ body: json
202
+ ? JSON.stringify(values)
203
+ : new URLSearchParams(values).toString(),
204
+ });
205
+ if (!response.ok) {
206
+ throw new Error(`oauth_refresh_failed:${response.status}`);
207
+ }
208
+ return mapTokenResponse(input.descriptor, (await response.json()), (input.now ?? (() => Date.now()))());
209
+ }
210
+ function mapTokenResponse(descriptor, json, nowMs, selectedResourceIds = []) {
211
+ // Slack returns { ok: false, error } on failure and nests team info.
212
+ if (descriptor.provider === "slack" && json.ok === false) {
213
+ throw new Error(`oauth_token_error:${String(json.error ?? "unknown")}`);
214
+ }
215
+ if (typeof json.error === "string") {
216
+ throw new Error(`oauth_token_error:${json.error}`);
217
+ }
218
+ const accessToken = typeof json.access_token === "string" ? json.access_token : null;
219
+ if (!accessToken) {
220
+ throw new Error("oauth_token_missing_access_token");
221
+ }
222
+ const scopeRaw = typeof json.scope === "string" ? json.scope : "";
223
+ const scope = scopeRaw ? scopeRaw.split(/[ ,]/).filter(Boolean) : [];
224
+ const expiresIn = typeof json.expires_in === "number" ? json.expires_in : null;
225
+ const team = json.team;
226
+ return {
227
+ accessToken,
228
+ refreshToken: typeof json.refresh_token === "string" ? json.refresh_token : null,
229
+ tokenType: typeof json.token_type === "string" ? json.token_type : null,
230
+ scope,
231
+ expiresAt: expiresIn ? new Date(nowMs + expiresIn * 1000).toISOString() : null,
232
+ account: team?.name ?? team?.id ?? null,
233
+ selectedResourceIds,
234
+ };
235
+ }
236
+ export function listen(port) {
237
+ return new Promise((resolve, reject) => {
238
+ const server = createServer();
239
+ server.on("error", reject);
240
+ server.listen(port, "127.0.0.1", () => {
241
+ const address = server.address();
242
+ resolve({ server, port: address.port });
243
+ });
244
+ });
245
+ }
246
+ export function captureAuthorizationCode(input) {
247
+ return new Promise((resolve, reject) => {
248
+ const timer = setTimeout(() => {
249
+ cleanup();
250
+ reject(new Error("oauth_timeout"));
251
+ }, input.timeoutMs);
252
+ function cleanup() {
253
+ clearTimeout(timer);
254
+ input.server.removeListener("request", onRequest);
255
+ }
256
+ function onRequest(req, res) {
257
+ const url = new URL(req.url ?? "/", "http://127.0.0.1");
258
+ if (url.pathname !== input.redirectPath) {
259
+ res.statusCode = 404;
260
+ res.end("not found");
261
+ return;
262
+ }
263
+ const error = url.searchParams.get("error");
264
+ const code = url.searchParams.get("code");
265
+ const returnedState = url.searchParams.get("state");
266
+ const finish = (status, message) => {
267
+ res.statusCode = status;
268
+ res.setHeader("content-type", "text/html; charset=utf-8");
269
+ res.end(`<!doctype html><meta charset="utf-8"><title>Axtary</title><body style="font:14px ui-monospace,monospace;background:#0a0a0a;color:#e5e5e5;padding:40px"><h1 style="font-size:16px">Axtary</h1><p>${message}</p><p style="color:#888">You can close this tab and return to your terminal.</p></body>`);
270
+ };
271
+ if (error) {
272
+ finish(400, `Authorization failed: ${escapeHtml(error)}.`);
273
+ cleanup();
274
+ reject(new Error(`oauth_authorization_error:${error}`));
275
+ return;
276
+ }
277
+ if (!constantTimeEquals(returnedState, input.state)) {
278
+ finish(400, "State mismatch — possible CSRF. Aborted.");
279
+ cleanup();
280
+ reject(new Error("oauth_state_mismatch"));
281
+ return;
282
+ }
283
+ if (!code) {
284
+ finish(400, "No authorization code received.");
285
+ cleanup();
286
+ reject(new Error("oauth_missing_code"));
287
+ return;
288
+ }
289
+ finish(200, "Connected. Token stored locally.");
290
+ cleanup();
291
+ resolve({
292
+ code,
293
+ selectedResourceIds: (url.searchParams.get("picked_file_ids") ?? "")
294
+ .split(",")
295
+ .map((value) => value.trim())
296
+ .filter(Boolean),
297
+ });
298
+ }
299
+ input.server.on("request", onRequest);
300
+ input.start().catch((startError) => {
301
+ cleanup();
302
+ reject(startError);
303
+ });
304
+ });
305
+ }
306
+ /**
307
+ * Constant-time comparison of the returned `state` against the expected nonce,
308
+ * so a mismatch cannot be probed byte-by-byte via response timing. Lengths are
309
+ * compared first (a length difference is not secret), then the bytes.
310
+ */
311
+ function constantTimeEquals(actual, expected) {
312
+ if (actual === null) {
313
+ return false;
314
+ }
315
+ const a = Buffer.from(actual);
316
+ const b = Buffer.from(expected);
317
+ return a.length === b.length && timingSafeEqual(a, b);
318
+ }
319
+ function escapeHtml(value) {
320
+ return value.replace(/[&<>"']/g, (char) => char === "&"
321
+ ? "&amp;"
322
+ : char === "<"
323
+ ? "&lt;"
324
+ : char === ">"
325
+ ? "&gt;"
326
+ : char === '"'
327
+ ? "&quot;"
328
+ : "&#39;");
329
+ }
330
+ export function defaultOpenBrowser(url) {
331
+ const command = process.platform === "darwin" ? "open" : process.platform === "win32" ? "cmd" : "xdg-open";
332
+ const args = process.platform === "win32" ? ["/c", "start", "", url] : [url];
333
+ const child = spawn(command, args, { stdio: "ignore", detached: true });
334
+ child.on("error", () => {
335
+ // Browser launch is best-effort; the CLI also prints the URL to paste manually.
336
+ });
337
+ child.unref();
338
+ }
339
+ //# sourceMappingURL=oauth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"oauth.js","sourceRoot":"","sources":["../src/oauth.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,103 @@
1
+ /**
2
+ * Cinematic-restraint rendering primitives for the Axtary human CLI.
3
+ *
4
+ * Design contract (product/skills/design.md + clig.dev + AGENTS.md):
5
+ * - Color communicates STATE only; everything else stays neutral.
6
+ * - Color auto-disables off a real terminal, under NO_COLOR / TERM=dumb, and
7
+ * when `--no-color` is passed — so piped/`--json`/CI output is plain text.
8
+ * - Output is status-first: a one-line plain-English verdict, then aligned
9
+ * fields. Hashes are truncated for the eye; full values stay in `--json`.
10
+ *
11
+ * These are pure string helpers. The `--json` path never calls them, so the
12
+ * machine-readable contract is unaffected by anything here.
13
+ */
14
+ /**
15
+ * Decide whether color should render. Pure so it is unit-testable; the CLI
16
+ * entrypoint calls this once with the real stdout/env and feeds the result to
17
+ * {@link setColorEnabled}.
18
+ */
19
+ export declare function resolveColor(opts: {
20
+ isTTY?: boolean;
21
+ env?: Record<string, string | undefined>;
22
+ noColorFlag?: boolean;
23
+ }): boolean;
24
+ export declare function setColorEnabled(value: boolean): void;
25
+ export declare function isColorEnabled(): boolean;
26
+ export declare const style: {
27
+ bold: (t: string) => string;
28
+ dim: (t: string) => string;
29
+ green: (t: string) => string;
30
+ red: (t: string) => string;
31
+ yellow: (t: string) => string;
32
+ cyan: (t: string) => string;
33
+ };
34
+ /**
35
+ * The states the CLI renders. Authorization decisions (allow/deny/step_up) and
36
+ * workflow/connection outcomes (executed/blocked/failed/completed) collapse to
37
+ * one of three semantic colors: positive, attention, negative.
38
+ */
39
+ export type RenderState = "allow" | "executed" | "completed" | "ok" | "deny" | "blocked" | "failed" | "error" | "step_up" | "warn" | "info";
40
+ /** A single colored glyph that encodes the state (and nothing else carries color by default). */
41
+ export declare function stateGlyph(state: RenderState): string;
42
+ /** Quiet wordmark header: ` axtary <command>`. The mark stays dim; the command is the subject. */
43
+ export declare function wordmark(command: string): string;
44
+ /** Status-first one-line verdict: glyph + plain-English sentence. */
45
+ export declare function verdict(state: RenderState, sentence: string): string;
46
+ /**
47
+ * Aligned label/value block. Labels are dimmed and padded to a common width so
48
+ * values form a clean column. Falsy values are dropped so a field never renders
49
+ * an empty or `undefined` line.
50
+ */
51
+ export declare function fields(rows: Array<[string, string | number | null | undefined]>): string;
52
+ /**
53
+ * A list of decision steps (a multi-step workflow or a demo's actions). Each
54
+ * row is a glyph + a name padded to a common width + a trailing detail, so the
55
+ * steps read as a scannable column.
56
+ */
57
+ export declare function steps(rows: Array<{
58
+ state: RenderState;
59
+ name: string;
60
+ detail: string;
61
+ }>): string;
62
+ /** Truncate a hash-like string for the eye: `sha256:9f3a1c…b1`. Non-hashes pass through. */
63
+ export declare function shortHash(value: string | null | undefined, head?: number, tail?: number): string | null;
64
+ /**
65
+ * Assemble a standard decision/result block:
66
+ * axtary <command>
67
+ *
68
+ * <glyph> <verdict sentence>
69
+ *
70
+ * label value
71
+ * ...
72
+ * Trailing newline included so callers can `stdout(...)` directly.
73
+ */
74
+ export declare function block(input: {
75
+ command: string;
76
+ state: RenderState;
77
+ verdict: string;
78
+ rows?: Array<[string, string | number | null | undefined]>;
79
+ }): string;
80
+ /**
81
+ * Axtary brand spinner. Keep the circled-A brand mark fixed while a quadrant
82
+ * arc orbits it; the mark is bolded because terminal fonts can render enclosed
83
+ * letters thinly.
84
+ */
85
+ export declare const SPINNER_FRAMES: string[];
86
+ export declare const SPINNER_BRAND = "\u24B6";
87
+ export type Spinner = {
88
+ /** Stop the spinner, clear its transient line, and resolve to a final state + message. */
89
+ stop: (state: RenderState, message: string) => void;
90
+ /** Clear the transient line without printing a resolution (caller prints its own result). */
91
+ clear: () => void;
92
+ };
93
+ /**
94
+ * A truthful spinner: it renders only when its stream is a TTY (never into a
95
+ * pipe or CI log) and only exists for the duration of genuine async work. On
96
+ * stop it resolves to the real terminal state — it never implies work that did
97
+ * not run. No-ops (returns a stop/clear that print nothing) when not on a TTY.
98
+ */
99
+ export declare function startSpinner(text: string, io?: {
100
+ stream?: NodeJS.WriteStream;
101
+ intervalMs?: number;
102
+ }): Spinner;
103
+ //# sourceMappingURL=render.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"render.d.ts","sourceRoot":"","sources":["../src/render.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAcH;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE;IACjC,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;IACzC,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB,GAAG,OAAO,CAMV;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI,CAEpD;AAED,wBAAgB,cAAc,IAAI,OAAO,CAExC;AAMD,eAAO,MAAM,KAAK;cACN,MAAM;aACP,MAAM;eACJ,MAAM;aACR,MAAM;gBACH,MAAM;cACR,MAAM;CACjB,CAAC;AAEF;;;;GAIG;AACH,MAAM,MAAM,WAAW,GACnB,OAAO,GACP,UAAU,GACV,WAAW,GACX,IAAI,GACJ,MAAM,GACN,SAAS,GACT,QAAQ,GACR,OAAO,GACP,SAAS,GACT,MAAM,GACN,MAAM,CAAC;AAMX,iGAAiG;AACjG,wBAAgB,UAAU,CAAC,KAAK,EAAE,WAAW,GAAG,MAAM,CAKrD;AAED,oGAAoG;AACpG,wBAAgB,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAEhD;AAED,qEAAqE;AACrE,wBAAgB,OAAO,CAAC,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAEpE;AAED;;;;GAIG;AACH,wBAAgB,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC,CAAC,GAAG,MAAM,CASxF;AAED;;;;GAIG;AACH,wBAAgB,KAAK,CACnB,IAAI,EAAE,KAAK,CAAC;IAAE,KAAK,EAAE,WAAW,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,GAChE,MAAM,CASR;AAED,4FAA4F;AAC5F,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAAE,IAAI,SAAI,EAAE,IAAI,SAAI,GAAG,MAAM,GAAG,IAAI,CAO7F;AAED;;;;;;;;;GASG;AACH,wBAAgB,KAAK,CAAC,KAAK,EAAE;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,WAAW,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,KAAK,CAAC,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC,CAAC,CAAC;CAC5D,GAAG,MAAM,CAOT;AAED;;;;GAIG;AACH,eAAO,MAAM,cAAc,UAAuB,CAAC;AACnD,eAAO,MAAM,aAAa,WAAM,CAAC;AAEjC,MAAM,MAAM,OAAO,GAAG;IACpB,0FAA0F;IAC1F,IAAI,EAAE,CAAC,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACpD,6FAA6F;IAC7F,KAAK,EAAE,MAAM,IAAI,CAAC;CACnB,CAAC;AAEF;;;;;GAKG;AACH,wBAAgB,YAAY,CAC1B,IAAI,EAAE,MAAM,EACZ,EAAE,GAAE;IAAE,MAAM,CAAC,EAAE,MAAM,CAAC,WAAW,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAAO,GAC5D,OAAO,CA0BT"}
package/dist/render.js ADDED
@@ -0,0 +1,172 @@
1
+ /**
2
+ * Cinematic-restraint rendering primitives for the Axtary human CLI.
3
+ *
4
+ * Design contract (product/skills/design.md + clig.dev + AGENTS.md):
5
+ * - Color communicates STATE only; everything else stays neutral.
6
+ * - Color auto-disables off a real terminal, under NO_COLOR / TERM=dumb, and
7
+ * when `--no-color` is passed — so piped/`--json`/CI output is plain text.
8
+ * - Output is status-first: a one-line plain-English verdict, then aligned
9
+ * fields. Hashes are truncated for the eye; full values stay in `--json`.
10
+ *
11
+ * These are pure string helpers. The `--json` path never calls them, so the
12
+ * machine-readable contract is unaffected by anything here.
13
+ */
14
+ const ANSI = {
15
+ reset: "\x1b[0m",
16
+ bold: "\x1b[1m",
17
+ dim: "\x1b[2m",
18
+ green: "\x1b[32m",
19
+ red: "\x1b[31m",
20
+ yellow: "\x1b[33m",
21
+ cyan: "\x1b[36m",
22
+ };
23
+ let colorEnabled = false;
24
+ /**
25
+ * Decide whether color should render. Pure so it is unit-testable; the CLI
26
+ * entrypoint calls this once with the real stdout/env and feeds the result to
27
+ * {@link setColorEnabled}.
28
+ */
29
+ export function resolveColor(opts) {
30
+ const env = opts.env ?? process.env;
31
+ if (opts.noColorFlag)
32
+ return false;
33
+ if (typeof env.NO_COLOR === "string" && env.NO_COLOR !== "")
34
+ return false;
35
+ if (env.TERM === "dumb")
36
+ return false;
37
+ return Boolean(opts.isTTY);
38
+ }
39
+ export function setColorEnabled(value) {
40
+ colorEnabled = value;
41
+ }
42
+ export function isColorEnabled() {
43
+ return colorEnabled;
44
+ }
45
+ function paint(code, text) {
46
+ return colorEnabled ? `${code}${text}${ANSI.reset}` : text;
47
+ }
48
+ export const style = {
49
+ bold: (t) => paint(ANSI.bold, t),
50
+ dim: (t) => paint(ANSI.dim, t),
51
+ green: (t) => paint(ANSI.green, t),
52
+ red: (t) => paint(ANSI.red, t),
53
+ yellow: (t) => paint(ANSI.yellow, t),
54
+ cyan: (t) => paint(ANSI.cyan, t),
55
+ };
56
+ const POSITIVE = new Set(["allow", "executed", "completed", "ok"]);
57
+ const NEGATIVE = new Set(["deny", "blocked", "failed", "error"]);
58
+ const ATTENTION = new Set(["step_up", "warn"]);
59
+ /** A single colored glyph that encodes the state (and nothing else carries color by default). */
60
+ export function stateGlyph(state) {
61
+ if (POSITIVE.has(state))
62
+ return style.green("✓");
63
+ if (NEGATIVE.has(state))
64
+ return style.red("✕");
65
+ if (ATTENTION.has(state))
66
+ return style.yellow("▲");
67
+ return style.dim("·");
68
+ }
69
+ /** Quiet wordmark header: ` axtary <command>`. The mark stays dim; the command is the subject. */
70
+ export function wordmark(command) {
71
+ return ` ${style.dim("axtary")} ${command}`;
72
+ }
73
+ /** Status-first one-line verdict: glyph + plain-English sentence. */
74
+ export function verdict(state, sentence) {
75
+ return ` ${stateGlyph(state)} ${sentence}`;
76
+ }
77
+ /**
78
+ * Aligned label/value block. Labels are dimmed and padded to a common width so
79
+ * values form a clean column. Falsy values are dropped so a field never renders
80
+ * an empty or `undefined` line.
81
+ */
82
+ export function fields(rows) {
83
+ const present = rows.filter(([, value]) => value !== null && value !== undefined && value !== "");
84
+ if (present.length === 0)
85
+ return "";
86
+ const width = Math.max(...present.map(([label]) => label.length));
87
+ return present
88
+ .map(([label, value]) => ` ${style.dim(label.padEnd(width))} ${value}`)
89
+ .join("\n");
90
+ }
91
+ /**
92
+ * A list of decision steps (a multi-step workflow or a demo's actions). Each
93
+ * row is a glyph + a name padded to a common width + a trailing detail, so the
94
+ * steps read as a scannable column.
95
+ */
96
+ export function steps(rows) {
97
+ if (rows.length === 0)
98
+ return "";
99
+ const width = Math.max(...rows.map((row) => row.name.length));
100
+ return rows
101
+ .map((row) => ` ${stateGlyph(row.state)} ${style.dim(row.name.padEnd(width))} ${row.detail}`)
102
+ .join("\n");
103
+ }
104
+ /** Truncate a hash-like string for the eye: `sha256:9f3a1c…b1`. Non-hashes pass through. */
105
+ export function shortHash(value, head = 6, tail = 2) {
106
+ if (!value)
107
+ return null;
108
+ const match = /^([a-z0-9]+:)?([0-9a-fA-F]{12,})$/.exec(value);
109
+ if (!match)
110
+ return value;
111
+ const prefix = match[1] ?? "";
112
+ const hex = match[2];
113
+ return `${prefix}${hex.slice(0, head)}…${hex.slice(-tail)}`;
114
+ }
115
+ /**
116
+ * Assemble a standard decision/result block:
117
+ * axtary <command>
118
+ *
119
+ * <glyph> <verdict sentence>
120
+ *
121
+ * label value
122
+ * ...
123
+ * Trailing newline included so callers can `stdout(...)` directly.
124
+ */
125
+ export function block(input) {
126
+ const parts = [wordmark(input.command), "", verdict(input.state, input.verdict)];
127
+ const fieldBlock = input.rows ? fields(input.rows) : "";
128
+ if (fieldBlock) {
129
+ parts.push("", fieldBlock);
130
+ }
131
+ return `${parts.join("\n")}\n`;
132
+ }
133
+ /**
134
+ * Axtary brand spinner. Keep the circled-A brand mark fixed while a quadrant
135
+ * arc orbits it; the mark is bolded because terminal fonts can render enclosed
136
+ * letters thinly.
137
+ */
138
+ export const SPINNER_FRAMES = ["◜", "◝", "◞", "◟"];
139
+ export const SPINNER_BRAND = "Ⓐ";
140
+ /**
141
+ * A truthful spinner: it renders only when its stream is a TTY (never into a
142
+ * pipe or CI log) and only exists for the duration of genuine async work. On
143
+ * stop it resolves to the real terminal state — it never implies work that did
144
+ * not run. No-ops (returns a stop/clear that print nothing) when not on a TTY.
145
+ */
146
+ export function startSpinner(text, io = {}) {
147
+ const stream = io.stream ?? process.stderr;
148
+ if (!stream.isTTY) {
149
+ return { stop: () => { }, clear: () => { } };
150
+ }
151
+ let frame = 0;
152
+ const line = () => `\r${style.bold(SPINNER_BRAND)}${style.dim(SPINNER_FRAMES[frame])} ${text}`;
153
+ const render = () => {
154
+ stream.write(line());
155
+ frame = (frame + 1) % SPINNER_FRAMES.length;
156
+ };
157
+ render();
158
+ const timer = setInterval(render, io.intervalMs ?? 90);
159
+ const wipe = () => {
160
+ clearInterval(timer);
161
+ // Overwrite the transient spinner line with spaces, then return to col 0.
162
+ stream.write(`\r${" ".repeat(text.length + 4)}\r`);
163
+ };
164
+ return {
165
+ stop: (state, message) => {
166
+ wipe();
167
+ stream.write(`${stateGlyph(state)} ${message}\n`);
168
+ },
169
+ clear: wipe,
170
+ };
171
+ }
172
+ //# sourceMappingURL=render.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"render.js","sourceRoot":"","sources":["../src/render.ts"],"names":[],"mappings":"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"}