@gapi/gcli 1.8.237 → 1.8.238
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/.agents/skills/changelog/SKILL.md +59 -0
- package/.agents/skills/cluster-targeting/SKILL.md +70 -0
- package/.agents/skills/gcli-command/SKILL.md +55 -0
- package/.agents/skills/local-ai-runners/SKILL.md +40 -0
- package/.claude/README.md +33 -0
- package/AGENTS.md +105 -0
- package/CLAUDE.md +20 -0
- package/README-CLI.md +385 -23
- package/README.md +40 -0
- package/docs/CHANGELOG.md +8 -0
- package/docs/changelog.d/2026-10-11-local-ai-runners-gcli-runner-commands-bridge-ollama-to-the-chat.md +25 -0
- package/docs/changelog.d/2026-10-11-local-ai-runners-gcli-runner-models-chooses-the-models-shown-in-chat.md +12 -0
- package/docs/changelog.d/2026-10-11-repo-ai-ready-package-setup-agents-md-skills-feature-changelog.md +18 -0
- package/docs/changelog.d/2026-10-11-repo-tests-workflow-runs-lint-and-tests-on-every-branch-push.md +18 -0
- package/docs/changelog.d/README.md +51 -0
- package/docs/features/README.md +33 -0
- package/docs/features/local-ai-runners.md +64 -0
- package/package.json +2 -1
- package/release/index.js +886 -92
- package/scripts/changelog.mjs +348 -0
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: changelog
|
|
3
|
+
description: Record every code change as a feature-keyed changelog fragment in docs/changelog.d/ (node scripts/changelog.mjs new) and keep the feature's living doc in docs/features/ current. Use after ANY change to source, schema, config or behavior, and whenever you need the history of a feature to debug or extend it (node scripts/changelog.mjs render --feature <f>). Never edit docs/CHANGELOG.md directly.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Feature changelog discipline
|
|
7
|
+
|
|
8
|
+
Two artifacts per feature, kept in the SAME commit as the change:
|
|
9
|
+
|
|
10
|
+
| Artifact | Holds | Edited how |
|
|
11
|
+
|---|---|---|
|
|
12
|
+
| `docs/features/<feature>.md` | Current state: what it does, architecture, files, config, how to test, how to debug, known limits | Updated in place - it must always describe what is true NOW |
|
|
13
|
+
| `docs/changelog.d/YYYY-MM-DD-<feature>-<slug>.md` | One change: what changed, how to test it, where to look when it breaks, what was verified | New file per change, never edited after merge |
|
|
14
|
+
|
|
15
|
+
`docs/CHANGELOG.md` is the archive - only `node scripts/changelog.mjs compact`
|
|
16
|
+
writes it (on the default branch, in its own commit).
|
|
17
|
+
|
|
18
|
+
## Workflow
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
node scripts/changelog.mjs features # existing feature slugs - reuse one
|
|
22
|
+
node scripts/changelog.mjs new local-ai-runners "model visibility per runner" --type feat
|
|
23
|
+
$EDITOR docs/changelog.d/2026-10-11-local-ai-runners-model-visibility-per-runner.md
|
|
24
|
+
$EDITOR docs/features/local-ai-runners.md # bring the living doc up to date
|
|
25
|
+
node scripts/changelog.mjs check # must print OK
|
|
26
|
+
git add docs/ <changed files> && git commit
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Starting work on an existing feature? Read its history first:
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
node scripts/changelog.mjs render --feature local-ai-runners
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Rules
|
|
36
|
+
|
|
37
|
+
- **Feature slug**: kebab-case, shared across the Lambforge repos
|
|
38
|
+
(gql-fission, graphql-server, graphql-server-lambdas,
|
|
39
|
+
graphql-server-functions, gcli) - a cross-repo feature uses the same slug
|
|
40
|
+
in every repo it touches, and each repo's fragment mentions the others.
|
|
41
|
+
`repo` is for changes owned by no feature (setup, tooling, deps).
|
|
42
|
+
- **New feature** = new `docs/features/<feature>.md` (outline in
|
|
43
|
+
`docs/features/README.md`) + a row in that README's index. `check` fails
|
|
44
|
+
without the doc.
|
|
45
|
+
- **Every entry has Test, Debug and Verification lines.** Test = how anyone
|
|
46
|
+
can re-test it later. Debug = where to look when it breaks (log prefixes,
|
|
47
|
+
collections, flags, failure modes). Verification = what YOU ran and saw.
|
|
48
|
+
- Say what is now true, not what you did ("runners heartbeat every 30s",
|
|
49
|
+
not "edited connection.ts").
|
|
50
|
+
- One entry per logical change; several changes in a day = several files.
|
|
51
|
+
- Add `**Commit:** <hash>` when writing an entry after the fact.
|
|
52
|
+
- Not needed for: typo-only doc edits, scratch work, release/version bumps.
|
|
53
|
+
|
|
54
|
+
## Compaction
|
|
55
|
+
|
|
56
|
+
When `docs/changelog.d/` grows past ~20 files, on the default branch:
|
|
57
|
+
`node scripts/changelog.mjs compact` then
|
|
58
|
+
`git commit -m "docs(changelog): compact N entries"`. Never urgent;
|
|
59
|
+
`render --feature` reads fragments and archive alike.
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: cluster-targeting
|
|
3
|
+
description: Add or extend a gcli command that touches a project resource which can live on a private cluster (lambda, environment, logs, load-spec). Use when adding a new --clusterId/--clusterName flag, or when a command's resource lookup needs to disambiguate between the shared cluster and a private one.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# gcli: targeting the right cluster
|
|
7
|
+
|
|
8
|
+
Lambforge projects can have private Talos/Hetzner clusters in addition to
|
|
9
|
+
the implicit shared one (full backend architecture:
|
|
10
|
+
`graphql-server-lambdas/docs/multi-cluster.md`). Every gcli command that
|
|
11
|
+
creates, reads, updates, or deletes a cluster-scoped resource (lambdas,
|
|
12
|
+
environments, logs, `load-spec.ts` manifests) needs to resolve which
|
|
13
|
+
cluster it's targeting instead of assuming the shared one.
|
|
14
|
+
|
|
15
|
+
## `resolveClusterId` — the one helper every command should use
|
|
16
|
+
|
|
17
|
+
`src/helpers.ts`:
|
|
18
|
+
|
|
19
|
+
```ts
|
|
20
|
+
export function resolveClusterId(
|
|
21
|
+
projectId: string,
|
|
22
|
+
hint: { clusterId?: string | null; clusterName?: string | null },
|
|
23
|
+
): Observable<string | undefined>
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
- `clusterId` wins when present (checked via `!= null`, **not** truthiness —
|
|
27
|
+
an explicit empty string is a deliberate "shared cluster only" signal on
|
|
28
|
+
some commands like `lambda:list`, and truthiness would silently treat
|
|
29
|
+
that the same as "not provided," changing existing behavior).
|
|
30
|
+
- Otherwise, if `clusterName` is given, looks it up via
|
|
31
|
+
`GraphqlClienAPI.projectClusters(projectId)` and resolves to that
|
|
32
|
+
cluster's id — or throws a descriptive error naming
|
|
33
|
+
`cluster:list --project <id>` as the way to see what's available.
|
|
34
|
+
- Neither given → resolves `undefined` (the shared cluster).
|
|
35
|
+
|
|
36
|
+
**Every command that accepts `--clusterId` should also accept
|
|
37
|
+
`--clusterName`** (clusterName is unique per project, so `clusterName +
|
|
38
|
+
projectId` is just as unambiguous as `clusterId` — and far more readable in
|
|
39
|
+
a hand-authored YAML manifest than a raw ObjectId). `clusterId` always wins
|
|
40
|
+
when both are passed. Confirmed call sites: `environment:{create,get,update,
|
|
41
|
+
delete}`, `lambda:{get,list,delete}`, `lambda:logs`/`logs:builder`,
|
|
42
|
+
`lambda/helpers/load-spec.ts` (so a `load-spec.yaml` manifest can reference
|
|
43
|
+
a cluster **by name**, keeping the file human-readable instead of full of
|
|
44
|
+
raw ObjectIds — see that file for the exact YAML shape).
|
|
45
|
+
|
|
46
|
+
## Adding a new cluster-scoped command/flag
|
|
47
|
+
|
|
48
|
+
1. Add `--clusterId <id>` AND `--clusterName <name>` flags to the command.
|
|
49
|
+
2. Call `resolveClusterId(projectId, { clusterId, clusterName })` before the
|
|
50
|
+
actual GraphQL call, and pass the resolved id through.
|
|
51
|
+
3. If the underlying GraphQL resolver doesn't yet accept a `clusterId` hint
|
|
52
|
+
for this operation, that's a backend gap — see
|
|
53
|
+
graphql-server-lambdas' `multi-cluster-scoping` skill before assuming the
|
|
54
|
+
frontend-side fix alone is sufficient.
|
|
55
|
+
|
|
56
|
+
## GraphQL layer specifics (different from gql-fission)
|
|
57
|
+
|
|
58
|
+
gcli builds every GraphQL operation as an inline `gql` template string
|
|
59
|
+
directly in `services/gql-client.ts` — there's no `.graphql` file + codegen
|
|
60
|
+
pipeline like gql-fission's. Adding a field/operation here is a plain code
|
|
61
|
+
edit to that file, not a "regenerate then hand-patch" dance. gcli keeps its
|
|
62
|
+
own **separate, hand-maintained** copy of `@introspection/index.ts` — a
|
|
63
|
+
type added on the backend still needs to be added here by hand; it is not
|
|
64
|
+
shared with or generated from gql-fission's copy.
|
|
65
|
+
|
|
66
|
+
## Testing
|
|
67
|
+
|
|
68
|
+
`jest.config.js` has no `moduleNameMapper` for the `~/` tsconfig path alias
|
|
69
|
+
— new test files must use relative imports (e.g. `'../src/helpers'`), not
|
|
70
|
+
`'~/helpers'`, or the test silently fails to resolve the module.
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: gcli-command
|
|
3
|
+
description: Add or change a gcli command (commander registration, lazy action modules, GraphqlClienAPI calls through the gateway, Logger output, tests, build/release, regenerating README-CLI.md). USE BEFORE adding a `gcli <area>:<verb>` command or a new API call in src/services/gql-client.ts.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Adding a gcli command
|
|
7
|
+
|
|
8
|
+
## Shape
|
|
9
|
+
|
|
10
|
+
```
|
|
11
|
+
src/commands/<area>/index.ts registerXCommands(program): .command('<area>:<verb>')
|
|
12
|
+
.description(...).option(...)
|
|
13
|
+
.action(lazy(() => import('./<verb>').then(m => m.default)))
|
|
14
|
+
src/commands/<area>/<verb>.ts export default (cmd: { ...options }) => Promise<...>
|
|
15
|
+
src/commands/index.ts add registerXCommands to `commands`
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
- Actions are lazy-imported - keep heavy imports inside the action module.
|
|
19
|
+
- Return a promise (`lastValueFrom(observable)` for rxjs flows); throw an
|
|
20
|
+
`Error` with an actionable message (`Run gcli login first`, `--id ...`).
|
|
21
|
+
- Output via `Logger` (`src/services/log.ts`: log/info/warn/error/table).
|
|
22
|
+
|
|
23
|
+
## API calls
|
|
24
|
+
|
|
25
|
+
`GraphqlClienAPI.query<T>({ query: gql`...`, variables })` in
|
|
26
|
+
`src/services/gql-client.ts`: POSTs to the `gcli login` URL with the stored
|
|
27
|
+
Firebase token (auto-refreshed after 30 min) - i.e. through the federation
|
|
28
|
+
gateway as the logged-in user. Selection sets are plain strings in
|
|
29
|
+
`src/services/types/*.fragment.ts`. Response types: `@introspection/index`
|
|
30
|
+
(regenerated with `npm run introspect` against a live gateway) or a local
|
|
31
|
+
interface next to the command (as `commands/runner/types.ts`).
|
|
32
|
+
|
|
33
|
+
Login state lives in `~/.graphql-server/` (`token`, `refresh`, `url`, `key`,
|
|
34
|
+
`project`, ...; paths in `src/types.ts`). A command needing its own state
|
|
35
|
+
adds a path there (the runner stores `runner.json`, mode 0600).
|
|
36
|
+
|
|
37
|
+
Project/cluster-scoped commands: `parseProjectId(cmd.project)`,
|
|
38
|
+
`resolveClusterId` in `src/helpers.ts`; see the `cluster-targeting` skill.
|
|
39
|
+
|
|
40
|
+
## Tests, build, docs
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
npx jest --coverage=false # test/*.spec.ts; jest maps ~/ @introspection/ @commands/
|
|
44
|
+
npx tsc --noEmit -p .
|
|
45
|
+
npx eslint --fix <files>
|
|
46
|
+
npm run build # esbuild -> release/index.js (committed!)
|
|
47
|
+
node release/index.js <area>:<verb> --help
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
- Mock the API in specs: `jest.mock('../src/services/gql-client', ...)`.
|
|
51
|
+
- `release/index.js` is committed and rewritten by every build - don't
|
|
52
|
+
commit it from a feature branch unless releasing (`git checkout -- release/index.js`).
|
|
53
|
+
- `README-CLI.md` is generated: `node release/index.js --all-help > README-CLI.md`
|
|
54
|
+
after a build. User-facing docs: a section in `README.md`.
|
|
55
|
+
- Changelog fragment + feature doc (`changelog` skill).
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: local-ai-runners
|
|
3
|
+
description: Work on the gcli local AI runner (runner:start/list/models/delete) - the subscriptions-transport-ws client that bridges a user's Ollama to the Lambforge chat. USE when the runner won't connect, drops requests, or before changing src/commands/runner/**.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# gcli local AI runner
|
|
7
|
+
|
|
8
|
+
Slice doc: `docs/features/local-ai-runners.md`. Canonical (protocol,
|
|
9
|
+
security, symptom table): `graphql-server/docs/features/local-ai-runners.md`.
|
|
10
|
+
|
|
11
|
+
## Invariants
|
|
12
|
+
|
|
13
|
+
- Outbound only: one WebSocket to `/subscriptions`
|
|
14
|
+
(`connectionParams.runnerToken`); subscription + mutations share it.
|
|
15
|
+
Never connect to RabbitMQ or open a port.
|
|
16
|
+
- `ALLOWED_REQUESTS` (`ollama.ts`) mirrors the backend's
|
|
17
|
+
`RUNNER_ALLOWED_PATHS` - only `POST /v1/chat/completions`. Change both or
|
|
18
|
+
neither.
|
|
19
|
+
- Every response frame of a request gets the next `seq`; batches are sent
|
|
20
|
+
sequentially (`FrameSender`). The backend re-orders, but don't rely on it.
|
|
21
|
+
- A request queued in Ollama sends `ping` every 30s, or the backend's 10-min
|
|
22
|
+
idle timeout kills it (spawned agent workers queue on one GPU).
|
|
23
|
+
- Socket close aborts every in-flight Ollama request; a refused token is
|
|
24
|
+
fatal (`RunnerAuthError`), everything else reconnects with backoff.
|
|
25
|
+
- Global `WebSocket` -> Node >= 22.
|
|
26
|
+
|
|
27
|
+
## Run it against a dev stack
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
gcli login --url http://localhost:9004/graphql ... # dev gateway
|
|
31
|
+
npm run build && node release/index.js runner:start # ws://localhost:9000/subscriptions derived
|
|
32
|
+
node release/index.js runner:models --show qwen3.8:27b # keep the picker short
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Tests
|
|
36
|
+
|
|
37
|
+
`npx jest test/runner.spec.ts --coverage=false` - `FakeServer` plays the
|
|
38
|
+
Lambforge socket (acks, operation replies, pushes requests), `fakeOllama`
|
|
39
|
+
plays Ollama (tags/show/streamed body, optional hold). Add a case there for
|
|
40
|
+
any protocol change.
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# .claude/ - Claude Code configuration for this repo
|
|
2
|
+
|
|
3
|
+
| Path | Committed? | Purpose |
|
|
4
|
+
|---|---|---|
|
|
5
|
+
| `skills` | yes (symlink) | -> `../.agents/skills`, the single source of truth for project skills. Edit skills THERE. |
|
|
6
|
+
| `settings.json` | yes, if present | Team-wide baseline (permissions, hooks) |
|
|
7
|
+
| `settings.local.json` | no (gitignored) | Your personal overrides for this repo |
|
|
8
|
+
| `worktrees/`, `scheduled_tasks.lock` | no (gitignored) | Ephemeral Claude Code state |
|
|
9
|
+
|
|
10
|
+
Related at the repo root: `AGENTS.md` (the canonical agent guide - tool
|
|
11
|
+
agnostic, read by other agents/editors too), `CLAUDE.md` (a thin loader that
|
|
12
|
+
imports AGENTS.md), `.mcp.json` (project MCP servers, if present).
|
|
13
|
+
|
|
14
|
+
## How settings layer
|
|
15
|
+
|
|
16
|
+
`~/.claude/settings.json` (you, all projects) -> `.claude/settings.json`
|
|
17
|
+
(this repo, team) -> `.claude/settings.local.json` (this repo, just you).
|
|
18
|
+
Scalars: later wins. Permission arrays merge, and a `deny` in any layer
|
|
19
|
+
beats an `allow` elsewhere - so you can always tighten locally:
|
|
20
|
+
|
|
21
|
+
```json
|
|
22
|
+
{ "permissions": { "ask": ["Bash(git push*)"], "deny": ["Read(./.env)"] } }
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Skills
|
|
26
|
+
|
|
27
|
+
A skill is `.agents/skills/<name>/SKILL.md`: YAML frontmatter (`name`,
|
|
28
|
+
`description` - the description is what decides when it auto-loads, so say
|
|
29
|
+
WHEN to use it) and then the checklist. Invoke with `/<name>`. When a
|
|
30
|
+
workflow proves itself or bites someone, update or add a skill in the same
|
|
31
|
+
change - same rule as docs.
|
|
32
|
+
|
|
33
|
+
Reference: https://docs.claude.com/en/docs/claude-code/settings
|
package/AGENTS.md
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
# gcli - agent & teammate guide (start here)
|
|
2
|
+
|
|
3
|
+
`@gapi/gcli`, the Lambforge platform CLI (package `gapi/packages/gcli` in the
|
|
4
|
+
`gapi` monorepo): login, projects, lambdas (create/update/logs/test, specs,
|
|
5
|
+
`lambforge.yaml`), environments, private clusters, RabbitMQ, plugins, the
|
|
6
|
+
MCP proxy, the esbuild-based `build`/`start`, and the local AI runner
|
|
7
|
+
(`runner:*`). TypeScript, commander, rxjs; bundled by esbuild into
|
|
8
|
+
`release/index.js` (also shipped as a Node SEA binary).
|
|
9
|
+
|
|
10
|
+
## The Lambforge platform (sibling repos)
|
|
11
|
+
|
|
12
|
+
Lambforge is a serverless-on-Kubernetes platform (lambdas on a Fission fork,
|
|
13
|
+
private Talos clusters, AI chat/agents, billing). The repos live side by
|
|
14
|
+
side in `reactive-solutions/`; each has its own `AGENTS.md`.
|
|
15
|
+
|
|
16
|
+
| Repo | Role |
|
|
17
|
+
|---|---|
|
|
18
|
+
| `gql-fission` | Frontend SPA (Lit + @rxdi/@rhtml, Parcel, Apollo) - talks only to the gateway (+ `/subscriptions` WS) |
|
|
19
|
+
| `graphql-server-federated` | Apollo federation gateway (dev :9004): verifies Firebase/CI tokens, forwards the user as a `user` header, composes subgraphs at startup |
|
|
20
|
+
| `graphql-server` | Main subgraph: users, teams, projects, billing, AI chat & agents, MCP server, local AI runners; hosts `/subscriptions` (dev :9000, RabbitMQ pub/sub) |
|
|
21
|
+
| `graphql-server-lambdas` | Lambdas/Fission, environments, secrets/configs, RabbitMQ, plugins, private clusters (multi-cluster), Atlas connector |
|
|
22
|
+
| `graphql-server-functions` | Monorepo of Fission lambdas: cluster-provisioner, billing/cost scrapers, invoices, code-runner, gateway-federation, mcp, ... |
|
|
23
|
+
| `gapi/packages/gcli` | `gcli` CLI: login, lambdas, environments, clusters, MCP proxy, local AI runner |
|
|
24
|
+
| `graphql-server-common` | Shared Mongoose models (`@stradivario/graphql-server-models`) |
|
|
25
|
+
|
|
26
|
+
**Cross-repo features use one feature slug everywhere** (e.g.
|
|
27
|
+
`local-ai-runners`): one canonical `docs/features/<slug>.md` in the repo
|
|
28
|
+
that owns most of it, a short slice doc in each other repo, and a changelog
|
|
29
|
+
fragment in every repo the change touches.
|
|
30
|
+
|
|
31
|
+
## Project skills (`.agents/skills/`, mirrored at `.claude/skills`)
|
|
32
|
+
|
|
33
|
+
| Skill | Owns |
|
|
34
|
+
|---|---|
|
|
35
|
+
| `gcli-command` | Adding a command: registration, lazy actions, `GraphqlClienAPI`, tests, build/release, regenerating `README-CLI.md` |
|
|
36
|
+
| `cluster-targeting` | Commands touching resources that can live on a private cluster (`--clusterId/--clusterName`) |
|
|
37
|
+
| `local-ai-runners` | `runner:*` - the outbound WS client bridging a user's Ollama to the chat |
|
|
38
|
+
| `changelog` | Feature-keyed changelog fragments + feature docs |
|
|
39
|
+
|
|
40
|
+
## Documentation map
|
|
41
|
+
|
|
42
|
+
| You need... | Read |
|
|
43
|
+
|---|---|
|
|
44
|
+
| User guide (every command, `lambforge.yaml`, MCP, build) | [`README.md`](README.md) |
|
|
45
|
+
| Generated `--all-help` output | [`README-CLI.md`](README-CLI.md) (regenerate, don't edit) |
|
|
46
|
+
| Features (current state) | [`docs/features/README.md`](docs/features/README.md) |
|
|
47
|
+
| Change history of a feature | `node scripts/changelog.mjs render --feature <slug>` |
|
|
48
|
+
| Local AI runner (slice; canonical in graphql-server) | [`docs/features/local-ai-runners.md`](docs/features/local-ai-runners.md) |
|
|
49
|
+
| Claude Code config in this package | [`.claude/README.md`](.claude/README.md) |
|
|
50
|
+
|
|
51
|
+
## Key patterns
|
|
52
|
+
|
|
53
|
+
- Commands: `src/commands/<area>/index.ts` registers `<area>:<verb>` with a
|
|
54
|
+
lazy `import('./<verb>')` action; register the area in
|
|
55
|
+
`src/commands/index.ts`.
|
|
56
|
+
- API: `GraphqlClienAPI.query` (`src/services/gql-client.ts`) talks to the
|
|
57
|
+
gateway as the `gcli login` user (token refreshed after 30 min). Login
|
|
58
|
+
state: `~/.graphql-server/` (paths in `src/types.ts`).
|
|
59
|
+
- `release/index.js` is COMMITTED and rewritten by every `npm run build` -
|
|
60
|
+
restore it (`git checkout -- release/index.js`) unless you are releasing.
|
|
61
|
+
- `README-CLI.md` = `node release/index.js --all-help` output.
|
|
62
|
+
|
|
63
|
+
## Running & testing
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
npx jest --coverage=false # test/*.spec.ts (jest maps ~/, @introspection/, @commands/)
|
|
67
|
+
npx tsc --noEmit -p .
|
|
68
|
+
npx eslint --fix <files>
|
|
69
|
+
npm run build # -> release/index.js
|
|
70
|
+
node release/index.js <command> --help
|
|
71
|
+
npm run patch # release: build, version bump, publish
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
CI (repo root `.github/workflows/`): **Tests** runs on every push to a
|
|
75
|
+
non-master branch - `npx @rxdi/bolt install`, then `npm run lint` and
|
|
76
|
+
`npm test` across all gapi workspaces (gcli included). **Publish** repeats
|
|
77
|
+
lint/test on master before publishing; **Release GCLI Binary** builds the
|
|
78
|
+
SEA binary on `v*` tags. Reproduce Tests locally from the repo root:
|
|
79
|
+
`npm run lint && npm test`.
|
|
80
|
+
|
|
81
|
+
## Docs, skills and changelog - same change, every time
|
|
82
|
+
|
|
83
|
+
This repo is documentation-driven. With every change:
|
|
84
|
+
|
|
85
|
+
1. **Changelog fragment** - `node scripts/changelog.mjs new <feature> "<summary>"`
|
|
86
|
+
-> fill in what changed + **Test** + **Debug** + **Verification** ->
|
|
87
|
+
`node scripts/changelog.mjs check`. Never edit `docs/CHANGELOG.md` (archive).
|
|
88
|
+
Details: the `changelog` skill, `docs/changelog.d/README.md`.
|
|
89
|
+
2. **Feature doc** - keep `docs/features/<feature>.md` true (new feature =
|
|
90
|
+
new doc + a row in `docs/features/README.md`).
|
|
91
|
+
3. **Skills / AGENTS.md** - learned something non-obvious, or a workflow
|
|
92
|
+
bit you? Update the owning skill (`.agents/skills/<name>/SKILL.md`) or
|
|
93
|
+
this file in the same change.
|
|
94
|
+
|
|
95
|
+
Before working on an existing feature: `node scripts/changelog.mjs render
|
|
96
|
+
--feature <slug>` + its feature doc. That is where "how to test" and "how
|
|
97
|
+
to debug" live.
|
|
98
|
+
|
|
99
|
+
## Pitfalls
|
|
100
|
+
|
|
101
|
+
- `gcli login` overwrites `~/.graphql-server/url`: logging into a dev
|
|
102
|
+
gateway points every later command (and `runner:start`) at dev.
|
|
103
|
+
- Jest needs the `moduleNameMapper` in `jest.config.js` for the `~/` alias -
|
|
104
|
+
without it any spec importing command code fails to resolve.
|
|
105
|
+
- `runner:start` needs Node >= 22 (global `WebSocket`).
|
package/CLAUDE.md
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# Claude Code entry point
|
|
2
|
+
|
|
3
|
+
The canonical agent/teammate guide is AGENTS.md - imported below so it loads
|
|
4
|
+
into every session automatically. AGENTS.md (not this file) is where content
|
|
5
|
+
lives: it is the tool-agnostic standard that other agents and editors read
|
|
6
|
+
too. Keep this file a thin loader; never duplicate guidance here.
|
|
7
|
+
|
|
8
|
+
@AGENTS.md
|
|
9
|
+
|
|
10
|
+
## Claude-specific notes
|
|
11
|
+
|
|
12
|
+
- Project skills auto-load from `.claude/skills` (a symlink to
|
|
13
|
+
`.agents/skills` - edit skills THERE, one source of truth). Invoke with
|
|
14
|
+
`/<name>`; the table is in AGENTS.md.
|
|
15
|
+
- Documentation-driven: every change ships with a changelog fragment
|
|
16
|
+
(`node scripts/changelog.mjs new <feature> "<summary>"`, then `check`) and an
|
|
17
|
+
up-to-date `docs/features/<feature>.md`. Learned something non-obvious?
|
|
18
|
+
Update the owning skill or AGENTS.md in the same change.
|
|
19
|
+
- Before touching an existing feature, read its history:
|
|
20
|
+
`node scripts/changelog.mjs render --feature <slug>`.
|