@remits/remits-cli 0.1.87 → 0.1.90
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 +4 -4
- package/index.js +60 -6
- package/package.json +1 -1
- package/skills/remits-cli/SKILL.md +317 -159
package/README.md
CHANGED
|
@@ -29,10 +29,10 @@ git add -A
|
|
|
29
29
|
git commit -m "sync passing changes"
|
|
30
30
|
git push
|
|
31
31
|
remits-cli components sync
|
|
32
|
-
remits-cli components sync --branch
|
|
33
|
-
remits-cli components sync --branch
|
|
32
|
+
remits-cli components sync --branch feature_branch --dry-run
|
|
33
|
+
remits-cli components sync --branch feature_branch --force-tombstones
|
|
34
34
|
remits-cli token --path page/my-embeddable
|
|
35
|
-
remits-cli token --path page/my-embeddable --variant-branch
|
|
35
|
+
remits-cli token --path page/my-embeddable --variant-branch feature_branch
|
|
36
36
|
remits-cli data-mode
|
|
37
37
|
remits-cli data-mode set prod
|
|
38
38
|
remits-cli sessions list
|
|
@@ -66,7 +66,7 @@ remits-cli install --skills --overwrite true
|
|
|
66
66
|
- `components commit` is a convenience wrapper that performs local git commit/push, then `components sync`, then local `git fetch`/`git pull --ff-only`.
|
|
67
67
|
- `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.
|
|
68
68
|
- `components push` is deprecated and currently behaves the same as `components stage`.
|
|
69
|
-
- `accountId` resolution for CLI commands: explicit `--account-id` flag wins, then the current repo's `account-info.json`, then the active session. For `remits-cli tool` calls the server applies a further precedence — explicit `--account-id` > `input.accountId` > session/repo default — so a tool can execute against a different account than the surrounding repo.
|
|
69
|
+
- `accountId` resolution for CLI commands: explicit `--account-id` flag wins, then the current repo's `account-info.json` (`resolution.accountId`, then the short-lived `repoContext.accountInfoAccountId`, then the legacy top-level id — legacy files are rooted at the hierarchy ROOT, so their top-level `id` may be an ancestor), then the active session. For `remits-cli tool` calls the server applies a further precedence — explicit `--account-id` > `input.accountId` > session/repo default — so a tool can execute against a different account than the surrounding repo.
|
|
70
70
|
- Auth sessions are stored per `accountId + dataMode + baseUrl`, so the same account can stay authenticated against both localhost and production without overwriting the other session.
|
|
71
71
|
- `--base-url` and `--data-mode` are independent. `--base-url` chooses the Remits host (`http://localhost:8080` vs deployed prod), while `--data-mode` chooses the data segment on that host (`test` vs `prod`). Do not assume `--data-mode prod` means the deployed prod host, or that `--data-mode test` means localhost.
|
|
72
72
|
- `remits-cli start` scans the machine for `account-info.json` files and rebuilds `~/.remits-cli/account-repos.json` before bringing up the background service.
|
package/index.js
CHANGED
|
@@ -268,6 +268,19 @@ function printResolvedBaseUrl(baseUrl) {
|
|
|
268
268
|
console.log('Base URL:', normalizeBaseUrl(baseUrl || DEFAULT_BASE_URL));
|
|
269
269
|
}
|
|
270
270
|
|
|
271
|
+
// A tool's OWN verdict, which is separate from whether the call was dispatched. Only an explicit
|
|
272
|
+
// failure signal counts: tools legitimately return strings, arrays, and maps with no `success` key.
|
|
273
|
+
// Used as a fallback when the platform build predates the envelope's `toolSuccess`.
|
|
274
|
+
function toolResultFailed(result) {
|
|
275
|
+
if (!result || typeof result !== 'object' || Array.isArray(result)) return false;
|
|
276
|
+
return result.success === false || result.is_error === true;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
function toolResultMessage(result) {
|
|
280
|
+
if (!toolResultFailed(result)) return null;
|
|
281
|
+
return result.message || result.error || 'The tool returned an error';
|
|
282
|
+
}
|
|
283
|
+
|
|
271
284
|
function readConfig() {
|
|
272
285
|
if (!fs.existsSync(CONFIG_FILE)) {
|
|
273
286
|
return {};
|
|
@@ -477,7 +490,21 @@ function loadAccountId(cwd) {
|
|
|
477
490
|
throw new Error('account-info.json not found in current directory');
|
|
478
491
|
}
|
|
479
492
|
const data = JSON.parse(fs.readFileSync(file, 'utf8'));
|
|
480
|
-
return Number(
|
|
493
|
+
return Number(accountIdFromAccountInfo(data));
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
// `resolution.accountId` is the account the export DESCRIBES, and the only key that is unambiguous in
|
|
497
|
+
// every shape: a legacy account-info.json is rooted at the hierarchy ROOT, so its top-level `id` is an
|
|
498
|
+
// ancestor, not this repo's account. `repoContext` is a short-lived earlier name for the same fact and is
|
|
499
|
+
// still read so checkouts written during that window keep resolving.
|
|
500
|
+
function accountIdFromAccountInfo(info) {
|
|
501
|
+
return (info && (
|
|
502
|
+
(info.resolution && info.resolution.accountId) ||
|
|
503
|
+
(info.repoContext && info.repoContext.accountInfoAccountId) ||
|
|
504
|
+
info.id ||
|
|
505
|
+
info.accountId ||
|
|
506
|
+
(info.account && info.account.id)
|
|
507
|
+
)) || null;
|
|
481
508
|
}
|
|
482
509
|
|
|
483
510
|
function loadAccountInfo(cwd) {
|
|
@@ -512,14 +539,23 @@ function buildAccountRepoEntryFromInfo(info, directory, source = 'discovered') {
|
|
|
512
539
|
if (!info || typeof info !== 'object') {
|
|
513
540
|
return null;
|
|
514
541
|
}
|
|
515
|
-
const accountId = Number(
|
|
542
|
+
const accountId = Number(accountIdFromAccountInfo(info));
|
|
516
543
|
if (!Number.isFinite(accountId) || accountId <= 0) {
|
|
517
544
|
return null;
|
|
518
545
|
}
|
|
519
546
|
return {
|
|
520
547
|
accountId,
|
|
521
|
-
name:
|
|
522
|
-
|
|
548
|
+
name: (info.resolution && info.resolution.accountName) ||
|
|
549
|
+
(info.repoContext && info.repoContext.accountInfoAccountName) ||
|
|
550
|
+
info.name ||
|
|
551
|
+
info.accountName ||
|
|
552
|
+
(info.account && info.account.name) ||
|
|
553
|
+
'',
|
|
554
|
+
type: (info.resolution && info.resolution.type) ||
|
|
555
|
+
info.type ||
|
|
556
|
+
info.accountType ||
|
|
557
|
+
(info.account && info.account.type) ||
|
|
558
|
+
null,
|
|
523
559
|
platformAccountId: info.platformAccountId || (info.platform && info.platform.id) || null,
|
|
524
560
|
directory: path.resolve(directory),
|
|
525
561
|
accountInfoPath: path.join(path.resolve(directory), 'account-info.json'),
|
|
@@ -2462,7 +2498,12 @@ async function toolCommand(flags) {
|
|
|
2462
2498
|
if (data.threadGroupingId) console.log('Thread grouping ID:', data.threadGroupingId);
|
|
2463
2499
|
console.log('Session log:', sessionJsonlFile(cwd));
|
|
2464
2500
|
console.log('Tool response file:', statusResponse.responseFile);
|
|
2465
|
-
|
|
2501
|
+
// A completed run can still carry a tool-level refusal — see toolResultFailed.
|
|
2502
|
+
const polledFailed = data.toolSuccess === false || toolResultFailed(data.result);
|
|
2503
|
+
if (polledFailed) {
|
|
2504
|
+
console.log('Tool error:', data.toolMessage || toolResultMessage(data.result));
|
|
2505
|
+
}
|
|
2506
|
+
if (data.status === 'failed' || polledFailed) process.exitCode = 1;
|
|
2466
2507
|
return;
|
|
2467
2508
|
}
|
|
2468
2509
|
|
|
@@ -2484,9 +2525,19 @@ async function toolCommand(flags) {
|
|
|
2484
2525
|
throw new Error(data.message || 'Tool execution failed');
|
|
2485
2526
|
}
|
|
2486
2527
|
|
|
2528
|
+
// `data.success` only means the tool was found and DISPATCHED. A tool that ran and refused (unmet
|
|
2529
|
+
// precondition, rejected enum value, validation failure) still comes back 200 with its own
|
|
2530
|
+
// success:false, and printing "Tool call succeeded" for that has caused agents to report work as
|
|
2531
|
+
// done that never happened. Prefer the server's hoisted verdict; fall back to introspecting the
|
|
2532
|
+
// result so this still works against an older platform build.
|
|
2533
|
+
const toolFailed = data.toolSuccess === false || toolResultFailed(data.result);
|
|
2534
|
+
const toolFailureMessage = data.toolMessage || toolResultMessage(data.result);
|
|
2535
|
+
|
|
2487
2536
|
printSessionResolutionWarning(sessionContext);
|
|
2488
2537
|
printResolvedBaseUrl(baseUrl);
|
|
2489
|
-
console.log(asyncMode ? 'Tool call started.'
|
|
2538
|
+
console.log(asyncMode ? 'Tool call started.'
|
|
2539
|
+
: (toolFailed ? 'Tool call FAILED — the tool ran and returned an error.' : 'Tool call succeeded.'));
|
|
2540
|
+
if (toolFailed && toolFailureMessage) console.log('Tool error:', toolFailureMessage);
|
|
2490
2541
|
console.log('Call ID:', callId);
|
|
2491
2542
|
console.log('Data mode:', data.dataMode || dataMode);
|
|
2492
2543
|
if (data.variantBranch || variantBranch) console.log('Variant branch:', data.variantBranch || variantBranch);
|
|
@@ -2500,6 +2551,9 @@ async function toolCommand(flags) {
|
|
|
2500
2551
|
console.log('Session log:', sessionJsonlFile(cwd));
|
|
2501
2552
|
console.log('Tool response file:', response.responseFile);
|
|
2502
2553
|
|
|
2554
|
+
// Non-zero exit so scripted/agent callers that check status notice the refusal too.
|
|
2555
|
+
if (toolFailed) process.exitCode = 1;
|
|
2556
|
+
|
|
2503
2557
|
if (asyncMode && waitForAsync) {
|
|
2504
2558
|
const finalStatus = await waitForToolStatus(api, cwd, {
|
|
2505
2559
|
token: session.token,
|
package/package.json
CHANGED
|
@@ -7,119 +7,120 @@ description: Use remits-cli for fast branch-scoped component staging, test execu
|
|
|
7
7
|
|
|
8
8
|
## Table of Contents
|
|
9
9
|
|
|
10
|
-
- Line
|
|
11
|
-
- Line
|
|
12
|
-
- Line
|
|
13
|
-
- Line
|
|
14
|
-
- Line
|
|
15
|
-
- Line
|
|
16
|
-
- Line
|
|
17
|
-
- Line
|
|
18
|
-
- Line
|
|
19
|
-
- Line
|
|
20
|
-
- Line
|
|
21
|
-
- Line
|
|
22
|
-
- Line
|
|
23
|
-
- Line
|
|
24
|
-
- Line
|
|
25
|
-
- Line
|
|
26
|
-
- Line
|
|
27
|
-
- Line
|
|
28
|
-
- Line
|
|
29
|
-
- Line
|
|
30
|
-
- Line
|
|
31
|
-
- Line
|
|
32
|
-
- Line
|
|
33
|
-
- Line
|
|
34
|
-
- Line
|
|
35
|
-
- Line
|
|
36
|
-
- Line
|
|
37
|
-
- Line
|
|
38
|
-
- Line
|
|
39
|
-
- Line
|
|
40
|
-
- Line
|
|
41
|
-
- Line
|
|
42
|
-
- Line
|
|
43
|
-
- Line
|
|
44
|
-
- Line
|
|
45
|
-
- Line
|
|
46
|
-
- Line
|
|
47
|
-
- Line
|
|
48
|
-
- Line
|
|
49
|
-
- Line
|
|
50
|
-
- Line
|
|
51
|
-
- Line
|
|
52
|
-
- Line
|
|
53
|
-
- Line
|
|
54
|
-
- Line
|
|
55
|
-
- Line
|
|
56
|
-
- Line
|
|
57
|
-
- Line
|
|
58
|
-
- Line
|
|
59
|
-
- Line
|
|
60
|
-
- Line
|
|
61
|
-
- Line
|
|
62
|
-
- Line
|
|
63
|
-
- Line
|
|
64
|
-
- Line
|
|
65
|
-
- Line
|
|
66
|
-
- Line
|
|
67
|
-
- Line
|
|
68
|
-
- Line
|
|
69
|
-
- Line
|
|
70
|
-
- Line
|
|
71
|
-
- Line
|
|
72
|
-
- Line
|
|
73
|
-
- Line
|
|
74
|
-
- Line
|
|
75
|
-
- Line
|
|
76
|
-
- Line
|
|
77
|
-
- Line
|
|
78
|
-
- Line
|
|
79
|
-
- Line
|
|
80
|
-
- Line
|
|
81
|
-
- Line
|
|
82
|
-
- Line
|
|
83
|
-
- Line
|
|
84
|
-
- Line
|
|
85
|
-
- Line
|
|
86
|
-
- Line
|
|
87
|
-
- Line
|
|
88
|
-
- Line
|
|
89
|
-
- Line
|
|
90
|
-
- Line
|
|
91
|
-
- Line
|
|
92
|
-
- Line
|
|
93
|
-
- Line
|
|
94
|
-
- Line
|
|
95
|
-
- Line
|
|
96
|
-
- Line
|
|
97
|
-
- Line
|
|
98
|
-
- Line
|
|
99
|
-
- Line
|
|
100
|
-
- Line
|
|
101
|
-
- Line
|
|
102
|
-
- Line
|
|
103
|
-
- Line
|
|
104
|
-
- Line
|
|
105
|
-
- Line
|
|
106
|
-
- Line
|
|
107
|
-
- Line
|
|
108
|
-
- Line
|
|
109
|
-
- Line
|
|
110
|
-
- Line
|
|
111
|
-
- Line
|
|
112
|
-
- Line
|
|
113
|
-
- Line
|
|
114
|
-
- Line
|
|
115
|
-
- Line
|
|
116
|
-
- Line
|
|
117
|
-
- Line
|
|
118
|
-
- Line
|
|
119
|
-
- Line
|
|
120
|
-
- Line
|
|
121
|
-
- Line
|
|
122
|
-
- Line
|
|
10
|
+
- Line 127: Account Targeting Model
|
|
11
|
+
- Line 134: Account types
|
|
12
|
+
- Line 149: How accounts connect (and why it changes what runs)
|
|
13
|
+
- Line 179: Users are a separate model — don't reason about them as a tree
|
|
14
|
+
- Line 192: Reading the shape
|
|
15
|
+
- Line 218: Repo selection rules
|
|
16
|
+
- Line 230: Component Integrity Rules: Repo ↔ Database Reconciliation (read before any sync/commit)
|
|
17
|
+
- Line 236: How the platform reconciles the repo into the database (the mechanism you must understand)
|
|
18
|
+
- Line 298: The surfaces and their intended behavior
|
|
19
|
+
- Line 322: Intended workflows
|
|
20
|
+
- Line 343: Pre-sync safety check (confirm ALL before `components sync` or `components commit`)
|
|
21
|
+
- Line 356: If something looks wrong — stop, don't paper over
|
|
22
|
+
- Line 380: Required Local Index Reads
|
|
23
|
+
- Line 414: Big Picture: How remits-cli State Is Organized
|
|
24
|
+
- Line 444: Support Ticket Mental Model
|
|
25
|
+
- Line 480: Efficiency Rules
|
|
26
|
+
- Line 492: Account Repository Index
|
|
27
|
+
- Line 517: Two Workflows
|
|
28
|
+
- Line 524: Test Mode vs Prod Mode
|
|
29
|
+
- Line 556: Platform Mental Model: Front Stage vs Back Stage
|
|
30
|
+
- Line 563: Documents vs Records
|
|
31
|
+
- Line 573: HTTP Audits
|
|
32
|
+
- Line 627: Record `content` / Context Mental Model
|
|
33
|
+
- Line 647: Provenance Fields
|
|
34
|
+
- Line 665: Why Persisted Context Looks Different From Runtime Context
|
|
35
|
+
- Line 686: Investigation Rule for Record Context
|
|
36
|
+
- Line 701: AI Request Response Records
|
|
37
|
+
- Line 708: AI Session Groupings
|
|
38
|
+
- Line 727: Correlation Keys
|
|
39
|
+
- Line 733: Node Reference Table
|
|
40
|
+
- Line 743: Repository vs External Context
|
|
41
|
+
- Line 750: Getting Started
|
|
42
|
+
- Line 752: Authentication
|
|
43
|
+
- Line 765: Host vs Data Mode
|
|
44
|
+
- Line 784: Tool Execution Lifecycle
|
|
45
|
+
- Line 838: Data Mode
|
|
46
|
+
- Line 848: Development Workflow
|
|
47
|
+
- Line 850: The Golden Rule: Writing Code Is Not Finishing the Job
|
|
48
|
+
- Line 862: Avoid Brittle Front-Stage Intelligence
|
|
49
|
+
- Line 875: The Development Fast Loop
|
|
50
|
+
- Line 879: Step 1: Understand the Request
|
|
51
|
+
- Line 894: Step 2: Make the Change
|
|
52
|
+
- Line 932: Step 3: Stage to Platform
|
|
53
|
+
- Line 947: Step 4: Verify the Change
|
|
54
|
+
- Line 1012: Step 5: Iterate If Needed
|
|
55
|
+
- Line 1022: Step 6: Update Documentation
|
|
56
|
+
- Line 1034: Step 7: Commit and Durable Sync
|
|
57
|
+
- Line 1072: Step 8: Close the Ticket
|
|
58
|
+
- Line 1087: User Confirmation Preferences
|
|
59
|
+
- Line 1097: Component Resolution: Staging Cache vs DB (which "version" actually runs)
|
|
60
|
+
- Line 1103: The three source layers + the compile cache
|
|
61
|
+
- Line 1126: Staging cache key format
|
|
62
|
+
- Line 1141: How the platform picks staged vs DB (the compile signature)
|
|
63
|
+
- Line 1163: When staged overrides apply
|
|
64
|
+
- Line 1187: Diagnosing which version is in play
|
|
65
|
+
- Line 1208: Stage / commit / clear with the MCP tools
|
|
66
|
+
- Line 1232: Stale after sync / commit (the in-memory compile cache)
|
|
67
|
+
- Line 1242: Account Resolution: how a request travels the account graph
|
|
68
|
+
- Line 1335: Branched Component Variants (per-account component overrides)
|
|
69
|
+
- Line 1343: The model (three moving parts)
|
|
70
|
+
- Line 1410: Which world does your working tree resolve? (read this before you run anything)
|
|
71
|
+
- Line 1476: Two levers, two different questions
|
|
72
|
+
- Line 1490: The SDLC is identical on a variant branch
|
|
73
|
+
- Line 1515: Promotion: getting the branch back into trunk
|
|
74
|
+
- Line 1557: Verifying as the subscriber
|
|
75
|
+
- Line 1576: Agents (Utility) on a variant branch
|
|
76
|
+
- Line 1588: Danger profile on a variant branch (different, not absent)
|
|
77
|
+
- Line 1616: Inspecting branches and drift
|
|
78
|
+
- Line 1648: Diagnosing a variant
|
|
79
|
+
- Line 1655: Production Support Workflow
|
|
80
|
+
- Line 1663: Investigation Strategy
|
|
81
|
+
- Line 1693: Presenting Findings
|
|
82
|
+
- Line 1701: Verifying a Production Issue Fix
|
|
83
|
+
- Line 1714: Tool Reference
|
|
84
|
+
- Line 1716: Execute a Tool
|
|
85
|
+
- Line 1745: `mcp_account_view`
|
|
86
|
+
- Line 1777: `mcp_account_user_admin`
|
|
87
|
+
- Line 1812: `mcp_firestore_search`
|
|
88
|
+
- Line 1850: `mcp_object_activity`
|
|
89
|
+
- Line 1859: `mcp_record_listing`
|
|
90
|
+
- Line 1884: `mcp_record_view`
|
|
91
|
+
- Line 1897: `mcp_ai_session_search`
|
|
92
|
+
- Line 1933: `mcp_run_action`
|
|
93
|
+
- Line 1977: `mcp_run_agent`
|
|
94
|
+
- Line 2013: `mcp_system_logs`
|
|
95
|
+
- Line 2036: `mcp_component_view`
|
|
96
|
+
- Line 2059: `mcp_component_grep`
|
|
97
|
+
- Line 2072: `mcp_support_ticket`
|
|
98
|
+
- Line 2121: `mcp_run_test`
|
|
99
|
+
- Line 2130: `mcp_component_edit`
|
|
100
|
+
- Line 2145: `mcp_component_create`
|
|
101
|
+
- Line 2159: `mcp_component_commit`
|
|
102
|
+
- Line 2167: `mcp_component_branches`
|
|
103
|
+
- Line 2186: `mcp_cache`
|
|
104
|
+
- Line 2198: `mcp_sql_query`
|
|
105
|
+
- Line 2233: `mcp_index_search`
|
|
106
|
+
- Line 2253: `mcp_get_guide`
|
|
107
|
+
- Line 2265: `mcp_test_fixture`
|
|
108
|
+
- Line 2278: `mcp_embeddable_test_url`
|
|
109
|
+
- Line 2290: `mcp_playwright_replay`
|
|
110
|
+
- Line 2305: `mcp_jvm_spike_triage`
|
|
111
|
+
- Line 2318: `mcp_support_ticket_queue`
|
|
112
|
+
- Line 2335: Multi-Session Support
|
|
113
|
+
- Line 2355: Persistent Service, Control Center, and Agent Dispatch
|
|
114
|
+
- Line 2364: Starting the Service
|
|
115
|
+
- Line 2390: Control Center
|
|
116
|
+
- Line 2405: Agent Dispatch
|
|
117
|
+
- Line 2426: Configuring the Preferred Agent
|
|
118
|
+
- Line 2437: Local State Files
|
|
119
|
+
- Line 2485: Command Reference
|
|
120
|
+
- Line 2527: Troubleshooting
|
|
121
|
+
- Line 2569: When Something Doesn't Work as Expected
|
|
122
|
+
- Line 2580: Back-Stage Escalation Workflow (platform defect/limitation)
|
|
123
|
+
- Line 2589: Escalation Bundle (tooling/operational issue)
|
|
123
124
|
|
|
124
125
|
`remits-cli` is the brainstem for both **development** and **production support**. You might run it inside an account repository (where `account-info.json` and `/components` already exist) or from outside any repo when a user needs help on another account. Your users are business professionals — they think in terms of what they can see in a browser.
|
|
125
126
|
|
|
@@ -156,7 +157,7 @@ An account is linked upward in two ways, and they coexist:
|
|
|
156
157
|
|
|
157
158
|
- **The primary parent** — one per account. The overwhelming majority of accounts have only this.
|
|
158
159
|
- **Membership edges** — extra links letting the *same account* be reached through **more than one** parent
|
|
159
|
-
(a customer in two product lines; a
|
|
160
|
+
(a customer in two product lines; a branch deployment reaching the same owner).
|
|
160
161
|
|
|
161
162
|
Any link can independently carry three things. They are **orthogonal** — never infer one from another:
|
|
162
163
|
|
|
@@ -190,17 +191,27 @@ this user see the wrong data?") use `mcp_sql_query` against `user` / `user_accou
|
|
|
190
191
|
|
|
191
192
|
### Reading the shape
|
|
192
193
|
|
|
193
|
-
`account-info.json` / `mcp_account_view` carry a `resolution` block
|
|
194
|
+
`account-info.json` / `mcp_account_view` carry a `resolution` block — the ONE place these facts appear
|
|
195
|
+
(nothing in it is repeated elsewhere in the file). Read it in this order:
|
|
194
196
|
|
|
197
|
+
- **`role`** + **`summary`** — `OWNER` (resolves its own component trunk: the files here ARE its components)
|
|
198
|
+
or `SUBSCRIBER` (resolves ANOTHER account's components with a variant branch applied). `summary` says it
|
|
199
|
+
in one sentence, naming the owner. Read this before you touch anything.
|
|
200
|
+
- **`accountId`** — the account described. In a repo export the top-level `id` is the same account; in a
|
|
201
|
+
legacy export it is the hierarchy ROOT, so prefer `resolution.accountId`.
|
|
195
202
|
- **`type`** — decide repo/ownership per the table above.
|
|
196
203
|
- **`resolvedDatabaseName`** vs **`databaseName`** — the namespace actually in effect vs the account's own
|
|
197
204
|
override. Check this first when documents are "missing".
|
|
198
205
|
- **`relationships`** — every link upward, primary first, each with its own `branchName` / `databaseName` /
|
|
199
206
|
`domainName`. **This is where you see that an account has two parents, and which link carries what.**
|
|
200
|
-
- **`componentBranch`** (+ `
|
|
201
|
-
|
|
207
|
+
- **`componentBranch`** (+ `componentOwnerAccountId` / `componentOwnerAccountName`) — the component-variant
|
|
208
|
+
branch in effect for this resolution and who owns it. A `SUBSCRIBER` with no `componentBranch` subscribes
|
|
209
|
+
through an edge that nothing anchored this resolution to (multi-parent, no path named) — `summary` says so.
|
|
202
210
|
- **`branchName`** — the account **repo's** trunk sync branch. Not a component-variant branch. Do not confuse
|
|
203
211
|
these two.
|
|
212
|
+
- **`parents`** / **`children`** — the anchored ancestor chain and a DIRECT-child summary with counts (repo
|
|
213
|
+
exports only; the default `mcp_account_view` shape carries the full tree instead). The deep tree is a
|
|
214
|
+
lookup — `mcp_account_user_admin` with `action:'hierarchy'` and a `depth` — never a committed artifact.
|
|
204
215
|
- **`componentBranches`** (top level) — variant branches this account **owns**, with drift and subscriber
|
|
205
216
|
counts. Check it before editing a shared component.
|
|
206
217
|
|
|
@@ -906,6 +917,7 @@ summary: One-line statement of what this component is for.
|
|
|
906
917
|
description: |
|
|
907
918
|
Longer technical description with line-number references to the key logic.
|
|
908
919
|
path: /page/merchant-portal # Readers and Embeddables only
|
|
920
|
+
injectionType: DIRECT # Embeddables only: DIRECT or IFRAME
|
|
909
921
|
category: default
|
|
910
922
|
auxiliary: false # `true` means the sync SKIPS the file entirely — see Auxiliary
|
|
911
923
|
mermaid: |
|
|
@@ -1124,7 +1136,7 @@ account:<accountId>:cli:<cliUserId>:components:<branch>:<family>:name:<normalize
|
|
|
1124
1136
|
component's OWN type enum such as `ObjectType`/`RuleType`, or absent — **never** the family), `hash`,
|
|
1125
1137
|
`updatedAt`, the staged content field(s) (`source`/`prompt`/`html`/`javascript`/`schema`/
|
|
1126
1138
|
`inputSchema`/`previewData`), and `.meta.yml` metadata fields such as `description`, `summary`, `mermaid`,
|
|
1127
|
-
`path`, `category`, and Schema flags (`enableTrigger`, `enableFullText`, `enableRAG`, `enableRevisions`,
|
|
1139
|
+
`path`, Embeddable `injectionType`, `category`, and Schema flags (`enableTrigger`, `enableFullText`, `enableRAG`, `enableRevisions`,
|
|
1128
1140
|
`enableBigQuerySync`, `enableRules`, `anchor`, `auxiliary`).
|
|
1129
1141
|
|
|
1130
1142
|
### How the platform picks staged vs DB (the compile signature)
|
|
@@ -1256,8 +1268,8 @@ edge's *child* as the execution account **and** the edge's *parent* as the branc
|
|
|
1256
1268
|
makes that edge's branch variants apply. An account-level host resolves the account with **no** anchor
|
|
1257
1269
|
(today's behavior). Edge wins, then the account's own host, so removing an edge degrades cleanly instead
|
|
1258
1270
|
of taking the hostname offline. Hosts are stored as bare lowercase hostnames; a full URL is normalized on
|
|
1259
|
-
the way in. This is what lets a
|
|
1260
|
-
tree — `
|
|
1271
|
+
the way in. This is what lets a branch deployment get its own domain without a separate account
|
|
1272
|
+
tree — `branch.example.com` and `app.example.com` can serve the same owner's components, one overlaid
|
|
1261
1273
|
with a branch.
|
|
1262
1274
|
|
|
1263
1275
|
**Two traversals, deliberately different.** Confusing them is the usual source of wrong conclusions:
|
|
@@ -1333,14 +1345,14 @@ resolve.
|
|
|
1333
1345
|
|
|
1334
1346
|
1. **The origin account owns the component and the branch.** Say platform account 1 owns
|
|
1335
1347
|
`Extract Invoice` (Action 50). Its repo `remits-<name>` has trunk branch `main` and a second git branch
|
|
1336
|
-
`
|
|
1337
|
-
2. **A `ComponentVariant` row is the overlay.** Committing on `
|
|
1338
|
-
**account 1**, on branch `
|
|
1348
|
+
`feature_branch`.
|
|
1349
|
+
2. **A `ComponentVariant` row is the overlay.** Committing on `feature_branch` stores rows owned by
|
|
1350
|
+
**account 1**, on branch `feature_branch`, for the components whose content **differs from trunk**. A git
|
|
1339
1351
|
branch physically contains every file; only the *differing* ones become variants. That is computed at
|
|
1340
1352
|
sync time — you never declare it.
|
|
1341
1353
|
3. **A child account subscribes via its relationship edge.** Account 101's `AccountRelationship` edge
|
|
1342
|
-
carries `branchName = '
|
|
1343
|
-
account 1's `
|
|
1354
|
+
carries `branchName = 'feature_branch'`. Resolution then walks 101's inheritance chain and applies
|
|
1355
|
+
account 1's `feature_branch` overlays.
|
|
1344
1356
|
|
|
1345
1357
|
Consequences worth internalizing:
|
|
1346
1358
|
|
|
@@ -1358,8 +1370,14 @@ Consequences worth internalizing:
|
|
|
1358
1370
|
only subscribe an account reachable from one you already have access to.
|
|
1359
1371
|
- **`--subscribe` sets the branch on an edge that must already exist — it cannot create one.** If the
|
|
1360
1372
|
account has no relationship edge to the owner you will get *"Account N has no relationship edge to
|
|
1361
|
-
subscribe; add a membership edge first"*.
|
|
1362
|
-
|
|
1373
|
+
subscribe; add a membership edge first"*. Create it with
|
|
1374
|
+
`mcp_account_user_admin` `action:'edge_add'` (`targetAccountId` = the child, `parentAccountId` = the
|
|
1375
|
+
owner), which also accepts `branchName` so you can create and subscribe in one call. The admin account
|
|
1376
|
+
page does the same thing.
|
|
1377
|
+
- **Many older accounts have no relationship row at all.** The edge table was introduced after the fact
|
|
1378
|
+
and never backfilled, so an account whose parent link is only `Account.parentId` resolves fine but has
|
|
1379
|
+
nothing for `--subscribe` to attach to. `mcp_account_user_admin` `action:'reparent'` with the account's
|
|
1380
|
+
*current* parent is the one-call repair: it creates the missing primary edge and changes nothing else.
|
|
1363
1381
|
- **When the account has several parents, say which edge you mean:**
|
|
1364
1382
|
`--subscribe <accountId> --parent-account <ownerId>`. Without it the CLI picks the edge to the owner
|
|
1365
1383
|
whose branch you are managing, then falls back to the account's primary edge — which may not be the
|
|
@@ -1389,7 +1407,7 @@ changes validation and where the subscriber's documents physically land. Treat s
|
|
|
1389
1407
|
same care as a trunk schema change.
|
|
1390
1408
|
|
|
1391
1409
|
**What a branch may override.** A variant speaks the same `.meta.yml` vocabulary trunk does — `name`,
|
|
1392
|
-
`description`, `summary`, `mermaid`, `category`, `type`, `path`, `collectionName`, `job`, `model`,
|
|
1410
|
+
`description`, `summary`, `mermaid`, `category`, `type`, `path`, `injectionType`, `collectionName`, `job`, `model`,
|
|
1393
1411
|
`agentTimeout`, `mcp`, `cli`, `global`, `purpose`, `auxiliary`, plus Schema flags (`enableTrigger`,
|
|
1394
1412
|
`enableFullText`, `enableRAG`, `enableRevisions`, `enableBigQuerySync`, `enableRules`, `anchor`) — and the
|
|
1395
1413
|
component's content files. Keys outside that set are ignored, deliberately: trunk cannot express them either,
|
|
@@ -1404,7 +1422,7 @@ the loop. The rule turns entirely on **trunk vs non-trunk**:
|
|
|
1404
1422
|
| Working tree | Staging scope | A run resolves | `components sync`/`commit` writes |
|
|
1405
1423
|
|---|---|---|---|
|
|
1406
1424
|
| **trunk** (`main`, or whatever `account-info.json` says) | that branch | trunk + **each account's subscribed** variant branch (production semantics) | the **live component rows** — full reconcile, creates/updates/**deletes** |
|
|
1407
|
-
| **any other branch** (`
|
|
1425
|
+
| **any other branch** (`feature_branch`) | that branch | trunk + **`feature_branch`** overlays | **`ComponentVariant` overlays on that branch only** — never touches trunk rows |
|
|
1408
1426
|
|
|
1409
1427
|
**The precedence trap that costs the most time:** `variantBranch` OUTRANKS every account's subscription. So
|
|
1410
1428
|
running a Test suite that asserts *production* semantics from a **variant checkout** pins every account in
|
|
@@ -1421,9 +1439,9 @@ remits-cli components status
|
|
|
1421
1439
|
```
|
|
1422
1440
|
|
|
1423
1441
|
```
|
|
1424
|
-
Working tree: VARIANT BRANCH "
|
|
1425
|
-
runs resolve: trunk + the '
|
|
1426
|
-
commit writes: ComponentVariant overlays on '
|
|
1442
|
+
Working tree: VARIANT BRANCH "feature_branch" (trunk is "main")
|
|
1443
|
+
runs resolve: trunk + the 'feature_branch' variant overlays
|
|
1444
|
+
commit writes: ComponentVariant overlays on 'feature_branch' (never touches trunk rows)
|
|
1427
1445
|
variants stored on this branch: 3
|
|
1428
1446
|
subscribing accounts: 101 (Acme Child)
|
|
1429
1447
|
```
|
|
@@ -1432,8 +1450,30 @@ Working tree: VARIANT BRANCH "feature_forked" (trunk is "main")
|
|
|
1432
1450
|
is still the OWNER's component repo: files under `components/` overlay that owner's trunk component ids, and
|
|
1433
1451
|
`components sync` writes `ComponentVariant` rows owned by that parent account. But if the checkout was synced
|
|
1434
1452
|
from a subscribing account reached through an `AccountRelationship` edge, the branch's `account-info.json`
|
|
1435
|
-
is intentionally refreshed from the subscriber's resolved account information.
|
|
1436
|
-
checkout answer "who am I acting as?" while preserving "who owns these component
|
|
1453
|
+
is intentionally rooted at that subscriber and refreshed from the subscriber's resolved account information.
|
|
1454
|
+
That is what lets a branch checkout answer "who am I acting as?" while preserving "who owns these component
|
|
1455
|
+
variants?"
|
|
1456
|
+
|
|
1457
|
+
Read the `resolution` block before acting from any checkout — it is the ONE place account-info states this
|
|
1458
|
+
(nothing in it is repeated elsewhere in the file):
|
|
1459
|
+
|
|
1460
|
+
- `resolution.role` — `OWNER` for a trunk/owner export, `SUBSCRIBER` for an account reached through an
|
|
1461
|
+
`AccountRelationship` branch edge. `resolution.summary` says the same thing in one sentence.
|
|
1462
|
+
- `resolution.accountId` — the account the local checkout should be treated as. **This, not the top-level
|
|
1463
|
+
`id`, is the key to read**: an `account-info.json` predating this shape is rooted at the hierarchy root.
|
|
1464
|
+
- `resolution.componentOwnerAccountId` — the account whose trunk component ids the files overlay and whose
|
|
1465
|
+
`ComponentVariant` rows sync writes. Equals `resolution.accountId` for an `OWNER`.
|
|
1466
|
+
- `resolution.componentBranch` / `resolution.scopeAccountId` — the branch and the path anchor that made this
|
|
1467
|
+
subscriber resolution possible.
|
|
1468
|
+
- `resolution.parents` / `resolution.children` / `resolution.relationships` — the account graph, stated once
|
|
1469
|
+
and compactly. The full descendant tree is a lookup (`mcp_account_user_admin`, `mcp_account_view`), not a
|
|
1470
|
+
committed artifact.
|
|
1471
|
+
|
|
1472
|
+
**One branch, one `account-info.json`.** There is exactly one git branch, so when a branch has MORE THAN ONE
|
|
1473
|
+
subscriber the refresh is skipped (the sync result says so under `accountInfo.skipped`/`reason`) and the file
|
|
1474
|
+
keeps describing the owner — which is at least true for all of them. Otherwise each subscriber's sync would
|
|
1475
|
+
rewrite the file as its own and hand the other subscriber's agent a file naming the wrong account. Overlay
|
|
1476
|
+
ownership is unaffected either way: variants always belong to the owner account.
|
|
1437
1477
|
|
|
1438
1478
|
Consequence: if a variant checkout's `account-info.json` is stale and still names the owner, run the first
|
|
1439
1479
|
repair sync with an explicit subscriber target, for example `remits-cli components sync --account-id 101`.
|
|
@@ -1459,13 +1499,13 @@ Both work on `remits-cli test run` and `remits-cli token`; `--variant-branch` al
|
|
|
1459
1499
|
The loop does not change shape — `edit → stage → verify → commit`:
|
|
1460
1500
|
|
|
1461
1501
|
```bash
|
|
1462
|
-
git checkout
|
|
1502
|
+
git checkout feature_branch # or: git checkout -b feature_branch
|
|
1463
1503
|
# edit components/actions/50_ExtractInvoice.groovy (KEEP the trunk id)
|
|
1464
1504
|
remits-cli components stage # Redis, scoped to this branch — same as always
|
|
1465
|
-
remits-cli test run --test "Invoice Tests" # resolves the
|
|
1505
|
+
remits-cli test run --test "Invoice Tests" # resolves the feature_branch world
|
|
1466
1506
|
remits-cli test run --test "Invoice Tests" --as-account 101 # ...as the real subscriber
|
|
1467
1507
|
# promote:
|
|
1468
|
-
git add -A && git commit -m "..." && git push origin
|
|
1508
|
+
git add -A && git commit -m "..." && git push origin feature_branch
|
|
1469
1509
|
remits-cli components sync --dry-run # inspect overrides/additions/tombstones without writes
|
|
1470
1510
|
remits-cli components sync # writes ComponentVariant overlays ONLY
|
|
1471
1511
|
```
|
|
@@ -1486,12 +1526,12 @@ by a **trunk** sync — the platform does not merge anything for you.
|
|
|
1486
1526
|
|
|
1487
1527
|
```bash
|
|
1488
1528
|
# 1. merge the branch into trunk (review the diff FIRST - see the deletion hazard below)
|
|
1489
|
-
git checkout main && git merge
|
|
1529
|
+
git checkout main && git merge feature_branch && git push origin main
|
|
1490
1530
|
# 2. trunk sync: creates real rows for new_* files, assigns ids, RENAMES those files on trunk
|
|
1491
1531
|
remits-cli components sync
|
|
1492
1532
|
git pull --ff-only origin main
|
|
1493
1533
|
# 3. bring trunk back into the branch so the two stop diverging
|
|
1494
|
-
git checkout
|
|
1534
|
+
git checkout feature_branch && git merge origin/main && git push origin feature_branch
|
|
1495
1535
|
remits-cli components sync # reconciles the branch's overlays
|
|
1496
1536
|
```
|
|
1497
1537
|
|
|
@@ -1584,9 +1624,9 @@ The analogous hazard is different and you must still respect it:
|
|
|
1584
1624
|
|
|
1585
1625
|
```bash
|
|
1586
1626
|
remits-cli components branches # branches with variants, counts, drift
|
|
1587
|
-
remits-cli components branch
|
|
1588
|
-
remits-cli components branch
|
|
1589
|
-
remits-cli components branch
|
|
1627
|
+
remits-cli components branch feature_branch # overridden / added / removed + subscribers
|
|
1628
|
+
remits-cli components branch feature_branch --diff 50 --component-type action
|
|
1629
|
+
remits-cli components branch feature_branch --subscribers
|
|
1590
1630
|
```
|
|
1591
1631
|
|
|
1592
1632
|
**Drift is the number to watch.** Each variant records the trunk content hash at the moment it was cut
|
|
@@ -1688,6 +1728,23 @@ remits-cli tool --name "mcp_firestore_search" --input '{"accountId": 37, "collec
|
|
|
1688
1728
|
|
|
1689
1729
|
Response saved to `./.remits-cli/tool-responses/<callId>.json`. Read the file to see results.
|
|
1690
1730
|
|
|
1731
|
+
**"Tool call succeeded" means DISPATCHED, not that the tool did what you asked.** A tool that runs
|
|
1732
|
+
and refuses — an unmet precondition, a rejected enum value, a failed validation — returns HTTP 200
|
|
1733
|
+
with its own `success: false` inside `result`. The CLI now prints `Tool call FAILED — the tool ran
|
|
1734
|
+
and returned an error.` plus a `Tool error:` line and exits non-zero, and the response envelope
|
|
1735
|
+
carries `toolSuccess` / `toolMessage`. **For any MUTATING call, confirm the tool's own verdict before
|
|
1736
|
+
reporting the work as done** — do not grep the terminal output for "succeeded":
|
|
1737
|
+
|
|
1738
|
+
```bash
|
|
1739
|
+
F=$(remits-cli tool --name mcp_support_ticket --input "$(cat payload.json)" --data-mode prod 2>&1 \
|
|
1740
|
+
| grep -o '[^ ]*tool-responses/[a-f0-9-]*\.json' | tail -1)
|
|
1741
|
+
python3 -c "import json;r=json.load(open('$F'))['result'];print(r.get('success'), r.get('message'))"
|
|
1742
|
+
```
|
|
1743
|
+
|
|
1744
|
+
Build non-trivial JSON into a file (e.g. with `python3 -c 'json.dumps(...)'`) and pass it as
|
|
1745
|
+
`--input "$(cat payload.json)"`. Long inline single-quoted JSON intermittently produces no response
|
|
1746
|
+
file at all.
|
|
1747
|
+
|
|
1691
1748
|
For long-running Action/Agent runners, use the tool's own async mode (`executionMode:"async"`), which returns
|
|
1692
1749
|
the `actionRunId`/`agentRunId` (and, for agents, `sessionId`) immediately:
|
|
1693
1750
|
|
|
@@ -1715,11 +1772,14 @@ Returns complete account structure — schemas, components, relationships.
|
|
|
1715
1772
|
Also returns two blocks that explain how the account RESOLVES, which is what you need before comparing
|
|
1716
1773
|
its behavior against component source:
|
|
1717
1774
|
|
|
1718
|
-
- `resolution` — `
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
`
|
|
1722
|
-
`
|
|
1775
|
+
- `resolution` — `role` (`OWNER` = resolves its own component trunk, `SUBSCRIBER` = resolves another
|
|
1776
|
+
account's components through a branch edge) and a one-sentence `summary`; `accountId` (the account
|
|
1777
|
+
described — the top level of this shape is the hierarchy ROOT, so do not read identity from there);
|
|
1778
|
+
`databaseName` (the account's own override, often null) vs `resolvedDatabaseName` (the storage namespace
|
|
1779
|
+
actually in effect); `branchName` (the repo sync branch) and `lastRepoSync`; `domainName` vs
|
|
1780
|
+
`resolvedDomainName` (the custom host in effect, which differs when reached through an edge host);
|
|
1781
|
+
`editMode`; and — when a component branch is in effect — `componentBranch` plus `componentOwnerAccountId`
|
|
1782
|
+
/ `componentOwnerAccountName`.
|
|
1723
1783
|
- `resolution.relationships` — **every structural link upward**, primary first: `parentAccountId` /
|
|
1724
1784
|
`parentAccountName` / `parentAccountCode` / `parentAccountType`, `primary` (true for the one link that
|
|
1725
1785
|
mirrors the account's primary parent), `active`, and the three independent link-scoped properties
|
|
@@ -1731,13 +1791,99 @@ its behavior against component source:
|
|
|
1731
1791
|
- `componentBranches` — the variant branches this account OWNS, with override/add/remove, subscriber, and
|
|
1732
1792
|
drift counts. Same summary the owner's `account-info.json` carries.
|
|
1733
1793
|
|
|
1734
|
-
Note: this tool does **not** return users. For
|
|
1735
|
-
`
|
|
1794
|
+
Note: this tool does **not** return users, and it returns EVERYTHING about one account. For users, for the
|
|
1795
|
+
deep account tree, or for small account/user updates, use `mcp_account_user_admin`.
|
|
1736
1796
|
|
|
1737
1797
|
| Parameter | Required | Description |
|
|
1738
1798
|
|-----------|----------|-------------|
|
|
1739
1799
|
| `accountId` | yes | Account ID |
|
|
1740
1800
|
|
|
1801
|
+
### `mcp_account_user_admin`
|
|
1802
|
+
The account-graph and user surface: the middle ground between `account-info.json` (which states structure
|
|
1803
|
+
compactly, because it is read into your context every session) and `mcp_account_view` (everything about one
|
|
1804
|
+
account).
|
|
1805
|
+
|
|
1806
|
+
- `action: 'hierarchy'` (default) — the descendant tree trimmed to `depth` (1-10, default 2; nodes cut off
|
|
1807
|
+
are marked `truncated` and still report their child count) and/or the anchored ancestor chain plus every
|
|
1808
|
+
edge (`direction: 'down'|'up'|'both'`). **This is how you get the deep tree account-info.json omits.**
|
|
1809
|
+
- `action: 'account'` — one account's `resolution` block plus masked configuration fields, without paying
|
|
1810
|
+
for the component inventory.
|
|
1811
|
+
- `action: 'users'` — an account's users at a hierarchy `scope` (`self`/`children`/`parents`/`hierarchy`),
|
|
1812
|
+
optional `email` substring filter. Extension fields are omitted here on purpose: they are stored **per
|
|
1813
|
+
account** and these users are bound to their own.
|
|
1814
|
+
- `action: 'user'` — one user (`userId` or `email`) with roles, account memberships, and extension fields
|
|
1815
|
+
**correctly scoped to the requested account**. It never grants membership as a side effect of a read, and
|
|
1816
|
+
tells you when the fields shown belong to a different account.
|
|
1817
|
+
- `action: 'account_update'` — write Account-schema configuration `fields`, and/or `name`/`status`
|
|
1818
|
+
(`ACTIVE`/`ON_HOLD`/`PENDING`).
|
|
1819
|
+
- `action: 'user_update'` — write User-schema `fields` under the named account (refused unless the user is a
|
|
1820
|
+
member or you pass `addAccount: true`, because the write would otherwise land on another account), plus
|
|
1821
|
+
`name`/`enabled` and membership add/remove.
|
|
1822
|
+
|
|
1823
|
+
**Building an account hierarchy** (the structural writes — this is how a coding agent provisions accounts
|
|
1824
|
+
without a browser):
|
|
1825
|
+
|
|
1826
|
+
- `action: 'account_create'` — create a child under `parentAccountId`, with its **primary relationship edge**,
|
|
1827
|
+
applying `type` / `databaseName` / `domainName` / `code` / `repositoryNameOverride` / `branchName` /
|
|
1828
|
+
`editMode` / … **at birth**. That ordering matters: the storage namespace is resolved from those properties,
|
|
1829
|
+
and the parent's cascaded schema fields are written into it during creation. Idempotent — an existing
|
|
1830
|
+
same-name account under that parent comes back with `reusedExisting: true`, unchanged.
|
|
1831
|
+
- `action: 'account_structure'` — change those properties on an existing account.
|
|
1832
|
+
- `action: 'edge_add'` / `'edge_update'` / `'edge_remove'` — manage a membership `AccountRelationship` edge to
|
|
1833
|
+
`parentAccountId`, including the three independent edge properties `branchName` (which component code runs),
|
|
1834
|
+
`databaseName` (branch-scoped namespace — stored, but inert until segment inheritance is enabled) and
|
|
1835
|
+
`domainName` (which host reaches the account through that edge). Cycles, self-edges, and removing the primary
|
|
1836
|
+
edge are all refused.
|
|
1837
|
+
- `action: 'reparent'` — move the account's **primary** edge (and `Account.parentId`) to `parentAccountId`.
|
|
1838
|
+
|
|
1839
|
+
> **The namespace guard.** An account's storage namespace resolves as
|
|
1840
|
+
> `databaseName ?: platform.code ?: code`, and `Account.setName` **regenerates `code`** — so renaming an
|
|
1841
|
+
> account whose namespace falls through to its own code silently repoints its storage. Any write that would
|
|
1842
|
+
> move the resolved namespace is **refused** unless you pass `confirmSegmentChange: true`, and the refusal
|
|
1843
|
+
> names both namespaces. To rename without moving storage, pin `code` to the old value in the same call.
|
|
1844
|
+
>
|
|
1845
|
+
> The namespace follows the **path**: the nearest `databaseName` walking up from the account — its own
|
|
1846
|
+
> first, then the edge it was reached through, then the same two questions at each account above — falling
|
|
1847
|
+
> back to the nearest `PLATFORM` ancestor's `code`. So a namespace set anywhere above is inherited by
|
|
1848
|
+
> everything below it until a nearer account or edge overrides it, and an edge answer is path-specific (the
|
|
1849
|
+
> same account reached through a different parent can resolve a different namespace).
|
|
1850
|
+
|
|
1851
|
+
Every write supports `dryRun: true`, which reports each `from -> to` without writing. Not here by design:
|
|
1852
|
+
component-branch subscription reporting and drift (`mcp_component_branches` — though `edge_add`/`edge_update`
|
|
1853
|
+
set the branch directly), and account/user **deletion** (admin only, so the destructive-teardown contract
|
|
1854
|
+
applies).
|
|
1855
|
+
|
|
1856
|
+
**Provisioning recipe** — a new product account under a platform, running its own component branch, with
|
|
1857
|
+
client accounts beneath it:
|
|
1858
|
+
|
|
1859
|
+
```
|
|
1860
|
+
1. mcp_account_user_admin action:'account_create' parentAccountId:<platform> name:'Adyen'
|
|
1861
|
+
type:'PLATFORM'|'PRODUCT' [databaseName:'...']
|
|
1862
|
+
2. git branch + push in the OWNER's repo, then `remits-cli components sync` from that checkout
|
|
1863
|
+
(non-trunk => writes ComponentVariant overlays only)
|
|
1864
|
+
3. mcp_account_user_admin action:'edge_update' targetAccountId:<new> parentAccountId:<platform>
|
|
1865
|
+
branchName:'<branch>' # or mcp_component_branches action:'subscribe'
|
|
1866
|
+
4. mcp_account_user_admin action:'account_create' parentAccountId:<new> name:'<business unit>'
|
|
1867
|
+
type:'CLIENT' # inherits the branch automatically
|
|
1868
|
+
```
|
|
1869
|
+
|
|
1870
|
+
> **Put the branch on the account's PRIMARY edge.** Component inheritance follows the *anchored* path, which
|
|
1871
|
+
> for an account with a `parentId` is its primary chain. An account that has both a primary edge and a
|
|
1872
|
+
> *membership* edge carrying the branch resolves **trunk** by default — the membership edge is never
|
|
1873
|
+
> anchored unless a request names it (`--as-account`, `--variant-branch`, or the edge's own host). Descendants
|
|
1874
|
+
> then inherit the branch down that primary chain automatically, which is what makes step 4 free.
|
|
1875
|
+
|
|
1876
|
+
| Parameter | Required | Description |
|
|
1877
|
+
|-----------|----------|-------------|
|
|
1878
|
+
| `action` | no | `hierarchy` (default), `account`, `users`, `user`, `account_update`, `user_update` |
|
|
1879
|
+
| `accountId` / `targetAccountId` | no | Account to act on; `targetAccountId` targets another account without moving tool resolution |
|
|
1880
|
+
| `depth` / `direction` | no | `hierarchy` only |
|
|
1881
|
+
| `scope` | no | `users` only |
|
|
1882
|
+
| `userId` / `email` | no | Identify the user (`user`, `user_update`); `email` is a filter for `users` |
|
|
1883
|
+
| `fields` / `name` / `status` / `enabled` | no | The update payload |
|
|
1884
|
+
| `addAccount` / `removeAccount` | no | Membership changes for `user_update` |
|
|
1885
|
+
| `dryRun` | no | Report the change without writing |
|
|
1886
|
+
|
|
1741
1887
|
### `mcp_firestore_search`
|
|
1742
1888
|
Query Firestore documents.
|
|
1743
1889
|
|
|
@@ -2013,10 +2159,10 @@ Create and manage the full lifecycle of account-relative `support_tickets`.
|
|
|
2013
2159
|
| `affectedComponent` | no | Component or platform area affected (`create`) |
|
|
2014
2160
|
| `implementationAccountId` / `implementationAccountName` | no | Owning `PLATFORM`/`PRODUCT` account when the ticket concerns shared implementation (e.g. a back-stage platform fix) |
|
|
2015
2161
|
| `stepsToReproduce` / `acceptanceCriteria` / `tags` | no | Extra `create` fields for defect/enhancement tickets |
|
|
2016
|
-
| `assignee` | no | Required for `accept` |
|
|
2017
|
-
| `status` | no | Required for `update_status`. Valid values: `in_progress`, `pending_review` |
|
|
2162
|
+
| `assignee` | no | Required for `accept`. The agent's own name by convention — `claude`, `codex`, `gemini` |
|
|
2163
|
+
| `status` | no | Required for `update_status`. Valid values: `in_progress`, `pending_review`. **The ticket must be `accept`ed first** — otherwise the call is rejected with *"Ticket must be accepted before updating status"* |
|
|
2018
2164
|
| `resolution` | no | Required for `complete` |
|
|
2019
|
-
| `category` / `summary` / `details` / `findings` / `nextStep` | no | Worklog fields for `record_progress` (`category` + `summary` required) |
|
|
2165
|
+
| `category` / `summary` / `details` / `findings` / `nextStep` | no | Worklog fields for `record_progress` (`category` + `summary` required). `category` is a **fixed enum** — `triage`, `investigation`, `reproduction`, `fix`, `verification`, `handoff`, `other` — and any other value fails the whole call. `findings` is a **list of strings**, not a paragraph |
|
|
2020
2166
|
| `artifactType` / `artifactLabel` / `contentBase64` / `gcsPath` / `url` | no | Evidence fields for `add_artifact` (screenshot/trace/log/test_result/link) |
|
|
2021
2167
|
| `notes` | no | Optional lifecycle note stored with the ticket activity |
|
|
2022
2168
|
| `attachmentIndex` | no | Zero-based index of the attachment to download. Used with `get_attachment`. |
|
|
@@ -2031,13 +2177,24 @@ Create and manage the full lifecycle of account-relative `support_tickets`.
|
|
|
2031
2177
|
|
|
2032
2178
|
This keeps file retrieval self-contained — no separate download endpoint is needed.
|
|
2033
2179
|
|
|
2034
|
-
**Recommended flow
|
|
2035
|
-
1. `read`
|
|
2036
|
-
2.
|
|
2180
|
+
**Recommended flow** — `accountId` is optional throughout; `ticketId` resolves the owning account:
|
|
2181
|
+
1. `read` — check ticket state and any attachments
|
|
2182
|
+
2. **`accept`** (with `assignee`) — this is a **hard precondition for `update_status`**, not just etiquette
|
|
2037
2183
|
3. `get_attachment` if attachments are present and relevant to the investigation
|
|
2038
|
-
4. `update_status`
|
|
2039
|
-
5.
|
|
2040
|
-
6.
|
|
2184
|
+
4. `update_status` — `in_progress` while working, `pending_review` when the fix is done but not yet deployed
|
|
2185
|
+
5. `record_progress` as you go — one `investigation` entry for the root cause, one `verification` entry for the proof
|
|
2186
|
+
6. investigate/fix/verify on the owning ticket account or its implementation account as appropriate
|
|
2187
|
+
7. `complete` (with `resolution`) or `release` if handing off
|
|
2188
|
+
|
|
2189
|
+
**Check each mutation actually landed.** Every action above is a write that can be refused while the
|
|
2190
|
+
CLI still reports the *call* as fine — see "Execute a Tool" for why, and read `result.success` from
|
|
2191
|
+
the response file. A silent no-op here means telling the user a ticket moved when it did not.
|
|
2192
|
+
|
|
2193
|
+
**Duplicates are common.** The same defect is often filed twice — once against the `CLIENT`/subscriber
|
|
2194
|
+
account where it was observed and once against the owning `PLATFORM`/`PRODUCT` account. Before
|
|
2195
|
+
starting, check `mcp_support_ticket_queue` for the same subject or affected component. Close the
|
|
2196
|
+
duplicate with a `resolution` naming the ticket that carries the real work, rather than investigating
|
|
2197
|
+
it twice.
|
|
2041
2198
|
|
|
2042
2199
|
**Automation rule:** If a ticket is involved, you should usually:
|
|
2043
2200
|
- `read` at the start
|
|
@@ -2471,7 +2628,8 @@ For tests specifically:
|
|
|
2471
2628
|
| Long-running tool times out | For `mcp_run_action`/`mcp_run_agent`, use the tool's own `executionMode:"async"` and poll with a `controlAction:"status"` call (see "Tool Execution Lifecycle"). For other long tools without their own async, use `remits-cli tool --async true` and poll `remits-cli tool status --call-id <callId>`. `--timeout-ms` only adjusts the per-request HTTP timeout; it is not a substitute for async. |
|
|
2472
2629
|
| Need to continue tracking a long Action or Agent after terminal disconnect | Read `./.remits-cli/tool-responses/<callId>.json` for the returned `actionRunId`/`agentRunId`/`sessionId`/`threadGroupingId`. Re-poll the run with a `controlAction:"status"` call carrying that `actionRunId`/`agentRunId`, or inspect the agent session via `mcp_ai_session_search` with the `sessionId`. |
|
|
2473
2630
|
| 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 (trunk, or the account's subscribed variant). `commit` to make it durable. See "Component Resolution". |
|
|
2474
|
-
| Need to know an account's shape (type, parents, namespace, branch) | `
|
|
2631
|
+
| Need to know an account's shape (role, type, parents, namespace, branch) | Read `resolution` — from the repo's `account-info.json`, or `mcp_account_user_admin` `action:'account'` (cheap), or `mcp_account_view` (full inventory): `role`/`summary`, `type`, `resolvedDatabaseName`, `relationships`, `componentBranch`, plus top-level `componentBranches`. Never infer structure from the account's name. |
|
|
2632
|
+
| Need the account tree below an account, or its users | `mcp_account_user_admin` (`action:'hierarchy'` with a `depth`, or `action:'users'`). `account-info.json` deliberately carries only direct children plus counts. |
|
|
2475
2633
|
| An account has two parents and you don't know which one a run used | `resolution.relationships` lists every link with its own `branchName`/`databaseName`/`domainName`. A membership-only account with several edges resolves **trunk and inherits nothing** until a path is named (`--as-account`, `--variant-branch`, or an edge host) — that is by design, not a bug. |
|
|
2476
2634
|
| Documents missing / written to the wrong place | Compare `resolution.databaseName` (the account's own override) with `resolution.resolvedDatabaseName` (what is actually in effect), and check for a `databaseName` on one of the `relationships` edges. Data does not inherit; components do. |
|
|
2477
2635
|
| A custom hostname resolves to an unexpected account | Compare `resolution.domainName` with `resolvedDomainName` and the edge `domainName`s. An **edge** host wins over the account's own host and additionally supplies the path travelled (which is what makes that edge's branch variants apply). |
|