@nitsan-ai/ragsuite-test 0.1.0 → 0.1.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/README.md CHANGED
@@ -2,84 +2,101 @@
2
2
 
3
3
  > **TESTING PACKAGE** — `@nitsan-ai/ragsuite-test` / `ragsuite-test` is temporary.
4
4
  > **Not** the final production `@nitsan-ai/ragsuite` / `ragsuite` CLI (later release).
5
- > Do **not** treat this as the long-term npm identity.
6
5
 
7
6
  Wraps monorepo Docker/native scripts. Does **not** reimplement compose.
8
7
 
9
- Requires **Node.js 18+**.
8
+ Requires **Node.js 18+**. **Docker is optional.** Public deploy path: **`npm` → `init --from-git`**.
10
9
 
11
- **Run modes (both fully supported):**
10
+ ## Prerequisites
12
11
 
13
- | Situation | Mode | Command |
14
- |-----------|------|---------|
15
- | You have Docker | `docker` (default) | `ragsuite-test init --mode docker` then `start` |
16
- | No Docker | `native` | Need Postgres **:5436** + Redis **:6382** on the host, then `ragsuite-test init --mode native` then `start` |
12
+ | Need | Why | How to get it |
13
+ |------|-----|----------------|
14
+ | Node.js 18+ | CLI + native frontend tooling | https://nodejs.org · `brew install node` · `sudo apt install nodejs` |
15
+ | git | `--from-git` clone | `xcode-select --install` · `brew install git` · `sudo apt install git` |
16
+ | **SMTP** | No prompts. Real values only in **local `.env`** (gitignored) | Gmail App Password → edit `.env` |
17
+ | LLM API key | Default in `.env.example` / `.env` — no prompt | Override in `.env` or `--llm-api-key` |
18
+ | **Either Docker** *or* **native data stores** | Run the stack | See modes below |
17
19
 
18
- Docker is **not** mandatory choose native in the wizard or pass `--mode native`.
20
+ ### Mode ADocker (optional)
19
21
 
20
- **Full tester steps:** [TEST_DISTRIBUTION.md](./TEST_DISTRIBUTION.md)
22
+ - Docker Desktop / daemon + `docker compose`
23
+ - https://www.docker.com/products/docker-desktop/
21
24
 
22
- ## Quick start (wizard)
25
+ ### Mode B — Native (no Docker)
23
26
 
24
- ```bash
25
- bash scripts/build-release-zip.sh
26
- cd cli && npm pack && npm install -g ./nitsan-ai-ragsuite-test-*.tgz
27
+ - `python3`, `yarn` (or corepack)
28
+ - Postgres on **localhost:5436**, database `ragsuite_v3`
29
+ - Redis on **localhost:6382**
30
+
31
+ ## Install (public)
27
32
 
28
- # Interactive:
29
- ragsuite-test init
33
+ ```bash
34
+ npm install -g @nitsan-ai/ragsuite-test
30
35
 
31
- # Or CI / noninteractive:
32
36
  ragsuite-test init --yes \
33
- --from-zip ../dist/ragsuite-server-test-1.0.0.zip \
37
+ --from-git \
34
38
  --install-dir ~/ragsuite-test \
35
- --mode docker \
36
- --llm-api-key 'your-key'
39
+ --mode docker
37
40
 
38
41
  ragsuite-test start --repo-root ~/ragsuite-test --detach
39
42
  # API http://localhost:9090 · Web http://localhost:9091
40
43
  ```
41
44
 
42
- `init` auto-generates `JWT_SECRET_KEY`, writes `.ragsuite-test/config.json`, checks ports **9090 / 9091 / 5436 / 6382**, and warns if SMTP is skipped (invites/email may fail).
45
+ SMTP + LLM: **no init prompts**. JWT is auto-generated. Real SMTP belongs only in local `.env` (never commit). If `.env.example` still has placeholders, init writes smoke SMTP so the app can start edit `.env` for real mail.
46
+
47
+ No Docker:
48
+
49
+ ```bash
50
+ ragsuite-test init --yes --from-git --install-dir ~/ragsuite-test --mode native
51
+ ragsuite-test start --repo-root ~/ragsuite-test
52
+ # API :9090 · Expo web :9191
53
+ ```
54
+
55
+ Existing checkout:
43
56
 
44
- ## Install sources
57
+ ```bash
58
+ ragsuite-test init --yes --repo-root /path/to/RAGSUITE --mode native
59
+ ```
45
60
 
46
- | Method | Flag |
47
- |--------|------|
48
- | Local ZIP | `--from-zip` (recommended for private testing) |
49
- | Existing checkout | `--repo-root` |
50
- | GitHub Release | `--from-release` — not implemented yet |
61
+ Interactive: `ragsuite-test init`
51
62
 
52
- Making GitHub public is **not** required for ZIP installs.
63
+ ## Ports
53
64
 
54
- ## Config
65
+ | Service | Port |
66
+ |---------|------|
67
+ | API | 9090 |
68
+ | Web (Docker) | 9091 |
69
+ | Web (native Expo) | 9191 |
70
+ | Postgres | 5436 |
71
+ | Redis | 6382 |
55
72
 
56
- - CLI: `<install>/.ragsuite-test/config.json`
57
- - Native PID/logs: `<install>/.ragsuite/native/` (Phase 4 scripts)
73
+ ```bash
74
+ ragsuite-test stop --repo-root ~/ragsuite-test
75
+ lsof -nP -iTCP:9090 -sTCP:LISTEN
76
+ docker ps
77
+ ```
58
78
 
59
79
  ## Commands
60
80
 
61
81
  | Command | Behavior |
62
82
  |---------|----------|
63
- | `init` | Installer wizard (ZIP/checkout → .env + config) |
83
+ | `init` | git clone or checkout → `.env` + config |
64
84
  | `start` / `stop` | `scripts/docker-*.sh` or `native-*.sh` |
65
- | `doctor` | `scripts/doctor.sh` |
85
+ | `doctor` | prereqs + `scripts/doctor.sh` |
66
86
  | `logs` / `update` / `version` | As before |
67
87
 
68
- ## Publish (testing package only — Phase 12)
88
+ ## Publish
69
89
 
70
- See [PUBLISH.md](./PUBLISH.md) (full runbook) and [TEST_DISTRIBUTION.md](./TEST_DISTRIBUTION.md) (tester steps + go/no-go).
90
+ See [PUBLISH.md](./PUBLISH.md) and [TEST_DISTRIBUTION.md](./TEST_DISTRIBUTION.md).
71
91
 
72
92
  ```bash
73
93
  cd cli && npm run prepublish:check
74
- # Only when someone says "publish now":
75
- RAGSUITE_TEST_ALLOW_PUBLISH=1 npm publish --access public
76
- # Or: GitHub Actions → CLI publish (workflow_dispatch, NPM_TOKEN)
77
- # Optional app ZIP: Actions → Release app ZIP
94
+ RAGSUITE_TEST_ALLOW_PUBLISH=1 npm publish --access public # only when approved
78
95
  ```
79
96
 
80
97
  ## Windows
81
98
 
82
- Use WSL or Git Bash (`bash` scripts).
99
+ Use WSL or Git Bash.
83
100
 
84
101
  ## Tests
85
102
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nitsan-ai/ragsuite-test",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "private": false,
5
5
  "description": "RAGSuite testing CLI (ragsuite-test) — install from ZIP or --repo-root checkout. Temporary npm identity before public ragsuite release.",
6
6
  "main": "src/index.js",
@@ -1,20 +1,24 @@
1
1
  'use strict';
2
2
 
3
- const fs = require('fs');
4
3
  const path = require('path');
5
4
  const { writeConfig, CONFIG_DIR } = require('../utils/config');
6
5
  const { ensureRagsuiteDir, resolveRepoRoot, looksLikeRepoRoot } = require('../utils/paths');
7
6
  const { assertSupportedInstall, installHint } = require('../utils/distribution');
8
7
  const {
8
+ DEFAULT_GIT_URL,
9
9
  defaultInstallDir,
10
- extractZipToInstallDir,
11
- } = require('../utils/zip-install');
10
+ cloneGitToInstallDir,
11
+ } = require('../utils/git-install');
12
12
  const { detectOs } = require('../utils/os-detect');
13
- const { printPrereqs, checkPrereqs } = require('../utils/prereqs');
14
- const { ask, confirm, choose } = require('../utils/prompt');
13
+ const {
14
+ printPrereqs,
15
+ resolvePreferredMode,
16
+ dockerDaemonRunning,
17
+ commandExists,
18
+ } = require('../utils/prereqs');
19
+ const { ask, choose } = require('../utils/prompt');
15
20
  const {
16
21
  generateJwtSecret,
17
- generateCiLlmKey,
18
22
  isPlaceholderSecret,
19
23
  writeInstallEnv,
20
24
  } = require('../utils/env-file');
@@ -22,30 +26,7 @@ const { assertPortsFree } = require('../utils/port');
22
26
  const { info, warn, error } = require('../utils/log');
23
27
 
24
28
  const name = 'init';
25
- const summary = 'Installer wizard: ZIP or checkout → .env + config';
26
-
27
- function help() {
28
- return `Usage: ragsuite-test init [options]
29
-
30
- Interactive installer (or --yes for CI) that:
31
- - detects OS / prerequisites
32
- - installs from ZIP or configures a checkout
33
- - writes .ragsuite-test/config.json and .env (JWT auto-generated)
34
- - checks ports 9090, 9091, 5436, 6382
35
-
36
- Install sources:
37
- --from-zip <path> Extract app ZIP into --install-dir
38
- --repo-root <path> Use an existing monorepo checkout
39
- --from-release <tag> Not implemented (download ZIP manually)
40
-
41
- Options:
42
- --install-dir <path> ZIP target (default: ~/ragsuite-test)
43
- --mode <docker|native> docker = Docker stack; native = no Docker (needs host Postgres/Redis)
44
- --llm-api-key <key> CUSTOM_LLM_INTERNAL_API_KEY (--yes)
45
- --force Overwrite non-empty install dir / existing .env
46
- --yes, -y Non-interactive (requires --from-zip or --repo-root)
47
- `;
48
- }
29
+ const summary = 'Installer wizard: git clone or checkout → .env + config';
49
30
 
50
31
  function printSuccess(repoRoot, mode) {
51
32
  info('');
@@ -61,7 +42,7 @@ function printSuccess(repoRoot, mode) {
61
42
  info(' Web http://localhost:9091 (Docker nginx)');
62
43
  }
63
44
  info('');
64
- info(' Mode reminder: docker needs Docker; native needs host Postgres/Redis (no Docker required).');
45
+ info(' Docker is optional: native mode needs host Postgres :5436 + Redis :6382.');
65
46
  info(' Each install directory is one deployment / one organization.');
66
47
  info('');
67
48
  info('Next steps:');
@@ -76,23 +57,57 @@ function printSuccess(repoRoot, mode) {
76
57
  info(installHint());
77
58
  }
78
59
 
79
- async function resolveLlmKey(g, env, interactive) {
80
- if (g.llmApiKey && !isPlaceholderSecret(g.llmApiKey)) {
81
- return g.llmApiKey;
82
- }
60
+ function help() {
61
+ return `Usage: ragsuite-test init [options]
62
+
63
+ Interactive installer (or --yes for CI) that:
64
+ - detects OS / prerequisites (Docker is optional)
65
+ - clones the public monorepo or configures an existing checkout
66
+ - writes .ragsuite-test/config.json and .env
67
+ - JWT is auto-generated; SMTP + LLM defaults come from .env.example
68
+ - checks ports 9090, 9091, 5436, 6382
69
+
70
+ Install sources (pick one):
71
+ --from-git [url] Clone public monorepo (default: ${DEFAULT_GIT_URL})
72
+ --repo-root <path> Use an existing monorepo checkout
73
+
74
+ Run mode (Docker is NOT required):
75
+ --mode native Default when Docker is unavailable — host Postgres/Redis
76
+ --mode docker Full compose stack (needs Docker Desktop / daemon)
77
+
78
+ Optional overrides (defaults come from .env.example — usually not needed):
79
+ --llm-api-key <key> Override CUSTOM_LLM_INTERNAL_API_KEY
80
+ --smtp-host / --smtp-user / --smtp-password / --email-from
81
+
82
+ Options:
83
+ --install-dir <path> Target for --from-git (default: ~/ragsuite-test)
84
+ --force Overwrite non-empty install dir / existing .env
85
+ --yes, -y Non-interactive (requires --from-git or --repo-root)
86
+ `;
87
+ }
88
+
89
+ function optionalSmtpOverrides(g, env) {
90
+ const host = g.smtpHost || env.RAGSUITE_TEST_SMTP_HOST || null;
91
+ const user = g.smtpUser || env.RAGSUITE_TEST_SMTP_USER || null;
92
+ const password = g.smtpPassword || env.RAGSUITE_TEST_SMTP_PASSWORD || null;
93
+ const emailFrom = g.emailFrom || env.RAGSUITE_TEST_EMAIL_FROM || null;
94
+ if (!host && !user && !password && !emailFrom) return null;
95
+ return { host, user, password, emailFrom };
96
+ }
97
+
98
+ function resolveLlmOverride(g, env) {
99
+ if (g.llmApiKey && !isPlaceholderSecret(g.llmApiKey)) return g.llmApiKey;
83
100
  if (env.RAGSUITE_TEST_LLM_API_KEY && !isPlaceholderSecret(env.RAGSUITE_TEST_LLM_API_KEY)) {
84
101
  return env.RAGSUITE_TEST_LLM_API_KEY;
85
102
  }
86
- if (g.yes || !interactive) {
87
- const key = generateCiLlmKey();
88
- warn(`Using generated smoke LLM key (${key.slice(0, 18)}…). Set a real CUSTOM_LLM_INTERNAL_API_KEY for production-like tests.`);
89
- return key;
90
- }
91
- for (;;) {
92
- const key = await ask('CUSTOM_LLM_INTERNAL_API_KEY', { yesMode: false });
93
- if (!isPlaceholderSecret(key)) return key;
94
- error('Key required and must not start with change-me');
95
- }
103
+ return null; // keep .env.example default
104
+ }
105
+
106
+ function countSources(fromGit, repoRootFlag) {
107
+ let n = 0;
108
+ if (fromGit !== null && fromGit !== undefined) n += 1;
109
+ if (repoRootFlag) n += 1;
110
+ return n;
96
111
  }
97
112
 
98
113
  async function run(ctx) {
@@ -101,45 +116,49 @@ async function run(ctx) {
101
116
  const interactive = Boolean(process.stdin.isTTY) && !g.yes;
102
117
 
103
118
  if (g.fromRelease) {
104
- error(
105
- `--from-release is not implemented. Download a ZIP (private Release asset or local file), then: ragsuite-test init --from-zip <file.zip>`,
106
- );
119
+ error('--from-release is not supported. Use --from-git or --repo-root.');
107
120
  return 1;
108
121
  }
109
122
 
110
- if (g.fromZip && g.repoRoot) {
111
- error('Use either --from-zip or --repo-root, not both');
123
+ if (countSources(g.fromGit, g.repoRoot) > 1) {
124
+ error('Use only one of --from-git or --repo-root');
112
125
  return 1;
113
126
  }
114
127
 
115
128
  const osInfo = detectOs();
116
129
  info(`OS: ${osInfo.label} (${osInfo.platform})`);
117
130
 
118
- let mode = g.mode || 'docker';
119
- let fromZip = g.fromZip;
131
+ let fromGit = g.fromGit;
120
132
  let repoRootFlag = g.repoRoot;
121
133
  let installDir = g.installDir || defaultInstallDir();
134
+ let mode = g.mode || null;
122
135
 
123
136
  if (g.yes) {
124
- if (!fromZip && !repoRootFlag) {
125
- error('--yes requires --from-zip <path> or --repo-root <path>');
137
+ if (fromGit === null && !repoRootFlag) {
138
+ error('--yes requires --from-git [url] or --repo-root <path>');
126
139
  return 1;
127
140
  }
128
- } else if (interactive && !fromZip && !repoRootFlag) {
141
+ } else if (interactive && fromGit === null && !repoRootFlag) {
129
142
  const method = await choose(
130
143
  'Install method:',
131
144
  [
132
- { id: 'zip', label: 'Local ZIP file (--from-zip)' },
133
- { id: 'checkout', label: 'Existing checkout (--repo-root)' },
145
+ {
146
+ id: 'git',
147
+ label: 'Public git clone (--from-git) — recommended',
148
+ },
149
+ {
150
+ id: 'checkout',
151
+ label: 'Existing checkout (--repo-root)',
152
+ },
134
153
  ],
135
154
  { defaultIndex: 0 },
136
155
  );
137
- if (method.id === 'zip') {
138
- fromZip = await ask('Path to app ZIP', { yesMode: false });
139
- if (!fromZip) {
140
- error('ZIP path required');
141
- return 1;
142
- }
156
+ if (method.id === 'git') {
157
+ const url = await ask('Git repository URL', {
158
+ defaultValue: DEFAULT_GIT_URL,
159
+ yesMode: false,
160
+ });
161
+ fromGit = url || DEFAULT_GIT_URL;
143
162
  installDir = await ask('Install directory', {
144
163
  defaultValue: defaultInstallDir(),
145
164
  yesMode: false,
@@ -152,63 +171,73 @@ async function run(ctx) {
152
171
  }
153
172
  }
154
173
 
174
+ const dockerOk = commandExists('docker') && dockerDaemonRunning();
155
175
  const modeChoice = await choose(
156
- 'Run mode (Docker is optional):',
176
+ 'Run mode (Docker is optional — native works without Docker):',
157
177
  [
158
- { id: 'docker', label: 'Docker — if you have Docker Desktop / daemon (default)' },
159
- { id: 'native', label: 'Native — no Docker; needs Postgres :5436 + Redis :6382 on this machine' },
178
+ {
179
+ id: 'native',
180
+ label: 'Native — no Docker; needs Postgres :5436 + Redis :6382 on this machine',
181
+ },
182
+ {
183
+ id: 'docker',
184
+ label: dockerOk
185
+ ? 'Docker — full compose stack (Docker Desktop / daemon)'
186
+ : 'Docker — not available on this machine (install Docker Desktop first)',
187
+ },
160
188
  ],
161
189
  { defaultIndex: 0 },
162
190
  );
163
191
  mode = modeChoice.id;
164
- } else if (!fromZip && !repoRootFlag) {
165
- error('Pass --from-zip / --repo-root, or run in a TTY for the interactive wizard');
192
+ if (mode === 'docker' && !dockerOk) {
193
+ warn('Docker is not available switching to native mode.');
194
+ mode = 'native';
195
+ }
196
+ } else if (fromGit === null && !repoRootFlag) {
197
+ error('Pass --from-git / --repo-root, or run in a TTY for the interactive wizard');
166
198
  return 1;
167
199
  }
168
200
 
169
- if (!printPrereqs(mode)) {
201
+ if (!mode) {
202
+ mode = resolvePreferredMode(g.mode);
203
+ info(`Run mode: ${mode} (Docker is optional; pass --mode docker|native to force)`);
204
+ }
205
+
206
+ const needGit = fromGit !== null && fromGit !== undefined;
207
+ if (!printPrereqs(mode, { needGit })) {
170
208
  error('Fix prerequisites above and re-run init');
171
209
  return 1;
172
210
  }
173
211
 
174
212
  const jwtSecret = generateJwtSecret();
175
213
  info(`JWT_SECRET_KEY will be auto-generated (…${jwtSecret.slice(-8)})`);
214
+ info('SMTP + LLM: using defaults from .env.example (optional flags can override).');
176
215
 
177
- const llmKey = await resolveLlmKey(g, ctx.env, interactive);
216
+ const llmKey = resolveLlmOverride(g, ctx.env);
217
+ const smtp = optionalSmtpOverrides(g, ctx.env);
178
218
 
179
- let smtpSkipped = true;
180
- if (interactive && !g.yes) {
181
- const configureSmtp = await confirm('Configure SMTP now? (needed for invites/email)', {
182
- defaultYes: false,
183
- });
184
- smtpSkipped = !configureSmtp;
185
- if (!smtpSkipped) {
186
- info('After init, edit SMTP_* in .env (SMTP_HOST, SMTP_USER, SMTP_PASSWORD, EMAIL_FROM).');
219
+ if (ctx.env.RAGSUITE_TEST_SKIP_PORT_CHECK !== '1') {
220
+ try {
221
+ await assertPortsFree();
222
+ } catch (err) {
223
+ error(err.message);
224
+ return 1;
187
225
  }
188
- } else {
189
- warn('SMTP skipped (--yes / noninteractive). Invites/email may fail until SMTP_* is set.');
190
- }
191
-
192
- // Port checks before mutating install (clearer UX)
193
- try {
194
- await assertPortsFree();
195
- } catch (err) {
196
- error(err.message);
197
- return 1;
198
226
  }
199
227
 
200
228
  let repoRoot;
201
229
  let source = 'checkout';
202
230
 
203
231
  try {
204
- if (fromZip) {
205
- info(`Extracting ZIP ${path.resolve(installDir)}`);
206
- const result = extractZipToInstallDir(fromZip, {
232
+ if (fromGit !== null && fromGit !== undefined) {
233
+ const url = fromGit === '' ? DEFAULT_GIT_URL : fromGit;
234
+ info(`Cloning ${url} ${path.resolve(installDir)}`);
235
+ const result = cloneGitToInstallDir(url, {
207
236
  installDir,
208
237
  force: g.force,
209
238
  });
210
239
  repoRoot = result.repoRoot;
211
- source = 'zip';
240
+ source = 'git';
212
241
  info(`Installed app at ${repoRoot}`);
213
242
  } else {
214
243
  repoRoot = resolveRepoRoot({
@@ -235,10 +264,10 @@ async function run(ctx) {
235
264
  force: g.force,
236
265
  jwtSecret,
237
266
  llmApiKey: llmKey,
238
- smtpSkipped,
267
+ smtp,
239
268
  });
240
269
  } catch (err) {
241
- if (err.code === 'ENV_EXISTS') {
270
+ if (err.code === 'ENV_EXISTS' || err.code === 'ENV_INCOMPLETE') {
242
271
  error(err.message);
243
272
  return 1;
244
273
  }
@@ -14,8 +14,7 @@ function help() {
14
14
  return `Usage: ragsuite-test update [options]
15
15
 
16
16
  Verifies the install/repo path and prints safe update steps.
17
- ZIP installs: download a newer ZIP and extract to a new dir (or backup + --force).
18
- Checkout installs: optional git fetch + status (no reset).
17
+ Git installs: git fetch + pull guidance (no destructive reset).
19
18
 
20
19
  Never runs docker compose down -v.
21
20
 
@@ -32,38 +31,26 @@ function run(ctx) {
32
31
  });
33
32
 
34
33
  const cfg = readConfig(repoRoot);
35
- const source = cfg && cfg.source === 'zip' ? 'zip' : 'checkout';
34
+ const source = (cfg && cfg.source) || 'checkout';
36
35
 
37
36
  info(`Install path OK: ${repoRoot}`);
38
37
  info(` source=${source}`);
39
38
  info('');
40
39
 
41
- if (source === 'zip') {
42
- info('This install came from a ZIP. Safe update steps:');
43
- info(' 1. ragsuite-test stop --repo-root ' + repoRoot);
44
- info(' 2. Download a newer release ZIP (do not wipe Docker volumes)');
45
- info(' 3. Extract to a NEW directory, e.g. --install-dir ~/ragsuite-test-v2');
46
- info(' or: backup this dir, then init --from-zip … --force');
47
- info(' 4. Copy your .env into the new install (do not commit secrets)');
48
- info(' 5. ragsuite-test doctor --repo-root <new-dir>');
49
- info(' 6. ragsuite-test start --repo-root <new-dir>');
50
- info('');
51
- info('Never: docker compose down -v (destroys Postgres/Chroma data).');
52
- return 0;
53
- }
54
-
55
- info('Safe update steps (checkout install):');
40
+ info('Safe update steps:');
56
41
  info(' 1. Stop the stack (ragsuite-test stop --repo-root …)');
57
- info(' 2. Update sources (git pull when you have remote access)');
42
+ info(' 2. Update sources (git pull)');
58
43
  info(' 3. Docker: npm run rebuild or docker compose build');
59
44
  info(' 4. Native: re-run backend/scripts/setup.sh if Python deps changed');
60
45
  info(' 5. Start again (ragsuite-test start --repo-root …)');
61
46
  info(' 6. Run doctor after upgrades');
62
47
  info('');
48
+ info('Never: docker compose down -v (destroys Postgres/Chroma data).');
49
+ info('');
63
50
 
64
51
  const gitDir = path.join(repoRoot, '.git');
65
52
  if (!fs.existsSync(gitDir)) {
66
- warn('No .git directory — skip fetch/status (ZIP or packed tree).');
53
+ warn('No .git directory — skip fetch/status. Re-init with --from-git if needed.');
67
54
  return 0;
68
55
  }
69
56
 
package/src/index.js CHANGED
@@ -31,16 +31,20 @@ function globalHelp() {
31
31
  'Global options:',
32
32
  ' --help, -h Show help',
33
33
  ' --repo-root <path> Monorepo / install root',
34
- ' --from-zip <path> init: extract app ZIP',
35
- ' --install-dir <path> init: ZIP target (default ~/ragsuite-test)',
36
- ' --from-release <tag> init: stub (not implemented)',
37
- ' --llm-api-key <key> init: CUSTOM_LLM_INTERNAL_API_KEY (--yes)',
34
+ ' --from-git [url] init: clone public monorepo',
35
+ ' --install-dir <path> init: target for --from-git (default ~/ragsuite-test)',
36
+ ' --llm-api-key <key> init: optional override for CUSTOM_LLM_INTERNAL_API_KEY',
37
+ ' --smtp-host <host> init: optional SMTP override',
38
+ ' --smtp-user <user> init: optional SMTP override',
39
+ ' --smtp-password <pass> init: optional SMTP override',
40
+ ' --email-from <email> init: optional SMTP override',
38
41
  ' --force init: overwrite non-empty install dir / .env',
39
42
  ' --yes, -y Non-interactive',
40
- ' --mode <docker|native> Override .ragsuite-test/config.json / RAGSUITE_MODE',
43
+ ' --mode <docker|native> Override config (Docker optional)',
41
44
  ' --dry-run Print actions without running (start/stop/doctor/logs)',
42
45
  '',
43
46
  'Env: RAGSUITE_REPO_ROOT or RAGSUITE_INSTALL_DIR',
47
+ ' RAGSUITE_TEST_LLM_API_KEY, RAGSUITE_TEST_SMTP_* , RAGSUITE_TEST_EMAIL_FROM',
44
48
  '',
45
49
  'Run ragsuite-test <command> --help for command details.',
46
50
  );
@@ -88,7 +92,7 @@ async function main(argv = process.argv) {
88
92
  const code = typeof result?.then === 'function' ? await result : result;
89
93
  return typeof code === 'number' ? code : 0;
90
94
  } catch (err) {
91
- if (err && (err.code === 'NOT_REPO_ROOT' || err.code === 'USAGE' || err.code === 'ZIP_SLIP' || err.code === 'INSTALL_DIR_NONEMPTY' || err.code === 'ZIP_INVALID' || err.code === 'ZIP_MISSING' || err.code === 'ENV_EXISTS' || err.code === 'PORT_IN_USE' || err.code === 'LLM_KEY_INVALID')) {
95
+ if (err && (err.code === 'NOT_REPO_ROOT' || err.code === 'USAGE' || err.code === 'INSTALL_DIR_NONEMPTY' || err.code === 'ENV_EXISTS' || err.code === 'ENV_INCOMPLETE' || err.code === 'PORT_IN_USE' || err.code === 'LLM_KEY_INVALID' || err.code === 'SMTP_REQUIRED' || err.code === 'GIT_CLONE_FAILED' || err.code === 'MISSING_GIT')) {
92
96
  error(err.message);
93
97
  return 1;
94
98
  }