@nitsan-ai/ragsuite-test 0.1.1 → 0.1.3

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
@@ -1,102 +1,100 @@
1
1
  # RAGSuite test CLI (`ragsuite-test`)
2
2
 
3
- > **TESTING PACKAGE** — `@nitsan-ai/ragsuite-test` / `ragsuite-test` is temporary.
4
- > **Not** the final production `@nitsan-ai/ragsuite` / `ragsuite` CLI (later release).
3
+ > **TESTING PACKAGE** — temporary name before the final `ragsuite` CLI.
5
4
 
6
- Wraps monorepo Docker/native scripts. Does **not** reimplement compose.
5
+ Two ways to run. Pick one:
7
6
 
8
- Requires **Node.js 18+**. **Docker is optional.** Public deploy path: **`npm` → `init --from-git`**.
7
+ | | **A) Git source** | **B) Docker images only** |
8
+ |--|-------------------|---------------------------|
9
+ | Command | `ragsuite-test init` | `ragsuite-test init --from-images` |
10
+ | On disk | Full monorepo clone | Tiny compose bundle only |
11
+ | App code visible? | Yes | **No** (runs in containers) |
12
+ | Needs | git + Node; Docker *or* native Postgres/Redis | Node + **Docker** |
13
+ | Best for | Dev, debugging, native mode, reading code | Testers / “just run the app” |
14
+ | Pros | Native mode; full scripts; offline rebuild from source | No source leak; faster to start; smaller disk |
15
+ | Cons | Source on disk; larger checkout | Needs published GHCR images; Docker required; no native mode |
9
16
 
10
- ## Prerequisites
17
+ ---
11
18
 
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 |
19
+ ## A) Git source (clone)
19
20
 
20
- ### Mode A — Docker (optional)
21
+ ```bash
22
+ npm install -g @nitsan-ai/ragsuite-test
23
+ ragsuite-test init
24
+ # clones https://github.com/nitsan-ai/RAGSUITE.git → ~/ragsuite-test
25
+ # auto: docker if daemon up, else native
21
26
 
22
- - Docker Desktop / daemon + `docker compose`
23
- - https://www.docker.com/products/docker-desktop/
27
+ ragsuite-test start --repo-root ~/ragsuite-test --detach # docker
28
+ # or after init --mode native:
29
+ # ragsuite-test start --repo-root ~/ragsuite-test
24
30
 
25
- ### Mode B — Native (no Docker)
31
+ # API http://localhost:9090
32
+ # Web http://localhost:9091 (docker) or :9191 (native)
33
+ ragsuite-test stop --repo-root ~/ragsuite-test
34
+ ```
26
35
 
27
- - `python3`, `yarn` (or corepack)
28
- - Postgres on **localhost:5436**, database `ragsuite_v3`
29
- - Redis on **localhost:6382**
36
+ ### Native (no Docker) — git install only
30
37
 
31
- ## Install (public)
38
+ Needs Postgres `:5436` (`ragsuite_v3`) and Redis `:6382`:
32
39
 
33
40
  ```bash
34
- npm install -g @nitsan-ai/ragsuite-test
41
+ ragsuite-test init --mode native
42
+ ragsuite-test start --repo-root ~/ragsuite-test
43
+ ```
35
44
 
36
- ragsuite-test init --yes \
37
- --from-git \
38
- --install-dir ~/ragsuite-test \
39
- --mode docker
45
+ ---
40
46
 
41
- ragsuite-test start --repo-root ~/ragsuite-test --detach
42
- # API http://localhost:9090 · Web http://localhost:9091
43
- ```
47
+ ## B) Docker images (no source on disk)
44
48
 
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.
49
+ **Maintainer (once):** publish imagesActions **Publish images (GHCR)**
50
+ (packages: `ghcr.io/nitsan-ai/ragsuite-backend`, `…/ragsuite-frontend`)
46
51
 
47
- No Docker:
52
+ **User:**
48
53
 
49
54
  ```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
55
+ npm install -g @nitsan-ai/ragsuite-test
56
+ ragsuite-test init --from-images
57
+ ragsuite-test start --repo-root ~/ragsuite-test --detach
58
+ # pulls images — does NOT clone app source
59
+ ragsuite-test stop --repo-root ~/ragsuite-test
53
60
  ```
54
61
 
55
- Existing checkout:
62
+ Optional pin:
56
63
 
57
64
  ```bash
58
- ragsuite-test init --yes --repo-root /path/to/RAGSUITE --mode native
65
+ # in ~/ragsuite-test/.env
66
+ IMAGE_TAG=1.0.0
67
+ IMAGE_REGISTRY=ghcr.io/nitsan-ai
59
68
  ```
60
69
 
61
- Interactive: `ragsuite-test init`
70
+ If images are private on GHCR, make packages public or `docker login ghcr.io`.
71
+
72
+ ---
73
+
74
+ ## Prerequisites
75
+
76
+ | Need | Git install | Images install |
77
+ |------|-------------|----------------|
78
+ | Node 18+ | Yes | Yes |
79
+ | git | Yes | No |
80
+ | Docker | Optional | **Required** |
81
+ | Postgres/Redis on host | Only for `--mode native` | No (in compose) |
82
+
83
+ SMTP/LLM: no init prompts. Real SMTP only in local `.env` (gitignored).
62
84
 
63
85
  ## Ports
64
86
 
65
87
  | Service | Port |
66
88
  |---------|------|
67
89
  | API | 9090 |
68
- | Web (Docker) | 9091 |
90
+ | Web (Docker/images) | 9091 |
69
91
  | Web (native Expo) | 9191 |
70
92
  | Postgres | 5436 |
71
93
  | Redis | 6382 |
72
94
 
73
- ```bash
74
- ragsuite-test stop --repo-root ~/ragsuite-test
75
- lsof -nP -iTCP:9090 -sTCP:LISTEN
76
- docker ps
77
- ```
78
-
79
- ## Commands
80
-
81
- | Command | Behavior |
82
- |---------|----------|
83
- | `init` | git clone or checkout → `.env` + config |
84
- | `start` / `stop` | `scripts/docker-*.sh` or `native-*.sh` |
85
- | `doctor` | prereqs + `scripts/doctor.sh` |
86
- | `logs` / `update` / `version` | As before |
87
-
88
- ## Publish
89
-
90
- See [PUBLISH.md](./PUBLISH.md) and [TEST_DISTRIBUTION.md](./TEST_DISTRIBUTION.md).
91
-
92
- ```bash
93
- cd cli && npm run prepublish:check
94
- RAGSUITE_TEST_ALLOW_PUBLISH=1 npm publish --access public # only when approved
95
- ```
96
-
97
- ## Windows
95
+ ## Publish CLI
98
96
 
99
- Use WSL or Git Bash.
97
+ See [PUBLISH.md](./PUBLISH.md). Version bump then Actions → **CLI publish**.
100
98
 
101
99
  ## Tests
102
100
 
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "@nitsan-ai/ragsuite-test",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "private": false,
5
- "description": "RAGSuite testing CLI (ragsuite-test) install from ZIP or --repo-root checkout. Temporary npm identity before public ragsuite release.",
5
+ "description": "RAGSuite testing CLI — init (git source) or init --from-images (pull-only, no source).",
6
6
  "main": "src/index.js",
7
7
  "bin": {
8
8
  "ragsuite-test": "./bin/ragsuite-test.js"
@@ -10,6 +10,7 @@
10
10
  "files": [
11
11
  "bin/",
12
12
  "src/",
13
+ "templates/",
13
14
  "package.json",
14
15
  "README.md",
15
16
  "LICENSE"
@@ -2,22 +2,22 @@
2
2
 
3
3
  const path = require('path');
4
4
  const { resolveMode } = require('../utils/config');
5
- const { resolveRepoRoot } = require('../utils/paths');
5
+ const { resolveRepoRoot, isImagesInstall } = require('../utils/paths');
6
6
  const { runScript } = require('../utils/spawn');
7
7
 
8
8
  const name = 'doctor';
9
- const summary = 'Run scripts/doctor.sh prerequisite checks';
9
+ const summary = 'Run doctor checks (git or images install)';
10
10
 
11
11
  function help() {
12
12
  return `Usage: ragsuite-test doctor [options]
13
13
 
14
- Runs scripts/doctor.sh. Mode selects which checklist gates the exit code
15
- (RAGSUITE_MODE / config / --mode). Both mode sections are still printed.
14
+ Git install: scripts/doctor.sh
15
+ Images install: scripts/docker-doctor-images.sh
16
16
 
17
17
  Options:
18
- --mode <docker|native> Gate exit on this mode (default: docker)
19
- --repo-root <path> Monorepo root
20
- --dry-run Print the script path and exit 0
18
+ --mode <docker|native> Git install gate
19
+ --repo-root <path>
20
+ --dry-run
21
21
  `;
22
22
  }
23
23
 
@@ -26,12 +26,16 @@ function run(ctx) {
26
26
  cwd: ctx.cwd,
27
27
  repoRootFlag: ctx.globals.repoRoot,
28
28
  });
29
- const mode = resolveMode({
30
- flagMode: ctx.globals.mode,
31
- repoRoot,
32
- env: ctx.env,
33
- });
34
- return runScript(repoRoot, path.join('scripts', 'doctor.sh'), [], {
29
+ const images = isImagesInstall(repoRoot);
30
+ const mode = images
31
+ ? 'docker'
32
+ : resolveMode({
33
+ flagMode: ctx.globals.mode,
34
+ repoRoot,
35
+ env: ctx.env,
36
+ });
37
+ const script = images ? 'docker-doctor-images.sh' : 'doctor.sh';
38
+ return runScript(repoRoot, path.join('scripts', script), [], {
35
39
  dryRun: ctx.globals.dryRun,
36
40
  env: { ...ctx.env, RAGSUITE_MODE: mode },
37
41
  });
@@ -2,56 +2,55 @@
2
2
 
3
3
  const path = require('path');
4
4
  const { writeConfig, CONFIG_DIR } = require('../utils/config');
5
- const { ensureRagsuiteDir, resolveRepoRoot, looksLikeRepoRoot } = require('../utils/paths');
5
+ const {
6
+ ensureRagsuiteDir,
7
+ resolveRepoRoot,
8
+ isImagesInstall,
9
+ } = require('../utils/paths');
6
10
  const { assertSupportedInstall, installHint } = require('../utils/distribution');
7
11
  const {
8
12
  DEFAULT_GIT_URL,
9
13
  defaultInstallDir,
10
14
  cloneGitToInstallDir,
11
15
  } = require('../utils/git-install');
16
+ const { materializeImagesInstall } = require('../utils/images-install');
12
17
  const { detectOs } = require('../utils/os-detect');
13
18
  const {
14
19
  printPrereqs,
15
20
  resolvePreferredMode,
16
- dockerDaemonRunning,
17
- commandExists,
18
21
  } = require('../utils/prereqs');
19
- const { ask, choose } = require('../utils/prompt');
20
22
  const {
21
23
  generateJwtSecret,
22
24
  isPlaceholderSecret,
23
25
  writeInstallEnv,
24
26
  } = require('../utils/env-file');
25
27
  const { assertPortsFree } = require('../utils/port');
26
- const { info, warn, error } = require('../utils/log');
28
+ const { info, error } = require('../utils/log');
27
29
 
28
30
  const name = 'init';
29
- const summary = 'Installer wizard: git clone or checkout .env + config';
31
+ const summary = 'Install: git clone (source) or pull-only Docker images';
30
32
 
31
- function printSuccess(repoRoot, mode) {
33
+ function printSuccess(repoRoot, mode, source) {
32
34
  info('');
33
35
  info('=== Install complete ===');
34
36
  info(` Install dir : ${repoRoot}`);
37
+ info(` Source : ${source}`);
35
38
  info(` Mode : ${mode}`);
36
39
  info(` Config : ${path.join(repoRoot, CONFIG_DIR, 'config.json')}`);
37
40
  info('');
38
41
  info(' API http://localhost:9090');
39
- if (mode === 'native') {
42
+ if (source === 'images') {
43
+ info(' Web http://localhost:9091 (images / Docker nginx)');
44
+ } else if (mode === 'native') {
40
45
  info(' Web http://localhost:9191 (Expo web — native mode)');
41
46
  } else {
42
47
  info(' Web http://localhost:9091 (Docker nginx)');
43
48
  }
44
49
  info('');
45
- info(' Docker is optional: native mode needs host Postgres :5436 + Redis :6382.');
46
- info(' Each install directory is one deployment / one organization.');
47
- info('');
48
50
  info('Next steps:');
49
- info(` 1. ragsuite-test start --repo-root ${repoRoot}${mode === 'docker' ? ' --detach' : ''}`);
50
- if (mode === 'native') {
51
- info(' 2. Open http://localhost:9191 and bootstrap the first admin');
52
- } else {
53
- info(' 2. Open http://localhost:9091 and bootstrap the first admin');
54
- }
51
+ const detach = mode === 'docker' || source === 'images' ? ' --detach' : '';
52
+ info(` 1. ragsuite-test start --repo-root ${repoRoot}${detach}`);
53
+ info(' 2. Open the Web URL above and bootstrap the first admin');
55
54
  info(` 3. ragsuite-test doctor --repo-root ${repoRoot}`);
56
55
  info('');
57
56
  info(installHint());
@@ -60,29 +59,27 @@ function printSuccess(repoRoot, mode) {
60
59
  function help() {
61
60
  return `Usage: ragsuite-test init [options]
62
61
 
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
62
+ Two install styles:
73
63
 
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)
64
+ A) Source on disk (git) default
65
+ ragsuite-test init
66
+ Clones ${DEFAULT_GIT_URL} ~/ragsuite-test
67
+ Supports --mode docker|native
77
68
 
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
69
+ B) No source (Docker images only)
70
+ ragsuite-test init --from-images
71
+ Copies a tiny compose bundle ~/ragsuite-test
72
+ Pulls ghcr.io/nitsan-ai/ragsuite-backend|frontend (no git clone of app code)
81
73
 
82
74
  Options:
83
- --install-dir <path> Target for --from-git (default: ~/ragsuite-test)
75
+ --from-images Pull-only images install (no monorepo source)
76
+ --from-git [url] Clone this URL (default public repo)
77
+ --repo-root <path> Configure an existing git checkout
78
+ --install-dir <path> Target dir (default: ~/ragsuite-test)
79
+ --mode <docker|native> Git install only (images install is always docker)
84
80
  --force Overwrite non-empty install dir / existing .env
85
- --yes, -y Non-interactive (requires --from-git or --repo-root)
81
+ --yes, -y Non-interactive
82
+ --llm-api-key / --smtp-* Optional overrides
86
83
  `;
87
84
  }
88
85
 
@@ -100,12 +97,13 @@ function resolveLlmOverride(g, env) {
100
97
  if (env.RAGSUITE_TEST_LLM_API_KEY && !isPlaceholderSecret(env.RAGSUITE_TEST_LLM_API_KEY)) {
101
98
  return env.RAGSUITE_TEST_LLM_API_KEY;
102
99
  }
103
- return null; // keep .env.example default
100
+ return null;
104
101
  }
105
102
 
106
- function countSources(fromGit, repoRootFlag) {
103
+ function countSources(fromGit, fromImages, repoRootFlag) {
107
104
  let n = 0;
108
105
  if (fromGit !== null && fromGit !== undefined) n += 1;
106
+ if (fromImages) n += 1;
109
107
  if (repoRootFlag) n += 1;
110
108
  return n;
111
109
  }
@@ -113,15 +111,14 @@ function countSources(fromGit, repoRootFlag) {
113
111
  async function run(ctx) {
114
112
  assertSupportedInstall();
115
113
  const g = ctx.globals;
116
- const interactive = Boolean(process.stdin.isTTY) && !g.yes;
117
114
 
118
115
  if (g.fromRelease) {
119
- error('--from-release is not supported. Use --from-git or --repo-root.');
116
+ error('--from-release is not supported. Use init, --from-images, --from-git, or --repo-root.');
120
117
  return 1;
121
118
  }
122
119
 
123
- if (countSources(g.fromGit, g.repoRoot) > 1) {
124
- error('Use only one of --from-git or --repo-root');
120
+ if (countSources(g.fromGit, g.fromImages, g.repoRoot) > 1) {
121
+ error('Use only one of --from-images, --from-git, or --repo-root');
125
122
  return 1;
126
123
  }
127
124
 
@@ -129,81 +126,30 @@ async function run(ctx) {
129
126
  info(`OS: ${osInfo.label} (${osInfo.platform})`);
130
127
 
131
128
  let fromGit = g.fromGit;
129
+ let fromImages = Boolean(g.fromImages);
132
130
  let repoRootFlag = g.repoRoot;
133
- let installDir = g.installDir || defaultInstallDir();
134
- let mode = g.mode || null;
131
+ const installDir = g.installDir || defaultInstallDir();
135
132
 
136
- if (g.yes) {
137
- if (fromGit === null && !repoRootFlag) {
138
- error('--yes requires --from-git [url] or --repo-root <path>');
139
- return 1;
140
- }
141
- } else if (interactive && fromGit === null && !repoRootFlag) {
142
- const method = await choose(
143
- 'Install method:',
144
- [
145
- {
146
- id: 'git',
147
- label: 'Public git clone (--from-git) — recommended',
148
- },
149
- {
150
- id: 'checkout',
151
- label: 'Existing checkout (--repo-root)',
152
- },
153
- ],
154
- { defaultIndex: 0 },
155
- );
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;
162
- installDir = await ask('Install directory', {
163
- defaultValue: defaultInstallDir(),
164
- yesMode: false,
165
- });
166
- } else {
167
- repoRootFlag = await ask('Path to existing RAGSUITE checkout', { yesMode: false });
168
- if (!repoRootFlag || !looksLikeRepoRoot(path.resolve(repoRootFlag))) {
169
- error('Not a valid checkout (need scripts/docker-start.sh)');
170
- return 1;
171
- }
172
- }
133
+ if (!fromImages && fromGit === null && !repoRootFlag) {
134
+ fromGit = '';
135
+ info(`Install style: git clone (source on disk)`);
136
+ info(` ${DEFAULT_GIT_URL} → ${path.resolve(installDir)}`);
137
+ }
173
138
 
174
- const dockerOk = commandExists('docker') && dockerDaemonRunning();
175
- const modeChoice = await choose(
176
- 'Run mode (Docker is optional — native works without Docker):',
177
- [
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
- },
188
- ],
189
- { defaultIndex: 0 },
190
- );
191
- mode = modeChoice.id;
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');
198
- return 1;
139
+ if (fromImages) {
140
+ info('Install style: Docker images only (no app source on disk)');
141
+ info(` Target: ${path.resolve(installDir)}`);
199
142
  }
200
143
 
201
- if (!mode) {
202
- mode = resolvePreferredMode(g.mode);
203
- info(`Run mode: ${mode} (Docker is optional; pass --mode docker|native to force)`);
144
+ let mode;
145
+ if (fromImages) {
146
+ mode = 'docker';
147
+ } else {
148
+ mode = g.mode || resolvePreferredMode(null);
204
149
  }
150
+ info(`Run mode: ${mode}`);
205
151
 
206
- const needGit = fromGit !== null && fromGit !== undefined;
152
+ const needGit = !fromImages && fromGit !== null && fromGit !== undefined;
207
153
  if (!printPrereqs(mode, { needGit })) {
208
154
  error('Fix prerequisites above and re-run init');
209
155
  return 1;
@@ -211,7 +157,7 @@ async function run(ctx) {
211
157
 
212
158
  const jwtSecret = generateJwtSecret();
213
159
  info(`JWT_SECRET_KEY will be auto-generated (…${jwtSecret.slice(-8)})`);
214
- info('SMTP + LLM: using defaults from .env.example (optional flags can override).');
160
+ info('SMTP + LLM: from .env.example into .env (no prompts).');
215
161
 
216
162
  const llmKey = resolveLlmOverride(g, ctx.env);
217
163
  const smtp = optionalSmtpOverrides(g, ctx.env);
@@ -229,7 +175,15 @@ async function run(ctx) {
229
175
  let source = 'checkout';
230
176
 
231
177
  try {
232
- if (fromGit !== null && fromGit !== undefined) {
178
+ if (fromImages) {
179
+ const result = materializeImagesInstall({
180
+ installDir,
181
+ force: g.force,
182
+ });
183
+ repoRoot = result.repoRoot;
184
+ source = 'images';
185
+ info(`Images bundle installed at ${repoRoot}`);
186
+ } else if (fromGit !== null && fromGit !== undefined) {
233
187
  const url = fromGit === '' ? DEFAULT_GIT_URL : fromGit;
234
188
  info(`Cloning ${url} → ${path.resolve(installDir)}`);
235
189
  const result = cloneGitToInstallDir(url, {
@@ -245,6 +199,7 @@ async function run(ctx) {
245
199
  repoRootFlag,
246
200
  env: ctx.env,
247
201
  });
202
+ if (isImagesInstall(repoRoot)) source = 'images';
248
203
  }
249
204
  } catch (err) {
250
205
  error(err.message || String(err));
@@ -277,7 +232,7 @@ async function run(ctx) {
277
232
 
278
233
  info(`Wrote ${path.join(repoRoot, CONFIG_DIR, 'config.json')}`);
279
234
  info(` mode=${cfg.mode} source=${cfg.source}`);
280
- printSuccess(repoRoot, mode);
235
+ printSuccess(repoRoot, mode, source);
281
236
  return 0;
282
237
  }
283
238
 
@@ -2,25 +2,25 @@
2
2
 
3
3
  const path = require('path');
4
4
  const { resolveMode } = require('../utils/config');
5
- const { resolveRepoRoot } = require('../utils/paths');
5
+ const { resolveRepoRoot, isImagesInstall } = require('../utils/paths');
6
6
  const { runScript } = require('../utils/spawn');
7
7
  const { assertApiPortFree } = require('../utils/port');
8
8
  const { error } = require('../utils/log');
9
9
 
10
10
  const name = 'start';
11
- const summary = 'Start stack via docker-start.sh or native-start.sh';
11
+ const summary = 'Start stack (git scripts or images pull-only)';
12
12
 
13
13
  function help() {
14
- return `Usage: ragsuite-test start [options] [-- script-args...]
14
+ return `Usage: ragsuite-test start [options]
15
15
 
16
- Calls scripts/docker-start.sh (mode=docker) or scripts/native-start.sh (mode=native).
17
- Does not reimplement compose logic. Extra args after -- are forwarded (e.g. --detach).
16
+ Git install: scripts/docker-start.sh or native-start.sh
17
+ Images install (--from-images): scripts/docker-start-images.sh (pull, no build)
18
18
 
19
19
  Options:
20
- --mode <docker|native> Override config / RAGSUITE_MODE
21
- --repo-root <path> Monorepo root
22
- --dry-run Print the script path and exit 0
23
- --detach, -d Forwarded to docker-start.sh (also accepted without --)
20
+ --mode <docker|native> Override (git install; images always docker)
21
+ --repo-root <path> Install root
22
+ --dry-run Print script path and exit 0
23
+ --detach, -d Detached start
24
24
  `;
25
25
  }
26
26
 
@@ -29,14 +29,22 @@ async function run(ctx) {
29
29
  cwd: ctx.cwd,
30
30
  repoRootFlag: ctx.globals.repoRoot,
31
31
  });
32
- const mode = resolveMode({
33
- flagMode: ctx.globals.mode,
34
- repoRoot,
35
- env: ctx.env,
36
- });
32
+ const images = isImagesInstall(repoRoot);
33
+ const mode = images
34
+ ? 'docker'
35
+ : resolveMode({
36
+ flagMode: ctx.globals.mode,
37
+ repoRoot,
38
+ env: ctx.env,
39
+ });
40
+
41
+ let scriptName;
42
+ if (images) {
43
+ scriptName = 'docker-start-images.sh';
44
+ } else {
45
+ scriptName = mode === 'native' ? 'native-start.sh' : 'docker-start.sh';
46
+ }
37
47
 
38
- const scriptName = mode === 'native' ? 'native-start.sh' : 'docker-start.sh';
39
- const rel = path.join('scripts', scriptName);
40
48
  const forward = normalizeStartArgs(ctx.commandArgs);
41
49
 
42
50
  if (!ctx.globals.dryRun) {
@@ -48,7 +56,7 @@ async function run(ctx) {
48
56
  }
49
57
  }
50
58
 
51
- return runScript(repoRoot, rel, forward, {
59
+ return runScript(repoRoot, path.join('scripts', scriptName), forward, {
52
60
  dryRun: ctx.globals.dryRun,
53
61
  env: { ...ctx.env, RAGSUITE_MODE: mode },
54
62
  });
@@ -2,22 +2,23 @@
2
2
 
3
3
  const path = require('path');
4
4
  const { resolveMode } = require('../utils/config');
5
- const { resolveRepoRoot } = require('../utils/paths');
5
+ const { resolveRepoRoot, isImagesInstall } = require('../utils/paths');
6
6
  const { runScript } = require('../utils/spawn');
7
7
 
8
8
  const name = 'stop';
9
- const summary = 'Stop stack via docker-stop.sh or native-stop.sh';
9
+ const summary = 'Stop stack (git scripts or images pull-only)';
10
10
 
11
11
  function help() {
12
12
  return `Usage: ragsuite-test stop [options]
13
13
 
14
- Calls scripts/docker-stop.sh or scripts/native-stop.sh based on mode.
15
- Never wipes Docker volumes (same as docker-stop.sh).
14
+ Git install: docker-stop.sh / native-stop.sh
15
+ Images install: docker-stop-images.sh
16
+ Never wipes Docker volumes.
16
17
 
17
18
  Options:
18
- --mode <docker|native> Override config / RAGSUITE_MODE
19
- --repo-root <path> Monorepo root
20
- --dry-run Print the script path and exit 0
19
+ --mode <docker|native> Override (git install)
20
+ --repo-root <path> Install root
21
+ --dry-run Print script path and exit 0
21
22
  `;
22
23
  }
23
24
 
@@ -26,12 +27,21 @@ function run(ctx) {
26
27
  cwd: ctx.cwd,
27
28
  repoRootFlag: ctx.globals.repoRoot,
28
29
  });
29
- const mode = resolveMode({
30
- flagMode: ctx.globals.mode,
31
- repoRoot,
32
- env: ctx.env,
33
- });
34
- const scriptName = mode === 'native' ? 'native-stop.sh' : 'docker-stop.sh';
30
+ const images = isImagesInstall(repoRoot);
31
+ const mode = images
32
+ ? 'docker'
33
+ : resolveMode({
34
+ flagMode: ctx.globals.mode,
35
+ repoRoot,
36
+ env: ctx.env,
37
+ });
38
+
39
+ const scriptName = images
40
+ ? 'docker-stop-images.sh'
41
+ : mode === 'native'
42
+ ? 'native-stop.sh'
43
+ : 'docker-stop.sh';
44
+
35
45
  return runScript(repoRoot, path.join('scripts', scriptName), [], {
36
46
  dryRun: ctx.globals.dryRun,
37
47
  env: { ...ctx.env, RAGSUITE_MODE: mode },