datagrok-tools 6.0.1 → 6.0.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/.claude/settings.local.json +22 -0
- package/.devcontainer/.gitattributes +1 -0
- package/.devcontainer/entrypoint.sh +38 -40
- package/CLAUDE.md +90 -1
- package/bin/commands/claude.js +34 -52
- package/package.json +1 -1
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"permissions": {
|
|
3
|
+
"allow": [
|
|
4
|
+
"Bash(find /c/repos/Datagrok -type f \\\\\\( -name \"Dockerfile*\" -o -name \"docker-compose*\" \\\\\\) 2>/dev/null | grep -v node_modules | head -20)",
|
|
5
|
+
"Bash(npm run:*)",
|
|
6
|
+
"Bash(docker build:*)",
|
|
7
|
+
"Bash(cd C:/repos/awesome && node C:/repos/Datagrok/public/tools/bin/grok.js claude destroy GROK-PLAYGROUND 2>&1)",
|
|
8
|
+
"Bash(cd C:/repos/awesome && node C:/repos/Datagrok/public/tools/bin/grok.js claude GROK-PLAYGROUND --in-place --keep --prompt \"echo hello and exit\" 2>&1)",
|
|
9
|
+
"Bash(cd C:/repos/awesome && node C:/repos/Datagrok/public/tools/bin/grok.js claude GROK-PLAYGROUND --in-place --keep --prompt \"echo done\" 2>&1)",
|
|
10
|
+
"Bash(git -C C:/repos/awesome rev-parse --show-toplevel 2>&1)",
|
|
11
|
+
"Bash(cd C:/repos/awesome && node C:/repos/Datagrok/public/tools/bin/grok.js claude GROK-PLAYGROUND 2>&1)",
|
|
12
|
+
"Bash(cd C:/repos/awesome && node C:/repos/Datagrok/public/tools/bin/grok.js claude GROK-PLAYGROUND --keep 2>&1)",
|
|
13
|
+
"Bash(MSYS_NO_PATHCONV=1 docker exec dg-pkg-grok-playground-tools-dev-1 ls /workspace/datagrok/ 2>&1)",
|
|
14
|
+
"Bash(MSYS_NO_PATHCONV=1 docker exec dg-pkg-grok-playground-tools-dev-1 ls -la /workspace/datagrok/packages/awesome 2>&1)",
|
|
15
|
+
"Bash(MSYS_NO_PATHCONV=1 docker exec dg-pkg-grok-playground-tools-dev-1 ls /workspace/datagrok/packages/awesome/ 2>&1)",
|
|
16
|
+
"Bash(MSYS_NO_PATHCONV=1 docker exec dg-pkg-grok-playground-tools-dev-1 bash -c 'echo \"=== Symlink ===\" && ls -la /workspace/datagrok/packages/awesome && echo \"=== Package contents ===\" && ls /workspace/datagrok/packages/awesome/ && echo \"=== Public repo root ===\" && ls /workspace/datagrok/js-api /workspace/datagrok/packages /workspace/datagrok/CLAUDE.md 2>&1 | head -5' 2>&1)",
|
|
17
|
+
"Bash(grep -r \"tools-dev\" /c/repos/Datagrok --include=\"*\" 2>/dev/null | head -20)",
|
|
18
|
+
"Bash(find /c/repos/Datagrok/public/tools/.devcontainer -type f -name \".*\" 2>/dev/null | sort)",
|
|
19
|
+
"Bash(grep -r \"tools-dev\" /c/repos/Datagrok/public/tools/bin --include=\"*.ts\" 2>/dev/null | head -20)"
|
|
20
|
+
]
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
*.sh text eol=lf
|
|
@@ -1,39 +1,23 @@
|
|
|
1
1
|
#!/bin/bash
|
|
2
2
|
set -e
|
|
3
3
|
|
|
4
|
-
#
|
|
5
|
-
|
|
4
|
+
# Map DG_VERSION to a git branch name for cloning the public repo.
|
|
5
|
+
# Docker tags like "latest" or "bleeding-edge" aren't git branches — use master.
|
|
6
|
+
# Explicit version numbers (e.g. "0.151.9") are tried as-is with a master fallback.
|
|
7
|
+
resolve_branch() {
|
|
6
8
|
local ver="${1:-latest}"
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
| node -e "
|
|
12
|
-
const data = JSON.parse(require('fs').readFileSync('/dev/stdin','utf8'));
|
|
13
|
-
const tags = (data.results||[]).map(t=>t.name).filter(n=>/^\d+\.\d+\.\d+$/.test(n));
|
|
14
|
-
tags.sort((a,b)=>{
|
|
15
|
-
const pa=a.split('.').map(Number), pb=b.split('.').map(Number);
|
|
16
|
-
return pb[0]-pa[0]||pb[1]-pa[1]||pb[2]-pa[2];
|
|
17
|
-
});
|
|
18
|
-
if(tags[0]) process.stdout.write(tags[0]);
|
|
19
|
-
" 2>/dev/null) || true
|
|
20
|
-
if [ -n "$resolved" ]; then
|
|
21
|
-
echo "[tools-dev] Resolved latest version: $resolved" >&2
|
|
22
|
-
echo "$resolved"
|
|
23
|
-
else
|
|
24
|
-
echo "[tools-dev] Could not resolve latest version, falling back to master" >&2
|
|
25
|
-
echo "master"
|
|
26
|
-
fi
|
|
27
|
-
else
|
|
28
|
-
echo "$ver"
|
|
29
|
-
fi
|
|
9
|
+
case "$ver" in
|
|
10
|
+
latest|bleeding-edge) echo "master" ;;
|
|
11
|
+
*) echo "$ver" ;;
|
|
12
|
+
esac
|
|
30
13
|
}
|
|
31
14
|
|
|
32
|
-
PUBLIC_DIR="
|
|
33
|
-
# Detect if /workspace/repo IS the public repo
|
|
34
|
-
|
|
15
|
+
PUBLIC_DIR="${DG_PUBLIC_DIR:-/workspace/datagrok}"
|
|
16
|
+
# Detect if /workspace/repo IS the public repo.
|
|
17
|
+
# Require .git to avoid false positives from packages that have public/js-api via npm link.
|
|
18
|
+
if [ -e "/workspace/repo/.git" ] && [ -d "/workspace/repo/js-api" ]; then
|
|
35
19
|
echo "[tools-dev] Public repo detected at /workspace/repo — skipping clone."
|
|
36
|
-
elif [ -d "/workspace/repo/public/js-api" ]; then
|
|
20
|
+
elif [ -e "/workspace/repo/.git" ] && [ -d "/workspace/repo/public/js-api" ]; then
|
|
37
21
|
echo "[tools-dev] Monorepo detected — public repo at /workspace/repo/public."
|
|
38
22
|
elif [ -d "$PUBLIC_DIR/js-api" ]; then
|
|
39
23
|
echo "[tools-dev] Public repo already at $PUBLIC_DIR."
|
|
@@ -43,31 +27,45 @@ else
|
|
|
43
27
|
if [ -n "$DG_PUBLIC_BRANCH" ]; then
|
|
44
28
|
BRANCH="$DG_PUBLIC_BRANCH"
|
|
45
29
|
else
|
|
46
|
-
BRANCH=$(
|
|
30
|
+
BRANCH=$(resolve_branch "${DG_VERSION:-latest}")
|
|
47
31
|
fi
|
|
48
|
-
|
|
49
|
-
|
|
32
|
+
# Sparse checkout: only fetch dirs needed for package context (js-api, libraries, help, packages)
|
|
33
|
+
# plus root files (CLAUDE.md, .claude/, etc.). Much faster than a full clone.
|
|
34
|
+
sparse_clone() {
|
|
35
|
+
local branch="$1"
|
|
36
|
+
git clone --depth 1 --branch "$branch" --filter=blob:none --no-checkout "$REPO" "$PUBLIC_DIR" \
|
|
37
|
+
&& git -C "$PUBLIC_DIR" sparse-checkout set --no-cone \
|
|
38
|
+
'/*' '!connectors/' '!docker/' '!docusaurus/' '!docusaurus-static/' \
|
|
39
|
+
'!environments/' '!hooks/' '!misc/' 'python-api/' '!datagrok-celery-task/' \
|
|
40
|
+
'/js-api/**' '/libraries/**' '/help/**' '/packages/**' '!help/uploads/**' \
|
|
41
|
+
&& git -C "$PUBLIC_DIR" checkout
|
|
42
|
+
}
|
|
43
|
+
echo "[tools-dev] Cloning public repo ($BRANCH, sparse) into $PUBLIC_DIR..."
|
|
44
|
+
sparse_clone "$BRANCH" \
|
|
50
45
|
|| { echo "[tools-dev] Branch '$BRANCH' not found, falling back to master."
|
|
51
|
-
|
|
46
|
+
rm -rf "$PUBLIC_DIR"
|
|
47
|
+
sparse_clone "master"; }
|
|
52
48
|
echo "[tools-dev] Public repo ready at $PUBLIC_DIR (branch: $(git -C "$PUBLIC_DIR" branch --show-current))."
|
|
53
49
|
fi
|
|
54
50
|
|
|
55
51
|
# ── Mount workspace inside public repo for non-public workspaces ──
|
|
56
52
|
# When TASK_KEY is set and workspace is not the public repo, link it into packages/
|
|
57
53
|
# so Claude Code walks up to find all public repo context (CLAUDE.md, .claude/, js-api/, etc.)
|
|
58
|
-
if [ -d "/workspace/repo/js-api" ]; then
|
|
54
|
+
if [ -e "/workspace/repo/.git" ] && [ -d "/workspace/repo/js-api" ]; then
|
|
59
55
|
echo "[tools-dev] Public repo IS the workspace — no linking needed."
|
|
60
|
-
elif [ -d "/workspace/repo/public/js-api" ]; then
|
|
56
|
+
elif [ -e "/workspace/repo/.git" ] && [ -d "/workspace/repo/public/js-api" ]; then
|
|
61
57
|
echo "[tools-dev] Monorepo detected — public context at /workspace/repo/public/."
|
|
62
58
|
elif [ -d "$PUBLIC_DIR/js-api" ]; then
|
|
63
59
|
# Cloned public repo — link workspace into packages/ and expose context at /workspace/
|
|
64
|
-
|
|
60
|
+
LINK_NAME="${FOLDER_NAME:-$TASK_KEY}"
|
|
61
|
+
if [ -n "$LINK_NAME" ]; then
|
|
65
62
|
mkdir -p "$PUBLIC_DIR/packages" 2>/dev/null || true
|
|
66
|
-
[ ! -e "$PUBLIC_DIR/packages/$
|
|
67
|
-
echo "[tools-dev] Workspace linked at $PUBLIC_DIR/packages/$
|
|
63
|
+
[ ! -e "$PUBLIC_DIR/packages/$LINK_NAME" ] && ln -s /workspace/repo "$PUBLIC_DIR/packages/$LINK_NAME"
|
|
64
|
+
echo "[tools-dev] Workspace linked at $PUBLIC_DIR/packages/$LINK_NAME"
|
|
68
65
|
fi
|
|
69
|
-
|
|
70
|
-
[ ! -e /workspace
|
|
66
|
+
PUBLIC_BASENAME=$(basename "$PUBLIC_DIR")
|
|
67
|
+
[ ! -e /workspace/.claude ] && ln -s "$PUBLIC_BASENAME/.claude" /workspace/.claude
|
|
68
|
+
[ ! -e /workspace/CLAUDE.md ] && ln -s "$PUBLIC_BASENAME/CLAUDE.md" /workspace/CLAUDE.md
|
|
71
69
|
echo "[tools-dev] Linked public repo context at /workspace/"
|
|
72
70
|
fi
|
|
73
71
|
|
package/CLAUDE.md
CHANGED
|
@@ -14,7 +14,7 @@ npm run build # Transpile TypeScript to JavaScript using Babe
|
|
|
14
14
|
npm run debug-source-map # Build with source maps for debugging
|
|
15
15
|
```
|
|
16
16
|
|
|
17
|
-
The build process uses Babel with `@babel/preset-typescript` to transpile TypeScript files from `bin/` (
|
|
17
|
+
The build process uses Babel with `@babel/preset-typescript` to transpile TypeScript files from `bin/` to `bin/` (in-place). **Important:** `.ts` source and `.js` output coexist in the same `bin/` directory — `grok.js` requires the transpiled `.js` files, not the `.ts` sources. After editing any `.ts` file, you must run `npm run build` before testing.
|
|
18
18
|
|
|
19
19
|
### Link for Local Development
|
|
20
20
|
```bash
|
|
@@ -42,13 +42,18 @@ The CLI uses a modular command pattern. Each command is a separate module that:
|
|
|
42
42
|
- `add.ts` - Add entities (functions, scripts, queries, etc.) to packages
|
|
43
43
|
- `publish.ts` - Upload and deploy packages to Datagrok servers
|
|
44
44
|
- `check.ts` - Validate package structure, signatures, imports
|
|
45
|
+
- `build.ts` - Build one package or recursively build all packages in a directory
|
|
45
46
|
- `test.ts` - Run Puppeteer-based tests for a single package
|
|
46
47
|
- `test-all.ts` - Run tests across multiple packages
|
|
48
|
+
- `stress-tests.ts` - Run stress tests (must be run from ApiTests package)
|
|
47
49
|
- `api.ts` - Auto-generate TypeScript wrappers for scripts/queries
|
|
48
50
|
- `link.ts` - Link libraries for plugin development
|
|
51
|
+
- `claude.ts` - Launch a Dockerized dev environment with Datagrok + Claude Code
|
|
49
52
|
- `migrate.ts` - Update legacy packages
|
|
50
53
|
- `init.ts` - Apply configuration to existing packages
|
|
51
54
|
|
|
55
|
+
The commands `api`, `check`, `link`, `publish`, and `test` support the `--all` flag to run recursively across all packages in the current directory.
|
|
56
|
+
|
|
52
57
|
### Template System
|
|
53
58
|
|
|
54
59
|
**Package Templates** (`package-template/`)
|
|
@@ -132,6 +137,90 @@ Tests use Puppeteer for headless browser automation:
|
|
|
132
137
|
- `--catchUnhandled` - Catch unhandled exceptions
|
|
133
138
|
- `--debug` - Debug breakpoints (requires `--gui`)
|
|
134
139
|
|
|
140
|
+
### `grok build` Command
|
|
141
|
+
|
|
142
|
+
Builds packages with `npm install` + `npm run build`. Supports:
|
|
143
|
+
- Single package: `grok build` (from package directory)
|
|
144
|
+
- Recursive: `grok build --recursive` (discovers and builds all packages in subdirectories)
|
|
145
|
+
- `--filter "name:Chem"` - Filter packages by package.json fields (supports regex, `&&` for multiple conditions)
|
|
146
|
+
- `--parallel N` - Max parallel build jobs (default 4)
|
|
147
|
+
- `--no-incremental` - Force full rebuild (default uses `--env incremental`)
|
|
148
|
+
|
|
149
|
+
### `grok claude` Command
|
|
150
|
+
|
|
151
|
+
Launches a full Dockerized development environment with Datagrok + Claude Code. The compose configuration is embedded in `claude.ts` — no external files needed.
|
|
152
|
+
|
|
153
|
+
```bash
|
|
154
|
+
grok claude <project> # Create worktree + start containers + launch Claude
|
|
155
|
+
grok claude <project> --in-place # Use current directory (no worktree)
|
|
156
|
+
grok claude <project> --keep # Leave containers running on exit
|
|
157
|
+
grok claude <project> --version 1.22.0 # Pin Datagrok version
|
|
158
|
+
grok claude <project> --profile full # Include spawner, JKG, demo DBs
|
|
159
|
+
grok claude <project> --profile scripting # Include JKG for Python/R/Julia
|
|
160
|
+
grok claude <project> --port 8080 # Fix Datagrok port (default: random free port)
|
|
161
|
+
grok claude <project> --prompt "fix bug" # Pass prompt to Claude Code (-p flag)
|
|
162
|
+
grok claude destroy <project> # Tear down containers + worktree + temp files
|
|
163
|
+
grok claude destroy-all # Destroy all known projects
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
**Project name restrictions:** `master` and `main` are rejected.
|
|
167
|
+
|
|
168
|
+
**Lifecycle:**
|
|
169
|
+
1. Creates git worktree at `~/pkg-worktrees/<project>` (unless `--in-place` or not in a git repo)
|
|
170
|
+
2. Writes `docker-compose.yaml` + `.env` + optional `docker-compose.override.yaml` to `$TMPDIR/dg-pkg-<project>`
|
|
171
|
+
3. Runs `docker compose up -d --wait`
|
|
172
|
+
4. Detects Claude working directory based on repo type (see below)
|
|
173
|
+
5. Launches `claude --dangerously-skip-permissions` inside the `tools-dev` container
|
|
174
|
+
6. On exit: stops containers (unless `--keep`)
|
|
175
|
+
|
|
176
|
+
**Version resolution:** `--version` flag > `bleeding-edge` (if inside public repo) > `latest`
|
|
177
|
+
|
|
178
|
+
**Compose services (embedded template):**
|
|
179
|
+
- Always started: `postgres` (pgvector:pg17), `rabbitmq`, `grok_pipe`, `datagrok`, `grok_connect`, `tools-dev`
|
|
180
|
+
- Profile `full`: adds `grok_spawner`
|
|
181
|
+
- Profile `scripting`/`full`: adds `jupyter_kernel_gateway`
|
|
182
|
+
- Profile `demo`/`full`: adds `world`, `test_db`, `northwind` demo databases
|
|
183
|
+
|
|
184
|
+
**Note:** The embedded template in `claude.ts` differs from `.devcontainer/docker-compose.yaml`:
|
|
185
|
+
- Embedded uses separate version vars per service (`DATAGROK_VERSION`, `GROK_CONNECT_VERSION`, `GROK_SPAWNER_VERSION`, `JKG_VERSION`, `TOOLS_DEV_VERSION`); `.devcontainer/` uses a single `DG_VERSION` for all
|
|
186
|
+
- Embedded mounts workspace at `/workspace/repo`; `.devcontainer/` mounts at `/workspace`
|
|
187
|
+
- Embedded has `grok_connect` always-on (no profile); `.devcontainer/` puts it under `profiles: ["full"]`
|
|
188
|
+
- Embedded uses `grok_pipe:latest`; `.devcontainer/` uses `grok_pipe:${DG_VERSION}`
|
|
189
|
+
- Embedded doesn't mount `~/.grok` from host; `.devcontainer/` does
|
|
190
|
+
|
|
191
|
+
**Host config override:** If `~/.claude` (or `CLAUDE_HOME`) is found on the host, a `docker-compose.override.yaml` is generated to bind-mount it into the container. Also mounts `~/.claude.json` if present.
|
|
192
|
+
|
|
193
|
+
**Working directory detection inside container:**
|
|
194
|
+
- Public repo root (has `js-api/`): `/workspace/repo`
|
|
195
|
+
- Monorepo (has `public/js-api/`): `/workspace/repo/public`
|
|
196
|
+
- External repo: `/workspace/datagrok/packages/<folder-name>` (waits up to 600s for entrypoint to clone public repo)
|
|
197
|
+
|
|
198
|
+
#### tools-dev Container (`Dockerfile.pkg_dev`)
|
|
199
|
+
|
|
200
|
+
Based on `node:22-bookworm-slim`. Pre-installed:
|
|
201
|
+
- Google Chrome stable (for Puppeteer), Playwright + Chromium
|
|
202
|
+
- `datagrok-tools` (grok CLI) and `@anthropic-ai/claude-code` (global npm)
|
|
203
|
+
- git, curl, jq, docker CLI
|
|
204
|
+
- Runs as `node` user (UID 1000, added to `docker` group)
|
|
205
|
+
|
|
206
|
+
#### Entrypoint (`entrypoint.sh`)
|
|
207
|
+
|
|
208
|
+
1. **Repo detection:** checks if `/workspace/repo` is the public repo (has `.git` + `js-api/`) or monorepo (`public/js-api/`)
|
|
209
|
+
2. **Auto-clone:** if workspace is not the public repo, sparse-clones it to `$DG_PUBLIC_DIR` (default `/workspace/datagrok`) — excludes `connectors/`, `docker/`, `environments/`, `python-api/`, etc. for speed. Branch resolved as: `DG_PUBLIC_BRANCH` > `DG_VERSION` mapped to branch > `master` fallback
|
|
210
|
+
3. **Workspace linking:** for non-public repos, symlinks `/workspace/repo` into the cloned repo's `packages/` dir and links `.claude`/`CLAUDE.md` at `/workspace/` for context discovery
|
|
211
|
+
4. **Grok config:** auto-creates `~/.grok/config.yaml` pointing to `http://datagrok:8080/api` with key `admin` (only if config doesn't already exist)
|
|
212
|
+
|
|
213
|
+
#### Profiles
|
|
214
|
+
|
|
215
|
+
| Profile | Additional services |
|
|
216
|
+
|---------|-------------------|
|
|
217
|
+
| (none) | postgres, rabbitmq, grok_pipe, datagrok, grok_connect, tools-dev |
|
|
218
|
+
| `scripting` | + jupyter_kernel_gateway |
|
|
219
|
+
| `demo` | + world, test_db, northwind |
|
|
220
|
+
| `full` | + grok_spawner, JKG, demo DBs |
|
|
221
|
+
|
|
222
|
+
See `.devcontainer/PACKAGES_DEV.md` for detailed usage docs, architecture diagram, MCP plugin setup (Jira/GitHub), and troubleshooting.
|
|
223
|
+
|
|
135
224
|
## Key Patterns and Conventions
|
|
136
225
|
|
|
137
226
|
### Naming Conventions
|
package/bin/commands/claude.js
CHANGED
|
@@ -243,16 +243,19 @@ services:
|
|
|
243
243
|
- \${WORKTREE_PATH:-.}:/workspace/repo
|
|
244
244
|
- \${DOCKER_SOCK}:/var/run/docker.sock
|
|
245
245
|
- npm_cache:/home/node/.npm
|
|
246
|
+
- public_repo:/workspace/datagrok
|
|
246
247
|
environment:
|
|
247
248
|
ANTHROPIC_API_KEY: \${ANTHROPIC_API_KEY:-}
|
|
248
249
|
DG_VERSION: \${DG_VERSION:-latest}
|
|
249
250
|
DG_PUBLIC_REPO: \${DG_PUBLIC_REPO:-https://github.com/datagrok-ai/public.git}
|
|
250
251
|
DG_PUBLIC_BRANCH: \${DG_PUBLIC_BRANCH:-}
|
|
252
|
+
DG_PUBLIC_DIR: \${DG_PUBLIC_DIR:-/workspace/datagrok}
|
|
251
253
|
JIRA_URL: \${JIRA_URL:-https://reddata.atlassian.net}
|
|
252
254
|
JIRA_USERNAME: \${JIRA_USERNAME:-}
|
|
253
255
|
JIRA_TOKEN: \${JIRA_TOKEN:-}
|
|
254
256
|
GITHUB_TOKEN: \${GITHUB_TOKEN:-}
|
|
255
257
|
TASK_KEY: \${TASK_KEY:-}
|
|
258
|
+
FOLDER_NAME: \${FOLDER_NAME:-}
|
|
256
259
|
working_dir: /workspace/repo
|
|
257
260
|
networks:
|
|
258
261
|
dg:
|
|
@@ -269,6 +272,7 @@ volumes:
|
|
|
269
272
|
demo_test:
|
|
270
273
|
demo_northwind:
|
|
271
274
|
npm_cache:
|
|
275
|
+
public_repo:
|
|
272
276
|
|
|
273
277
|
networks:
|
|
274
278
|
dg:
|
|
@@ -332,7 +336,7 @@ function writeProjectFiles(taskKey, args, worktreeRoot, dgPort) {
|
|
|
332
336
|
const dockerSock = process.platform === 'win32' ? '//var/run/docker.sock' : '/var/run/docker.sock';
|
|
333
337
|
|
|
334
338
|
// Generate .env — all paths use forward slashes for Docker compatibility
|
|
335
|
-
const envLines = [`WORKTREE_PATH=${toDockerPath(worktreeRoot)}`, `DG_PORT=${dgPort}`, `TASK_KEY=${taskKey.toLowerCase()}`, `DOCKER_SOCK=${dockerSock}`, `DATAGROK_VERSION=${args.version || 'latest'}`, `DG_VERSION=${args.version || 'latest'}`, `GROK_CONNECT_VERSION=${args['grok-connect-version'] || 'latest'}`, `GROK_SPAWNER_VERSION=${args['grok-spawner-version'] || 'latest'}`, `JKG_VERSION=${args['jkg-version'] || 'latest'}`, `TOOLS_DEV_VERSION=${args['tools-dev-version'] || 'latest'}`];
|
|
339
|
+
const envLines = [`WORKTREE_PATH=${toDockerPath(worktreeRoot)}`, `DG_PORT=${dgPort}`, `TASK_KEY=${taskKey.toLowerCase()}`, `DOCKER_SOCK=${dockerSock}`, `DATAGROK_VERSION=${args.version || 'latest'}`, `DG_VERSION=${args.version || 'latest'}`, `GROK_CONNECT_VERSION=${args['grok-connect-version'] || 'latest'}`, `GROK_SPAWNER_VERSION=${args['grok-spawner-version'] || 'latest'}`, `JKG_VERSION=${args['jkg-version'] || 'latest'}`, `TOOLS_DEV_VERSION=${args['tools-dev-version'] || 'latest'}`, `FOLDER_NAME=${_path.default.basename(worktreeRoot)}`];
|
|
336
340
|
for (const env of ['ANTHROPIC_API_KEY', 'DG_PUBLIC_BRANCH', 'JIRA_URL', 'JIRA_USERNAME', 'JIRA_TOKEN', 'GITHUB_TOKEN']) if (process.env[env]) envLines.push(`${env}=${process.env[env]}`);
|
|
337
341
|
_fs.default.writeFileSync(_path.default.join(projectDir, '.env'), envLines.join('\n') + '\n');
|
|
338
342
|
|
|
@@ -540,61 +544,39 @@ async function claude(args) {
|
|
|
540
544
|
return false;
|
|
541
545
|
}
|
|
542
546
|
|
|
543
|
-
//
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
// Determine whether this is a public repo and compute Claude working directory
|
|
548
|
-
const isPublic = repoRoot ? isPublicRepo(repoRoot) : false;
|
|
549
|
-
const claudeWorkDir = isPublic ? '/workspace/repo/public' : `/workspace/public/packages/${taskKey}`;
|
|
550
|
-
|
|
551
|
-
// Fix ownership on bind-mounted directories (host UID may differ from container node user)
|
|
547
|
+
// Determine Claude working directory based on repo type
|
|
548
|
+
// Only trust public-repo markers when we are inside a real git repo — packages can have
|
|
549
|
+
// public/js-api via node_modules symlinks, which would cause a false positive.
|
|
552
550
|
const containerName = `dg-pkg-${taskKey.toLowerCase()}-tools-dev-1`;
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
(0, _child_process.spawnSync)('docker', ['cp', grokConfigPath, `${containerName}:/home/node/.grok/config.yaml`], {
|
|
564
|
-
stdio: 'inherit'
|
|
565
|
-
});
|
|
566
|
-
(0, _child_process.spawnSync)('docker', ['exec', '-u', 'root', containerName, 'chown', 'node:node', '/home/node/.grok/config.yaml'], {
|
|
567
|
-
stdio: 'inherit'
|
|
551
|
+
let claudeWorkDir;
|
|
552
|
+
if (repoRoot && _fs.default.existsSync(_path.default.join(repoRoot, 'js-api'))) claudeWorkDir = '/workspace/repo';else if (repoRoot && _fs.default.existsSync(_path.default.join(repoRoot, 'public', 'js-api'))) claudeWorkDir = '/workspace/repo/public';else {
|
|
553
|
+
// External repo: entrypoint clones public repo and creates symlink — wait for it
|
|
554
|
+
const folderName = _path.default.basename(worktreeRoot);
|
|
555
|
+
claudeWorkDir = `/workspace/datagrok/packages/${folderName}`;
|
|
556
|
+
color.info(`Waiting for workspace at ${claudeWorkDir} (streaming container logs)...`);
|
|
557
|
+
|
|
558
|
+
// Stream container logs so the user can see clone progress (don't inherit stdin)
|
|
559
|
+
const logsProc = (0, _child_process.spawn)('docker', ['logs', '-f', containerName], {
|
|
560
|
+
stdio: ['ignore', 'inherit', 'inherit']
|
|
568
561
|
});
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
t = 'default: local\\nservers:\\n local:\\n url: http://datagrok:8080/api\\n key: admin\\n';
|
|
580
|
-
} else if (!t.includes('datagrok:8080')) {
|
|
581
|
-
t = t.replace(/^(servers:)/m, '\\$1\\n local:\\n url: http://datagrok:8080/api\\n key: admin');
|
|
582
|
-
t = t.replace(/^default:.*/m, 'default: local');
|
|
583
|
-
} else {
|
|
584
|
-
t = t.replace(/^default:.*/m, 'default: local');
|
|
562
|
+
let ready = false;
|
|
563
|
+
const waitStart = Date.now();
|
|
564
|
+
for (let i = 0; i < 120; i++) {
|
|
565
|
+
const check = (0, _child_process.spawnSync)('docker', ['exec', containerName, 'test', '-d', claudeWorkDir]);
|
|
566
|
+
if (check.status === 0) {
|
|
567
|
+
ready = true;
|
|
568
|
+
break;
|
|
569
|
+
}
|
|
570
|
+
if (i > 0 && i % 12 === 0) color.info(`Still waiting for workspace... (${Math.round((Date.now() - waitStart) / 1000)}s elapsed)`);
|
|
571
|
+
await new Promise(r => setTimeout(r, 5000));
|
|
585
572
|
}
|
|
586
|
-
fs.writeFileSync(p, t);
|
|
587
|
-
`], {
|
|
588
|
-
stdio: 'inherit'
|
|
589
|
-
});
|
|
590
573
|
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
});
|
|
574
|
+
// Stop streaming logs
|
|
575
|
+
logsProc.kill('SIGKILL');
|
|
576
|
+
if (!ready) {
|
|
577
|
+
color.warn(`${claudeWorkDir} not available after 600s — falling back to /workspace/repo`);
|
|
578
|
+
claudeWorkDir = '/workspace/repo';
|
|
579
|
+
}
|
|
598
580
|
}
|
|
599
581
|
const claudeArgs = ['--dangerously-skip-permissions'];
|
|
600
582
|
if (args.prompt) claudeArgs.push('-p', args.prompt);
|
package/package.json
CHANGED