@remits/remits-cli 0.1.84 → 0.1.86
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 +7 -1
- package/index.js +271 -11
- package/package.json +3 -2
- package/skills/remits-cli/SKILL.md +581 -101
package/README.md
CHANGED
|
@@ -29,7 +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 feature_forked --dry-run
|
|
33
|
+
remits-cli components sync --branch feature_forked --force-tombstones
|
|
32
34
|
remits-cli token --path page/my-embeddable
|
|
35
|
+
remits-cli token --path page/my-embeddable --variant-branch feature_forked
|
|
33
36
|
remits-cli data-mode
|
|
34
37
|
remits-cli data-mode set prod
|
|
35
38
|
remits-cli sessions list
|
|
@@ -54,10 +57,12 @@ remits-cli install --skills --overwrite true
|
|
|
54
57
|
## How It Works
|
|
55
58
|
|
|
56
59
|
- `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.
|
|
60
|
+
- Schema `.meta.yml` sidecars can stage/sync the schema flags: `enableTrigger`, `enableFullText`, `enableRAG`, `enableRevisions`, `enableBigQuerySync`, `enableRules`, `anchor`, and `auxiliary`.
|
|
57
61
|
- `components status` shows the branch/user staging entries that can shadow DB components during CLI-scoped test-mode execution.
|
|
58
62
|
- `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
63
|
- `components stage`, `components status`, and `components clear` print concise summaries by default. Add `--json` or `--verbose` to print the full server response.
|
|
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.
|
|
64
|
+
- `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 non-dry-run sync, the platform clears the branch/user staging scope so staged aliases cannot keep shadowing the newly synced DB rows.
|
|
65
|
+
- On trunk, `components sync` performs the full repo-to-DB reconcile. On a non-trunk branch, it writes `ComponentVariant` overlays only. `--dry-run` is accepted only for non-trunk variant syncs and reports overrides/additions/tombstones without writing variants, caching the sync SHA, or clearing staging. `--force-tombstones` is accepted only for non-trunk variant syncs and should be used only when missing trunk component files are intentional tombstone overrides.
|
|
61
66
|
- `components commit` is a convenience wrapper that performs local git commit/push, then `components sync`, then local `git fetch`/`git pull --ff-only`.
|
|
62
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.
|
|
63
68
|
- `components push` is deprecated and currently behaves the same as `components stage`.
|
|
@@ -76,6 +81,7 @@ remits-cli install --skills --overwrite true
|
|
|
76
81
|
- Avoid commas in individual test names. The `--names` filter is comma-delimited, so a single test case whose name contains commas cannot be targeted cleanly through `remits-cli test run --names ...`.
|
|
77
82
|
- Test activity is streamed from websocket `TestSuite` events while final status is also polled from `/cli/test`.
|
|
78
83
|
- Tool execution writes the full response to a separate file so large payloads do not bloat the session log.
|
|
84
|
+
- `--variant-branch <name|none>` is available on `test run`, `token`, `tools`, and `tool`. Use it to probe a committed branch variant from any checkout; omit it to resolve the execution account's normal subscription, or pass `none`/`trunk` to force subscription semantics from a variant checkout.
|
|
79
85
|
|
|
80
86
|
## Service, Dashboard, WebSocket, and Tmux Lifecycle
|
|
81
87
|
|
package/index.js
CHANGED
|
@@ -352,7 +352,7 @@ function sessionJsonlFile(cwd) {
|
|
|
352
352
|
return path.join(paths.sessionsDir, currentLocalSessionName(cwd) + '.jsonl');
|
|
353
353
|
}
|
|
354
354
|
|
|
355
|
-
const CONTENT_FIELDS = new Set(['source', 'html', 'javascript', 'css', 'schema', 'inputSchema', 'previewData']);
|
|
355
|
+
const CONTENT_FIELDS = new Set(['source', 'html', 'javascript', 'css', 'schema', 'inputSchema', 'previewData', 'messages']);
|
|
356
356
|
|
|
357
357
|
function sanitizeForLog(value) {
|
|
358
358
|
if (value === null || value === undefined) {
|
|
@@ -1113,6 +1113,7 @@ function collectComponents(cwd) {
|
|
|
1113
1113
|
readers: 'reader',
|
|
1114
1114
|
actions: 'action',
|
|
1115
1115
|
embeddables: 'embeddable',
|
|
1116
|
+
i18n: 'i18n',
|
|
1116
1117
|
rules: 'rule',
|
|
1117
1118
|
templates: 'htmltemplate',
|
|
1118
1119
|
agents: 'utility',
|
|
@@ -1182,6 +1183,8 @@ function collectComponents(cwd) {
|
|
|
1182
1183
|
component.previewData = content;
|
|
1183
1184
|
} else if (type === 'tool' && ext === 'json') {
|
|
1184
1185
|
component.inputSchema = content;
|
|
1186
|
+
} else if (type === 'i18n' && ext === 'json') {
|
|
1187
|
+
component.messages = content;
|
|
1185
1188
|
} else if (type === 'schema' && ext === 'json') {
|
|
1186
1189
|
component.schema = content;
|
|
1187
1190
|
}
|
|
@@ -1718,11 +1721,42 @@ function printStageSummary(response, flags) {
|
|
|
1718
1721
|
}
|
|
1719
1722
|
|
|
1720
1723
|
function printStatusSummary(response, flags) {
|
|
1724
|
+
printBranchContext(response);
|
|
1721
1725
|
console.log('Staged count:', response.stagedCount || 0);
|
|
1722
1726
|
printComponentTypeCounts(response.entries || []);
|
|
1723
1727
|
printComponentCommandResponse('Components staging', response, flags);
|
|
1724
1728
|
}
|
|
1725
1729
|
|
|
1730
|
+
// Make the working tree's meaning explicit. An agent may be standing in a TRUNK checkout or in a
|
|
1731
|
+
// VARIANT branch's checkout, and the two differ on BOTH ends of the loop: what a run resolves, and
|
|
1732
|
+
// what a commit writes. Inferring that from the branch name alone is exactly the kind of ambiguity
|
|
1733
|
+
// that leads to editing the wrong world.
|
|
1734
|
+
function printBranchContext(response) {
|
|
1735
|
+
const ctx = response && response.branchContext;
|
|
1736
|
+
if (!ctx) return;
|
|
1737
|
+
|
|
1738
|
+
console.log('');
|
|
1739
|
+
if (ctx.onTrunk) {
|
|
1740
|
+
console.log('Working tree: TRUNK (' + response.branchName + ')');
|
|
1741
|
+
} else {
|
|
1742
|
+
console.log('Working tree: VARIANT BRANCH "' + response.branchName + '" (trunk is "' + ctx.trunkBranch + '")');
|
|
1743
|
+
}
|
|
1744
|
+
console.log(' runs resolve: ' + ctx.resolves);
|
|
1745
|
+
console.log(' commit writes: ' + ctx.commitWrites);
|
|
1746
|
+
|
|
1747
|
+
if (!ctx.onTrunk) {
|
|
1748
|
+
console.log(' variants stored on this branch: ' + (ctx.variantCount || 0));
|
|
1749
|
+
const subs = ctx.subscribers || [];
|
|
1750
|
+
if (subs.length) {
|
|
1751
|
+
console.log(' subscribing accounts: ' + subs.map((s) =>
|
|
1752
|
+
s.accountId + (s.accountName ? ' (' + s.accountName + ')' : '')).join(', '));
|
|
1753
|
+
} else {
|
|
1754
|
+
console.log(' subscribing accounts: none yet — subscribe an account\'s relationship edge to this branch');
|
|
1755
|
+
}
|
|
1756
|
+
}
|
|
1757
|
+
console.log('');
|
|
1758
|
+
}
|
|
1759
|
+
|
|
1726
1760
|
function printClearSummary(response, flags) {
|
|
1727
1761
|
console.log('Cleared keys:', response.clearedCount || 0);
|
|
1728
1762
|
console.log('Remaining staged count:', response.remainingCount || 0);
|
|
@@ -1827,6 +1861,8 @@ async function syncComponentsCommand(flags) {
|
|
|
1827
1861
|
const baseUrl = flags['base-url'] || session.baseUrl || DEFAULT_BASE_URL;
|
|
1828
1862
|
const branchName = flags.branch || currentBranch(cwd);
|
|
1829
1863
|
const dataMode = resolveDataMode(flags, session);
|
|
1864
|
+
const forceTombstones = flagEnabled(flags['force-tombstones']) || flagEnabled(flags.forceTombstones);
|
|
1865
|
+
const dryRun = flagEnabled(flags['dry-run']) || flagEnabled(flags.dryRun);
|
|
1830
1866
|
const api = buildAxios(baseUrl, session.token);
|
|
1831
1867
|
|
|
1832
1868
|
const response = await loggedPost(api, cwd, '/cli/components', {
|
|
@@ -1834,6 +1870,8 @@ async function syncComponentsCommand(flags) {
|
|
|
1834
1870
|
accountId,
|
|
1835
1871
|
branchName,
|
|
1836
1872
|
dataMode,
|
|
1873
|
+
forceTombstones,
|
|
1874
|
+
dryRun,
|
|
1837
1875
|
mode: 'sync',
|
|
1838
1876
|
components: []
|
|
1839
1877
|
}).then((r) => r.data);
|
|
@@ -1851,10 +1889,174 @@ async function syncComponentsCommand(flags) {
|
|
|
1851
1889
|
printResolvedBaseUrl(baseUrl);
|
|
1852
1890
|
console.log('Data mode:', response.dataMode || dataMode);
|
|
1853
1891
|
console.log('Mode:', response.mode || 'sync');
|
|
1892
|
+
if (response.sync && response.sync.dryRun) {
|
|
1893
|
+
console.log('Dry run: no variants were written and staging was not cleared.');
|
|
1894
|
+
}
|
|
1854
1895
|
console.log('Components sync:', JSON.stringify(response, null, 2));
|
|
1855
1896
|
return response;
|
|
1856
1897
|
}
|
|
1857
1898
|
|
|
1899
|
+
// Inspect committed branch variants: durable, branch-scoped overlays of this account's components.
|
|
1900
|
+
// Unlike `components status` (which shows the ephemeral Redis staging cache), these are what
|
|
1901
|
+
// subscribing accounts actually resolve in production.
|
|
1902
|
+
async function branchesComponentsCommand(flags) {
|
|
1903
|
+
const cwd = process.cwd();
|
|
1904
|
+
ensureLocalState(cwd);
|
|
1905
|
+
const sessionContext = resolveSessionContext(cwd, flags);
|
|
1906
|
+
const { session, accountId } = sessionContext;
|
|
1907
|
+
const baseUrl = flags['base-url'] || session.baseUrl || DEFAULT_BASE_URL;
|
|
1908
|
+
const api = buildAxios(baseUrl, session.token);
|
|
1909
|
+
|
|
1910
|
+
// `components branch <name>` and `components branches` share this handler; the positional argument
|
|
1911
|
+
// after the subcommand is the branch name when present.
|
|
1912
|
+
const positional = flags._ && flags._[2];
|
|
1913
|
+
const branchName = flags.branch || positional;
|
|
1914
|
+
|
|
1915
|
+
// Without a branch there is nothing to detail, so always list. With one, the mutating flags
|
|
1916
|
+
// (--subscribe/--unsubscribe/--retire) win, then the narrower read views, and the default is the
|
|
1917
|
+
// branch's full status.
|
|
1918
|
+
let mode = 'list';
|
|
1919
|
+
if (branchName || flags.unsubscribe !== undefined) {
|
|
1920
|
+
if (flags.subscribe !== undefined) mode = 'subscribe';
|
|
1921
|
+
else if (flags.unsubscribe !== undefined) mode = 'unsubscribe';
|
|
1922
|
+
else if (flagEnabled(flags.retire)) mode = 'retire';
|
|
1923
|
+
else if (flags.diff !== undefined) mode = 'diff';
|
|
1924
|
+
else if (flagEnabled(flags.subscribers)) mode = 'subscribers';
|
|
1925
|
+
else mode = 'status';
|
|
1926
|
+
}
|
|
1927
|
+
|
|
1928
|
+
// `--diff 42` carries the component id inline; a bare `--diff` falls back to --component-id/--name.
|
|
1929
|
+
const componentId = mode === 'diff'
|
|
1930
|
+
? (flags.diff === true ? (flags['component-id'] || flags.id) : flags.diff)
|
|
1931
|
+
: undefined;
|
|
1932
|
+
|
|
1933
|
+
// `--subscribe 101` / `--unsubscribe 101` name the account whose relationship edge carries (or drops)
|
|
1934
|
+
// the branch subscription. Subscribing is what makes a branch actually reachable in production.
|
|
1935
|
+
const subscribeAccountId = (mode === 'subscribe' || mode === 'unsubscribe')
|
|
1936
|
+
? ((mode === 'subscribe' ? flags.subscribe : flags.unsubscribe) === true
|
|
1937
|
+
? (flags['subscribe-account'] || flags['account-id'])
|
|
1938
|
+
: (mode === 'subscribe' ? flags.subscribe : flags.unsubscribe))
|
|
1939
|
+
: undefined;
|
|
1940
|
+
|
|
1941
|
+
const response = await loggedPost(api, cwd, '/cli/branches', {
|
|
1942
|
+
token: session.token,
|
|
1943
|
+
accountId,
|
|
1944
|
+
mode,
|
|
1945
|
+
branchName,
|
|
1946
|
+
componentType: flags['component-type'] || flags.type,
|
|
1947
|
+
componentId,
|
|
1948
|
+
componentName: flags['component-name'] || flags.name,
|
|
1949
|
+
subscribeAccountId,
|
|
1950
|
+
parentAccountId: flags['parent-account'],
|
|
1951
|
+
// Optional branch-scoped custom host set on the same edge as the subscription.
|
|
1952
|
+
// `--domain none` clears it; omitting the flag leaves any existing host untouched.
|
|
1953
|
+
domainName: flags.domain || flags['domain-name'],
|
|
1954
|
+
force: flagEnabled(flags.force)
|
|
1955
|
+
}).then((r) => r.data);
|
|
1956
|
+
|
|
1957
|
+
if (!response.success) {
|
|
1958
|
+
throw new Error(response.message || 'Branch lookup failed');
|
|
1959
|
+
}
|
|
1960
|
+
|
|
1961
|
+
if (flagEnabled(flags.json)) {
|
|
1962
|
+
console.log(JSON.stringify(response, null, 2));
|
|
1963
|
+
return response;
|
|
1964
|
+
}
|
|
1965
|
+
|
|
1966
|
+
printSessionResolutionWarning(sessionContext);
|
|
1967
|
+
printResolvedBaseUrl(baseUrl);
|
|
1968
|
+
printBranchesSummary(response);
|
|
1969
|
+
return response;
|
|
1970
|
+
}
|
|
1971
|
+
|
|
1972
|
+
function printBranchesSummary(response) {
|
|
1973
|
+
console.log('Trunk branch:', response.trunk || 'main');
|
|
1974
|
+
|
|
1975
|
+
if (response.mode === 'list') {
|
|
1976
|
+
const branches = response.branches || [];
|
|
1977
|
+
if (!branches.length) {
|
|
1978
|
+
console.log('No component variant branches for this account.');
|
|
1979
|
+
return;
|
|
1980
|
+
}
|
|
1981
|
+
console.log('');
|
|
1982
|
+
branches.forEach((b) => {
|
|
1983
|
+
const drift = b.drifted ? ' DRIFTED: ' + b.drifted : '';
|
|
1984
|
+
console.log(' ' + b.branch +
|
|
1985
|
+
' (overridden ' + b.overridden + ', added ' + b.added + ', removed ' + b.removed +
|
|
1986
|
+
', subscribers ' + b.subscribers + ')' + drift);
|
|
1987
|
+
});
|
|
1988
|
+
console.log('');
|
|
1989
|
+
console.log('Detail: remits-cli components branch <name>');
|
|
1990
|
+
return;
|
|
1991
|
+
}
|
|
1992
|
+
|
|
1993
|
+
if (response.mode === 'status') {
|
|
1994
|
+
console.log('Branch:', response.branch);
|
|
1995
|
+
const show = (label, rows) => {
|
|
1996
|
+
if (!rows || !rows.length) return;
|
|
1997
|
+
console.log('');
|
|
1998
|
+
console.log(label + ' (' + rows.length + '):');
|
|
1999
|
+
rows.forEach((r) => {
|
|
2000
|
+
const drift = r.drifted ? ' <- DRIFTED (origin changed since this variant was cut)' : '';
|
|
2001
|
+
console.log(' ' + r.kind + ' ' + (r.id != null ? r.id : 'new') + ' ' + r.name + drift);
|
|
2002
|
+
});
|
|
2003
|
+
};
|
|
2004
|
+
show('Overridden', response.overridden);
|
|
2005
|
+
show('Added', response.added);
|
|
2006
|
+
show('Removed', response.removed);
|
|
2007
|
+
|
|
2008
|
+
if (response.driftedCount) {
|
|
2009
|
+
console.log('');
|
|
2010
|
+
console.log(response.driftedCount + ' variant(s) drifted. Compare with: remits-cli components branch ' +
|
|
2011
|
+
response.branch + ' --diff <componentId> --component-type <kind>');
|
|
2012
|
+
}
|
|
2013
|
+
const subs = response.subscribers || [];
|
|
2014
|
+
console.log('');
|
|
2015
|
+
console.log('Subscribers (' + subs.length + '):');
|
|
2016
|
+
subs.forEach((s) => {
|
|
2017
|
+
console.log(' account ' + s.accountId + (s.accountName ? ' (' + s.accountName + ')' : '') +
|
|
2018
|
+
' via ' + (s.viaPrimaryEdge ? 'primary' : 'membership') + ' edge -> parent ' + s.parentAccountId +
|
|
2019
|
+
(s.domainName ? ' [host ' + s.domainName + ']' : ''));
|
|
2020
|
+
});
|
|
2021
|
+
return;
|
|
2022
|
+
}
|
|
2023
|
+
|
|
2024
|
+
if (response.mode === 'diff') {
|
|
2025
|
+
console.log('Branch:', response.branch);
|
|
2026
|
+
console.log(response.kind + ' ' + (response.componentId != null ? response.componentId : 'new') + ' ' + response.componentName);
|
|
2027
|
+
if (response.branchOnly) console.log('(branch-only component: no trunk row)');
|
|
2028
|
+
if (response.tombstone) console.log('(tombstone: this branch REMOVES the component)');
|
|
2029
|
+
if (response.drifted) console.log('DRIFTED: the origin component changed after this variant was cut.');
|
|
2030
|
+
const fields = response.fields || {};
|
|
2031
|
+
Object.keys(fields).forEach((key) => {
|
|
2032
|
+
const f = fields[key];
|
|
2033
|
+
console.log('');
|
|
2034
|
+
console.log('--- ' + key + (f.changed ? ' (changed)' : ' (same as trunk)') + ' ---');
|
|
2035
|
+
if (f.changed) {
|
|
2036
|
+
console.log(' variant length: ' + (f.variant ? f.variant.length : 0) +
|
|
2037
|
+
', trunk length: ' + (f.trunk ? f.trunk.length : 0));
|
|
2038
|
+
}
|
|
2039
|
+
});
|
|
2040
|
+
console.log('');
|
|
2041
|
+
console.log('Full content: re-run with --json');
|
|
2042
|
+
return;
|
|
2043
|
+
}
|
|
2044
|
+
|
|
2045
|
+
if (response.mode === 'subscribe' || response.mode === 'unsubscribe' || response.mode === 'retire') {
|
|
2046
|
+
console.log(response.message);
|
|
2047
|
+
return;
|
|
2048
|
+
}
|
|
2049
|
+
|
|
2050
|
+
console.log('Branch:', response.branch);
|
|
2051
|
+
const subs = response.subscribers || [];
|
|
2052
|
+
console.log('Subscribers (' + subs.length + '):');
|
|
2053
|
+
subs.forEach((s) => {
|
|
2054
|
+
console.log(' account ' + s.accountId + (s.accountName ? ' (' + s.accountName + ')' : '') +
|
|
2055
|
+
' via ' + (s.viaPrimaryEdge ? 'primary' : 'membership') + ' edge -> parent ' + s.parentAccountId +
|
|
2056
|
+
(s.domainName ? ' [host ' + s.domainName + ']' : ''));
|
|
2057
|
+
});
|
|
2058
|
+
}
|
|
2059
|
+
|
|
1858
2060
|
async function commitComponentsCommand(flags) {
|
|
1859
2061
|
const cwd = process.cwd();
|
|
1860
2062
|
ensureLocalState(cwd);
|
|
@@ -1863,6 +2065,9 @@ async function commitComponentsCommand(flags) {
|
|
|
1863
2065
|
const commitMessage = String(flags.message || ('remits-cli commit sync ' + new Date().toISOString()));
|
|
1864
2066
|
const allowEmpty = flags['allow-empty'] === true || flags['allow-empty'] === 'true';
|
|
1865
2067
|
const skipGit = flags['skip-git'] === true || flags['skip-git'] === 'true';
|
|
2068
|
+
if (flagEnabled(flags['dry-run']) || flagEnabled(flags.dryRun)) {
|
|
2069
|
+
throw new Error('components commit does not support --dry-run because it performs local git writes. Use `remits-cli components sync --dry-run`.');
|
|
2070
|
+
}
|
|
1866
2071
|
|
|
1867
2072
|
if (!skipGit) {
|
|
1868
2073
|
console.log('Phase 1/3: local git commit/push');
|
|
@@ -2038,9 +2243,17 @@ async function testCommand(flags) {
|
|
|
2038
2243
|
const names = flags.names ? String(flags.names).split(',').map((s) => s.trim()).filter(Boolean) : [];
|
|
2039
2244
|
|
|
2040
2245
|
const api = buildAxios(baseUrl, session.token);
|
|
2246
|
+
// --as-account runs the Test AS a (descendant) subscriber account, so that account's relationship
|
|
2247
|
+
// edge selects the component branch and the run resolves what production will.
|
|
2248
|
+
const asAccountId = flags['as-account'] || flags['as-account-id'];
|
|
2249
|
+
// --variant-branch explicitly probes a committed variant branch. Normally omitted: variants resolve
|
|
2250
|
+
// from the account's subscription edge, which is what production does.
|
|
2251
|
+
const variantBranch = flags['variant-branch'];
|
|
2041
2252
|
const start = await loggedPost(api, cwd, '/cli/test', {
|
|
2042
2253
|
token: session.token,
|
|
2043
2254
|
accountId,
|
|
2255
|
+
asAccountId,
|
|
2256
|
+
variantBranch,
|
|
2044
2257
|
branchName,
|
|
2045
2258
|
dataMode,
|
|
2046
2259
|
testId: /^\d+$/.test(String(testRef)) ? Number(testRef) : undefined,
|
|
@@ -2091,9 +2304,15 @@ async function tokenCommand(flags) {
|
|
|
2091
2304
|
const dataMode = resolveDataMode(flags, session);
|
|
2092
2305
|
|
|
2093
2306
|
const api = buildAxios(baseUrl, session.token);
|
|
2307
|
+
// --as-account mints the token for a (descendant) subscriber so browser verification of an
|
|
2308
|
+
// Embeddable resolves that account's branch variants rather than the owner's trunk.
|
|
2309
|
+
// --variant-branch explicitly probes a committed variant branch before any edge subscribes.
|
|
2310
|
+
const variantBranch = flags['variant-branch'];
|
|
2094
2311
|
const data = await loggedPost(api, cwd, '/cli/token', {
|
|
2095
2312
|
token: session.token,
|
|
2096
2313
|
accountId,
|
|
2314
|
+
asAccountId: flags['as-account'] || flags['as-account-id'],
|
|
2315
|
+
variantBranch,
|
|
2097
2316
|
branchName,
|
|
2098
2317
|
dataMode
|
|
2099
2318
|
}).then((r) => r.data);
|
|
@@ -2104,9 +2323,13 @@ async function tokenCommand(flags) {
|
|
|
2104
2323
|
|
|
2105
2324
|
const base = baseUrl.replace(/\/$/, '');
|
|
2106
2325
|
const embeddablePath = flags.path || flags['embeddable-path'];
|
|
2107
|
-
|
|
2326
|
+
let embeddableUrl = embeddablePath
|
|
2108
2327
|
? (base + '/s/' + data.tokenKey + '/' + String(embeddablePath).replace(/^\/+/, ''))
|
|
2109
2328
|
: null;
|
|
2329
|
+
if (embeddableUrl && data.variantBranch) {
|
|
2330
|
+
const separator = embeddableUrl.includes('?') ? '&' : '?';
|
|
2331
|
+
embeddableUrl += separator + 'variantBranch=' + encodeURIComponent(data.variantBranch);
|
|
2332
|
+
}
|
|
2110
2333
|
|
|
2111
2334
|
const output = {
|
|
2112
2335
|
success: true,
|
|
@@ -2114,6 +2337,7 @@ async function tokenCommand(flags) {
|
|
|
2114
2337
|
tokenKey: data.tokenKey,
|
|
2115
2338
|
accountId: data.accountId,
|
|
2116
2339
|
branchName: data.branchName,
|
|
2340
|
+
variantBranch: data.variantBranch,
|
|
2117
2341
|
dataMode: data.dataMode || dataMode,
|
|
2118
2342
|
shortBasePath: data.shortBasePath,
|
|
2119
2343
|
embeddableUrl
|
|
@@ -2131,11 +2355,13 @@ async function toolsCommand(flags) {
|
|
|
2131
2355
|
const baseUrl = flags['base-url'] || session.baseUrl || DEFAULT_BASE_URL;
|
|
2132
2356
|
const branchName = flags.branch || currentBranch(cwd);
|
|
2133
2357
|
const dataMode = resolveDataMode(flags, session);
|
|
2358
|
+
const variantBranch = flags['variant-branch'];
|
|
2134
2359
|
const api = buildAxios(baseUrl, session.token);
|
|
2135
2360
|
|
|
2136
2361
|
const data = await loggedPost(api, cwd, '/cli/tools', {
|
|
2137
2362
|
token: session.token,
|
|
2138
2363
|
accountId,
|
|
2364
|
+
variantBranch,
|
|
2139
2365
|
branchName,
|
|
2140
2366
|
dataMode
|
|
2141
2367
|
}).then((r) => r.data);
|
|
@@ -2148,6 +2374,7 @@ async function toolsCommand(flags) {
|
|
|
2148
2374
|
accountId,
|
|
2149
2375
|
baseUrl: normalizeBaseUrl(baseUrl),
|
|
2150
2376
|
branchName,
|
|
2377
|
+
variantBranch: data.variantBranch || variantBranch,
|
|
2151
2378
|
dataMode: data.dataMode || dataMode,
|
|
2152
2379
|
fetchedAt: new Date().toISOString(),
|
|
2153
2380
|
tools: data.tools || []
|
|
@@ -2157,6 +2384,7 @@ async function toolsCommand(flags) {
|
|
|
2157
2384
|
printResolvedBaseUrl(baseUrl);
|
|
2158
2385
|
console.log('Tools refreshed.');
|
|
2159
2386
|
console.log('Data mode:', data.dataMode || dataMode);
|
|
2387
|
+
if (data.variantBranch || variantBranch) console.log('Variant branch:', data.variantBranch || variantBranch);
|
|
2160
2388
|
console.log('Tools file:', toolsFile);
|
|
2161
2389
|
console.log('Tool count:', (data.tools || []).length);
|
|
2162
2390
|
}
|
|
@@ -2194,6 +2422,7 @@ async function toolCommand(flags) {
|
|
|
2194
2422
|
const baseUrl = flags['base-url'] || session.baseUrl || DEFAULT_BASE_URL;
|
|
2195
2423
|
const branchName = flags.branch || currentBranch(cwd);
|
|
2196
2424
|
const dataMode = resolveDataMode(flags, session);
|
|
2425
|
+
const variantBranch = flags['variant-branch'];
|
|
2197
2426
|
const timeoutMs = parsePositiveInt(flags['timeout-ms'] || flags.timeoutMs, 60000);
|
|
2198
2427
|
const callId = String(flags['call-id'] || flags.callId || crypto.randomUUID());
|
|
2199
2428
|
const asyncMode = flagEnabled(flags.async) || flagEnabled(input.async);
|
|
@@ -2243,6 +2472,7 @@ async function toolCommand(flags) {
|
|
|
2243
2472
|
accountIdExplicit,
|
|
2244
2473
|
branchName,
|
|
2245
2474
|
dataMode,
|
|
2475
|
+
variantBranch,
|
|
2246
2476
|
name: String(toolName),
|
|
2247
2477
|
input,
|
|
2248
2478
|
callId,
|
|
@@ -2259,6 +2489,7 @@ async function toolCommand(flags) {
|
|
|
2259
2489
|
console.log(asyncMode ? 'Tool call started.' : 'Tool call succeeded.');
|
|
2260
2490
|
console.log('Call ID:', callId);
|
|
2261
2491
|
console.log('Data mode:', data.dataMode || dataMode);
|
|
2492
|
+
if (data.variantBranch || variantBranch) console.log('Variant branch:', data.variantBranch || variantBranch);
|
|
2262
2493
|
if (data.status) console.log('Status:', data.status);
|
|
2263
2494
|
if (data.threadGroupingId) console.log('Thread grouping ID:', data.threadGroupingId);
|
|
2264
2495
|
// Make the resolved component version explicit so callers never assume staged vs DB.
|
|
@@ -4731,26 +4962,50 @@ async function main() {
|
|
|
4731
4962
|
console.log(' remits-cli listen [stop|status] [--foreground true] # compatibility alias');
|
|
4732
4963
|
console.log(' remits-cli data-mode [set test|prod]');
|
|
4733
4964
|
console.log(' remits-cli install --skills [--target codex|claude|gemini|all] [--overwrite true]');
|
|
4734
|
-
console.log(' remits-cli tools [--base-url URL] [--account-id ID] [--data-mode test|prod]');
|
|
4735
|
-
console.log(' remits-cli tool --name <toolName> [--base-url URL] [--input \"{...}\"|--input-file file.json] [--data-mode test|prod] [--timeout-ms 60000] [--async true --wait true]');
|
|
4965
|
+
console.log(' remits-cli tools [--base-url URL] [--account-id ID] [--branch BRANCH] [--data-mode test|prod] [--variant-branch NAME|none]');
|
|
4966
|
+
console.log(' remits-cli tool --name <toolName> [--base-url URL] [--branch BRANCH] [--input \"{...}\"|--input-file file.json] [--data-mode test|prod] [--variant-branch NAME|none] [--timeout-ms 60000] [--async true --wait true]');
|
|
4736
4967
|
console.log(' remits-cli tool status --call-id <callId> [--base-url URL] [--account-id ID] [--data-mode test|prod]');
|
|
4737
4968
|
console.log(' remits-cli components stage [--base-url URL] [--account-id ID] [--branch BRANCH] [--data-mode test|prod] [--json|--verbose]');
|
|
4738
4969
|
console.log(' remits-cli components status [--base-url URL] [--account-id ID] [--branch BRANCH] [--component-type TYPE --component-id ID] [--json|--verbose]');
|
|
4739
4970
|
console.log(' remits-cli components clear [--base-url URL] [--account-id ID] [--branch BRANCH] [--component-type TYPE] [--component-id ID] [--all] [--json|--verbose]');
|
|
4740
|
-
console.log(' remits-cli components sync [--base-url URL] [--account-id ID] [--branch BRANCH] [--data-mode test|prod]');
|
|
4741
|
-
console.log(' remits-cli components commit [--message \"msg\"] [--allow-empty true|false] [--skip-git true|false] [--branch BRANCH] [--data-mode test|prod]');
|
|
4742
|
-
console.log(' remits-cli
|
|
4743
|
-
console.log(' remits-cli
|
|
4971
|
+
console.log(' remits-cli components sync [--base-url URL] [--account-id ID] [--branch BRANCH] [--data-mode test|prod] [--force-tombstones] [--dry-run]');
|
|
4972
|
+
console.log(' remits-cli components commit [--message \"msg\"] [--allow-empty true|false] [--skip-git true|false] [--branch BRANCH] [--data-mode test|prod] [--force-tombstones]');
|
|
4973
|
+
console.log(' remits-cli components branches [--json] # committed branch variants for this account');
|
|
4974
|
+
console.log(' remits-cli components branch <name> [--diff <componentId> --component-type <kind>] [--subscribers] [--json]');
|
|
4975
|
+
console.log(' remits-cli components branch <name> --subscribe <accountId> # make an account resolve this branch');
|
|
4976
|
+
console.log(' remits-cli components branch <name> --unsubscribe <accountId> # return that account to trunk');
|
|
4977
|
+
console.log(' remits-cli components branch <name> --retire [--force] # delete the branch\'s overlays');
|
|
4978
|
+
console.log(' remits-cli test run --test <id|name> [--base-url URL] [--names name1,name2] [--watch true|false] [--data-mode test|prod] [--as-account ID] [--variant-branch NAME]');
|
|
4979
|
+
console.log(' remits-cli token [--base-url URL] [--branch BRANCH] [--path embeddable/path] [--data-mode test|prod] [--as-account ID] [--variant-branch NAME|none]');
|
|
4980
|
+
console.log('');
|
|
4981
|
+
console.log(' --as-account <ID> verifies AS a descendant subscriber account, so its relationship edge');
|
|
4982
|
+
console.log(' selects the component branch and the run resolves exactly what production will.');
|
|
4983
|
+
console.log(' --variant-branch <NAME> explicitly probes a committed variant branch (e.g. before any');
|
|
4984
|
+
console.log(' edge subscribes to it). Omit it to resolve what the account actually subscribes to.');
|
|
4744
4985
|
process.exit(0);
|
|
4745
4986
|
}
|
|
4746
4987
|
|
|
4747
4988
|
if (command === 'components' && wantsHelp) {
|
|
4748
|
-
console.log('Usage: remits-cli components <stage|status|clear|sync|commit>');
|
|
4989
|
+
console.log('Usage: remits-cli components <stage|status|clear|sync|commit|branches|branch>');
|
|
4749
4990
|
console.log(' remits-cli components stage [--base-url URL] [--account-id ID] [--branch BRANCH] [--data-mode test|prod] [--json|--verbose]');
|
|
4750
4991
|
console.log(' remits-cli components status [--base-url URL] [--account-id ID] [--branch BRANCH] [--component-type TYPE --component-id ID] [--json|--verbose]');
|
|
4751
4992
|
console.log(' remits-cli components clear [--base-url URL] [--account-id ID] [--branch BRANCH] [--component-type TYPE] [--component-id ID] [--all] [--json|--verbose]');
|
|
4752
|
-
console.log(' remits-cli components sync [--base-url URL] [--account-id ID] [--branch BRANCH] [--data-mode test|prod]');
|
|
4753
|
-
console.log(' remits-cli components commit [--message \"msg\"] [--allow-empty true|false] [--skip-git true|false] [--branch BRANCH] [--data-mode test|prod]');
|
|
4993
|
+
console.log(' remits-cli components sync [--base-url URL] [--account-id ID] [--branch BRANCH] [--data-mode test|prod] [--force-tombstones] [--dry-run]');
|
|
4994
|
+
console.log(' remits-cli components commit [--message \"msg\"] [--allow-empty true|false] [--skip-git true|false] [--branch BRANCH] [--data-mode test|prod] [--force-tombstones]');
|
|
4995
|
+
console.log('');
|
|
4996
|
+
console.log(' --force-tombstones applies only on non-trunk variant syncs, when a missing trunk');
|
|
4997
|
+
console.log(' component file is intentionally being recorded as a tombstone override.');
|
|
4998
|
+
console.log(' --dry-run reports the variant override/add/remove plan without writing variants,');
|
|
4999
|
+
console.log(' updating sync SHA cache, or clearing staged CLI entries.');
|
|
5000
|
+
console.log('');
|
|
5001
|
+
console.log('Committed branch variants (durable overlays subscribing accounts resolve in production):');
|
|
5002
|
+
console.log(' remits-cli components branches [--json]');
|
|
5003
|
+
console.log(' remits-cli components branch <name> [--json] # overridden/added/removed + drift');
|
|
5004
|
+
console.log(' remits-cli components branch <name> --diff <componentId> --component-type <kind> [--json]');
|
|
5005
|
+
console.log(' remits-cli components branch <name> --subscribers [--json]');
|
|
5006
|
+
console.log(' remits-cli components branch <name> --subscribe <accountId> [--parent-account <id>] [--domain <host>]');
|
|
5007
|
+
console.log(' remits-cli components branch <name> --unsubscribe <accountId>');
|
|
5008
|
+
console.log(' remits-cli components branch <name> --retire [--force]');
|
|
4754
5009
|
process.exit(0);
|
|
4755
5010
|
}
|
|
4756
5011
|
|
|
@@ -4787,6 +5042,11 @@ async function main() {
|
|
|
4787
5042
|
return;
|
|
4788
5043
|
}
|
|
4789
5044
|
|
|
5045
|
+
if (command === 'components' && (subcommand === 'branches' || subcommand === 'branch')) {
|
|
5046
|
+
await branchesComponentsCommand(args);
|
|
5047
|
+
return;
|
|
5048
|
+
}
|
|
5049
|
+
|
|
4790
5050
|
if (command === 'data-mode' || command === 'datamode' || command === 'data-model' || command === 'datamodel') {
|
|
4791
5051
|
await dataModeCommand(args, subcommand);
|
|
4792
5052
|
return;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@remits/remits-cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.86",
|
|
4
4
|
"description": "Local CLI for auth, component sync, and live test execution against Remits",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"private": false,
|
|
@@ -28,7 +28,8 @@
|
|
|
28
28
|
"automation"
|
|
29
29
|
],
|
|
30
30
|
"scripts": {
|
|
31
|
-
"start": "node index.js"
|
|
31
|
+
"start": "node index.js",
|
|
32
|
+
"test": "node --test test/*.test.js"
|
|
32
33
|
},
|
|
33
34
|
"dependencies": {
|
|
34
35
|
"@stomp/stompjs": "^7.2.0",
|