@gapi/gcli 1.8.244 → 1.8.246

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.
@@ -29,6 +29,11 @@ security, symptom table): `graphql-server/docs/features/local-ai-runners.md`.
29
29
  for "token refused" in sync with `RestartPreventExitStatus`. Tests must
30
30
  pass an explicit home dir to `SystemdUserService` (os.homedir() ignored a
31
31
  changed HOME under jest and wrote into the real `~/.config` once).
32
+ `runner:daemon:start`/`:restart` check the outcome after ~2 s
33
+ (`reportStarted`, exit 78 -> the `--reset` hint) - a refused runner exits
34
+ within a second, so "started" alone would be a lie. Your local `gcli` and
35
+ the installed unit may both run this repo's `release/index.js` (npm link),
36
+ so a build changes what the service runs on its next restart.
32
37
 
33
38
  ## Run it against a dev stack
34
39
 
package/README-CLI.md CHANGED
@@ -58,6 +58,9 @@ Commands:
58
58
  runner:start [options] Connect this machine's Ollama to the Lambforge chat as a local AI runner (outbound connection only - works behind NAT, Ollama is never exposed)
59
59
  runner:daemon:install|runner:start:daemon [options] Run the runner in the background as a systemd user service: starts with your session, restarts on failure (Linux)
60
60
  runner:daemon:status [options] Show the runner service status (systemctl --user status)
61
+ runner:daemon:start [options] Start the installed runner service, and report whether it stays up
62
+ runner:daemon:stop [options] Stop the runner service (it stays installed and starts at your next login)
63
+ runner:daemon:restart [options] Restart the runner service (e.g. after `gcli login` to another server)
61
64
  runner:daemon:logs [options] Follow the runner service log (journalctl --user -f)
62
65
  runner:daemon:uninstall [options] Stop and remove the runner service (the runner stays registered)
63
66
  runner:list List your local AI runners and the models they serve
@@ -66,6 +69,16 @@ Commands:
66
69
  workspace:start [options] Connect the current directory to the Lambforge chat as a local workspace: the AI agents can read/edit its files and run commands here (outbound connection only - works behind NAT)
67
70
  workspace:list [options] List your local workspaces (online status, directory, processes)
68
71
  workspace:delete [options] Delete a local workspace and revoke its token (default: the one registered for this directory)
72
+ workflow:list [options] List the project workflows
73
+ workflow:get [options] Print a workflow as YAML (the format workflow:apply reads), or write it with -o
74
+ workflow:generate [options] Draft a workflow with AI from plain language (or change one with --name / --from). Prints or writes YAML; saves only with --apply
75
+ workflow:apply [options] Create or update a workflow from a YAML/JSON file (workflow: {name, description, definition})
76
+ workflow:validate [options] Check a workflow file against the cluster (lambdas exist, graph is valid)
77
+ workflow:delete [options] Delete a workflow and all of its runs
78
+ workflow:run [options] Start a run; the JSON input is the first step request body. --wait follows it to the end
79
+ workflow:runs [options] List a workflow runs, newest first
80
+ workflow:status [options] Show a run: its step events, error and output (--follow until it ends)
81
+ workflow:cancel [options] Cancel a running run
69
82
  help [command] display help for command
70
83
  
71
84
  --- Subcommand: login ---
@@ -879,6 +892,33 @@ Usage: gcli runner:daemon:status [options]
879
892
 
880
893
  Show the runner service status (systemctl --user status)
881
894
 
895
+ Options:
896
+ --service <name> systemd unit name (default: lambforge-runner)
897
+ -h, --help display help for command
898
+ 
899
+ --- Subcommand: runner:daemon:start ---
900
+ Usage: gcli runner:daemon:start [options]
901
+
902
+ Start the installed runner service, and report whether it stays up
903
+
904
+ Options:
905
+ --service <name> systemd unit name (default: lambforge-runner)
906
+ -h, --help display help for command
907
+ 
908
+ --- Subcommand: runner:daemon:stop ---
909
+ Usage: gcli runner:daemon:stop [options]
910
+
911
+ Stop the runner service (it stays installed and starts at your next login)
912
+
913
+ Options:
914
+ --service <name> systemd unit name (default: lambforge-runner)
915
+ -h, --help display help for command
916
+ 
917
+ --- Subcommand: runner:daemon:restart ---
918
+ Usage: gcli runner:daemon:restart [options]
919
+
920
+ Restart the runner service (e.g. after `gcli login` to another server)
921
+
882
922
  Options:
883
923
  --service <name> systemd unit name (default: lambforge-runner)
884
924
  -h, --help display help for command
@@ -979,3 +1019,118 @@ Delete a local workspace and revoke its token (default: the one registered for t
979
1019
  Options:
980
1020
  --id <id> Workspace id (see `gcli workspace:list`)
981
1021
  -h, --help display help for command
1022
+ 
1023
+ --- Subcommand: workflow:list ---
1024
+ Usage: gcli workflow:list [options]
1025
+
1026
+ List the project workflows
1027
+
1028
+ Options:
1029
+ -p, --project <project>
1030
+ -h, --help display help for command
1031
+ 
1032
+ --- Subcommand: workflow:get ---
1033
+ Usage: gcli workflow:get [options]
1034
+
1035
+ Print a workflow as YAML (the format workflow:apply reads), or write it with -o
1036
+
1037
+ Options:
1038
+ -p, --project <project>
1039
+ -n, --name <name> Workflow name
1040
+ -o, --out <file> Write the YAML to this file
1041
+ -h, --help display help for command
1042
+ 
1043
+ --- Subcommand: workflow:generate ---
1044
+ Usage: gcli workflow:generate [options]
1045
+
1046
+ Draft a workflow with AI from plain language (or change one with --name / --from). Prints or writes YAML; saves only with --apply
1047
+
1048
+ Options:
1049
+ -p, --project <project>
1050
+ -d, --description <text> What the workflow should do, e.g. "charge the card
1051
+ with retries, then email the receipt"
1052
+ -n, --name <name> Workflow name: an existing one is changed, a new
1053
+ one is named so
1054
+ --from <file> Change this workflow file instead
1055
+ -o, --out <file> Write the draft YAML to this file
1056
+ --apply Save the draft as the workflow (needs a name)
1057
+ -h, --help display help for command
1058
+ 
1059
+ --- Subcommand: workflow:apply ---
1060
+ Usage: gcli workflow:apply [options]
1061
+
1062
+ Create or update a workflow from a YAML/JSON file (workflow: {name, description, definition})
1063
+
1064
+ Options:
1065
+ -p, --project <project>
1066
+ -f, --file <file> Workflow file
1067
+ -n, --name <name> Overrides workflow.name from the file
1068
+ -d, --description <text> Overrides workflow.description
1069
+ -h, --help display help for command
1070
+ 
1071
+ --- Subcommand: workflow:validate ---
1072
+ Usage: gcli workflow:validate [options]
1073
+
1074
+ Check a workflow file against the cluster (lambdas exist, graph is valid)
1075
+
1076
+ Options:
1077
+ -p, --project <project>
1078
+ -f, --file <file> Workflow file
1079
+ -h, --help display help for command
1080
+ 
1081
+ --- Subcommand: workflow:delete ---
1082
+ Usage: gcli workflow:delete [options]
1083
+
1084
+ Delete a workflow and all of its runs
1085
+
1086
+ Options:
1087
+ -p, --project <project>
1088
+ -n, --name <name> Workflow name
1089
+ -h, --help display help for command
1090
+ 
1091
+ --- Subcommand: workflow:run ---
1092
+ Usage: gcli workflow:run [options]
1093
+
1094
+ Start a run; the JSON input is the first step request body. --wait follows it to the end
1095
+
1096
+ Options:
1097
+ -p, --project <project>
1098
+ -n, --name <name> Workflow name
1099
+ -i, --input <json> Run input as JSON (default {})
1100
+ --input-file <file> Read the run input from a JSON file
1101
+ -w, --wait Print each step as it happens until the run ends
1102
+ -h, --help display help for command
1103
+ 
1104
+ --- Subcommand: workflow:runs ---
1105
+ Usage: gcli workflow:runs [options]
1106
+
1107
+ List a workflow runs, newest first
1108
+
1109
+ Options:
1110
+ -p, --project <project>
1111
+ -n, --name <name> Workflow name
1112
+ -l, --limit <limit> How many (default 50)
1113
+ -h, --help display help for command
1114
+ 
1115
+ --- Subcommand: workflow:status ---
1116
+ Usage: gcli workflow:status [options]
1117
+
1118
+ Show a run: its step events, error and output (--follow until it ends)
1119
+
1120
+ Options:
1121
+ -p, --project <project>
1122
+ -n, --name <name> Workflow name
1123
+ -r, --run <run> Run name (see workflow:runs)
1124
+ -f, --follow Keep printing events until the run ends
1125
+ -h, --help display help for command
1126
+ 
1127
+ --- Subcommand: workflow:cancel ---
1128
+ Usage: gcli workflow:cancel [options]
1129
+
1130
+ Cancel a running run
1131
+
1132
+ Options:
1133
+ -p, --project <project>
1134
+ -n, --name <name> Workflow name
1135
+ -r, --run <run> Run name (see workflow:runs)
1136
+ -h, --help display help for command
package/README.md CHANGED
@@ -761,6 +761,61 @@ gcli cron:list
761
761
  gcli cron:delete --lambdaName 'my-function'
762
762
  ```
763
763
 
764
+ ### Workflows
765
+
766
+ A workflow runs several lambdas as one process: each step gets the previous
767
+ step's response, steps can retry, branch (Choice), fan out (Parallel / Map)
768
+ or wait, and every run is recorded step by step. Workflows must be included
769
+ in the project's plan (`allowWorkflows`).
770
+
771
+ ```bash
772
+ # Draft one with AI from plain language (MiniMax), review the YAML, save it
773
+ gcli workflow:generate -d "charge the card with retries; if it fails wait 1h and email the customer; otherwise send the receipt" -o order-flow.yaml
774
+ gcli workflow:apply -f order-flow.yaml --name order-flow # create or update by name
775
+
776
+ # Or change an existing one in place
777
+ gcli workflow:generate --name order-flow -d "add a 5 minute wait before the email" --apply
778
+
779
+ # Run it and watch each step
780
+ gcli workflow:run --name order-flow --input '{"orderId": 42}' --wait
781
+ gcli workflow:runs --name order-flow
782
+ gcli workflow:status --name order-flow --run order-flow-abc12 --follow
783
+ gcli workflow:cancel --name order-flow --run order-flow-abc12
784
+
785
+ gcli workflow:list
786
+ gcli workflow:get --name order-flow -o order-flow.yaml # edit, then workflow:apply
787
+ gcli workflow:validate -f order-flow.yaml
788
+ gcli workflow:delete --name order-flow # also deletes its runs
789
+ ```
790
+
791
+ The file `workflow:get` / `workflow:generate` write (and `workflow:apply`
792
+ reads) - a Fission `kind: Workflow` manifest or a bare `startAt` + `states`
793
+ works too:
794
+
795
+ ```yaml
796
+ workflow:
797
+ name: order-flow
798
+ description: Charge, then mail the receipt
799
+ definition:
800
+ startAt: charge
801
+ states:
802
+ charge:
803
+ type: Task
804
+ function: { type: name, name: charge }
805
+ retry: { maxAttempts: 3, backoffBase: 2s, backoffCap: 30s }
806
+ next: mail
807
+ mail:
808
+ type: Task
809
+ function: { type: name, name: mailer }
810
+ end: true
811
+ ```
812
+
813
+ Step types: Task (call a lambda), Choice (branch on a value), Parallel,
814
+ Map (once per list item), Wait (durable pause), Succeed, Fail. A step gets
815
+ one attempt unless it has `retry`. Runs can only be started by
816
+ `workflow:run` (or the UI / API) - HTTP and cron triggers cannot start a
817
+ workflow yet.
818
+
764
819
  ### Monitoring & Testing
765
820
 
766
821
  Debug your functions directly from the terminal.
@@ -890,7 +945,7 @@ running until Ctrl+C and reconnects on its own.
890
945
  | `gcli runner:list` | Your runners: online status, last seen, models |
891
946
  | `gcli runner:models` | List which models are shown in the chat; `--show a,b` shows only those, `--all` shows every model, `--none` hides them all; `--id` picks a runner (default: this machine's) |
892
947
  | `gcli runner:delete` | Delete a runner and revoke its token (`--id`, default: this machine's) |
893
- | `gcli runner:start:daemon` / `runner:daemon:install` | Install + start the runner as a systemd user service (Linux); `runner:daemon:status`, `runner:daemon:logs`, `runner:daemon:uninstall` manage it |
948
+ | `gcli runner:start:daemon` / `runner:daemon:install` | Install + start the runner as a systemd user service (Linux); `runner:daemon:start`, `:stop`, `:restart`, `:status`, `:logs`, `:uninstall` manage it |
894
949
 
895
950
  ### Run it in the background (systemd, Linux)
896
951
 
@@ -899,6 +954,9 @@ npm i -g @gapi/gcli # a stable install - not the npx cache
899
954
  gcli login
900
955
  gcli runner:start:daemon # = runner:daemon:install; same options as runner:start
901
956
  gcli runner:daemon:status
957
+ gcli runner:daemon:stop # stop it (stays installed, starts at next login)
958
+ gcli runner:daemon:start # start it again; tells you if it does not stay up
959
+ gcli runner:daemon:restart # e.g. after `gcli login` to another server
902
960
  gcli runner:daemon:logs # follow the log (Ctrl+C to stop following)
903
961
  gcli runner:daemon:uninstall # stop + remove the service (runner stays registered)
904
962
  ```
@@ -0,0 +1,25 @@
1
+ ## 2026-10-24 - local-ai-runners: runner:daemon:start / stop / restart, and start reports whether the runner stays up
2
+
3
+ **Feature:** local-ai-runners · **Type:** feat
4
+
5
+ Why: after `runner:daemon:install` there was no gcli way to start or stop the service (only raw `systemctl --user`), and a service whose token Lambforge refuses failed silently: `runner:daemon:status` showed `status=78` with no explanation of what to do.
6
+
7
+ - New commands (`src/commands/runner/index.ts`, `daemon-commands.ts`), all with `--service`:
8
+ - `runner:daemon:start` and `runner:daemon:restart` run `systemctl --user start/restart`. After ~2 s, `reportStarted` reads `ActiveState`/`ExecMainStatus` (`SystemdUserService.outcome`) and reports:
9
+ - running: says so;
10
+ - exit 78 (`RUNNER_AUTH_EXIT_CODE`): the token was refused - the runner was deleted, or registered on another server than `~/.graphql-server/url` - with the hint to re-register via `gcli runner:daemon:install --reset`;
11
+ - any other exit: points to `runner:daemon:logs`.
12
+ - `runner:daemon:stop`: `systemctl --user stop`. The unit stays enabled and starts at the next login; `uninstall` removes it.
13
+ - All three refuse with "not installed - run `gcli runner:daemon:install` first" when the unit file is missing.
14
+ - `SystemdUserService`: `installed()`, `start()`, `stop()`, `restart()`, `outcome()`.
15
+ - README, `README-CLI.md` (regenerated) and `docs/features/local-ai-runners.md` updated.
16
+ - **Test:**
17
+ - `npx jest --coverage=false test/runner-daemon.spec.ts` covers: the systemctl calls, `installed()`, and the three `reportStarted` outcomes.
18
+ - Live: `gcli runner:daemon:stop`, `gcli runner:daemon:start`, then `gcli runner:daemon:status`.
19
+ - **Debug:**
20
+ - "did not stay up": `gcli runner:daemon:logs`.
21
+ - "refused this runner's token": compare `~/.graphql-server/url` with the server the runner was registered on, then `runner:daemon:install --reset`.
22
+ - **Verification:**
23
+ - jest: 11 suites, 103 tests pass (4 new). `tsc --noEmit` and eslint are clean.
24
+ - `npm run build`: `--help` lists the new commands.
25
+ - Not run against the real systemd unit.
@@ -0,0 +1,8 @@
1
+ ## 2026-10-25 - workflows: workflow commands with AI drafts
2
+
3
+ **Feature:** workflows · **Type:** feat
4
+
5
+ - New `workflow:*` commands (`src/commands/workflow/`): list, get (YAML), generate (AI draft via `generateWorkflowDraft`, from plain language or as a change to an existing workflow / file; `-o` writes YAML, `--apply` saves), apply (create or update by name), validate, delete, run (`--wait` prints each step event live until the run ends), runs, status (`--follow`), cancel. Workflows are addressed by name. Files: `workflow: {name, description, definition}`, a `kind: Workflow` manifest, or a bare definition. API in `gql-client.ts` (Workflows section), fragments in `services/types/workflow.fragment.ts`.
6
+ - **Test:** `npx jest --coverage=false test/workflow.spec.ts` (file shapes, input parsing, event rendering, apply create/update, generate change + apply, run --wait).
7
+ - **Debug:** see `docs/features/workflows.md`; the commands need a user login (not granted to CI tokens yet).
8
+ - **Verification:** jest 6/6; tsc + eslint clean; build OK and `--help` lists the 10 commands (`release/index.js` restored, README-CLI.md regenerated); all 10 GraphQL documents validated against the live local gateway schema. Not run end to end here: the gcli login points at production, which has no workflows yet.
@@ -35,3 +35,4 @@ Outline (drop sections that don't apply):
35
35
  | `lambforge-agent-skill` | [lambforge-agent-skill.md](lambforge-agent-skill.md) | The agent skill that teaches gcli + `mcp:start`; canonical doc in gql-fission |
36
36
  | `dedicated-platform-cluster` | [dedicated-platform-cluster.md](dedicated-platform-cluster.md) | `cluster:status/health/scale/autoscale/...` commands; canonical doc in lambforge-agent |
37
37
  | `ci-token-scopes` | [ci-token-scopes.md](ci-token-scopes.md) | Which permission each command needs; `mq-trigger:*` commands; canonical doc in graphql-server |
38
+ | `workflows` | [workflows.md](workflows.md) | `workflow:*` commands incl. AI drafts (`workflow:generate`); canonical doc in graphql-server-lambdas |
@@ -14,6 +14,8 @@ what lives in gcli.
14
14
  | `gcli runner:models [--id] [--show a,b \| --all \| --none]` | Which models appear in the chat picker; no flag = list |
15
15
  | `gcli runner:delete [--id]` | Delete a runner and revoke its token (default: the saved one) |
16
16
  | `gcli runner:daemon:install` (alias `runner:start:daemon`) `[runner:start options] [--service] [--dry-run]` | Resolve/register the runner now (saves `runner.json`), then install + enable + restart a systemd USER unit running `runner:start --ollama <resolved>` (Linux) |
17
+ | `gcli runner:daemon:start` / `:restart` `[--service]` | `systemctl --user start/restart`, then after ~2 s reads `ActiveState`/`ExecMainStatus` (`SystemdUserService.outcome`): running, or an error - exit 78 = token refused (deleted, or registered on another server than `~/.graphql-server/url`) with the `runner:daemon:install --reset` hint. Refuses when the unit is not installed |
18
+ | `gcli runner:daemon:stop` `[--service]` | `systemctl --user stop` (stays enabled: starts again at the next login) |
17
19
  | `gcli runner:daemon:status` / `:logs` / `:uninstall` | `systemctl --user status`, `journalctl --user -f`, disable --now + remove the unit |
18
20
 
19
21
  Endpoints: `--wsUrl` > `runner.json` > derived from the `gcli login` URL
@@ -0,0 +1,49 @@
1
+ # Workflows — gcli slice
2
+
3
+ **Feature slug:** `workflows` · canonical doc:
4
+ `graphql-server-lambdas/docs/features/workflows.md` (AI drafts:
5
+ `graphql-server/docs/features/workflows.md`).
6
+
7
+ `workflow:*` commands (`src/commands/workflow/`), all as the `gcli login`
8
+ user through the gateway; workflows are addressed by **name** (resolved to
9
+ the id with `listWorkflows`):
10
+
11
+ | Command | API |
12
+ |---|---|
13
+ | `workflow:list` | `listWorkflows` |
14
+ | `workflow:get -n [-o file]` | `listWorkflows` → YAML |
15
+ | `workflow:generate -d "..." [-n name \| --from file] [-o file] [--apply]` | `generateWorkflowDraft` (graphql-server, MiniMax M3.1 Flash); `--apply` = `workflow:apply` |
16
+ | `workflow:apply -f file [-n] [-d]` | `createWorkflow`, or `updateWorkflow` when the name exists |
17
+ | `workflow:validate -f file` | `validateWorkflow` (graph + lambdas on the cluster) |
18
+ | `workflow:delete -n` | `deleteWorkflow` (runs too) |
19
+ | `workflow:run -n [-i json \| --input-file] [--wait]` | `startWorkflowRun`; `--wait` polls `getWorkflowRun` every 2 s and prints each new event until the run is terminal |
20
+ | `workflow:runs -n [-l]` | `listWorkflowRuns` |
21
+ | `workflow:status -n -r run [--follow]` | `getWorkflowRun` (events, error, output) |
22
+ | `workflow:cancel -n -r run` | `cancelWorkflowRun` |
23
+
24
+ The workflow file (`definition.ts` `parseWorkflowFile`) accepts
25
+ `workflow: {name, description, clusterId, definition}`, the same without the
26
+ `workflow:` key, a Fission `kind: Workflow` manifest, or a bare definition;
27
+ `toWorkflowYaml` writes the first form. API calls are in
28
+ `src/services/gql-client.ts` (Workflows section), selection sets in
29
+ `src/services/types/workflow.fragment.ts`, types in
30
+ `src/commands/workflow/types.ts`.
31
+
32
+ Not granted to CI tokens (INTEGRATION role) yet: the workflow resolvers are
33
+ USER-only in graphql-server-lambdas, so these commands need `gcli login`.
34
+
35
+ ## How to test
36
+
37
+ `npx jest --coverage=false test/workflow.spec.ts`. Real: log in to a
38
+ gateway whose project has `allowWorkflows`, then
39
+ `gcli workflow:generate -d "..." -n demo --apply` and
40
+ `gcli workflow:run -n demo --wait`.
41
+
42
+ ## How to debug
43
+
44
+ - `No workflow "x"`: names are per project (`-p` or the `gcli login`
45
+ project).
46
+ - `Workflows are not available on your current plan`: the plan lacks
47
+ `allowWorkflows`.
48
+ - `Workflows are not enabled on this cluster`: the cluster runs Fission
49
+ without `workflows.enabled` (canonical doc, Requires).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gapi/gcli",
3
- "version": "1.8.244",
3
+ "version": "1.8.246",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/Stradivario/gapi.git"