@algochad/archcoder 2.0.2
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 +113 -0
- package/bin/cli-entry.js +55 -0
- package/bin/cli-output.js +145 -0
- package/bin/cli.js +5108 -0
- package/bin/cli.test.js +56 -0
- package/dist/apple-touch-icon-120x120.png +0 -0
- package/dist/apple-touch-icon-152x152.png +0 -0
- package/dist/apple-touch-icon-167x167.png +0 -0
- package/dist/apple-touch-icon-180x180.png +0 -0
- package/dist/apple-touch-icon.png +0 -0
- package/dist/apple-touch-icon.svg +67 -0
- package/dist/assets/MultiRunWindow-BZp3MjJP.js +1 -0
- package/dist/assets/SettingsWindow-DoGYXpX7.js +1 -0
- package/dist/assets/TerminalView-BN7BR5Ff.js +3 -0
- package/dist/assets/TimelineDialog-ZQ33oVQR.js +1 -0
- package/dist/assets/ToolOutputDialog-Blv3pnug.js +16 -0
- package/dist/assets/ibm-plex-mono-latin-400-normal-CvHOgSBP.woff +0 -0
- package/dist/assets/ibm-plex-mono-latin-400-normal-DMJ8VG8y.woff2 +0 -0
- package/dist/assets/ibm-plex-mono-latin-500-normal-CB9ihrfo.woff +0 -0
- package/dist/assets/ibm-plex-mono-latin-500-normal-DSY6xOcd.woff2 +0 -0
- package/dist/assets/ibm-plex-mono-latin-600-normal-BgSNZQsw.woff2 +0 -0
- package/dist/assets/ibm-plex-mono-latin-600-normal-DWFSQ4vo.woff +0 -0
- package/dist/assets/ibm-plex-sans-latin-400-normal-CDDApCn2.woff2 +0 -0
- package/dist/assets/ibm-plex-sans-latin-400-normal-CYLoc0-x.woff +0 -0
- package/dist/assets/ibm-plex-sans-latin-500-normal-6ng42L7E.woff2 +0 -0
- package/dist/assets/ibm-plex-sans-latin-500-normal-BgVn5rGT.woff +0 -0
- package/dist/assets/ibm-plex-sans-latin-600-normal-Cu4Hd6ag.woff +0 -0
- package/dist/assets/ibm-plex-sans-latin-600-normal-CuJfVYMP.woff2 +0 -0
- package/dist/assets/index-CtCEGYrr.css +1 -0
- package/dist/assets/index-o_d2wtWC.js +48 -0
- package/dist/assets/main-5QGBtzdq.css +1 -0
- package/dist/assets/main-B6oiMU86.js +8033 -0
- package/dist/assets/vendor--DbVqbJpV.css +1 -0
- package/dist/assets/vendor-.bun-HTKwyaEM.js +10086 -0
- package/dist/assets/wasm-CG6Dc4jp.js +1 -0
- package/dist/assets/worker-bqd4RMrj.js +155 -0
- package/dist/favicon-16.png +0 -0
- package/dist/favicon-32.png +0 -0
- package/dist/favicon.png +0 -0
- package/dist/favicon.svg +67 -0
- package/dist/index.html +533 -0
- package/dist/logo-dark-192x192.png +0 -0
- package/dist/logo-dark-512x512.svg +16 -0
- package/dist/logo-light-192x192.png +0 -0
- package/dist/logo-light-512x512.svg +16 -0
- package/dist/pwa-192.png +0 -0
- package/dist/pwa-512.png +0 -0
- package/dist/pwa-maskable-192.png +0 -0
- package/dist/pwa-maskable-512.png +0 -0
- package/dist/site.webmanifest +22 -0
- package/dist/sw.js +1 -0
- package/package.json +107 -0
- package/public/apple-touch-icon-120x120.png +0 -0
- package/public/apple-touch-icon-152x152.png +0 -0
- package/public/apple-touch-icon-167x167.png +0 -0
- package/public/apple-touch-icon-180x180.png +0 -0
- package/public/apple-touch-icon.png +0 -0
- package/public/apple-touch-icon.svg +67 -0
- package/public/favicon-16.png +0 -0
- package/public/favicon-32.png +0 -0
- package/public/favicon.png +0 -0
- package/public/favicon.svg +67 -0
- package/public/logo-dark-192x192.png +0 -0
- package/public/logo-dark-512x512.svg +16 -0
- package/public/logo-light-192x192.png +0 -0
- package/public/logo-light-512x512.svg +16 -0
- package/public/pwa-192.png +0 -0
- package/public/pwa-512.png +0 -0
- package/public/pwa-maskable-192.png +0 -0
- package/public/pwa-maskable-512.png +0 -0
- package/public/site.webmanifest +22 -0
- package/server/TERMINAL_INPUT_WS_PROTOCOL.md +44 -0
- package/server/index.d.ts +37 -0
- package/server/index.js +14694 -0
- package/server/lib/cloudflare-tunnel.js +650 -0
- package/server/lib/git/DOCUMENTATION.md +146 -0
- package/server/lib/git/credentials.js +74 -0
- package/server/lib/git/identity-storage.js +110 -0
- package/server/lib/git/index.js +6 -0
- package/server/lib/git/service.js +3117 -0
- package/server/lib/github/DOCUMENTATION.md +170 -0
- package/server/lib/github/auth.js +307 -0
- package/server/lib/github/device-flow.js +50 -0
- package/server/lib/github/index.js +24 -0
- package/server/lib/github/octokit.js +10 -0
- package/server/lib/github/pr-status.js +478 -0
- package/server/lib/github/repo/index.js +55 -0
- package/server/lib/installer/desktop.js +289 -0
- package/server/lib/installer/download.js +208 -0
- package/server/lib/installer/index.js +45 -0
- package/server/lib/installer/platform.js +100 -0
- package/server/lib/notifications/DOCUMENTATION.md +61 -0
- package/server/lib/notifications/index.js +1 -0
- package/server/lib/notifications/message.js +49 -0
- package/server/lib/notifications/message.test.js +59 -0
- package/server/lib/opencode/DOCUMENTATION.md +59 -0
- package/server/lib/opencode/agents.js +634 -0
- package/server/lib/opencode/auth.js +81 -0
- package/server/lib/opencode/commands.js +339 -0
- package/server/lib/opencode/index.js +66 -0
- package/server/lib/opencode/mcp.js +206 -0
- package/server/lib/opencode/providers.js +96 -0
- package/server/lib/opencode/shared.js +527 -0
- package/server/lib/opencode/skills.js +480 -0
- package/server/lib/opencode/tunnel-auth.js +591 -0
- package/server/lib/opencode/ui-auth.js +510 -0
- package/server/lib/package-manager.js +505 -0
- package/server/lib/quota/DOCUMENTATION.md +55 -0
- package/server/lib/quota/index.js +24 -0
- package/server/lib/quota/providers/claude.js +107 -0
- package/server/lib/quota/providers/codex.js +113 -0
- package/server/lib/quota/providers/copilot.js +165 -0
- package/server/lib/quota/providers/google/api.js +92 -0
- package/server/lib/quota/providers/google/auth.js +108 -0
- package/server/lib/quota/providers/google/index.js +124 -0
- package/server/lib/quota/providers/google/transforms.js +109 -0
- package/server/lib/quota/providers/index.js +152 -0
- package/server/lib/quota/providers/interface.js +55 -0
- package/server/lib/quota/providers/kimi.js +108 -0
- package/server/lib/quota/providers/minimax-cn-coding-plan.js +15 -0
- package/server/lib/quota/providers/minimax-coding-plan.js +15 -0
- package/server/lib/quota/providers/minimax-shared.js +136 -0
- package/server/lib/quota/providers/nanogpt.js +124 -0
- package/server/lib/quota/providers/ollama-cloud.js +112 -0
- package/server/lib/quota/providers/openai.js +91 -0
- package/server/lib/quota/providers/openrouter.js +92 -0
- package/server/lib/quota/providers/zai.js +91 -0
- package/server/lib/quota/utils/auth.js +46 -0
- package/server/lib/quota/utils/formatters.js +76 -0
- package/server/lib/quota/utils/index.js +10 -0
- package/server/lib/quota/utils/transformers.js +55 -0
- package/server/lib/skills-catalog/DOCUMENTATION.md +178 -0
- package/server/lib/skills-catalog/cache.js +32 -0
- package/server/lib/skills-catalog/clawdhub/api.js +158 -0
- package/server/lib/skills-catalog/clawdhub/index.js +30 -0
- package/server/lib/skills-catalog/clawdhub/install.js +238 -0
- package/server/lib/skills-catalog/clawdhub/scan.js +113 -0
- package/server/lib/skills-catalog/curated-sources.js +21 -0
- package/server/lib/skills-catalog/git.js +77 -0
- package/server/lib/skills-catalog/index.js +42 -0
- package/server/lib/skills-catalog/install.js +294 -0
- package/server/lib/skills-catalog/scan.js +221 -0
- package/server/lib/skills-catalog/source.js +85 -0
- package/server/lib/terminal/DOCUMENTATION.md +114 -0
- package/server/lib/terminal/index.js +12 -0
- package/server/lib/terminal/input-ws-protocol.js +66 -0
- package/server/lib/terminal/input-ws-protocol.test.js +138 -0
- package/server/lib/tts/DOCUMENTATION.md +134 -0
- package/server/lib/tts/index.js +16 -0
- package/server/lib/tts/service.js +162 -0
- package/server/lib/tts/summarization.js +171 -0
- package/server/lib/tunnels/index.js +166 -0
- package/server/lib/tunnels/providers/cloudflare.js +260 -0
- package/server/lib/tunnels/registry.js +51 -0
- package/server/lib/tunnels/types.js +219 -0
- package/server/lib/utils/lru.js +107 -0
- package/server/lib/utils/sse.js +121 -0
package/README.md
ADDED
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
# @algochad/archcoder
|
|
2
|
+
|
|
3
|
+
Run [OpenCode](https://opencode.ai) in your browser. Install the CLI, open `localhost:3000`, done. Works on desktop browsers, tablets, and phones as a PWA.
|
|
4
|
+
|
|
5
|
+
[](https://discord.gg/uPECDcCQN)
|
|
6
|
+
|
|
7
|
+
ArchCoder is a private project. For support, contact [@algochad](https://x.com/algochad).
|
|
8
|
+
|
|
9
|
+
## Install
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
# Quick install
|
|
13
|
+
curl -fsSL https://archcoder.archlast.com/cli | bash
|
|
14
|
+
|
|
15
|
+
# Or using your preferred package manager
|
|
16
|
+
npm install -g @algochad/archcoder
|
|
17
|
+
pnpm add -g @algochad/archcoder
|
|
18
|
+
bun add -g @algochad/archcoder
|
|
19
|
+
yarn global add @algochad/archcoder
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
> **Prerequisites:** [OpenCode CLI](https://opencode.ai) installed, Node.js 20+.
|
|
23
|
+
|
|
24
|
+
## Usage
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
archcoder # Start on port 3000
|
|
28
|
+
archcoder --port 8080 # Custom port
|
|
29
|
+
archcoder --ui-password secret # Password-protect UI
|
|
30
|
+
archcoder tunnel help # Tunnel lifecycle commands
|
|
31
|
+
archcoder tunnel providers # Show provider capabilities
|
|
32
|
+
archcoder tunnel profile add --provider cloudflare --mode managed-remote --name prod-main --hostname app.example.com --token <token>
|
|
33
|
+
archcoder tunnel start --profile prod-main
|
|
34
|
+
archcoder tunnel start --provider cloudflare --mode quick --qr
|
|
35
|
+
archcoder tunnel start --provider cloudflare --mode managed-local --config ~/.cloudflared/config.yml
|
|
36
|
+
archcoder tunnel status --all # Show tunnel state across instances
|
|
37
|
+
archcoder tunnel stop --port 3000 # Stop tunnel only (server stays running)
|
|
38
|
+
archcoder logs # Follow latest instance logs
|
|
39
|
+
OPENCODE_PORT=4096 OPENCODE_SKIP_START=true archcoder # Connect to external OpenCode server
|
|
40
|
+
OPENCODE_HOST=https://myhost:4096 OPENCODE_SKIP_START=true archcoder # Connect via custom host/HTTPS
|
|
41
|
+
archcoder stop # Stop server
|
|
42
|
+
archcoder update # Update to latest version
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### Tunnel behavior notes
|
|
46
|
+
|
|
47
|
+
- One active tunnel per running ArchCoder instance (port).
|
|
48
|
+
- Starting a different tunnel mode/provider on the same instance replaces the active tunnel.
|
|
49
|
+
- Replacing or stopping a tunnel revokes existing connect links and invalidates remote tunnel sessions.
|
|
50
|
+
- Connect links are one-time tokens; generating a new link revokes the previous unused link.
|
|
51
|
+
|
|
52
|
+
**Optional env vars:**
|
|
53
|
+
```yaml
|
|
54
|
+
environment:
|
|
55
|
+
UI_PASSWORD: your_secure_password
|
|
56
|
+
ARCHCODER_TUNNEL_MODE: quick # quick | managed-remote | managed-local
|
|
57
|
+
ARCHCODER_TUNNEL_PROVIDER: cloudflare
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
For `managed-remote` mode, also set:
|
|
61
|
+
|
|
62
|
+
```yaml
|
|
63
|
+
environment:
|
|
64
|
+
ARCHCODER_TUNNEL_MODE: managed-remote
|
|
65
|
+
ARCHCODER_TUNNEL_HOSTNAME: app.example.com
|
|
66
|
+
ARCHCODER_TUNNEL_TOKEN: <token>
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
For `managed-local` mode, you can set:
|
|
70
|
+
|
|
71
|
+
```yaml
|
|
72
|
+
environment:
|
|
73
|
+
ARCHCODER_TUNNEL_MODE: managed-local
|
|
74
|
+
ARCHCODER_TUNNEL_CONFIG: /home/archcoder/.cloudflared/config.yml
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Managed-local path note: `ARCHCODER_TUNNEL_CONFIG` must use a container path under `/home/archcoder/...`. If the config file references `credentials-file`, ensure that JSON path is also mounted and reachable inside the container.
|
|
78
|
+
|
|
79
|
+
**Data directory:** mount `data/` for persistent storage. Ensure permissions:
|
|
80
|
+
```bash
|
|
81
|
+
mkdir -p data/archcoder data/opencode/share data/opencode/config data/ssh
|
|
82
|
+
chown -R 1000:1000 data/
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
</details>
|
|
86
|
+
|
|
87
|
+
<details>
|
|
88
|
+
<summary>Background & daemon mode</summary>
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
archcoder # Runs in background by default
|
|
92
|
+
archcoder stop # Stop background server
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
</details>
|
|
96
|
+
|
|
97
|
+
## What makes the web version special
|
|
98
|
+
|
|
99
|
+
- **Remote access** - Cloudflare tunnel with QR onboarding. Scan from your phone, start coding.
|
|
100
|
+
- **Mobile-first PWA** - optimized chat controls, keyboard-safe layouts, drag-to-reorder projects
|
|
101
|
+
- **Background notifications** - know when your agent finishes, even from another tab
|
|
102
|
+
- **Self-update** - update and restart from the UI, server settings stay intact
|
|
103
|
+
- **Cross-tab tracking** - session activity stays in sync across browser tabs
|
|
104
|
+
|
|
105
|
+
- Cloudflare tunnel access with quick, managed-remote, and managed-local modes
|
|
106
|
+
- One-scan onboarding with tunnel QR + password URL helpers
|
|
107
|
+
- Mobile-first experience: optimized chat controls, keyboard-safe layouts, and attachment-friendly UI
|
|
108
|
+
- Background notifications plus reliable cross-tab session activity tracking
|
|
109
|
+
- Built-in self-update + restart flow that keeps your server settings intact
|
|
110
|
+
|
|
111
|
+
## License
|
|
112
|
+
|
|
113
|
+
MIT
|
package/bin/cli-entry.js
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { fileURLToPath, pathToFileURL } from 'url';
|
|
4
|
+
|
|
5
|
+
function normalizeCliEntryPath(filePath, realpath = fs.realpathSync) {
|
|
6
|
+
if (typeof filePath !== 'string' || filePath.trim().length === 0) {
|
|
7
|
+
return null;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const resolvedPath = path.resolve(filePath);
|
|
11
|
+
try {
|
|
12
|
+
return realpath(resolvedPath);
|
|
13
|
+
} catch {
|
|
14
|
+
return resolvedPath;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function isModuleCliExecution(
|
|
19
|
+
entryPath = process.argv[1],
|
|
20
|
+
moduleUrl,
|
|
21
|
+
realpath = fs.realpathSync,
|
|
22
|
+
expectedBinName,
|
|
23
|
+
) {
|
|
24
|
+
if (typeof entryPath !== 'string' || entryPath.trim().length === 0) {
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
if (typeof moduleUrl !== 'string' || moduleUrl.trim().length === 0) {
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
try {
|
|
32
|
+
const normalizedEntryPath = normalizeCliEntryPath(entryPath, realpath);
|
|
33
|
+
const normalizedModulePath = normalizeCliEntryPath(fileURLToPath(moduleUrl), realpath);
|
|
34
|
+
if (!normalizedEntryPath || !normalizedModulePath) {
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
37
|
+
if (pathToFileURL(normalizedEntryPath).href === pathToFileURL(normalizedModulePath).href) {
|
|
38
|
+
return true;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (typeof expectedBinName === 'string' && expectedBinName.trim().length > 0) {
|
|
42
|
+
const parsedEntryName = path.parse(normalizedEntryPath).name.toLowerCase();
|
|
43
|
+
return parsedEntryName === expectedBinName.trim().toLowerCase();
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return false;
|
|
47
|
+
} catch {
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export {
|
|
53
|
+
normalizeCliEntryPath,
|
|
54
|
+
isModuleCliExecution,
|
|
55
|
+
};
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI output formatting adapter.
|
|
3
|
+
*
|
|
4
|
+
* Wraps @clack/prompts for structured, beautiful terminal output.
|
|
5
|
+
* Custom formatters (icons, redaction) live here to isolate the
|
|
6
|
+
* formatting dependency from the rest of the CLI.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import {
|
|
10
|
+
intro,
|
|
11
|
+
outro,
|
|
12
|
+
log,
|
|
13
|
+
note,
|
|
14
|
+
box,
|
|
15
|
+
progress,
|
|
16
|
+
spinner,
|
|
17
|
+
confirm,
|
|
18
|
+
select,
|
|
19
|
+
text,
|
|
20
|
+
password,
|
|
21
|
+
cancel,
|
|
22
|
+
isCancel,
|
|
23
|
+
} from '@clack/prompts';
|
|
24
|
+
|
|
25
|
+
// ── Provider icons ──────────────────────────────────────────────
|
|
26
|
+
|
|
27
|
+
const TUNNEL_PROVIDER_ICON = {
|
|
28
|
+
cloudflare: '☁',
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
function formatProviderWithIcon(provider) {
|
|
32
|
+
if (typeof provider !== 'string' || provider.trim().length === 0) {
|
|
33
|
+
return 'unknown';
|
|
34
|
+
}
|
|
35
|
+
const normalized = provider.trim().toLowerCase();
|
|
36
|
+
const icon = TUNNEL_PROVIDER_ICON[normalized];
|
|
37
|
+
return icon ? `${icon} ${normalized}` : normalized;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// ── Status-aware log dispatch ───────────────────────────────────
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Print a status-tagged message using clack log primitives.
|
|
44
|
+
*
|
|
45
|
+
* @param {'success'|'warning'|'error'|'info'|'neutral'} status
|
|
46
|
+
* @param {string} message Primary line
|
|
47
|
+
* @param {string} [detail] Optional dim secondary line appended after newline
|
|
48
|
+
*/
|
|
49
|
+
function logStatus(status, message, detail) {
|
|
50
|
+
const full = detail ? `${message}\n${detail}` : message;
|
|
51
|
+
switch (status) {
|
|
52
|
+
case 'success':
|
|
53
|
+
log.success(full);
|
|
54
|
+
break;
|
|
55
|
+
case 'warning':
|
|
56
|
+
log.warn(full);
|
|
57
|
+
break;
|
|
58
|
+
case 'error':
|
|
59
|
+
log.error(full);
|
|
60
|
+
break;
|
|
61
|
+
case 'info':
|
|
62
|
+
case 'neutral':
|
|
63
|
+
default:
|
|
64
|
+
log.info(full);
|
|
65
|
+
break;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// ── TTY detection ───────────────────────────────────────────────
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Whether both stdout and stdin are interactive TTYs.
|
|
73
|
+
* Prompts must be disabled when stdin is piped (e.g. --token-stdin).
|
|
74
|
+
*/
|
|
75
|
+
const isTTY = Boolean(process.stdout?.isTTY) && Boolean(process.stdin?.isTTY);
|
|
76
|
+
|
|
77
|
+
function isJsonMode(options) {
|
|
78
|
+
return Boolean(options?.json);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function isQuietMode(options) {
|
|
82
|
+
return Boolean(options?.quiet);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function shouldRenderHumanOutput(options) {
|
|
86
|
+
return !isJsonMode(options) && !isQuietMode(options);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function canPrompt(options) {
|
|
90
|
+
return shouldRenderHumanOutput(options) && isTTY;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function createSpinner(options) {
|
|
94
|
+
return canPrompt(options) ? spinner() : null;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
async function createProgress(options, config) {
|
|
98
|
+
return canPrompt(options) ? progress(config) : null;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function printJson(payload) {
|
|
102
|
+
const base = payload && typeof payload === 'object' && !Array.isArray(payload)
|
|
103
|
+
? { ...payload }
|
|
104
|
+
: { data: payload };
|
|
105
|
+
|
|
106
|
+
const messages = Array.isArray(base.messages) ? base.messages : undefined;
|
|
107
|
+
const hasWarning = Boolean(messages?.some((entry) => entry?.level === 'warning'));
|
|
108
|
+
const hasError = Boolean(messages?.some((entry) => entry?.level === 'error'));
|
|
109
|
+
const normalizedStatus = base.status === 'ok' || base.status === 'warning' || base.status === 'error'
|
|
110
|
+
? base.status
|
|
111
|
+
: (hasError ? 'error' : (hasWarning ? 'warning' : 'ok'));
|
|
112
|
+
|
|
113
|
+
const output = {
|
|
114
|
+
status: normalizedStatus,
|
|
115
|
+
...base,
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
process.stdout.write(`${JSON.stringify(output, null, 2)}\n`);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
export {
|
|
122
|
+
intro,
|
|
123
|
+
outro,
|
|
124
|
+
log,
|
|
125
|
+
note,
|
|
126
|
+
box,
|
|
127
|
+
progress,
|
|
128
|
+
spinner,
|
|
129
|
+
confirm,
|
|
130
|
+
select,
|
|
131
|
+
text,
|
|
132
|
+
password,
|
|
133
|
+
cancel,
|
|
134
|
+
isCancel,
|
|
135
|
+
isTTY,
|
|
136
|
+
isJsonMode,
|
|
137
|
+
isQuietMode,
|
|
138
|
+
shouldRenderHumanOutput,
|
|
139
|
+
canPrompt,
|
|
140
|
+
createSpinner,
|
|
141
|
+
createProgress,
|
|
142
|
+
printJson,
|
|
143
|
+
formatProviderWithIcon,
|
|
144
|
+
logStatus,
|
|
145
|
+
};
|