@remits/remits-cli 0.1.77 → 0.1.80

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/README.md CHANGED
@@ -55,7 +55,8 @@ remits-cli install --skills --overwrite true
55
55
 
56
56
  - `components stage` uploads the current working tree into the staging cache used by test-mode execution. It replaces the branch/user staging scope with the current manifest, so stale aliases from prior stages are removed.
57
57
  - `components status` shows the branch/user staging entries that can shadow DB components during CLI-scoped test-mode execution.
58
- - `components clear` clears the branch/user staging scope. Use `--component-type` + `--component-id` to clear one component; omit them to clear all staged entries for the current branch.
58
+ - `components clear` clears staged entries. Scope it with `--component-type` and/or `--component-id`. Component ids are type-local, so an id alone clears that one component when the id is staged in only one family; if the same id is staged across multiple families it returns an ambiguity error asking you to add `--component-type`. With no filter it clears every staged entry for the current branch; pass `--all` to force the full-branch wipe explicitly.
59
+ - `components stage`, `components status`, and `components clear` print concise summaries by default. Add `--json` or `--verbose` to print the full server response.
59
60
  - `components sync` performs a server-side sync from the git remote into the Remits platform for the selected branch. It does not run local git commands. After a successful sync, the platform clears the branch/user staging scope so staged aliases cannot keep shadowing the newly synced DB rows.
60
61
  - `components commit` is a convenience wrapper that performs local git commit/push, then `components sync`, then local `git fetch`/`git pull --ff-only`.
61
62
  - `components sync` returns the post-sync branch SHA produced by the platform. `components commit` verifies that `origin/<branch>` and local `HEAD` both match that exact SHA after the final pull.
package/index.js CHANGED
@@ -92,6 +92,10 @@ function parseArgs(argv) {
92
92
  return out;
93
93
  }
94
94
 
95
+ function flagEnabled(value) {
96
+ return value === true || value === 'true' || value === '1' || value === 'yes';
97
+ }
98
+
95
99
  function ensureSessionDir() {
96
100
  if (!fs.existsSync(SESSION_DIR)) {
97
101
  fs.mkdirSync(SESSION_DIR, { recursive: true });
@@ -1635,11 +1639,80 @@ async function pushComponentsCommand(flags) {
1635
1639
  components
1636
1640
  }).then((r) => r.data);
1637
1641
 
1642
+ if (flagEnabled(flags.json)) {
1643
+ console.log(JSON.stringify(response, null, 2));
1644
+ return response;
1645
+ }
1646
+
1638
1647
  printSessionResolutionWarning(sessionContext);
1639
1648
  printResolvedBaseUrl(baseUrl);
1640
1649
  console.log('Data mode:', response.dataMode || dataMode);
1641
1650
  console.log('Mode:', response.mode || mode);
1642
- console.log('Components sync:', JSON.stringify(response, null, 2));
1651
+ printStageSummary(response, flags);
1652
+ }
1653
+
1654
+ function shouldPrintFullComponentResponse(flags) {
1655
+ return flagEnabled(flags.verbose);
1656
+ }
1657
+
1658
+ function printFullResponseHint() {
1659
+ console.log('Full response: use --json or --verbose');
1660
+ }
1661
+
1662
+ function componentTypeCounts(entries) {
1663
+ const counts = {};
1664
+ for (const entry of entries || []) {
1665
+ const type = entry.componentType || entry.type || 'Unknown';
1666
+ counts[type] = (counts[type] || 0) + 1;
1667
+ }
1668
+ return counts;
1669
+ }
1670
+
1671
+ function printComponentTypeCounts(entries) {
1672
+ const counts = componentTypeCounts(entries);
1673
+ const summary = Object.keys(counts)
1674
+ .sort()
1675
+ .map((type) => type + ':' + counts[type])
1676
+ .join(', ');
1677
+ if (summary) {
1678
+ console.log('By type:', summary);
1679
+ }
1680
+ }
1681
+
1682
+ function printComponentCommandResponse(label, response, flags) {
1683
+ if (shouldPrintFullComponentResponse(flags)) {
1684
+ console.log(label + ':', JSON.stringify(response, null, 2));
1685
+ return;
1686
+ }
1687
+ printFullResponseHint();
1688
+ }
1689
+
1690
+ function printStageSummary(response, flags) {
1691
+ console.log('Updated:', response.updated || 0);
1692
+ console.log('Unchanged:', response.unchanged || 0);
1693
+ console.log('Skipped:', Array.isArray(response.skipped) ? response.skipped.length : 0);
1694
+ if (response.reconcile) {
1695
+ console.log('Reconciled stale keys:', response.reconcile.removedCount || 0);
1696
+ }
1697
+ if (response.staging) {
1698
+ console.log('Remaining staged count:', response.staging.remainingCount || 0);
1699
+ }
1700
+ printComponentCommandResponse('Components stage', response, flags);
1701
+ }
1702
+
1703
+ function printStatusSummary(response, flags) {
1704
+ console.log('Staged count:', response.stagedCount || 0);
1705
+ printComponentTypeCounts(response.entries || []);
1706
+ printComponentCommandResponse('Components staging', response, flags);
1707
+ }
1708
+
1709
+ function printClearSummary(response, flags) {
1710
+ console.log('Cleared keys:', response.clearedCount || 0);
1711
+ console.log('Remaining staged count:', response.remainingCount || 0);
1712
+ if (Array.isArray(response.clearedKeys) && response.clearedKeys.length && response.clearedKeys.length <= 10) {
1713
+ console.log('Cleared:', response.clearedKeys.join(', '));
1714
+ }
1715
+ printComponentCommandResponse('Components clear', response, flags);
1643
1716
  }
1644
1717
 
1645
1718
  async function statusComponentsCommand(flags) {
@@ -1666,12 +1739,16 @@ async function statusComponentsCommand(flags) {
1666
1739
  throw new Error(response.message || 'Staging status failed');
1667
1740
  }
1668
1741
 
1742
+ if (flagEnabled(flags.json)) {
1743
+ console.log(JSON.stringify(response, null, 2));
1744
+ return response;
1745
+ }
1746
+
1669
1747
  printSessionResolutionWarning(sessionContext);
1670
1748
  printResolvedBaseUrl(baseUrl);
1671
1749
  console.log('Data mode:', response.dataMode || dataMode);
1672
1750
  console.log('Mode:', response.mode || 'status');
1673
- console.log('Staged count:', response.stagedCount || 0);
1674
- console.log('Components staging:', JSON.stringify(response, null, 2));
1751
+ printStatusSummary(response, flags);
1675
1752
  return response;
1676
1753
  }
1677
1754
 
@@ -1687,13 +1764,23 @@ async function clearComponentsCommand(flags) {
1687
1764
  const componentType = flags['component-type'] || flags.type;
1688
1765
  const componentId = flags['component-id'] || flags.id;
1689
1766
 
1767
+ // A clear is SCOPED when a type and/or id is given. Component ids are type-local, so an id alone can
1768
+ // match more than one family; the server clears it only when unambiguous and otherwise returns an
1769
+ // ambiguity error asking for --component-type (pass the type to target exactly one). Only escalate to
1770
+ // clearAll (the whole branch/user scope) when NO filter is supplied — never because a filter was
1771
+ // partial. Passing `--all` forces the full-scope wipe.
1772
+ const hasType = Boolean(componentType && String(componentType).trim());
1773
+ const hasId = componentId !== undefined && componentId !== null && String(componentId).trim() !== '';
1774
+ const scoped = hasType || hasId;
1775
+ const clearAll = flagEnabled(flags.all) || flagEnabled(flags['clear-all']) || !scoped;
1776
+
1690
1777
  const response = await loggedPost(api, cwd, '/cli/components', {
1691
1778
  token: session.token,
1692
1779
  accountId,
1693
1780
  branchName,
1694
1781
  dataMode,
1695
1782
  mode: 'clear',
1696
- clearAll: !(componentType && componentId),
1783
+ clearAll,
1697
1784
  componentType,
1698
1785
  componentId
1699
1786
  }).then((r) => r.data);
@@ -1702,13 +1789,16 @@ async function clearComponentsCommand(flags) {
1702
1789
  throw new Error(response.message || 'Staging clear failed');
1703
1790
  }
1704
1791
 
1792
+ if (flagEnabled(flags.json)) {
1793
+ console.log(JSON.stringify(response, null, 2));
1794
+ return response;
1795
+ }
1796
+
1705
1797
  printSessionResolutionWarning(sessionContext);
1706
1798
  printResolvedBaseUrl(baseUrl);
1707
1799
  console.log('Data mode:', response.dataMode || dataMode);
1708
1800
  console.log('Mode:', response.mode || 'clear');
1709
- console.log('Cleared count:', response.clearedCount || 0);
1710
- console.log('Remaining staged count:', response.remainingCount || 0);
1711
- console.log('Components staging:', JSON.stringify(response, null, 2));
1801
+ printClearSummary(response, flags);
1712
1802
  return response;
1713
1803
  }
1714
1804
 
@@ -1735,6 +1825,11 @@ async function syncComponentsCommand(flags) {
1735
1825
  throw new Error(response.message || 'Server sync failed');
1736
1826
  }
1737
1827
 
1828
+ if (flagEnabled(flags.json)) {
1829
+ console.log(JSON.stringify(response, null, 2));
1830
+ return response;
1831
+ }
1832
+
1738
1833
  printSessionResolutionWarning(sessionContext);
1739
1834
  printResolvedBaseUrl(baseUrl);
1740
1835
  console.log('Data mode:', response.dataMode || dataMode);
@@ -4338,6 +4433,7 @@ function releaseAutoUpdateLock() {
4338
4433
  function shouldAutoUpdate(command, flags) {
4339
4434
  if (!command || command === 'help' || command === '--help') return false;
4340
4435
  if (flags && flags['no-auto-update']) return false;
4436
+ if (flags && flagEnabled(flags.json)) return false;
4341
4437
  if (process.env.REMITS_CLI_AUTO_UPDATE && AUTO_UPDATE_DISABLED_VALUES.has(String(process.env.REMITS_CLI_AUTO_UPDATE).toLowerCase())) {
4342
4438
  return false;
4343
4439
  }
@@ -4408,6 +4504,7 @@ async function main() {
4408
4504
  const args = parseArgs(originalArgv);
4409
4505
  const [command, subcommand] = args._;
4410
4506
  const wantsHelp = args.help === true || subcommand === 'help' || subcommand === '--help' || args._.includes('--help');
4507
+ const wantsJson = flagEnabled(args.json);
4411
4508
 
4412
4509
  if (shouldAutoUpdate(command, args)) {
4413
4510
  const requireSuccessfulAutoUpdate = command === 'start';
@@ -4421,7 +4518,7 @@ async function main() {
4421
4518
  // Skip for lifecycle subcommands and help.
4422
4519
  const isLifecycleCmd = command === 'listen' || command === 'start' || command === 'stop' || command === 'status';
4423
4520
  const isHelpCmd = !command || command === 'help' || command === '--help' || wantsHelp;
4424
- if (!isHelpCmd && !isLifecycleCmd && !isListenerRunning()) {
4521
+ if (!wantsJson && !isHelpCmd && !isLifecycleCmd && !isListenerRunning()) {
4425
4522
  try {
4426
4523
  const dashboardUrl = await autoStartServiceIfNeeded();
4427
4524
  if (dashboardUrl) {
@@ -4436,7 +4533,7 @@ async function main() {
4436
4533
  // only platform-authenticated users ever receive them. `auth` syncs its own
4437
4534
  // guides, so it is excluded here.
4438
4535
  const GUIDE_SYNC_COMMANDS = new Set(['components', 'test', 'token', 'tools', 'tool']);
4439
- if (!isHelpCmd && GUIDE_SYNC_COMMANDS.has(command)) {
4536
+ if (!wantsJson && !isHelpCmd && GUIDE_SYNC_COMMANDS.has(command)) {
4440
4537
  try { await ensureGuidesSynced(process.cwd(), args); } catch (_) { /* best-effort */ }
4441
4538
  }
4442
4539
 
@@ -4454,9 +4551,9 @@ async function main() {
4454
4551
  console.log(' remits-cli install --skills [--target codex|claude|gemini|all] [--overwrite true]');
4455
4552
  console.log(' remits-cli tools [--base-url URL] [--account-id ID] [--data-mode test|prod]');
4456
4553
  console.log(' remits-cli tool --name <toolName> [--base-url URL] [--input \"{...}\"|--input-file file.json] [--data-mode test|prod]');
4457
- console.log(' remits-cli components stage [--base-url URL] [--account-id ID] [--branch BRANCH] [--data-mode test|prod]');
4458
- console.log(' remits-cli components status [--base-url URL] [--account-id ID] [--branch BRANCH] [--component-type TYPE --component-id ID]');
4459
- console.log(' remits-cli components clear [--base-url URL] [--account-id ID] [--branch BRANCH] [--component-type TYPE --component-id ID]');
4554
+ console.log(' remits-cli components stage [--base-url URL] [--account-id ID] [--branch BRANCH] [--data-mode test|prod] [--json|--verbose]');
4555
+ console.log(' remits-cli components status [--base-url URL] [--account-id ID] [--branch BRANCH] [--component-type TYPE --component-id ID] [--json|--verbose]');
4556
+ console.log(' remits-cli components clear [--base-url URL] [--account-id ID] [--branch BRANCH] [--component-type TYPE] [--component-id ID] [--all] [--json|--verbose]');
4460
4557
  console.log(' remits-cli components sync [--base-url URL] [--account-id ID] [--branch BRANCH] [--data-mode test|prod]');
4461
4558
  console.log(' remits-cli components commit [--message \"msg\"] [--allow-empty true|false] [--skip-git true|false] [--branch BRANCH] [--data-mode test|prod]');
4462
4559
  console.log(' remits-cli test run --test <id|name> [--base-url URL] [--names name1,name2] [--watch true|false] [--data-mode test|prod]');
@@ -4466,9 +4563,9 @@ async function main() {
4466
4563
 
4467
4564
  if (command === 'components' && wantsHelp) {
4468
4565
  console.log('Usage: remits-cli components <stage|status|clear|sync|commit>');
4469
- console.log(' remits-cli components stage [--base-url URL] [--account-id ID] [--branch BRANCH] [--data-mode test|prod]');
4470
- console.log(' remits-cli components status [--base-url URL] [--account-id ID] [--branch BRANCH] [--component-type TYPE --component-id ID]');
4471
- console.log(' remits-cli components clear [--base-url URL] [--account-id ID] [--branch BRANCH] [--component-type TYPE --component-id ID]');
4566
+ console.log(' remits-cli components stage [--base-url URL] [--account-id ID] [--branch BRANCH] [--data-mode test|prod] [--json|--verbose]');
4567
+ console.log(' remits-cli components status [--base-url URL] [--account-id ID] [--branch BRANCH] [--component-type TYPE --component-id ID] [--json|--verbose]');
4568
+ console.log(' remits-cli components clear [--base-url URL] [--account-id ID] [--branch BRANCH] [--component-type TYPE] [--component-id ID] [--all] [--json|--verbose]');
4472
4569
  console.log(' remits-cli components sync [--base-url URL] [--account-id ID] [--branch BRANCH] [--data-mode test|prod]');
4473
4570
  console.log(' remits-cli components commit [--message \"msg\"] [--allow-empty true|false] [--skip-git true|false] [--branch BRANCH] [--data-mode test|prod]');
4474
4571
  process.exit(0);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@remits/remits-cli",
3
- "version": "0.1.77",
3
+ "version": "0.1.80",
4
4
  "description": "Local CLI for auth, component sync, and live test execution against Remits",
5
5
  "license": "MIT",
6
6
  "private": false,
@@ -217,7 +217,7 @@ Use `mcp_support_ticket` to manage lifecycle:
217
217
  - `update_status` — move to `in_progress` or `pending_review`
218
218
  - `complete` — resolve the ticket with a summary of what was done
219
219
  - `release` — unassign if you cannot continue
220
- - Always call `mcp_support_ticket` with the ticket's owning `accountId`.
220
+ - **Pulling a ticket by number is enough — you do NOT need to know its account first.** The `ticketId` IS the ticket's globally-unique anchor id, and `mcp_support_ticket` resolves the owning account from it for every action that operates on an existing ticket (`read`, `accept`, `update_status`, `complete`, `release`, `record_progress`, `add_artifact`, `get_attachment`). So when a user says "pull ticket 19463", just call `read` with `{ "action": "read", "ticketId": "19463" }` from any authenticated **prod** session (the ticket lives in prod data) — omit `accountId` entirely. The response returns the resolved `accountId`/`accountName` (and `implementationAccountId` when set); use those for any follow-up work. **Only `create` requires an explicit `accountId`** (a brand-new ticket has no anchor to resolve from). If a bare `ticketId` returns "Support ticket not found", double-check you are in `--data-mode prod`, then fall back to passing an explicit `accountId`.
221
221
  - If a ticket is part of the request, manage the lifecycle proactively. Do not wait for the human user to remind you to read, accept, update, complete, or release it.
222
222
 
223
223
  Ticket-routing context:
@@ -811,8 +811,9 @@ TestMode still uses the committed DB source. Staging remains a dev/verification
811
811
  - **Confirm the DB version:** `mcp_component_view` reads the live DB source directly (no staging, no compile
812
812
  cache), so it is the source of truth for "what was committed."
813
813
  - **Ask the CLI what is staged:** `remits-cli components status` lists the current branch/user staged entries,
814
- including `componentSource`, staged fields, aliases, hashes, and TTLs. `remits-cli components clear` removes
815
- those entries when you intentionally want to fall back to DB source.
814
+ including staged fields, aliases, hashes, and TTLs. The default terminal output is concise; pass `--json` or
815
+ `--verbose` when you need the full staged-entry payload. `remits-cli components clear` removes those entries
816
+ when you intentionally want to fall back to DB source.
816
817
 
817
818
  ### Stage / commit / clear with the MCP tools
818
819
 
@@ -1108,9 +1109,9 @@ Create and manage the full lifecycle of account-relative `support_tickets`.
1108
1109
 
1109
1110
  | Parameter | Required | Description |
1110
1111
  |-----------|----------|-------------|
1111
- | `accountId` | yes | The account that owns the support ticket |
1112
+ | `accountId` | conditional | The account that owns the support ticket. **Required only for `create`.** For every other action it is optional — the tool resolves the owning account from `ticketId` (the ticket's anchor id) and returns it. Pass it only to override/disambiguate. |
1112
1113
  | `action` | yes | `create`, `read`, `accept`, `update_status`, `complete`, `release`, `record_progress`, `add_artifact`, or `get_attachment` |
1113
- | `ticketId` | conditional | Required for every action **except** `create` (which returns the new ticket ID) |
1114
+ | `ticketId` | conditional | Required for every action **except** `create` (which returns the new ticket ID). Alone it is sufficient to resolve the ticket and its owning account. |
1114
1115
  | `subject` | conditional | Short title. Required for `create`. |
1115
1116
  | `type` | conditional | Required for `create`: `enhancement`, `defect`, `question`, `task`, or `incident` |
1116
1117
  | `priority` | no | `low`/`medium`/`high`/`critical` for `create` (default `medium`) |
@@ -1371,9 +1372,9 @@ remits-cli stop
1371
1372
  remits-cli status
1372
1373
  remits-cli listen [stop|status] [--foreground true] # compatibility alias
1373
1374
  remits-cli data-mode [set test|prod]
1374
- remits-cli components stage [--branch <name>] [--data-mode test|prod]
1375
- remits-cli components status [--branch <name>] [--component-type <type>] [--component-id <id>]
1376
- remits-cli components clear [--branch <name>] [--component-type <type>] [--component-id <id>]
1375
+ remits-cli components stage [--branch <name>] [--data-mode test|prod] [--json|--verbose]
1376
+ remits-cli components status [--branch <name>] [--component-type <type>] [--component-id <id>] [--json|--verbose]
1377
+ remits-cli components clear [--branch <name>] [--component-type <type>] [--component-id <id>] [--all] [--json|--verbose] # id alone scopes to one component when unambiguous (ids are type-local; add --component-type if the same id is staged in multiple families); no filter clears the whole branch scope; --all forces the full wipe
1377
1378
  remits-cli components sync [--branch <name>] [--data-mode test|prod] # gated durable repo->DB reconciliation only
1378
1379
  remits-cli components commit [--message "msg"] [--data-mode test|prod]
1379
1380
  remits-cli test run --test <id|name> [--names "a,b"] [--watch true|false] [--data-mode test|prod]
@@ -1402,7 +1403,7 @@ For tests specifically:
1402
1403
  | Tool parameters rejected | Tool schemas may be cached. Run `remits-cli tools` to refresh `.remits-cli/tools/tools.json` with latest schemas. |
1403
1404
  | Tool response missing | Check `./.remits-cli/tool-responses/` |
1404
1405
  | Staged change has no effect in a live (non-CLI) run | Staged overrides resolve only under a CLI TestMode (`branchName`+`cliUserId`). Live webhooks and other non-CLI runtime paths still use the DB. `commit` to make it durable. See "Component Resolution". |
1405
- | New source shown by `mcp_component_view` but old behavior persists after sync/commit | In-memory compile cache (`CLOSURE_CACHE`, version-keyed, per instance) still holds the prior closure. Environmental; the platform owner recycles the instance. |
1406
+ | New source shown by `mcp_component_view` but old behavior persists after sync/commit | The compile cache (`CLOSURE_CACHE`) is keyed by `version:<N>:<sourceHash12>`, so a source change on the same version now invalidates it automatically — a run right after sync/commit picks up the new source. If old behavior still persists, confirm the run actually hit the synced instance and that no staged override is still shadowing DB (`remits-cli components status`). |
1406
1407
  | Staged Reader test run throws `No enum constant ObjectType.<family>` | The staged entry has the component family in `type` (should be `kind`). Clear + re-stage; if it persists, the `mcp_component_edit` tool on that instance is on an old/cached version. Inspect with `mcp_cache`. |
1407
1408
  | Unsure whether a run used staged vs DB source | Query `mcp_system_logs` for `Using Cached BCD` — `Signature: cli:<hash>` = staged, `version:<N>:<sourceHash12>` = DB. CLI/MCP tool results also report `componentSource` and `componentSignature` when available. |
1408
1409
  | Service already running | Run `remits-cli status` to get the dashboard URL, or `remits-cli stop` before restarting. |