@remits/remits-cli 0.1.109 → 0.1.110

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/index.js CHANGED
@@ -5617,13 +5617,37 @@ function resolveAgentId(flags, options = {}) {
5617
5617
  );
5618
5618
  }
5619
5619
 
5620
+ /**
5621
+ * The host and lane a support agent registers against when it is told nothing.
5622
+ *
5623
+ * An agent works REAL support tickets, and it must be startable from any directory on the machine —
5624
+ * not only from inside an account repo. So it defaults to the platform host the CLI ships with
5625
+ * (`REMITS_BASE_URL` when set) and to the `prod` lane.
5626
+ *
5627
+ * That is a deliberate exception to the CLI's test-first default, which exists to stop a developer
5628
+ * ITERATING from touching live data. Registering presence mutates no business data, and a test-lane
5629
+ * agent is silently useless for support: it registers, appears online, and can never be routed a
5630
+ * production ticket. Ask for `--data-mode test` when you want a fixture agent.
5631
+ */
5632
+ function agentDefaults(flags, entry) {
5633
+ return {
5634
+ baseUrl: normalizeBaseUrl(
5635
+ (flags && flags['base-url']) || (entry && entry.baseUrl) || DEFAULT_BASE_URL),
5636
+ dataMode: normalizeDataMode(
5637
+ (flags && (flags['data-mode'] || flags.dataMode)) || (entry && entry.dataMode) || 'prod')
5638
+ };
5639
+ }
5640
+
5620
5641
  function agentSessionFor(flags, entry) {
5621
5642
  const cwd = (entry && entry.cwd) || process.cwd();
5643
+ const defaults = agentDefaults(flags, entry);
5622
5644
  const context = resolveSessionContext(cwd, Object.assign({}, flags, {
5623
- 'base-url': (flags && flags['base-url']) || (entry && entry.baseUrl) || undefined
5645
+ 'base-url': defaults.baseUrl,
5646
+ 'data-mode': defaults.dataMode
5624
5647
  }));
5625
5648
  if (!context.session || !context.session.token) {
5626
- throw new Error('No authenticated session. Run: remits-cli auth');
5649
+ throw new Error('No authenticated session for ' + defaults.baseUrl +
5650
+ '. Run: remits-cli auth --base-url ' + defaults.baseUrl);
5627
5651
  }
5628
5652
  // resolveSessionContext names it `resolvedBaseUrl` and resolves no data lane, so normalize both here
5629
5653
  // rather than letting each caller re-derive them. Destructuring `{ baseUrl, dataMode }` off it yields
@@ -5631,8 +5655,8 @@ function agentSessionFor(flags, entry) {
5631
5655
  return {
5632
5656
  session: context.session,
5633
5657
  accountId: context.accountId,
5634
- baseUrl: normalizeBaseUrl(context.resolvedBaseUrl || (entry && entry.baseUrl) || DEFAULT_BASE_URL),
5635
- dataMode: resolveDataMode(flags, context.session),
5658
+ baseUrl: defaults.baseUrl,
5659
+ dataMode: defaults.dataMode,
5636
5660
  sessionResolutionWarning: context.sessionResolutionWarning
5637
5661
  };
5638
5662
  }
@@ -5712,6 +5736,9 @@ async function agentRegisterCommand(flags, options = {}) {
5712
5736
  cwd,
5713
5737
  baseUrl,
5714
5738
  dataMode,
5739
+ // The accounts the platform ACCEPTED, so `agent list` can scope itself to the work this session
5740
+ // can actually be routed rather than to whichever session happened to be most recent.
5741
+ accountIds: response.accountIds || [],
5715
5742
  accountId: Number(session.accountId) || null,
5716
5743
  anchorPid: anchor.pid,
5717
5744
  anchorSource: anchor.source,
@@ -5729,19 +5756,31 @@ async function agentRegisterCommand(flags, options = {}) {
5729
5756
  return;
5730
5757
  }
5731
5758
 
5732
- console.log('Registered agent ' + response.agentId);
5759
+ const accepted = response.accountIds || [];
5760
+ console.log('Registered as a support agent: ' + response.agentId);
5733
5761
  console.log(' label ' + payload.label);
5734
- console.log(' data lane ' + dataMode + (dataMode === 'prod' ? ' (production data)' : ''));
5735
- console.log(' accounts ' + (response.accountIds || []).join(', '));
5762
+ console.log(' platform ' + baseUrl);
5763
+ console.log(' data lane ' + dataMode + (dataMode === 'prod' ? ' (live support tickets)' : ' (fixtures only)'));
5764
+ console.log(' accounts ' + accepted.length + ' account(s) this session can be routed work for');
5765
+ console.log(' ' + accepted.join(', '));
5736
5766
  console.log(' heartbeat every ' + Math.round(AGENT_HEARTBEAT_INTERVAL_MS / 1000) + 's, anchored to pid ' +
5737
- anchor.pid + ' (' + anchor.source + ')');
5767
+ anchor.pid + ' (' + anchor.source + '), ends when this session ends');
5738
5768
  if ((response.skippedAccounts || []).length) {
5739
5769
  console.log(' refused ' + response.skippedAccounts
5740
5770
  .map((entry) => entry.accountId + ' (' + entry.reason + ')').join(', '));
5741
5771
  }
5772
+ if (dataMode !== 'prod') {
5773
+ console.log('');
5774
+ console.log('NOTE: a ' + dataMode + '-lane agent never receives production tickets. Re-register with');
5775
+ console.log(' --data-mode prod to take real support work.');
5776
+ }
5742
5777
  console.log('');
5743
- console.log('This session is now available for support tickets. Ask for work with:');
5744
- console.log(' remits-cli agent work');
5778
+ console.log('You are on duty. The support loop, repeated for as long as you are working:');
5779
+ console.log(' 1. remits-cli agent work --wait 600 # ask for work; returns as soon as any arrives');
5780
+ console.log(' 2. remits-cli agent status --state working --ticket <id> --activity "what you are doing"');
5781
+ console.log(' 3. work the ticket; keep step 2 current as you change what you are doing');
5782
+ console.log(' 4. close it out via mcp_support_ticket (accept -> update_status -> complete)');
5783
+ console.log(' 5. remits-cli agent status --state idle # then go back to step 1');
5745
5784
  }
5746
5785
 
5747
5786
  function readCliVersion() {
@@ -5946,11 +5985,24 @@ async function agentWorkCommand(flags) {
5946
5985
 
5947
5986
  async function agentListCommand(flags) {
5948
5987
  const cwd = process.cwd();
5949
- const context = agentSessionFor(flags, null);
5950
- const accountId = resolvePreferredAccountId(cwd, flags, context.session);
5951
- const response = await buildAxios(context.baseUrl, context.session.token, 15000)
5988
+ const mine = listLocalAgents()[0] || null;
5989
+ const context = agentSessionFor(flags, mine);
5990
+
5991
+ // An explicit --account-id asks about one account. Otherwise, if this machine has a registered
5992
+ // agent, scope to the accounts it was accepted for — the peers it could actually share work with.
5993
+ // Falling back to "whichever session was most recent" answers a question nobody asked.
5994
+ const explicitAccountId = Number(flags && flags['account-id']);
5995
+ const scopedAccountIds = (!Number.isFinite(explicitAccountId) && mine && Array.isArray(mine.accountIds))
5996
+ ? mine.accountIds
5997
+ : null;
5998
+ const accountId = Number.isFinite(explicitAccountId) && explicitAccountId > 0
5999
+ ? explicitAccountId
6000
+ : (scopedAccountIds ? null : resolvePreferredAccountId(cwd, flags, context.session));
6001
+
6002
+ const response = await buildAxios(context.baseUrl, context.session.token, 20000)
5952
6003
  .post('/cli/agents', {
5953
6004
  accountId,
6005
+ accountIds: scopedAccountIds,
5954
6006
  dataMode: context.dataMode,
5955
6007
  all: flagEnabled(flags.all)
5956
6008
  }).then((r) => r.data);
@@ -5959,12 +6011,14 @@ async function agentListCommand(flags) {
5959
6011
  console.log(JSON.stringify(response, null, 2));
5960
6012
  return;
5961
6013
  }
6014
+ const scopeLabel = accountId ? 'account ' + accountId
6015
+ : (scopedAccountIds ? scopedAccountIds.length + ' account(s) this session covers' : 'your accounts');
5962
6016
  const agents = (response && response.agents) || [];
5963
6017
  if (!agents.length) {
5964
- console.log('No agents are registered for account ' + accountId + ' in the ' + context.dataMode + ' lane.');
6018
+ console.log('No agents are registered for ' + scopeLabel + ' in the ' + context.dataMode + ' lane.');
5965
6019
  return;
5966
6020
  }
5967
- console.log(agents.length + ' agent(s) available for account ' + accountId + ':');
6021
+ console.log(agents.length + ' agent(s) available across ' + scopeLabel + ':');
5968
6022
  for (const agent of agents) {
5969
6023
  console.log('');
5970
6024
  console.log(' ' + agent.agentId);
@@ -6008,9 +6062,13 @@ async function agentCommand(flags, subcommand) {
6008
6062
  function printAgentHelp() {
6009
6063
  console.log('Usage: remits-cli agent <subcommand>');
6010
6064
  console.log('');
6011
- console.log(' register [--label NAME] [--data-mode test|prod] [--account-id ID]');
6012
- console.log(' Make THIS terminal session available to work support tickets. Starts a heartbeat');
6013
- console.log(' that ends when this session ends, so a closed tab stops receiving work on its own.');
6065
+ console.log(' register [--label NAME] [--data-mode test|prod] [--base-url URL]');
6066
+ console.log(' Make THIS terminal session available to work support tickets. Runs from ANY');
6067
+ console.log(' directory — it registers for every account repo indexed on this machine that your');
6068
+ console.log(' user can reach, so you do not have to be inside a particular repo. Defaults to the');
6069
+ console.log(' production platform and the prod lane, because a support agent works real tickets.');
6070
+ console.log(' Starts a heartbeat that ends when this session ends, so a closed tab stops');
6071
+ console.log(' receiving work on its own.');
6014
6072
  console.log('');
6015
6073
  console.log(' work [--wait SECONDS] [--json]');
6016
6074
  console.log(' Ask for the tickets routed to this session. With --wait it keeps asking until');
@@ -6021,6 +6079,9 @@ function printAgentHelp() {
6021
6079
  console.log('');
6022
6080
  console.log(' list [--account-id ID] [--json] Who else is available for an account.');
6023
6081
  console.log(' release Deregister this session immediately.');
6082
+ console.log('');
6083
+ console.log(' After `register`, the other subcommands need no flags: they reuse the platform, lane');
6084
+ console.log(' and identity this session registered with.');
6024
6085
  }
6025
6086
 
6026
6087
  async function listenCommand(flags) {
@@ -6589,8 +6650,8 @@ async function main() {
6589
6650
  console.log(' remits-cli auth [--base-url URL] [--account-id ID] [--port 8765] [--data-mode test|prod]');
6590
6651
  console.log(' remits-cli sessions [list|remove] [--account-id ID] [--base-url URL] [--data-mode test|prod]');
6591
6652
  console.log(' remits-cli config [set] [--agent claude|codex|gemini]');
6592
- console.log(' remits-cli agent register [--label NAME] [--data-mode test|prod] # make THIS terminal available for tickets');
6593
- console.log(' remits-cli agent work [--wait SECONDS] [--json] # ask for tickets routed to this session');
6653
+ console.log(' remits-cli agent register # become a support agent (any directory, prod by default)');
6654
+ console.log(' remits-cli agent work [--wait SECONDS] # ask for tickets routed to this session');
6594
6655
  console.log(' remits-cli agent status [--state idle|working|paused] [--ticket ID] [--activity "..."]');
6595
6656
  console.log(' remits-cli agent list [--account-id ID] # who else is available');
6596
6657
  console.log(' remits-cli agent release # stop receiving tickets now');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@remits/remits-cli",
3
- "version": "0.1.109",
3
+ "version": "0.1.110",
4
4
  "description": "Local CLI for auth, component sync, and live test execution against Remits",
5
5
  "license": "MIT",
6
6
  "private": false,
@@ -20,6 +20,8 @@ description: Use remits-cli for fast branch-scoped component staging, test execu
20
20
  - [Required Local Index Reads](#required-local-index-reads)
21
21
  - [Big Picture: How remits-cli State Is Organized](#big-picture-how-remits-cli-state-is-organized)
22
22
  - [Support Ticket Mental Model](#support-ticket-mental-model)
23
+ - [You are an agent, and you register yourself](#you-are-an-agent-and-you-register-yourself)
24
+ - [The loop](#the-loop)
23
25
  - [Efficiency Rules](#efficiency-rules)
24
26
  - [Account Repository Index](#account-repository-index)
25
27
  - [Two Workflows](#two-workflows)
@@ -460,16 +462,21 @@ workflows, and never one product's view of it.
460
462
 
461
463
  ### You are an agent, and you register yourself
462
464
 
463
- Work reaches you because **this terminal session registered itself as available**:
465
+ **If the user says anything like "register to become a support agent", run exactly this and nothing
466
+ else first:**
464
467
 
465
468
  ```bash
466
- remits-cli agent register # this tab is now a routable agent
467
- remits-cli agent work # ask for the tickets routed to it
469
+ remits-cli agent register
468
470
  ```
469
471
 
470
- Three tabs running Claude are three agents. Each is independently routable, each reports its own
471
- activity, and each stops receiving work when its tab closes — a heartbeat process is anchored to the
472
- session and dies with it, so a crashed agent and a quit agent look identical to the platform.
472
+ No flags, no setup, **no need to be in an account repo** — run it from wherever the session started.
473
+ It registers this terminal for every account repo indexed on this machine that your user can reach,
474
+ against the production platform and the production lane, and prints the accounts it was accepted for.
475
+ It also prints the support loop; follow it.
476
+
477
+ Three tabs running an agent are three agents. Each is independently routable, each reports its own
478
+ activity, and each stops receiving work when its tab closes — a heartbeat anchored to the session dies
479
+ with it, so a crashed agent and a quit agent look identical to the platform.
473
480
 
474
481
  **Nothing is pushed at you.** A terminal mid-task cannot receive a push, so delivery is you asking.
475
482
  That is why the routing decision is a durable field on the ticket rather than a message: you can
@@ -487,21 +494,35 @@ A ticket routed to you is not yet yours. Claim it with `accept`, and the queue t
487
494
 
488
495
  ### The loop
489
496
 
497
+ After `register`, **no agent command needs a flag** — they reuse the platform, lane and identity this
498
+ session registered with.
499
+
490
500
  ```bash
491
- remits-cli agent register --label "claude@merchant-statements"
492
- remits-cli agent work --wait 300 # blocks until something arrives
501
+ remits-cli agent work --wait 600 # returns as soon as work arrives
493
502
  remits-cli agent status --state working --ticket 22454 --activity "reproducing the upload failure"
494
- # ... investigate, fix, verify ...
495
- remits-cli agent status --activity "verifying the fix on localhost"
496
- # ... then close the ticket lifecycle through mcp_support_ticket ...
497
- remits-cli agent status --state idle # ready for the next one
503
+ # ... investigate, fix, verify — keep `status` current as what you are doing changes ...
504
+ # ... close the ticket lifecycle through mcp_support_ticket (accept -> update_status -> complete) ...
505
+ remits-cli agent status --state idle # then ask for work again
498
506
  ```
499
507
 
508
+ **Stay on duty.** When `agent work` returns nothing, ask again — do not stop and wait to be
509
+ re-prompted. Registration persists for the life of the session (the heartbeat keeps you visible and
510
+ routable even while you are not polling), but collecting work is something you have to do.
511
+
500
512
  **Report what you are doing.** `agent status` is how an operator watching the dashboard, or another
501
513
  agent, knows this session is alive and what it is on. It costs one command and it is the difference
502
514
  between a visible queue and a silent one. Update it when you change what you are doing, not on a
503
515
  timer.
504
516
 
517
+ **Work the ticket in the right repo.** A ticket names its `accountId`, and often an
518
+ `implementationAccountId` — the platform/product account whose repo holds the code. Resolve that to a
519
+ local directory through `~/.remits-cli/account-repos.json` and `cd` there before making changes. You
520
+ registered from anywhere; you do not fix anything from anywhere.
521
+
522
+ **Lane note:** `register` defaults to the production lane because a support agent works real tickets.
523
+ `--data-mode test` registers a fixture agent instead, which will never be routed a production ticket —
524
+ use it only when you are deliberately testing the routing itself.
525
+
505
526
  ### Seeing the queue as a human does
506
527
 
507
528
  `remits-cli start` opens a browser control center showing the same facts you are acting on: which
@@ -2750,19 +2771,27 @@ so in its own output; when a test run genuinely needs prod data, pass the flag.
2750
2771
  independent of everything else — no background service is required, and every tab is its own agent.
2751
2772
 
2752
2773
  ```bash
2753
- remits-cli agent register # this session is now routable
2774
+ remits-cli agent register # this session is now routable — no flags, any directory
2754
2775
  remits-cli agent work --wait 300 # ask for tickets routed here
2755
2776
  remits-cli agent status --state working --ticket 22454 --activity "reproducing"
2756
- remits-cli agent list # who else is available for this account
2777
+ remits-cli agent list # who else is available across the accounts you cover
2757
2778
  remits-cli agent release # stop receiving tickets right now
2758
2779
  ```
2759
2780
 
2781
+ **Defaults exist so the user does not have to type them.** With no flags, `register` targets the
2782
+ production platform (`REMITS_BASE_URL` when set) and the **prod** lane, and claims every account repo
2783
+ indexed on this machine. That is a deliberate exception to the CLI's test-first default: registering
2784
+ presence mutates no business data, and a test-lane agent is silently useless for support — it appears
2785
+ online and can never be routed a production ticket. Every command after `register` reuses the
2786
+ platform, lane and identity it registered with.
2787
+
2760
2788
  ### What registration actually does
2761
2789
 
2762
2790
  - Mints an `agentId` for this session and tells the platform which account repos this machine has
2763
- checked out. The platform **verifies** those claims against what your user can access and returns
2764
- the ones it refused, so "I registered but never get tickets for account 52" is answerable from the
2765
- registration output alone.
2791
+ checked out — read from the machine-wide index (`~/.remits-cli/account-repos.json`), which is why
2792
+ the working directory does not matter. The platform **verifies** those claims against what your user
2793
+ can access and returns the ones it refused, so "I registered but never get tickets for account 52"
2794
+ is answerable from the registration output alone.
2766
2795
  - Starts a small detached heartbeat process **anchored to the agent process that owns this terminal**
2767
2796
  (it walks up the process tree to find `claude`/`codex`/`gemini`, then an interactive shell). When
2768
2797
  that process ends, the heartbeat ends and the session stops being routable within a couple of