graphban-cli 0.8.0__tar.gz → 0.8.2__tar.gz

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.
Files changed (34) hide show
  1. {graphban_cli-0.8.0 → graphban_cli-0.8.2}/PKG-INFO +5 -3
  2. {graphban_cli-0.8.0 → graphban_cli-0.8.2}/README.md +4 -2
  3. {graphban_cli-0.8.0 → graphban_cli-0.8.2}/pyproject.toml +1 -1
  4. {graphban_cli-0.8.0 → graphban_cli-0.8.2}/src/gban/cli.py +3 -1
  5. {graphban_cli-0.8.0 → graphban_cli-0.8.2}/src/gban/data/stack_sdks.toml +31 -0
  6. {graphban_cli-0.8.0 → graphban_cli-0.8.2}/src/gban/skills/graphban-delegation/SKILL.md +7 -4
  7. graphban_cli-0.8.2/src/gban/skills/graphban-grill/SKILL.md +56 -0
  8. graphban_cli-0.8.2/src/gban/skills/graphban-scan/SKILL.md +31 -0
  9. graphban_cli-0.8.2/src/gban/skills/graphban-wave/SKILL.md +64 -0
  10. {graphban_cli-0.8.0 → graphban_cli-0.8.2}/src/gban/stackmap.py +475 -74
  11. {graphban_cli-0.8.0 → graphban_cli-0.8.2}/tests/test_setup.py +16 -0
  12. {graphban_cli-0.8.0 → graphban_cli-0.8.2}/tests/test_stackmap.py +236 -14
  13. graphban_cli-0.8.2/uv.lock +207 -0
  14. graphban_cli-0.8.0/src/gban/skills/graphban-scan/SKILL.md +0 -23
  15. {graphban_cli-0.8.0 → graphban_cli-0.8.2}/.gitignore +0 -0
  16. {graphban_cli-0.8.0 → graphban_cli-0.8.2}/LICENSE +0 -0
  17. {graphban_cli-0.8.0 → graphban_cli-0.8.2}/src/gban/__init__.py +0 -0
  18. {graphban_cli-0.8.0 → graphban_cli-0.8.2}/src/gban/client.py +0 -0
  19. {graphban_cli-0.8.0 → graphban_cli-0.8.2}/src/gban/config.py +0 -0
  20. {graphban_cli-0.8.0 → graphban_cli-0.8.2}/src/gban/doctor.py +0 -0
  21. {graphban_cli-0.8.0 → graphban_cli-0.8.2}/src/gban/gitignore.py +0 -0
  22. {graphban_cli-0.8.0 → graphban_cli-0.8.2}/src/gban/setup.py +0 -0
  23. {graphban_cli-0.8.0 → graphban_cli-0.8.2}/src/gban/skills/graphban-orient/SKILL.md +0 -0
  24. {graphban_cli-0.8.0 → graphban_cli-0.8.2}/src/gban/skills/graphban-prd/SKILL.md +0 -0
  25. {graphban_cli-0.8.0 → graphban_cli-0.8.2}/src/gban/skills/graphban-review/SKILL.md +0 -0
  26. {graphban_cli-0.8.0 → graphban_cli-0.8.2}/src/gban/skills/graphban-work/SKILL.md +0 -0
  27. {graphban_cli-0.8.0 → graphban_cli-0.8.2}/src/gban/skills/watch-wave/SKILL.md +0 -0
  28. {graphban_cli-0.8.0 → graphban_cli-0.8.2}/src/gban/swamp.py +0 -0
  29. {graphban_cli-0.8.0 → graphban_cli-0.8.2}/tests/test_acts.py +0 -0
  30. {graphban_cli-0.8.0 → graphban_cli-0.8.2}/tests/test_doctor.py +0 -0
  31. {graphban_cli-0.8.0 → graphban_cli-0.8.2}/tests/test_login_projects.py +0 -0
  32. {graphban_cli-0.8.0 → graphban_cli-0.8.2}/tests/test_packaging.py +0 -0
  33. {graphban_cli-0.8.0 → graphban_cli-0.8.2}/tests/test_session.py +0 -0
  34. {graphban_cli-0.8.0 → graphban_cli-0.8.2}/tests/test_swamp.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: graphban-cli
3
- Version: 0.8.0
3
+ Version: 0.8.2
4
4
  Summary: gban — a Graphban client for the human at a terminal
5
5
  Project-URL: Homepage, https://github.com/asc-me/graphban
6
6
  Project-URL: Repository, https://github.com/asc-me/graphban
@@ -202,8 +202,10 @@ What it reads:
202
202
 
203
203
  - Compose files (`compose.yml`, `docker-compose.yml`, and the `compose.*` / `docker-compose.*` variants): a service with `build` is a deployable, a service with only `image` is infrastructure, and `depends_on` is an edge. `environment` contributes variable **names** and, when a value is a literal URL, the bare host.
204
204
  - Dockerfiles (`Dockerfile`, `Dockerfile.*`, `*.Dockerfile`), for the deployable they sit in and for a `FROM` image the table knows.
205
- - Dependency manifests (`package.json`, `pyproject.toml`, `requirements*.txt`, `go.mod`, `Cargo.toml`, `Gemfile`), matched against the known-SDK table and attributed to the deployable whose directory contains them.
206
- - `.env.example` only. A real `.env` is not a template and is not opened. Source files are not scanned.
205
+ - Dependency manifests (`package.json`, `pyproject.toml`, `requirements*.txt`, `go.mod`, `Cargo.toml`, `Gemfile`). Every `package.json` and `Cargo.toml` is a component named from the manifest's `name`. The known-SDK table adds edges; it is not what decides whether the component exists. `file:` and `workspace:` dependencies (and a Cargo `path` or `workspace = true`) are internal edges. Other manifests still become a component only when a dependency hits the table, and that edge is attributed to the component whose directory contains the file.
206
+ - Deploy manifests (`vercel.json`, `railway.json`, `railway.toml`, `fly.toml`, `netlify.toml`, `render.yaml`) are a platform node. The file body is not stored.
207
+ - `.env.example` only. A real `.env` is not a template and is not opened. A commented `KEY=` is read and the edge is `state: documented` rather than `set`. `*_TOKEN`, `*_CLIENT_ID`, and `*_CLIENT_SECRET` count, and so do `*_BASE` and `*_ISSUER` when the value is a URL. A passphrase (`AUTH_SECRET`, `ENCRYPTION_KEY`) is not an edge unless a table row names it. Values stay out of the record.
208
+ - Source files are not scanned. There is no source-HTTP pass in this command. stderr always prints a coverage line: files read, files that produced nothing, commented template keys skipped, and that source was not scanned. Exit 0 means the record was built.
207
209
 
208
210
  The known-SDK table ships at `cli/src/gban/data/stack_sdks.toml` and is versioned with `gban`. A checkout may add rows in `.graphban/stack-sdks.toml` (same shape); those rows are consulted first.
209
211
 
@@ -187,8 +187,10 @@ What it reads:
187
187
 
188
188
  - Compose files (`compose.yml`, `docker-compose.yml`, and the `compose.*` / `docker-compose.*` variants): a service with `build` is a deployable, a service with only `image` is infrastructure, and `depends_on` is an edge. `environment` contributes variable **names** and, when a value is a literal URL, the bare host.
189
189
  - Dockerfiles (`Dockerfile`, `Dockerfile.*`, `*.Dockerfile`), for the deployable they sit in and for a `FROM` image the table knows.
190
- - Dependency manifests (`package.json`, `pyproject.toml`, `requirements*.txt`, `go.mod`, `Cargo.toml`, `Gemfile`), matched against the known-SDK table and attributed to the deployable whose directory contains them.
191
- - `.env.example` only. A real `.env` is not a template and is not opened. Source files are not scanned.
190
+ - Dependency manifests (`package.json`, `pyproject.toml`, `requirements*.txt`, `go.mod`, `Cargo.toml`, `Gemfile`). Every `package.json` and `Cargo.toml` is a component named from the manifest's `name`. The known-SDK table adds edges; it is not what decides whether the component exists. `file:` and `workspace:` dependencies (and a Cargo `path` or `workspace = true`) are internal edges. Other manifests still become a component only when a dependency hits the table, and that edge is attributed to the component whose directory contains the file.
191
+ - Deploy manifests (`vercel.json`, `railway.json`, `railway.toml`, `fly.toml`, `netlify.toml`, `render.yaml`) are a platform node. The file body is not stored.
192
+ - `.env.example` only. A real `.env` is not a template and is not opened. A commented `KEY=` is read and the edge is `state: documented` rather than `set`. `*_TOKEN`, `*_CLIENT_ID`, and `*_CLIENT_SECRET` count, and so do `*_BASE` and `*_ISSUER` when the value is a URL. A passphrase (`AUTH_SECRET`, `ENCRYPTION_KEY`) is not an edge unless a table row names it. Values stay out of the record.
193
+ - Source files are not scanned. There is no source-HTTP pass in this command. stderr always prints a coverage line: files read, files that produced nothing, commented template keys skipped, and that source was not scanned. Exit 0 means the record was built.
192
194
 
193
195
  The known-SDK table ships at `cli/src/gban/data/stack_sdks.toml` and is versioned with `gban`. A checkout may add rows in `.graphban/stack-sdks.toml` (same shape); those rows are consulted first.
194
196
 
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "graphban-cli"
3
- version = "0.8.0"
3
+ version = "0.8.2"
4
4
  description = "gban — a Graphban client for the human at a terminal"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.12"
@@ -433,12 +433,14 @@ def cmd_stack(args) -> int:
433
433
  start = Path(args.repo).expanduser() if args.repo else Path.cwd()
434
434
  project = (config.resolve(args.project, config.PROJECT_ENV, "project") or "").strip()
435
435
  try:
436
- record, warnings = stackmap.build_record(start, project_id=project)
436
+ record, warnings, coverage = stackmap.build_record(start, project_id=project)
437
437
  except stackmap.MapError as exc:
438
438
  print(f"{PROG}: {exc}", file=sys.stderr)
439
439
  return EXIT_REFUSED
440
440
  for warning in warnings:
441
441
  print(f"{PROG}: {warning}", file=sys.stderr)
442
+ # Always. A three-node map that exits 0 is not a finished topology.
443
+ print(f"{PROG}: {coverage}", file=sys.stderr)
442
444
  text = stackmap.canonical(record)
443
445
  if args.dry_run:
444
446
  sys.stdout.write(text)
@@ -148,6 +148,27 @@ label = "SendGrid"
148
148
  protocol = "https"
149
149
  domains = ["sendgrid.com", "sendgrid.net"]
150
150
 
151
+ [[sdk]]
152
+ id = "resend"
153
+ packages = ["resend"]
154
+ node = "resend"
155
+ group = "external"
156
+ kind = ""
157
+ label = "Resend"
158
+ protocol = "https"
159
+ domains = ["resend.com"]
160
+
161
+ [[sdk]]
162
+ id = "vercel"
163
+ packages = ["@vercel/functions"]
164
+ prefix = "@vercel/"
165
+ node = "vercel"
166
+ group = "external"
167
+ kind = ""
168
+ label = "Vercel"
169
+ protocol = "https"
170
+ domains = ["vercel.com", "vercel.app"]
171
+
151
172
  [[sdk]]
152
173
  id = "supabase"
153
174
  packages = ["supabase", "@supabase/supabase-js"]
@@ -175,3 +196,13 @@ group = "infrastructure"
175
196
  kind = "redis"
176
197
  label = "Redis"
177
198
  protocol = "redis"
199
+
200
+ [[env]]
201
+ id = "creem"
202
+ names = ["CREEM_API_KEY"]
203
+ node = "creem"
204
+ group = "external"
205
+ kind = ""
206
+ label = "Creem"
207
+ protocol = "https"
208
+ domains = ["creem.io"]
@@ -1,6 +1,10 @@
1
1
  ---
2
2
  name: graphban-delegation
3
- description: Hand a Graphban work item to a child agent running on a cheaper model, and enable delegation on a project that does not have it yet. Use when asked to delegate, fan out, spawn a worker, mint seats, retire a wave, or run a wave.
3
+ description: >
4
+ Hand one Graphban item to one child on a cheaper model, and enable
5
+ delegation on a project that does not have it yet. Use when asked to
6
+ delegate one item, spawn one worker, mint seats, or retire a wave.
7
+ A whole PRD is /graphban-wave.
4
8
  ---
5
9
 
6
10
  # Delegating a Graphban item
@@ -197,6 +201,5 @@ So a delegated item needs a second agent to review it. Plan for that, or the wor
197
201
 
198
202
  ## When not to use this
199
203
 
200
- For a whole backlog, ask the person to run `gbfleet until` instead. It runs the wave with no
201
- model in the loop; fanning the same work out by hand keeps your context awake for the wave's
202
- entire length just to poll and adjudicate.
204
+ A whole PRD is `graphban-wave`. It runs `gbfleet until` for that PRD. Fanning the items out
205
+ from here keeps a frontier context polling for the wave's whole length.
@@ -0,0 +1,56 @@
1
+ ---
2
+ name: graphban-grill
3
+ description: >
4
+ Settle a Graphban PRD grill from the product why and the PRD's intent.
5
+ Auto-record answers the context already decides, and ask the user only
6
+ the questions it does not. Use when grilling a PRD, running a grill,
7
+ answer_grill, or when the user runs /graphban-grill.
8
+ user-invocable: true
9
+ ---
10
+
11
+ # Grill
12
+
13
+ `grill_prd` returns questions and records nothing. An answer counts only after `answer_grill`. The grader ignores the PRD body: a decision that exists only in the document is still unanswered.
14
+
15
+ ## Sources
16
+
17
+ Read both before you classify a question.
18
+
19
+ 1. `get_prd`. The intent is the framing: Problem, Goals, Non-goals, and an intent heading when the PRD has one.
20
+ 2. Why the app exists: `docs/product-overview.md` (philosophy, goals, non-goals) and `docs/design-philosophy.md`. This bounds the PRD. It does not fill a hole the PRD left open.
21
+
22
+ A source decides a question only when you can quote the sentence. Memory, code, and a guess are not sources.
23
+
24
+ ## Split
25
+
26
+ For each question, write a one- or two-sentence recommendation, then:
27
+
28
+ - **accept** — that sentence already decides it, the two sources do not conflict, and the answer is words rather than a prototype. Record it.
29
+ - **ask** — the sources are silent, they conflict, both readings are reasonable, or the question needs a prototype. These are the only questions you put to the user.
30
+
31
+ Silence is ask. A fluent inference is ask. Do not accept a new boundary, a new error behavior, or a new contract field that neither source states.
32
+
33
+ ## Record an accept
34
+
35
+ Fold the decision into the PRD with `update_prd(section=...)` first. Then `answer_grill` once, with that decision alone.
36
+
37
+ One call per decision. A reply that covers several dimensions is one answer, and the grader leaves the rest outstanding.
38
+
39
+ Say `deferred` only when a source already defers it. "Later" without that word stays unanswered.
40
+
41
+ Read the return:
42
+
43
+ - `graded: false` — stop. Say `ungraded_reason`. Do not send another answer.
44
+ - `stalled: true` — stop. Tell the user. Three answers moved nothing.
45
+ - `complete: true` — the grill finished and the body just froze. The fold had to happen before this call.
46
+ - `body_absorbed: false` — the transcript is ahead of the spec. Fold the answers it names before you continue.
47
+
48
+ Do not set `approved`. Finishing the grill does that.
49
+
50
+ ## Ask
51
+
52
+ Show only the ask list. For each: the question, the recommendation, and one line on why the sources do not decide it.
53
+
54
+ Record nothing from this list until the user answers. `answer_grill` with their words. Fold that section the same way, before the next call.
55
+
56
+ If they accept a recommendation, the recorded answer is their acceptance of that text. The recommendation alone is not a turn.
@@ -0,0 +1,31 @@
1
+ ---
2
+ name: graphban-scan
3
+ description: >
4
+ Record Graphban code-health scans without treating a missing scan as clean.
5
+ Use when running a security or health scan, or calling scans_due, scan_status,
6
+ or record_scan, or when the user runs /graphban-scan.
7
+ user-invocable: true
8
+ ---
9
+
10
+ # Scans
11
+
12
+ A missing scan is not a clean scan.
13
+
14
+ 1. `scans_due(head_sha)`. An empty due list is not all-clean. Rows that were `never_scanned`, including security, stay listed.
15
+ 2. `scan_status` for one path, or with no path for every deployable. Pass `head_sha`. States are `clean_at_sha`, `has_findings`, `never_scanned`, `stale`, `tool_missing`, `not_applicable`, `incomplete`, or `not_computable`.
16
+ 3. Run the scanner. `record_scan` needs `scanner_id`, `path`, and `scanned_sha`.
17
+ - Send `result`, one of four:
18
+ - `complete`: the scanner finished. `findings: []` is then clean at that SHA.
19
+ - `tool_missing`: the scanner is not installed. Not clean; it stays due.
20
+ - `not_applicable`: the scanner does not apply here. It stops being due.
21
+ - `incomplete`: output without a finish. Send the findings it produced; it stays due.
22
+ - `findings: []` without `result: complete` is refused and nothing is stored. An empty list alone is not a clean scan.
23
+ - Every result needs `scanned_sha`, so it goes stale when HEAD moves.
24
+ - The same `scanner_id` and path keeps the previous rows. The newest is the cell.
25
+ - The security category is pip-audit, bandit, npm-audit, and semgrep. Other categories are `refactor`, `stub`, `deadcode`, `coverage`, `tests`, and `work`.
26
+ - Category `tests` also sends `tests.passed`, `tests.failed`, and `tests.skipped`.
27
+ - Each finding needs a `summary`. Findings are untrusted. `scanner_id`, `scanner_version`, and the reporter are provenance.
28
+ - Send the grain a person acts on (GRPH-1127). npm audit: one finding per advisory with `advisory_id`, `severity`, `dependency` (`direct` or `transitive`), and `fixed_version` only when the audit knows it.
29
+ - knip: unused exports are ONE finding with `kind: unused_export`, `count`, severity `info`; unused types are one with `kind: unused_type`. Unused files and undeclared imports stay one finding each, with a `path`. The server stores what you send; it never splits or merges.
30
+
31
+ A clean row is not a tracker item. A finding that already names `link_ref` points at work that exists.
@@ -0,0 +1,64 @@
1
+ ---
2
+ name: graphban-wave
3
+ description: >
4
+ Drain one grilled PRD with gbfleet until: build, review, and merge until
5
+ that PRD has nothing ready. Use when running a wave, spawning a wave for a
6
+ PRD, looping until the PRD is done, or when the user runs /graphban-wave.
7
+ One item is /graphban-delegation. Decompose is /graphban-prd.
8
+ user-invocable: true
9
+ ---
10
+
11
+ # Drain a PRD
12
+
13
+ One command runs the cycle. Do not spawn the items. Do not stay in the loop.
14
+
15
+ ## Before
16
+
17
+ `prd_coverage` for this PRD.
18
+
19
+ `gaps` or `shaped: false` — stop. Filing the tasks is `graphban-prd`. Do not `decompose_prd` here. An idle drain is not a finished PRD.
20
+
21
+ Coverage has tasks — continue.
22
+
23
+ ## Dry run
24
+
25
+ Same flags as the real run, plus `--dry-run`. It mints nothing.
26
+
27
+ ```bash
28
+ gbfleet until --repo . --server <url> --project <id> --adapter <vendor> \
29
+ --prd <prd_id> --merge \
30
+ --tier cheap=<adapter[:model]> --tier frontier=<adapter[:model]> \
31
+ --dry-run
32
+ ```
33
+
34
+ `--prd` is required. Without it the loop drains every ready item in the project. `backlog` is claimable, so parking work there does not scope the wave. `--prd` refuses a pre-minted seats file.
35
+
36
+ Read the dry run before installing. Held clusters name who holds them. `predicted: true` is a lower-confidence grouping. A plan for the wrong PRD is a stop.
37
+
38
+ A backend change whose acceptance is the Postgres suite needs `--allow psql` on both the dry run and the install.
39
+
40
+ ## Run
41
+
42
+ Drop `--dry-run` and hand the process to the machine. This session ending must not kill it.
43
+
44
+ ```bash
45
+ gbfleet service install --name <prd_id> -- --repo . --server <url> --project <id> \
46
+ --adapter <vendor> --prd <prd_id> --merge \
47
+ --tier cheap=<adapter[:model]> --tier frontier=<adapter[:model]>
48
+ ```
49
+
50
+ `--tier` is what a tier means on this machine. Omit a tier the Fleet tier map already pins. `--request cheap` or `--request frontier` forces every delegation to that tier. The default follows each item's brief. Do not pick a model per item.
51
+
52
+ A service already installed under that name: `gbfleet service status --name <prd_id>` and leave it. A second `until` on the same repo mints another child onto the same cluster.
53
+
54
+ `gbfleet service status` prints the PATH the unit captured. An empty PATH is a drain that will not find the adapter. The API key is the one already stored for this repo. Do not print it, and do not pass a new one.
55
+
56
+ ## While it runs
57
+
58
+ Status is `gbfleet service status --name <prd_id>`. The ledger is `fleet_status`. Do not attach a spawn watcher, and do not spawn a replacement.
59
+
60
+ `until` is idle when that PRD has nothing ready, nothing unsigned, and no live lease. `WAVE_IDLE` while items are still `next`, or held in review, is not done.
61
+
62
+ `review-unsigned` can be a review row outside this PRD. Say which item. Do not start another drain over it, and do not `sign_off` it yourself.
63
+
64
+ `--merge` lands the pull requests this wave opened. Leave every other open pull request. A salvage branch can be the only copy of the work.