@catalyst-cloud/cli 0.13.0 → 0.13.1

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 (137) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/README.md +26 -29
  3. package/dist/args.js +16 -0
  4. package/dist/ask.js +30 -18
  5. package/dist/capabilities.js +5 -0
  6. package/dist/cli.js +18 -5
  7. package/dist/environment.js +1 -1
  8. package/dist/legacy.js +224 -0
  9. package/dist/project.js +129 -0
  10. package/dist/release.js +1 -1
  11. package/dist/repo.js +297 -0
  12. package/dist/runtime-verb.js +1 -1
  13. package/dist/secret.js +1 -1
  14. package/dist/skill-shape.js +21 -13
  15. package/dist/skills.js +44 -4
  16. package/dist/transport.js +26 -1
  17. package/package.json +5 -4
  18. package/skills/catalyst-github/SKILL.md +7 -7
  19. package/skills/catalyst-github/references/is-it-mergeable.md +8 -2
  20. package/skills/catalyst-github/references/what-a-pr-accumulates.md +3 -3
  21. package/skills/catalyst-github/scripts/is-it-mergeable.mjs +3 -3
  22. package/skills/catalyst-github/scripts/lib/cli.mjs +9 -7
  23. package/skills/catalyst-github/scripts/lib/credential.mjs +2 -2
  24. package/skills/catalyst-github/scripts/read-pr.mjs +2 -2
  25. package/skills/catalyst-linear/SKILL.md +17 -19
  26. package/skills/catalyst-linear/agents/openai.yaml +1 -1
  27. package/skills/catalyst-linear/agents/portability.yaml +1 -1
  28. package/skills/catalyst-linear/references/reading-a-ticket.md +9 -26
  29. package/skills/catalyst-linear/references/what-a-ticket-accumulates.md +2 -2
  30. package/skills/catalyst-linear/references/writing-to-linear.md +7 -9
  31. package/skills/catalyst-linear/scripts/comment.mjs +1 -1
  32. package/skills/catalyst-linear/scripts/create-ticket.mjs +1 -1
  33. package/skills/catalyst-linear/scripts/label.mjs +1 -1
  34. package/skills/catalyst-linear/scripts/lib/cli.mjs +9 -7
  35. package/skills/catalyst-linear/scripts/lib/credential.mjs +2 -2
  36. package/skills/catalyst-linear/scripts/move.mjs +1 -1
  37. package/skills/catalyst-linear/scripts/read-ticket.mjs +1 -1
  38. package/skills/catalyst-linear/scripts/search.mjs +1 -1
  39. package/skills/catalyst-onboard/SKILL.md +37 -57
  40. package/skills/catalyst-onboard/agents/openai.yaml +2 -2
  41. package/skills/catalyst-onboard/agents/portability.yaml +1 -1
  42. package/skills/catalyst-onboard/references/connecting-this-machine.md +35 -0
  43. package/skills/catalyst-onboard/references/declaring-a-repository.md +7 -17
  44. package/skills/catalyst-onboard/references/local-sync.md +19 -7
  45. package/skills/catalyst-onboard/references/reading-ready.md +79 -0
  46. package/skills/catalyst-onboard/references/replacing-a-credential.md +8 -33
  47. package/skills/catalyst-onboard/references/repository-agent-setup.md +23 -0
  48. package/skills/catalyst-onboard/references/skill-sources.md +13 -19
  49. package/skills/catalyst-onboard/references/the-one-path.md +18 -74
  50. package/skills/catalyst-onboard/references/what-a-phase-needs.md +21 -28
  51. package/skills/catalyst-onboard/references/what-the-browser-owns.md +20 -37
  52. package/skills/{catalyst-setup → catalyst-onboard}/scripts/check.mjs +10 -9
  53. package/skills/catalyst-onboard/scripts/lib/cli.mjs +6 -4
  54. package/skills/catalyst-onboard/scripts/lib/credential.mjs +2 -2
  55. package/skills/catalyst-onboard/scripts/where-am-i.mjs +60 -4
  56. package/skills/run-this-project/SKILL.md +23 -25
  57. package/skills/run-this-project/agents/openai.yaml +1 -1
  58. package/skills/run-this-project/agents/portability.yaml +1 -1
  59. package/skills/run-this-project/references/making-work-ready.md +20 -37
  60. package/skills/run-this-project/references/reacting-to-events.md +25 -48
  61. package/skills/run-this-project/references/stalls-and-escalation.md +20 -42
  62. package/skills/run-this-project/scripts/lib/cli.mjs +7 -5
  63. package/skills/run-this-project/scripts/lib/credential.mjs +2 -2
  64. package/skills/run-this-project/scripts/scope-status.mjs +0 -0
  65. package/skills/run-this-project/scripts/watch-scope.mjs +1 -1
  66. package/skills/unstick/SKILL.md +12 -12
  67. package/skills/unstick/agents/openai.yaml +1 -1
  68. package/skills/unstick/agents/portability.yaml +1 -1
  69. package/skills/unstick/references/playbook.md +13 -13
  70. package/skills/unstick/scripts/lib/cli.mjs +6 -4
  71. package/skills/unstick/scripts/lib/credential.mjs +2 -2
  72. package/skills/unstick/scripts/unstick.mjs +1 -1
  73. package/skills/what-needs-me/SKILL.md +12 -14
  74. package/skills/what-needs-me/agents/openai.yaml +2 -2
  75. package/skills/what-needs-me/agents/portability.yaml +1 -1
  76. package/skills/what-needs-me/references/raising-a-decision.md +8 -16
  77. package/skills/what-needs-me/references/reading-the-inbox.md +6 -13
  78. package/skills/what-needs-me/references/settling-an-answer.md +6 -12
  79. package/skills/what-needs-me/scripts/inbox.mjs +14 -13
  80. package/skills/what-needs-me/scripts/lib/cli.mjs +6 -4
  81. package/skills/what-needs-me/scripts/lib/credential.mjs +2 -2
  82. package/skills/what-needs-me/scripts/raise.mjs +1 -1
  83. package/skills/what-needs-me/scripts/settle.mjs +1 -1
  84. package/skills/what-this-repo-needs/SKILL.md +10 -19
  85. package/skills/what-this-repo-needs/references/what-each-group-means.md +14 -44
  86. package/skills/what-this-repo-needs/scripts/check.mjs +2 -2
  87. package/skills/what-this-repo-needs/scripts/inventory.mjs +2 -2
  88. package/skills/what-this-repo-needs/scripts/lib/cli.mjs +11 -9
  89. package/skills/what-this-repo-needs/scripts/lib/credential.mjs +2 -2
  90. package/skills/whats-happening/SKILL.md +27 -21
  91. package/skills/whats-happening/agents/openai.yaml +1 -1
  92. package/skills/whats-happening/references/coding-accounts.md +24 -0
  93. package/skills/whats-happening/references/routing-work.md +11 -29
  94. package/skills/whats-happening/references/settings-and-where-they-live.md +20 -0
  95. package/skills/whats-happening/references/stages-and-mapping.md +25 -0
  96. package/skills/whats-happening/references/status-reply.md +21 -23
  97. package/skills/whats-happening/references/the-ladder.md +30 -0
  98. package/skills/whats-happening/references/what-runs-next.md +32 -0
  99. package/skills/whats-happening/references/when-a-phase-fails.md +27 -0
  100. package/skills/whats-happening/references/why-is-it-stuck.md +30 -44
  101. package/skills/whats-happening/scripts/explain.mjs +1 -1
  102. package/skills/whats-happening/scripts/lib/cli.mjs +7 -5
  103. package/skills/whats-happening/scripts/lib/credential.mjs +2 -2
  104. package/skills/{how-catalyst-works → whats-happening}/scripts/show-my-map.mjs +18 -32
  105. package/skills/whats-happening/scripts/snapshot.mjs +10 -6
  106. package/skills/catalyst-onboard/references/choosing-a-coding-account.md +0 -52
  107. package/skills/catalyst-onboard/references/who-fixes-what.md +0 -64
  108. package/skills/catalyst-setup/SKILL.md +0 -36
  109. package/skills/catalyst-setup/agents/openai.yaml +0 -6
  110. package/skills/catalyst-setup/agents/portability.yaml +0 -4
  111. package/skills/catalyst-setup/references/what-each-check-means.md +0 -88
  112. package/skills/catalyst-setup/scripts/lib/cli.mjs +0 -103
  113. package/skills/catalyst-setup/scripts/lib/credential.mjs +0 -29
  114. package/skills/catalyst-setup/scripts/replica-status.mjs +0 -46
  115. package/skills/connect-me/SKILL.md +0 -63
  116. package/skills/connect-me/agents/openai.yaml +0 -6
  117. package/skills/connect-me/agents/portability.yaml +0 -5
  118. package/skills/connect-me/references/keeping-the-replica-running.md +0 -88
  119. package/skills/connect-me/scripts/lib/cli.mjs +0 -185
  120. package/skills/connect-me/scripts/lib/credential.mjs +0 -29
  121. package/skills/connect-me/scripts/verify-connection.mjs +0 -68
  122. package/skills/how-catalyst-works/SKILL.md +0 -45
  123. package/skills/how-catalyst-works/agents/openai.yaml +0 -6
  124. package/skills/how-catalyst-works/agents/portability.yaml +0 -4
  125. package/skills/how-catalyst-works/references/coding-accounts.md +0 -51
  126. package/skills/how-catalyst-works/references/settings-and-where-they-live.md +0 -20
  127. package/skills/how-catalyst-works/references/stages-and-mapping.md +0 -56
  128. package/skills/how-catalyst-works/references/the-ladder.md +0 -41
  129. package/skills/how-catalyst-works/references/what-catalyst-is.md +0 -30
  130. package/skills/how-catalyst-works/references/what-runs-next.md +0 -95
  131. package/skills/how-catalyst-works/references/when-a-phase-fails.md +0 -57
  132. package/skills/how-catalyst-works/scripts/explain-ticket.mjs +0 -41
  133. package/skills/how-catalyst-works/scripts/lib/cli.mjs +0 -164
  134. package/skills/how-catalyst-works/scripts/lib/credential.mjs +0 -29
  135. package/skills/how-catalyst-works/scripts/whats-running.mjs +0 -65
  136. package/skills/whats-happening/references/reading-the-board.md +0 -43
  137. package/skills/whats-happening/references/reprioritising.md +0 -37
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  // watch-scope.mjs — subscribe to the tenant stream filtered to one scope and pass every in-scope
3
- // frame through, one JSON line each. This is `catalyst-skills watch` with the scope flags checked
3
+ // frame through, one JSON line each. This is `catalyst watch` with the scope flags checked
4
4
  // up front; the CLI owns the socket, the cursor file, the replay and the reconnects.
5
5
  import { CHECK_FAILED_EXIT, execCli, parseFlags, requireConfigured, wantsHelp } from "./lib/cli.mjs";
6
6
 
@@ -1,32 +1,31 @@
1
1
  ---
2
2
  name: unstick
3
3
  description: >-
4
- Get a stuck Catalyst Cloud ticket moving again. Use when the person asks "why is this parked and can you release it?", "unpark this", "get things flowing again", "the outage is over, retry what failed", or hands you a ticket that is not moving. Reads why nothing runs and what holds the ticket through the catalyst-skills CLI, decides whether the recorded cause is fixed, previews the release, releases every governor holding the ticket the right way (or one failure class across a team), and raises an ask only for what a person has to do. Never releases a cause it cannot show changed without saying so.
5
- disable-model-invocation: true
6
- allowed-tools: Bash(catalyst-skills:*) Bash(npx @catalyst-cloud/catalyst-skills:*)
4
+ Get a stuck Catalyst Cloud ticket moving again. Use when the person asks "why is this parked and can you release it?", "unpark this", "get things flowing again", "the outage is over, retry what failed", or hands you a ticket that is not moving. Reads why nothing runs and what holds the ticket through the catalyst CLI, decides whether the recorded cause is fixed, previews the release, releases every governor holding the ticket the right way (or one failure class across a team), and raises an ask only for what a person has to do. Never releases a cause it cannot show changed without saying so.
5
+ allowed-tools: Bash(catalyst:*) Bash(npx -p @catalyst-cloud/cli catalyst:*)
7
6
  ---
8
- <!-- vendored-from: @catalyst-cloud/catalyst-skills@0.13.0 — written in this repository for customer tenants -->
7
+ <!-- vendored-from: @catalyst-cloud/catalyst-skills@0.13.1 — written in this repository for customer accounts -->
9
8
 
10
9
  # Unstick
11
10
 
12
- You get one stuck ticket, or one set of tickets stuck for the same reason, moving again. The cloud parks or holds a ticket when retrying would only repeat a failure: after repeated failures, when the repair-round cap is spent, when a repair changed nothing, when the same validate failure recurred. Each of those is a governor. Once its cause is fixed, the person's own key releases it; nothing here needs an operator.
11
+ You get one stuck ticket, or one set of tickets stuck for the same reason, moving again. The cloud parks or holds a ticket when retrying would only repeat a failure: after repeated failures, when the repair-round cap is spent, when a repair changed nothing, when the same validate failure recurred. Each of those is a governor. Once its cause is fixed, the person's own key releases most of them. Two refuse that release: a round-threshold hold (a push the fleet did not make, or an answer to its ask, grants one more cycle) and a review that will not converge (a human comment on the ticket resumes it).
13
12
 
14
13
  ## Run first
15
14
 
16
- Scripts are run, never read. Each prints `--help`; exit 2 means this machine is not connected (run `catalyst-skills login`).
15
+ Scripts are run, never read. Each prints `--help`; exit 2 means this machine is not connected (run `catalyst login`).
17
16
 
18
- - `node scripts/unstick.mjs <ticket>` — one JSON document: the eligibility explanation, the execution history (every governor holding the ticket with what releases it, and past releases), and a dry-run release showing what a release would clear and refuse. Changes nothing.
19
- - `node scripts/unstick.mjs <ticket> --because "<what changed>"` — the same, then the real release. Add `--retry-unchanged` only when you can say what changed outside what the cloud can see.
20
- - `node scripts/unstick.mjs --class <failure-class> --team <key> [--because "<what changed>"]` — the same for every ticket on one team parked under one failure class (at most 25 per call).
17
+ - `node scripts/unstick.mjs <ticket>`: one JSON document: the eligibility explanation, the execution history (every governor holding the ticket with what releases it, and past releases), and a dry-run release showing what a release would clear and refuse. Changes nothing.
18
+ - `node scripts/unstick.mjs <ticket> --because "<what changed>"`: the same, then the real release. Add `--retry-unchanged` only when you can say what changed outside what the cloud can see.
19
+ - `node scripts/unstick.mjs --class <failure-class> --team <key> [--because "<what changed>"]`: the same for every ticket on one team parked under one failure class (at most 25 per call).
21
20
 
22
- The verbs underneath are `catalyst-skills explain <ticket>`, `catalyst-skills explain <ticket> --history` and `catalyst-skills release <ticket> --because <text> [--retry-unchanged] [--dry-run]`.
21
+ The verbs underneath are `catalyst explain <ticket>`, `catalyst explain <ticket> --history` and `catalyst release <ticket> --because <text> [--retry-unchanged] [--dry-run]`.
23
22
 
24
23
  ## Load on demand
25
24
 
26
25
  | when | read |
27
26
  | -- | -- |
28
27
  | deciding whether to release, what a refusal means, when to ask a person | `references/playbook.md` |
29
- | what a reason in the explanation means | the `whats-happening` skill's why-is-it-stuck reference, or `how-catalyst-works` |
28
+ | what a reason in the explanation means, or what clears each kind of hold | the `whats-happening` skill: its why-is-it-stuck and when-a-phase-fails references |
30
29
  | a refusal needs a decision or a person's action | the `what-needs-me` skill |
31
30
  | a refusal names a person's pull request or its review | the `catalyst-github` skill |
32
31
 
@@ -38,4 +37,5 @@ The verbs underneath are `catalyst-skills explain <ticket>`, `catalyst-skills ex
38
37
  - **One release per cause.** If the history shows a release for the same failure and nothing has changed since, a second release buys the same failure. Raise an ask instead.
39
38
  - **A refusal names its fix.** Do the fix when it is yours to do; everything else is one ask through `what-needs-me`, attached to an existing ask for the same decision. Never close or merge a person's pull request, and never answer an ask as the person.
40
39
  - **A shared cause is one note.** Several tickets parked by one outage or one bad image are one class release and one line in your reply, never one ask per ticket.
41
- - **Their tenant, as them.** Every read and write goes through the CLI and the person's own login. You never name another tenant.
40
+ - **What a release costs.** A release is a write: it is recorded against the person's name with your `--because`, shown to everyone who reads the ticket's history, and it spends a round of work the cloud will run again. The dry run is free; run it first.
41
+ - **Their account, as them.** Every read and write goes through the CLI and the person's own login. You never name another account.
@@ -3,4 +3,4 @@ interface:
3
3
  short_description: "Find out why a Catalyst ticket is parked or held and release it once its cause is fixed; asks only for what needs a person"
4
4
  default_prompt: "Use $unstick to find out why <ticket> is stuck and get it moving again."
5
5
  policy:
6
- allow_implicit_invocation: false
6
+ allow_implicit_invocation: true
@@ -1,5 +1,5 @@
1
1
  identity: { pack: catalyst-cloud-skills, skill: unstick }
2
2
  effects: [external-write]
3
3
  mutating: true
4
- invocation: explicit
4
+ invocation: implicit
5
5
  exposure: [catalog]
@@ -1,18 +1,18 @@
1
1
  # The unstick playbook
2
2
 
3
- This reference restates how a person's release of a stuck ticket works and the order you follow. The cloud does the deciding: it reads every governor holding the ticket and either releases all of them or releases nothing and names, for each one it refuses, the action that does fix it. Your job is to read, judge whether the cause is fixed, and say so honestly.
3
+ The cloud does the deciding: it reads every governor holding the ticket and either releases all of them or releases nothing and names, for each one it refuses, the action that does fix it. Your job is to read, judge whether the cause is fixed, and say so honestly.
4
4
 
5
5
  ## The order
6
6
 
7
- 1. **Why is nothing running?** `catalyst-skills explain <ticket>`. If the reason is not a park or a hold (for example `blocked`, `not_at_dispatch_stage`, an ask, a missing environment check, `scope_overlap`), there is nothing to release: follow the `whats-happening` skill's why-is-it-stuck reference instead and stop here.
8
- 2. **What holds it, and has it been released before?** `catalyst-skills explain <ticket> --history`. Read three things: the "Held by" lines (each governor and what releases it), the last failure (its class and summary), and the "Releases" lines (who released it before, why, and what happened).
7
+ 1. **Why is nothing running?** `catalyst explain <ticket>`. If the reason is not a park or a hold (for example `blocked`, `not_at_dispatch_stage`, an ask, a missing environment check, `scope_overlap`), there is nothing to release: follow the `whats-happening` skill's why-is-it-stuck reference instead and stop here.
8
+ 2. **What holds it, and has it been released before?** `catalyst explain <ticket> --history`. Read three things: the "Held by" lines (each governor and what releases it), the last failure (its class and summary), and the "Releases" lines (who released it before, why, and what happened).
9
9
  3. **Is the cause fixed?** Decide from evidence, in this order:
10
- - a push to the ticket's branch, a comment on the ticket that says what to change, or main moving on since the park: the cloud can see these, and a release goes through;
11
- - a change the cloud cannot see (a provider outage that ended, a rotated secret, a re-enrolled coding account, a fixed tenant setting): release with `--retry-unchanged`, and the reason you give names that change;
10
+ - a push to the ticket's branch, a comment on the ticket that says what to change, or main moving on since the park: the cloud can see these, and a release goes through. A validate-budget hold needs exactly this (a push or a comment since the hold), or `--retry-unchanged` with the change named;
11
+ - a change the cloud cannot see (a provider outage that ended, a rotated secret, a re-enrolled coding account, a fixed account setting): release with `--retry-unchanged`, and the reason you give names that change;
12
12
  - nothing changed: do not release. Tell the person what failed and what would have to change.
13
13
  If a previous release in the history named the same failure and nothing has changed since, the next release will fail the same way. Do not release again; raise an ask.
14
- 4. **Preview.** `catalyst-skills release <ticket> --dry-run`. It prints what a release would clear and what it would refuse, and changes nothing.
15
- 5. **Release.** `catalyst-skills release <ticket> --because "<the change>"`. Report what it released, verbatim, with the ticket id. A warning line (for example, that a released repair round runs again at the escalated tier and a second cap parks it again) goes in your reply too.
14
+ 4. **Preview.** `catalyst release <ticket> --dry-run`. It prints what a release would clear and what it would refuse, and changes nothing.
15
+ 5. **Release.** `catalyst release <ticket> --because "<the change>"`. Report what it released, verbatim, with the ticket id. A warning line (for example, that a released repair round runs again at the escalated tier and a second cap parks it again) goes in your reply too.
16
16
  6. **Act on each refusal.** A refusal is terminal for that attempt: nothing was released. Each names its fix; the table below says who does it.
17
17
 
18
18
  ## What a refusal means and who fixes it
@@ -23,10 +23,10 @@ This reference restates how a person's release of a stuck ticket works and the o
23
23
  | `lease_held` | a phase is running on the ticket right now | nobody; wait for the phase's outcome comment, then look again |
24
24
  | `branch_still_missing` | the ticket's branch was never pushed | it releases itself when the branch appears; check the earlier phases through `catalyst-linear` |
25
25
  | `human_owned_pr` | a person opened the pull request this ticket would work on | that person closes or merges it, or hands it to Catalyst; never close a person's pull request yourself |
26
- | `review_not_converging` | review and repair kept finding new problems | a person reads the findings (`catalyst-github`) and comments on the ticket to resume; raise an ask for that read |
27
- | `round_threshold` | the ticket spent its lifetime repair budget | a person answers the ask the cloud already raised, or pushes a fix; point at that ask, do not raise a second one |
28
- | `base_revision_lost` | the ticket's base commit is gone | whoever administers the tenant re-pins it; raise one ask |
29
- | `remediate_cap` | this tenant keeps the repair-round cap for an administrator | whoever administers the tenant; raise one ask |
26
+ | `review_not_converging` | validate and repair cycles kept finding new problems | a person reads the findings (`catalyst-github`) and comments on the ticket: the comment resumes at validate, and `catalyst: resume implement` resumes at implement. A push alone does not clear it, and it has no ask and no default. Raise an ask for that read |
27
+ | `round_threshold` | the ticket spent its lifetime repair budget | a person answers the ask the cloud already raised, or pushes a fix the fleet did not make; each grants one more cycle, and a comment does not. After 48 hours unanswered, the ask's default (re-plan) applies. Point at that ask; do not raise a second one |
28
+ | `base_revision_lost` | the ticket's base commit is gone | an operator re-pins it; raise one ask |
29
+ | `remediate_cap` | this account keeps the repair-round cap for an administrator | a workspace owner or admin; raise one ask |
30
30
  | `unknown_park` | a park this bundle does not know | raise one ask with the ticket id and the park name, verbatim |
31
31
  | `held_beyond_class` | a class release reached a ticket held by more than that class | release that ticket on its own, from step 1 |
32
32
  | `team_changed` (the ticket moved teams during the check) | the release was checked for one team and the ticket is now on another | run the release again |
@@ -37,8 +37,8 @@ Raise an ask only through `what-needs-me`, with the stuck ticket in what it bloc
37
37
 
38
38
  When several tickets on one team are parked for the same failure class (the explanation and the history show the same class, typically an outage or a runner problem that has since ended):
39
39
 
40
- 1. `catalyst-skills release --class <failure-class> --team <key> --dry-run` to see which tickets it reaches.
41
- 2. `catalyst-skills release --class <failure-class> --team <key> --because "<the change>" --retry-unchanged` when the change is one the cloud cannot see.
40
+ 1. `catalyst release --class <failure-class> --team <key> --dry-run` to see which tickets it reaches.
41
+ 2. `catalyst release --class <failure-class> --team <key> --because "<the change>" --retry-unchanged` when the change is one the cloud cannot see.
42
42
  3. Report one line: how many released, which were refused and why, and whether more remain (run it again for the next batch).
43
43
 
44
44
  A ticket the class release refuses is listed and left alone; take it through the single-ticket order above.
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- // lib/cli.mjs — the one way a skill script reaches Catalyst Cloud: spawn the catalyst-skills CLI.
2
+ // lib/cli.mjs — the one way a skill script reaches Catalyst Cloud: spawn the catalyst CLI.
3
3
  // The CLI holds the SDK and the key; this file holds neither. It reads customer.json only
4
4
  // to learn where the CLI lives, and it exits 2 with one line when the machine is not connected.
5
5
  // Run any script beside this one with --help; this file is a library and is never run directly.
@@ -8,7 +8,9 @@ import { existsSync, readFileSync } from "node:fs";
8
8
  import { join } from "node:path";
9
9
  import { CONNECT_COMMAND, hasCredential } from "./credential.mjs";
10
10
 
11
- export const PACKAGE = "@catalyst-cloud/catalyst-skills";
11
+ export const PACKAGE = "@catalyst-cloud/cli";
12
+ /** The package ships two commands, so npx needs the one to run named: `npx -p <package> catalyst`. */
13
+ export const NPX_ARGS = ["-p", PACKAGE, "catalyst"];
12
14
  export const NOT_CONFIGURED_EXIT = 2;
13
15
 
14
16
  export function configPath() {
@@ -36,7 +38,7 @@ function notConfigured(why) {
36
38
  }
37
39
 
38
40
  /**
39
- * Run one catalyst-skills verb and return {code, stdout, stderr}. Uses the CLI path the login
41
+ * Run one catalyst verb and return {code, stdout, stderr}. Uses the CLI path the login
40
42
  * recorded when it still exists, else `npx <package>`. A CLI exit of 2 with a "not joined" or
41
43
  * "not connected" line is turned into this script's own exit 2, so every caller sees one contract.
42
44
  */
@@ -44,7 +46,7 @@ export function runCli(args, opts = {}) {
44
46
  const cfg = loadConfig();
45
47
  const useRecorded = typeof cfg.cliPath === "string" && existsSync(cfg.cliPath);
46
48
  const cmd = useRecorded ? process.execPath : "npx";
47
- const argv = useRecorded ? [cfg.cliPath, ...args] : [PACKAGE, ...args];
49
+ const argv = useRecorded ? [cfg.cliPath, ...args] : [...NPX_ARGS, ...args];
48
50
  const res = spawnSync(cmd, argv, {
49
51
  input: opts.stdin,
50
52
  encoding: "utf8",
@@ -6,12 +6,12 @@
6
6
  //
7
7
  // customer.json carries exactly one credential: a personal key (`key`), or the keyless login's
8
8
  // session (`auth`, the recommended rail). A script never reads either for its value: it spawns the
9
- // catalyst-skills CLI, which authenticates with whichever is present and refreshes a login's token
9
+ // catalyst CLI, which authenticates with whichever is present and refreshes a login's token
10
10
  // itself. A new credential kind lands here, once.
11
11
 
12
12
  /** The command that connects this machine, as every not-connected line names it. */
13
13
  export const CONNECT_COMMAND =
14
- "npx @catalyst-cloud/catalyst-skills login (or, with a personal key: CATALYST_CLOUD_TOKEN=<your personal key> npx @catalyst-cloud/catalyst-skills login)";
14
+ "npx -p @catalyst-cloud/cli catalyst login (or, with a personal key: CATALYST_CLOUD_TOKEN=<your personal key> npx -p @catalyst-cloud/cli catalyst login)";
15
15
 
16
16
  /** True when `cfg` (parsed customer.json) holds a usable credential of either kind. Never throws. */
17
17
  export function hasCredential(cfg) {
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  // unstick.mjs — "why is this stuck, and can it be released?" in one JSON document. Runs
3
- // `catalyst-skills explain`, `explain --history` and a dry-run `release` for one ticket (or a dry-run
3
+ // `catalyst explain`, `explain --history` and a dry-run `release` for one ticket (or a dry-run
4
4
  // class release for one team), and only with --because runs the real release. Reaches the cloud only
5
5
  // by spawning the CLI.
6
6
  import { mustRun, parseFlags, parseJson, printHelp, runCli } from "./lib/cli.mjs";
@@ -1,23 +1,22 @@
1
1
  ---
2
2
  name: what-needs-me
3
3
  description: >-
4
- The human's decision inbox on a Catalyst Cloud tenant, and the one way an agent raises a decision on their behalf. Use when the person asks "what needs me?", "what am I blocking?", or when active work is gated on a choice only they can make. Lists open asks ranked by what each answer releases, files an ask through the cloud's ask route with the tenant's own template, and records the answer so the held work releases. Never answers as the human, never duplicates an open ask.
5
- disable-model-invocation: true
6
- allowed-tools: Bash(catalyst-skills:*) Bash(npx @catalyst-cloud/catalyst-skills:*)
4
+ The human's decision inbox on Catalyst Cloud, and the one way an agent raises a decision on their behalf. Use when the person asks "what needs me?", "what am I blocking?", or when active work is gated on a choice only they can make. Lists open asks ranked by how much open work each one holds, files an ask through the cloud's ask route with the account's own template, and records the answer so the held work releases. Never answers as the human, never duplicates an open ask.
5
+ allowed-tools: Bash(catalyst:*) Bash(npx -p @catalyst-cloud/cli catalyst:*)
7
6
  ---
8
- <!-- vendored-from: @catalyst-cloud/catalyst-skills@0.13.0 — written in this repository for customer tenants -->
7
+ <!-- vendored-from: @catalyst-cloud/catalyst-skills@0.13.1 — written in this repository for customer accounts -->
9
8
 
10
9
  # What needs me
11
10
 
12
- An ask is one decision only the human can make, filed as a ticket in their own Linear so that question, options, default, answer and who answered are one record. This skill reads that inbox ranked by blast radius, raises a new ask when work is gated, and settles the answer so the held work releases. The cloud renders the ask body from the tenant's template, applies the ask labels and creates the blocking relations; you pass fields, never headings.
11
+ An ask is one decision only the human can make, filed as a ticket in their own Linear so that question, options, default, answer and who answered are one record. This skill reads that inbox ranked by how much open work each ask holds, raises a new ask when work is gated, and settles the answer so the held work releases. The cloud renders the ask body from the account's template, applies the ask labels and creates the blocking relations; you pass fields, never headings.
13
12
 
14
13
  ## Run first
15
14
 
16
- Scripts are run, never read. Each prints `--help`; exit 2 means this machine is not connected (run the `connect-me` skill), exit 1 means the check itself failed or an argument was missing.
15
+ Scripts are run, never read. Each prints `--help`; exit 2 means this machine is not connected (the `catalyst-onboard` skill connects it), exit 1 means the check itself failed or an argument was missing.
17
16
 
18
- - `node scripts/inbox.mjs --help` — the open asks assigned to the connected person, ranked by the priority-weighted work each holds; `--anyone` for the whole tenant; `--json` for `{scope, asks}`.
19
- - `node scripts/raise.mjs --help` — file one decision: `--team`, `--title`, `--option` (repeated), `--default`, and `--blocks` (repeated) or `--nothing-to-block`.
20
- - `node scripts/settle.mjs --help` — record the answering comment on an ask and post a release note on every ticket it held; `--close` moves the ask to the done slot.
17
+ - `node scripts/inbox.mjs --help`: the open asks assigned to the connected person, most open tickets held first, then the oldest; `--anyone` for everyone's; `--json` for `{scope, asks}`.
18
+ - `node scripts/raise.mjs --help`: file one decision: `--team`, `--title`, `--option` (repeated), `--default`, and `--blocks` (repeated) or `--nothing-to-block`.
19
+ - `node scripts/settle.mjs --help`: record the answering comment on an ask and post a release note on every ticket it held; `--close` moves the ask to the done slot.
21
20
 
22
21
  ## Load on demand
23
22
 
@@ -33,9 +32,8 @@ The `catalyst-linear` skill posts the comment that carries an answer given in ch
33
32
 
34
33
  - **File before proceeding on the default.** Work may run on a default only after the ask exists; a default with no ticket behind it is a guess, not a decision.
35
34
  - **One ask per decision.** Read the inbox first; attach new held tickets to an open ask rather than filing a twin. Duplicates split one decision's urgency across rows.
36
- - **Every ask names what it blocks.** The ranking the human sees is by held work weighted by priority, never by age; an ask that holds nothing does not reach Waiting on me unless you chose `--nothing-to-block` on purpose.
37
- - **Never answer as the human.** You do not pick an option, close an ask on their behalf, or post in their voice. Their answer is quoted into the ask as the app actor and recorded with its comment id.
38
- - **A free-text reply is recorded, never interpreted into an option.** If it does not answer the question, ask the one clarification in the thread and leave the ask open.
35
+ - **Every ask names what it blocks.** The ranking the human sees is by the count of open tickets each ask holds, then the oldest ask; priority is not a weight. An ask that holds nothing does not reach Waiting on me unless you chose `--nothing-to-block` on purpose.
36
+ - **A write is visible.** Filing an ask puts a ticket in the person's Linear, assigns it to them, holds every ticket it names, and spends the daily write budget; settling posts a comment on the ask and on every held ticket. Read the inbox before you file.
37
+ - **The human answers for themselves.** Their answer is quoted into the ask as the app actor and recorded with its comment id; a free-text reply is recorded as written, never turned into an option.
39
38
  - **Escalate inward.** A project owner raises asks for its scope; the desk raises what has no owner; a single stuck ticket or a provider outage is never an ask.
40
- - **Tenant facts come from the contract.** Team keys, label names, the option cap and the template are read live by the CLI; never restate them.
41
- - **Cite an identifier only after the create call returned it.**
39
+ - **Account facts come from the contract.** Team keys, label names, the option cap and the template are read live by the CLI. Cite an identifier only after the create call returned it.
@@ -1,6 +1,6 @@
1
1
  interface:
2
2
  display_name: "What needs me"
3
- short_description: "Your decision inbox on Catalyst Cloud, ranked by what each answer releases; raises and settles asks"
3
+ short_description: "Your decision inbox on Catalyst Cloud, ranked by how much open work each ask holds; raises and settles asks"
4
4
  default_prompt: "Use $what-needs-me to show me what is waiting on my decision."
5
5
  policy:
6
- allow_implicit_invocation: false
6
+ allow_implicit_invocation: true
@@ -1,5 +1,5 @@
1
1
  identity: { pack: catalyst-cloud-skills, skill: what-needs-me }
2
2
  effects: [external-write]
3
3
  mutating: true
4
- invocation: explicit
4
+ invocation: implicit
5
5
  exposure: [catalog]
@@ -1,41 +1,33 @@
1
1
  # Raising a decision
2
2
 
3
- This reference restates invariants: what an ask is, when it is filed, and what it must carry. The body text, the headings, the option format and the cap on options are tenant facts served by the contract's `askTemplate` block and rendered by the cloud itself; `node scripts/raise.mjs` passes fields and never composes a heading.
4
-
5
- ## What an ask is
6
-
7
- An ask is one decision only the human can make, filed as a ticket in the tenant's own Linear so that the question, the options, the default, the answer and who answered are one record the next agent can read. The cloud labels it as an ask, excludes it from dispatch (a question is never work), and holds every ticket it blocks until it is answered. It appears in the human's Waiting-on-me view when it is assigned to them and blocks open work.
3
+ The body, headings, option format and option cap come from the contract's `askTemplate` and are rendered by the cloud; `node scripts/raise.mjs` passes fields. The cloud labels the ask, keeps it out of dispatch, and holds every ticket it blocks until it is answered.
8
4
 
9
5
  ## When to file one
10
6
 
11
- File an ask when active work is gated on a product call, a priority call between two things that cannot both go first, an approval, or an action only the human can physically take (a click in settings, a credential, a payment). File it **before** proceeding on the default, never after, and never only as a TODO line, a board row, a handoff note or a chat question. Those may point at the ask's identifier; they never replace it.
7
+ File an ask when active work is gated on a product call, a priority call between two things that cannot both go first, an approval, or an action only the human can take (a click in settings, a credential, a payment). File it **before** proceeding on the default. A TODO line, board row, handoff note or chat question may point at the ask's identifier, never replace it.
12
8
 
13
- Do not file one for brainstorming, a design back-and-forth, a question the human asked first, a retry-or-abandon call a project owner can make, or a system-level failure (a provider down, out of capacity, rate-limited: that is one status line, and the affected tickets retry on their own).
9
+ Brainstorming, design back-and-forth, a question the human asked first, a retry-or-abandon call a project owner can make, and a system-level failure (one status line; the tickets retry on their own) are not asks.
14
10
 
15
11
  ## What it carries
16
12
 
17
13
  1. **The question**, one sentence, as the title (`--title`).
18
14
  2. **Context** the human needs to answer without opening anything else (`--context`), short.
19
15
  3. **Options**, each one line, realistic, at most the number the contract allows (`--option`, repeated). The cloud letters and formats them.
20
- 4. **The default if silent** (`--default`): what proceeds and after how long. It must be sane enough to actually run. Note that nothing in the cloud applies the default on a timer; the raising agent applies it, after the ask exists, and records that it did.
21
- 5. **What it blocks** (`--blocks`, repeated): every ticket held until the answer lands. The cloud creates the blocking relations atomically with the ticket. An ask that holds nothing is refused unless you say `--nothing-to-block` on purpose, because an ask with no blocking relation never surfaces in Waiting on me and is indistinguishable from ordinary work.
16
+ 4. **The default if silent** (`--default`): what proceeds and after how long. It must be sane enough to actually run. The raising agent applies it, after the ask exists, and records that it did; the cloud applies no default on a timer for the asks you raise. The exception is the ask a validate-budget or round-threshold hold raises: the cloud applies its default (re-plan) after 48 hours unanswered.
17
+ 5. **What it blocks** (`--blocks`, repeated): every ticket held until the answer lands, related atomically with the ask. An ask that holds nothing is refused unless you pass `--nothing-to-block` on purpose, because it never surfaces in Waiting on me. Name every held ticket: the inbox ranks by that count (`references/reading-the-inbox.md`), so an ask that names one ticket when it really holds a project sinks below one holding two chores.
22
18
 
23
19
  `--ask-key` is an idempotency key: a re-run with the same key does not file a second ask.
24
20
 
25
21
  ## One ask per decision
26
22
 
27
- Run `node scripts/inbox.mjs` first and read the titles. When the same decision is already open, attach the new held tickets to it rather than filing again (the `catalyst-linear` skill adds the relation or a comment naming them). Duplicates split one decision's urgency across several rows and sink it below trivia in the ranking.
23
+ Run `node scripts/inbox.mjs` first. When the same decision is already open, attach the new held tickets to it (the `catalyst-linear` skill adds the relation or a comment) rather than filing a twin that splits its urgency.
28
24
 
29
25
  ## Who raises, and where
30
26
 
31
27
  - A decision inside a project scope is raised by that project's owner; the desk raises what has no owner.
32
- - The ask is filed on the team the held work belongs to (`--team`), from the contract's team list. An approvals team, when the contract names one, is where an approval with no natural team goes.
33
- - Never raise an ask on someone else's behalf about their own scope, and never answer one for the human.
28
+ - The ask goes on the held work's team (`--team`); an approval with no natural team goes to the approvals team when the contract names one.
29
+ - Each scope's owner raises its own asks, and the human answers them.
34
30
 
35
31
  ## After filing
36
32
 
37
33
  Cite the identifier the script printed, and only that. Proceed on the default if the work allows it, and say so in the ask's thread (a bookkeeping comment) so the record shows the default was taken. When the answer arrives, `references/settling-an-answer.md`.
38
-
39
- ## Ranking
40
-
41
- The human sees asks ranked by how much open work each holds, weighted by that work's priority (urgent counts most), never by age. That is why `--blocks` must be complete: an ask that names one held ticket when it really holds a project sinks below a chore.
@@ -1,10 +1,8 @@
1
1
  # Reading the inbox
2
2
 
3
- This reference restates invariants: what "waiting on me" means, how declared and inferred asks differ, and how to present the queue. The label that marks an ask, its prefix, and the release label are the contract's `vocabulary`; `node scripts/inbox.mjs` reads them from the CLI and never from prose.
4
-
5
3
  ## What waiting-on-me means
6
4
 
7
- The tenant's own Waiting-on-me view lists a ticket for a person when all four hold:
5
+ The account's own Waiting-on-me view lists a ticket for a person when all four hold:
8
6
 
9
7
  1. it is **assigned** to that person;
10
8
  2. it has **no delegate** (a ticket delegated to an agent is the agent's, not the human's);
@@ -17,16 +15,15 @@ So an ask that holds nothing is real, but the person may never see it in their o
17
15
 
18
16
  ## What the script reads
19
17
 
20
- `catalyst-skills ask list` reads every page of the tenant's issues, not a windowed sample, so an empty list means nothing is assigned to you rather than that the read stopped early. It reads the open tickets carrying the team's ask label (by the label ids and prefix the contract serves), follows each one's blocking relations to the tickets it holds, drops held tickets that are already terminal, and scores the rest by priority weight: urgent 4, high 3, medium 2, low 1, none 1. It filters to **the connected person** by default: `login` recorded who they are and their Linear user id, and the list keeps only asks assigned to that id. `--anyone` lists the whole tenant. The JSON answer carries a `scope` — `mine` (with the label and Linear id), `anyone`, `unmatched` (the person's Linear identity is not matched yet: an admin does that in Settings → Members, and until then the whole list is shown with a stderr line saying so), or `no-person` (the machine is connected with the tenant's account key, which names nobody: the whole list, with a line saying to log in with a personal key). Read the scope before presenting the list, and say which you got: "what needs me" is the `mine` list, "what needs anyone" is `--anyone`, and an empty `mine` list names the wider count so it never reads as "nothing needs anyone".
18
+ `catalyst ask list` reads every page, so an empty list is real. It follows each open ask's blocking relations, drops held tickets already terminal, and ranks by the count of open tickets each ask holds (its `score`), then the oldest ask, then the identifier: the cloud's own Waiting-on-me order. Priority is not a weight; age only breaks a tie. It keeps the connected person's asks by default (`--anyone` for everyone's) and reports a `scope`: `mine`, `anyone`, `unmatched` (the Linear identity is not matched, so everyone's list is shown with a stderr line), or `no-person` (connected with the account key, which names nobody). Say which scope you got, and give the wider count beside an empty `mine` list so it never reads as "nothing needs anyone".
21
19
 
22
20
  ## The identity is not the same as the personal Linear grant
23
21
 
24
- Two different stored facts can disagree, and when asks are not reaching someone this is the first thing to check, before the grant. The **identity** is who you are in Linear: resolved automatically by an email match, or picked by an admin at Settings → Members when it is not. The **personal Linear grant** is proven by connecting Linear yourself — a person action, not an admin one. Connecting Linear personally does **not** set the identity; the two are separate, and the identity is checked first, then the grant. An identity that resolved automatically cannot be re-pointed by the member themselves — that needs an operator; a manual pick by an admin is refused if another member already claims that Linear user. Everything that notifies or assigns a human needs a resolved identity: with no identity there is no ask and no push, and nothing is assigned to that person — even for someone who has connected Linear themselves. Do not report that as an empty queue. `what needs me` does not go quiet in that state: the scope comes back `unmatched`, the whole tenant's open asks are listed, and a line says the identity is not matched yet (*What the script reads*, above). The honest answer is "nothing is assigned to you yet, so this is everyone's list, not yours — an admin matches your identity at Settings → Members".
22
+ When asks are not reaching someone, check the identity first, then the grant. The **identity** is who they are in Linear, resolved by an email match or matched by the person (`catalyst identity linear status`, `options`, then `catalyst identity linear set <linearUserId>`). The **personal Linear grant** is proven by connecting Linear themselves. Connecting Linear personally does **not** set the identity. An auto-resolved identity, or one another member claims, needs an owner or admin at Settings → Members. With no identity nothing is assigned to them, even after they connect Linear, so an `unmatched` scope is not an empty queue: say "nothing is assigned to you yet, so this is everyone's list; match your identity with `catalyst identity linear set` and it becomes yours".
25
23
 
26
24
  ## Presenting the queue
27
25
 
28
- - Ranked by score, highest first. Never by age, never by identifier. An ask that holds a project outranks one that holds a chore, whatever their dates.
29
- - One line per ask: rank, identifier, what it holds (identifiers), the question. The human decides from the question and the held work, so both must be on the line.
26
+ - In the script's order, one line per ask: rank, identifier, what it holds (identifiers), the question.
30
27
  - Asks that hold nothing come after a break, marked as not visible in Waiting on me until they block something.
31
28
  - When the list is empty, say "nothing needs you" and stop. Do not pad it with suspected asks.
32
29
  - A ticket `explain` flagged as `ask_shape_suspected` (its text reads as a decision but it carries no ask label) is mentioned separately with a question mark: it is either an ask the human should label, or a false positive they release with the release label the contract names.
@@ -34,9 +31,5 @@ Two different stored facts can disagree, and when asks are not reaching someone
34
31
  ## What the inbox is not
35
32
 
36
33
  - It is not the dispatch queue. Held tickets are excluded from dispatch by their blocking relation; answering the ask releases them into the ordinary order.
37
- - It is not a place to answer. Nothing in this skill picks an option, closes an ask on the human's behalf, or posts in their voice. When they answer in chat, `references/settling-an-answer.md`.
38
- - It is not a stall detector. A ticket parked by repeated failures, a merge hold, or a coding-account wall is a status question for `whats-happening`, not a decision until someone makes it one by raising an ask.
39
-
40
- ## Free-text and interpreted replies
41
-
42
- A human reply that names no option is recorded by the cloud and interpreted for display, but never auto-applied and never written back to Linear as a decision. Treat it the same way: read it, ask the human to confirm which option it means if that is unclear, and settle only once a comment on the ask states the answer.
34
+ - It is not a place to answer; an answer goes through `references/settling-an-answer.md`.
35
+ - It is not a stall detector. A park, a merge hold or a coding-account wall is a status question for `whats-happening` until someone raises an ask.
@@ -1,24 +1,20 @@
1
1
  # Settling an answer
2
2
 
3
- This reference restates invariants: where an answer is posted, how it is recorded, and how held work is released. The routes and the bookkeeping marker are the contract's; `node scripts/settle.mjs` reads them through the CLI.
4
-
5
- ## The rule
6
-
7
- The answer lives on the ask. Wherever it arrived (a comment on the ask, a comment on a held ticket, a chat message, a call), it ends as a comment on the ask ticket, and that comment is recorded as the accepted answer. Question, options, default, answer and who answered are then one record.
3
+ The answer lives on the ask. Wherever it arrived (the ask's thread, a held ticket, chat, a call), it ends as a comment on the ask, recorded as the accepted answer, so question, options, default, answer and who answered are one record.
8
4
 
9
5
  ## The three steps
10
6
 
11
- **1. Post the answer where it should live.** If the human answered in the ask's thread, nothing to do. If they answered anywhere else, post a comment on the ask that states the answer, as the app actor, never as the human, and attribute it in the text ("the owner answered in chat: option B"). Use the `catalyst-linear` skill's comment script; it returns the comment id. Do not paraphrase into a different option; quote what they said.
7
+ **1. Post the answer where it should live.** An answer given anywhere but the ask's thread becomes a comment on the ask, as the app actor, quoting them and attributing it ("the owner answered in chat: option B"), through the `catalyst-linear` skill's comment script, which returns the comment id.
12
8
 
13
9
  **2. Record it.** `node scripts/settle.mjs <ask> --answer <commentId> --role <role>` calls the cloud's ask-accept with the ask, the answering comment and the role doing the recording. The script first checks the comment is really on the ask (an id from a different ticket is refused before anything is written), then records, then reads the ask's blocking relations.
14
10
 
15
- **3. Release the held work.** For every open ticket the ask blocks, the script posts one bookkeeping comment naming the ask, the comment id and the first line of the answer, so the next phase or agent on that ticket reads the decision without opening the ask. The comment carries the contract's bookkeeping prefix, which means the cloud's comment-wake trigger ignores it: a record, not a turn in a conversation. Pass `--no-release-note` to skip this when the held tickets are about to be canceled anyway.
11
+ **3. Release the held work.** On every open ticket the ask blocks, the script posts one bookkeeping comment naming the ask, the comment id and the answer's first line, so the next agent there reads the decision; the marker keeps it from waking anyone. `--no-release-note` skips this for tickets about to be canceled.
16
12
 
17
13
  With `--close`, the script also moves the ask to its team's done slot. The blocking relations stay on the record; a done ticket does not block anything, so the held tickets become dispatchable on the cloud's next pass. Close only when the answer is complete; an answer that raises a follow-up question keeps the ask open and the follow-up goes in the same thread.
18
14
 
19
15
  ## Free-text replies
20
16
 
21
- A reply that names no option ("do whichever is cheaper", "ask me again Thursday") is recorded exactly as written. Nothing in the cloud or in this skill turns it into an option. Read it, decide whether it answers the question, and if it does not, reply in the thread with the one clarification needed and leave the ask open. If it does, settle with that comment as the answer and let the release note carry the quoted line.
17
+ A reply that names no option ("do whichever is cheaper", "ask me again Thursday") is recorded exactly as written; nothing turns it into an option. If it answers the question, settle with it and let the release note quote it. If it does not, reply in the thread with the one clarification needed and leave the ask open.
22
18
 
23
19
  ## Who settles
24
20
 
@@ -26,12 +22,10 @@ The role that raised the ask, or the owner of the scope it belongs to. The desk
26
22
 
27
23
  ## After settling
28
24
 
29
- - Tell the human, in one line, what was recorded and what it released.
30
- - The held tickets need no further action from you: their exclusion reason was the blocking relation, and the queue recomputes on the cloud's next pass. If one stays excluded, `whats-happening` explains why.
31
- - If the answer changes priorities or scope, that is a routing change for the project owner, not a second ask.
25
+ Tell the human in one line what was recorded and what it released. The held tickets rejoin the queue on the cloud's next pass; if one stays excluded, `whats-happening` explains why. An answer that changes priorities or scope is a routing change for the project owner, not a second ask.
32
26
 
33
27
  ## When it cannot be settled
34
28
 
35
29
  - The comment id is not on the ask: post the answer on the ask first, then settle with the new id.
36
30
  - The write budget for the day is spent: the CLI names the budget from the contract and exits 2. Say so; the record waits, the human's answer is not lost.
37
- - The ask is on a team the contract does not list: the tenant admin maps the team in settings; the `catalyst-setup` skill reads readiness.
31
+ - The ask is on a team the contract does not list: a workspace owner or admin maps the team (`catalyst team map <KEY>`); the `catalyst-onboard` skill reads readiness.
@@ -1,23 +1,24 @@
1
1
  #!/usr/bin/env node
2
- // inbox.mjs — "what needs me?": the open asks on this tenant, ranked by what each answer releases.
3
- // A thin wrapper over `catalyst-skills ask list`, which reads the open tickets carrying the team's
4
- // ask label (from the contract), follows each one's blocking relations, and weights held work by
5
- // priority. By default the CLI keeps only the asks assigned to the connected person; --anyone widens
6
- // to the whole tenant. Prints the ranked list; --json prints the CLI's {scope, asks} unchanged.
2
+ // inbox.mjs — "what needs me?": the open asks in this cloud account, ranked by what each answer releases.
3
+ // A thin wrapper over `catalyst ask list`, which reads the open tickets carrying the team's
4
+ // ask label (from the contract), follows each one's blocking relations, and ranks by the count of
5
+ // open tickets held, then the oldest ask. By default the CLI keeps only the asks assigned to the
6
+ // connected person; --anyone widens to the whole account. Prints the ranked list; --json prints the
7
+ // CLI's {scope, asks} unchanged.
7
8
  import { mustRun, parseFlags, parseJson, printHelp } from "./lib/cli.mjs";
8
9
 
9
10
  const SPEC = {
10
11
  json: { value: false, help: "print the CLI's answer as JSON: {scope, asks: [{identifier, title, state, blocks[], score, assigneeId}]}" },
11
12
  team: { value: true, help: "only asks whose identifier carries this team key" },
12
13
  all: { value: false, help: "include asks that hold nothing (by default they are listed last, marked)" },
13
- anyone: { value: false, help: "every open ask in the tenant, not only the ones assigned to you" },
14
+ anyone: { value: false, help: "every open ask in the account, not only the ones assigned to you" },
14
15
  };
15
16
 
16
17
  const { help, flags } = parseFlags(process.argv.slice(2), SPEC);
17
18
  if (help) {
18
19
  printHelp("node scripts/inbox.mjs [--json] [--team K] [--all] [--anyone] [--help]", SPEC, [
19
- "Rank: the sum over held open tickets of a priority weight (urgent 4 ... low 1, none 1), highest first.",
20
- "An ask that holds nothing is real but will not appear in the tenant's Waiting-on-me view; it is",
20
+ "Rank: most open tickets blocked first, then the oldest ask; priority is not a weight.",
21
+ "An ask that holds nothing is real but will not appear in the Waiting-on-me view; it is",
21
22
  "listed last with a marker so you can attach the work it should block (references/reading-the-inbox.md).",
22
23
  ]);
23
24
  process.exit(0);
@@ -33,11 +34,11 @@ if (flags.json) {
33
34
  }
34
35
  // Say whose list this is before the list, so an empty "mine" never reads as "nothing needs anyone".
35
36
  if (scope.kind === "mine") process.stdout.write(`asks assigned to ${scope.label}:\n`);
36
- else if (scope.kind === "anyone") process.stdout.write("every open ask in the tenant:\n");
37
- else if (scope.kind === "unmatched") process.stdout.write(`every open ask (your Linear identity is not matched yet — an admin matches it in Settings → Members):\n`);
38
- else process.stdout.write("every open ask (connected with the tenant's account key, which names no person — log in with your personal key to see only yours):\n");
37
+ else if (scope.kind === "anyone") process.stdout.write("every open ask in the account:\n");
38
+ else if (scope.kind === "unmatched") process.stdout.write(`every open ask (your Linear identity is not matched yet; match it with: catalyst identity linear set):\n`);
39
+ else process.stdout.write("every open ask (connected with the account key, which names no person — log in with your personal key to see only yours):\n");
39
40
  if (wanted.length === 0) {
40
- process.stdout.write(scope.kind === "mine" ? "nothing needs you: no open asks assigned to you (--anyone lists the tenant's)\n" : "nothing needs anyone: no open asks\n");
41
+ process.stdout.write(scope.kind === "mine" ? "nothing needs you: no open asks assigned to you (--anyone lists everyone's)\n" : "nothing needs anyone: no open asks\n");
41
42
  process.exit(0);
42
43
  }
43
44
  const holding = wanted.filter((r) => r.blocks.length > 0);
@@ -45,7 +46,7 @@ const idle = wanted.filter((r) => r.blocks.length === 0);
45
46
  let n = 0;
46
47
  for (const r of holding) {
47
48
  n += 1;
48
- process.stdout.write(`${n}. ${r.identifier} holds ${r.blocks.length} (weight ${r.score}): ${r.blocks.join(", ")}\n ${r.title}\n`);
49
+ process.stdout.write(`${n}. ${r.identifier} holds ${r.blocks.length}: ${r.blocks.join(", ")}\n ${r.title}\n`);
49
50
  }
50
51
  if (idle.length && (flags.all || holding.length === 0)) {
51
52
  process.stdout.write(`${holding.length ? "\n" : ""}asks that hold nothing (not shown in Waiting on me until they block something):\n`);
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- // lib/cli.mjs — the one way a skill script reaches Catalyst Cloud: spawn the catalyst-skills CLI.
2
+ // lib/cli.mjs — the one way a skill script reaches Catalyst Cloud: spawn the catalyst CLI.
3
3
  // The CLI holds the SDK and the key; this file holds neither. It reads customer.json only
4
4
  // to learn where the CLI lives, and it exits 2 with one line when the machine is not connected.
5
5
  // Run any script beside this one with --help; this file is a library and is never run directly.
@@ -8,7 +8,9 @@ import { existsSync, readFileSync } from "node:fs";
8
8
  import { join } from "node:path";
9
9
  import { CONNECT_COMMAND, hasCredential } from "./credential.mjs";
10
10
 
11
- export const PACKAGE = "@catalyst-cloud/catalyst-skills";
11
+ export const PACKAGE = "@catalyst-cloud/cli";
12
+ /** The package ships two commands, so npx needs the one to run named: `npx -p <package> catalyst`. */
13
+ export const NPX_ARGS = ["-p", PACKAGE, "catalyst"];
12
14
  export const NOT_CONFIGURED_EXIT = 2;
13
15
 
14
16
  export function configPath() {
@@ -36,7 +38,7 @@ function notConfigured(why) {
36
38
  }
37
39
 
38
40
  /**
39
- * Run one catalyst-skills verb and return {code, stdout, stderr}. Uses the CLI path the login
41
+ * Run one catalyst verb and return {code, stdout, stderr}. Uses the CLI path the login
40
42
  * recorded when it still exists, else `npx <package>`. A CLI exit of 2 with a "not joined" or
41
43
  * "not connected" line is turned into this script's own exit 2, so every caller sees one contract.
42
44
  */
@@ -44,7 +46,7 @@ export function runCli(args, opts = {}) {
44
46
  const cfg = loadConfig();
45
47
  const useRecorded = typeof cfg.cliPath === "string" && existsSync(cfg.cliPath);
46
48
  const cmd = useRecorded ? process.execPath : "npx";
47
- const argv = useRecorded ? [cfg.cliPath, ...args] : [PACKAGE, ...args];
49
+ const argv = useRecorded ? [cfg.cliPath, ...args] : [...NPX_ARGS, ...args];
48
50
  const res = spawnSync(cmd, argv, {
49
51
  input: opts.stdin,
50
52
  encoding: "utf8",
@@ -6,12 +6,12 @@
6
6
  //
7
7
  // customer.json carries exactly one credential: a personal key (`key`), or the keyless login's
8
8
  // session (`auth`, the recommended rail). A script never reads either for its value: it spawns the
9
- // catalyst-skills CLI, which authenticates with whichever is present and refreshes a login's token
9
+ // catalyst CLI, which authenticates with whichever is present and refreshes a login's token
10
10
  // itself. A new credential kind lands here, once.
11
11
 
12
12
  /** The command that connects this machine, as every not-connected line names it. */
13
13
  export const CONNECT_COMMAND =
14
- "npx @catalyst-cloud/catalyst-skills login (or, with a personal key: CATALYST_CLOUD_TOKEN=<your personal key> npx @catalyst-cloud/catalyst-skills login)";
14
+ "npx -p @catalyst-cloud/cli catalyst login (or, with a personal key: CATALYST_CLOUD_TOKEN=<your personal key> npx -p @catalyst-cloud/cli catalyst login)";
15
15
 
16
16
  /** True when `cfg` (parsed customer.json) holds a usable credential of either kind. Never throws. */
17
17
  export function hasCredential(cfg) {
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  // raise.mjs — file one decision for the human as an ask ticket, through the cloud's own ask route.
3
- // Wraps `catalyst-skills ask raise`. You pass fields (question, options, default, what it blocks);
3
+ // Wraps `catalyst ask raise`. You pass fields (question, options, default, what it blocks);
4
4
  // the cloud renders the body from the tenant's ask template, applies the ask labels, and creates the
5
5
  // blocking relations in one atomic write. Headings are never composed here.
6
6
  import { mustRun, parseFlags, parseJson, printHelp } from "./lib/cli.mjs";
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  // settle.mjs — record the human's answer on an ask and release the work it held.
3
- // 1. `catalyst-skills ask accept <ask> --answer <commentId> --role <role>` records which comment is
3
+ // 1. `catalyst ask accept <ask> --answer <commentId> --role <role>` records which comment is
4
4
  // the accepted answer, as the app actor.
5
5
  // 2. Every open ticket the ask blocks gets one bookkeeping comment naming the ask and the answer,
6
6
  // so the next agent on that ticket reads the decision without opening the ask.