@remits/remits-cli 0.1.169 → 0.1.170
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 +8 -0
- package/index.js +91 -8
- package/lib/builder-kit.js +43 -0
- package/package.json +2 -1
- package/skills/remits-cli/references/command-reference.md +17 -0
package/README.md
CHANGED
|
@@ -2,6 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
Local CLI for rapid Remits component testing without push/sync cycles.
|
|
4
4
|
|
|
5
|
+
Builder onboarding: `remits-cli builder setup --account-id <owner> --directory <new-checkout>` uses your
|
|
6
|
+
Remits sign-in to clone the account repository with a short-lived Git credential, select a workspace,
|
|
7
|
+
sync guides and install the Remits Builder Claude Code plugin. No GitHub user account is required.
|
|
8
|
+
|
|
9
|
+
Review staged changes: `remits-cli components propose --title "Describe the change"` creates or updates a
|
|
10
|
+
GitHub PR from your current staging lane. It applies account landing policy and leaves merging and
|
|
11
|
+
synchronization to the reviewer. Use `components propose --help` for scope and verification options.
|
|
12
|
+
|
|
5
13
|
## Install
|
|
6
14
|
|
|
7
15
|
```bash
|
package/index.js
CHANGED
|
@@ -9,13 +9,13 @@
|
|
|
9
9
|
- L2802 Account Repos, Guide Sync, And Platform Repo
|
|
10
10
|
- L3701 Component Discovery And HTTP Logging
|
|
11
11
|
- L4484 Skill Delivery And TOC Resolution
|
|
12
|
-
-
|
|
13
|
-
-
|
|
14
|
-
-
|
|
15
|
-
-
|
|
16
|
-
-
|
|
17
|
-
-
|
|
18
|
-
-
|
|
12
|
+
- L4849 Auth And Component Staging
|
|
13
|
+
- L5485 Component Summaries, Status, And Sync Gates
|
|
14
|
+
- L7826 Branches, Promotion, Commit, And Test Runs
|
|
15
|
+
- L10139 Tokens, Tools, Verification, And Config
|
|
16
|
+
- L11656 Service Dashboard And WebSocket Listener
|
|
17
|
+
- L14166 Agent And Ticket Workflows
|
|
18
|
+
- L18936 Help, Auto Update, And Command Dispatch
|
|
19
19
|
*/
|
|
20
20
|
|
|
21
21
|
/*
|
|
@@ -4795,6 +4795,56 @@ async function installSkillsCommand(flags) {
|
|
|
4795
4795
|
}
|
|
4796
4796
|
}
|
|
4797
4797
|
|
|
4798
|
+
async function builderCommand(flags, subcommand) {
|
|
4799
|
+
const kit = require('./lib/builder-kit');
|
|
4800
|
+
if (flagEnabled(flags.help) || !subcommand) {
|
|
4801
|
+
console.log('remits-cli builder setup --account-id <owner> --directory <new-checkout> [--base-url <host>]');
|
|
4802
|
+
return;
|
|
4803
|
+
}
|
|
4804
|
+
if (!['setup', 'credential'].includes(subcommand)) throw new Error('Expected builder setup.');
|
|
4805
|
+
// Git appends get/store/erase. Never store a token and never emit ordinary CLI output on this door.
|
|
4806
|
+
const operation = flags._ && flags._[2];
|
|
4807
|
+
if (subcommand === 'credential' && operation !== 'get') return;
|
|
4808
|
+
const context = resolveSessionContext(process.cwd(), flags);
|
|
4809
|
+
const { session, accountId } = context;
|
|
4810
|
+
const baseUrl = flags['base-url'] || session.baseUrl || DEFAULT_BASE_URL;
|
|
4811
|
+
const api = buildAxios(baseUrl, session.token);
|
|
4812
|
+
const fields = subcommand === 'credential' ? kit.credentialRequest(fs.readFileSync(0, 'utf8')) : null;
|
|
4813
|
+
if (fields && (fields.protocol !== 'https' || fields.host !== 'github.com' || !fields.path)) return;
|
|
4814
|
+
// Deliberately bypass request evidence logging: this response is a credential, not tool output.
|
|
4815
|
+
let result;
|
|
4816
|
+
try {
|
|
4817
|
+
result = (await api.post('/cli/builderCredential', { token: session.token, accountId })).data;
|
|
4818
|
+
} catch (_) {
|
|
4819
|
+
throw new Error('Builder repository access was refused. Check your Remits sign-in and owner membership.');
|
|
4820
|
+
}
|
|
4821
|
+
if (!result.success || !result.token) throw new Error('No Builder Kit credential was issued.');
|
|
4822
|
+
if (subcommand === 'credential') {
|
|
4823
|
+
if (!kit.matchesRepository(fields, result.repository)) return;
|
|
4824
|
+
process.stdout.write('username=x-access-token\npassword=' + result.token + '\n\n');
|
|
4825
|
+
return;
|
|
4826
|
+
}
|
|
4827
|
+
const directory = path.resolve(flags.directory || result.repository.split('/')[1]);
|
|
4828
|
+
const helper = kit.helperCommand(process.execPath, __filename, accountId, baseUrl);
|
|
4829
|
+
kit.cloneRepository({ cloneUrl: result.cloneUrl, directory, helper });
|
|
4830
|
+
process.chdir(directory);
|
|
4831
|
+
ensureLocalState(directory);
|
|
4832
|
+
await workspaceCommand({ _: ['workspace', 'use'], auto: true });
|
|
4833
|
+
await ensureGuidesSynced(directory, { ...flags, 'account-id': accountId });
|
|
4834
|
+
const plugin = path.join(directory, '.claude', 'skills', 'remits-builder');
|
|
4835
|
+
const refs = path.join(plugin, 'references');
|
|
4836
|
+
ensureDir(path.join(plugin, '.claude-plugin'));
|
|
4837
|
+
atomicWriteFile(path.join(plugin, '.claude-plugin', 'plugin.json'), JSON.stringify({
|
|
4838
|
+
name: 'remits-builder', version: '1.0.0', author: { name: 'Remits' }, license: 'MIT', skills: '.',
|
|
4839
|
+
description: 'Build and verify Remits components in your own workspace.'
|
|
4840
|
+
}, null, 2) + '\n');
|
|
4841
|
+
atomicWriteFile(path.join(plugin, 'SKILL.md'), buildSkillSourceBody(refs));
|
|
4842
|
+
writeSkillReferences(refs);
|
|
4843
|
+
console.log('Builder Kit ready: ' + directory);
|
|
4844
|
+
// Delivered references contain local paths; keep this installation local to this checkout.
|
|
4845
|
+
fs.appendFileSync(path.join(directory, '.git', 'info', 'exclude'), '\n/.claude/skills/remits-builder/\n');
|
|
4846
|
+
}
|
|
4847
|
+
|
|
4798
4848
|
/*
|
|
4799
4849
|
## Auth And Component Staging
|
|
4800
4850
|
*/
|
|
@@ -6206,6 +6256,23 @@ async function statusComponentsCommand(flags) {
|
|
|
6206
6256
|
return response;
|
|
6207
6257
|
}
|
|
6208
6258
|
|
|
6259
|
+
async function proposeComponentsCommand(flags) {
|
|
6260
|
+
const cwd = process.cwd();
|
|
6261
|
+
const context = resolveSessionContext(cwd, flags);
|
|
6262
|
+
requireAccountRepoContext(cwd, flags, 'components propose', context);
|
|
6263
|
+
const { session, accountId } = context;
|
|
6264
|
+
const api = buildAxios(flags['base-url'] || session.baseUrl || DEFAULT_BASE_URL, session.token);
|
|
6265
|
+
const response = await loggedPost(api, cwd, '/cli/components', {
|
|
6266
|
+
token: session.token, accountId, mode: 'propose',
|
|
6267
|
+
branchName: flags.branch || currentBranch(cwd), workspace: resolveWorkspace(cwd, flags),
|
|
6268
|
+
title: flags.title, acknowledge: flags.acknowledge,
|
|
6269
|
+
verificationEnvelopeId: verificationEnvelopeIdForCommand(cwd, flags, context),
|
|
6270
|
+
dataMode: resolveDataMode(flags, session)
|
|
6271
|
+
}).then(r => r.data);
|
|
6272
|
+
if (!response.success) throw new Error(response.message || 'Proposal failed');
|
|
6273
|
+
console.log(flagEnabled(flags.json) ? JSON.stringify(response, null, 2) : response.pullRequest.url);
|
|
6274
|
+
}
|
|
6275
|
+
|
|
6209
6276
|
async function lanesComponentsCommand(flags) {
|
|
6210
6277
|
const cwd = process.cwd();
|
|
6211
6278
|
ensureLocalState(cwd);
|
|
@@ -19168,7 +19235,13 @@ function printComponentsHelp(subcommand) {
|
|
|
19168
19235
|
console.log('--safe also gates the server sync plan before any trunk rows or ComponentVariant overlays are written.');
|
|
19169
19236
|
return;
|
|
19170
19237
|
}
|
|
19171
|
-
|
|
19238
|
+
if (subcommand === 'propose') {
|
|
19239
|
+
console.log('Usage: remits-cli components propose [--account-id ID] [--branch BASE] [--workspace NAME] [--title TITLE] [--verify-envelope ID] [--acknowledge TEXT] [--json]');
|
|
19240
|
+
console.log('Creates or updates a GitHub PR from every staged component in your lane. Account landing policy applies.');
|
|
19241
|
+
console.log('Review the PR before merging; this command does not merge or synchronize components.');
|
|
19242
|
+
return;
|
|
19243
|
+
}
|
|
19244
|
+
console.log('Usage: remits-cli components <stage|status|lanes|entries|clear|sync|commit|propose|promotion|branches|branch>');
|
|
19172
19245
|
console.log('');
|
|
19173
19246
|
console.log('All staging subcommands accept --workspace NAME to isolate a lane on the same branch,');
|
|
19174
19247
|
console.log('so several agents can iterate at once. See: remits-cli workspace --help');
|
|
@@ -19407,6 +19480,11 @@ async function main() {
|
|
|
19407
19480
|
const wantsHelp = args.help === true || subcommand === 'help' || subcommand === '--help' || args._.includes('--help');
|
|
19408
19481
|
const wantsJson = flagEnabled(args.json);
|
|
19409
19482
|
|
|
19483
|
+
if (command === 'builder') {
|
|
19484
|
+
await builderCommand(args, subcommand);
|
|
19485
|
+
return;
|
|
19486
|
+
}
|
|
19487
|
+
|
|
19410
19488
|
// Inference callbacks must keep one protocol version for the supervisor's lifetime. They do not
|
|
19411
19489
|
// auto-update, auto-start the support listener, or depend on a component checkout.
|
|
19412
19490
|
if (command === 'ai') {
|
|
@@ -19633,6 +19711,11 @@ async function main() {
|
|
|
19633
19711
|
return;
|
|
19634
19712
|
}
|
|
19635
19713
|
|
|
19714
|
+
if (command === 'components' && subcommand === 'propose') {
|
|
19715
|
+
await proposeComponentsCommand(args);
|
|
19716
|
+
return;
|
|
19717
|
+
}
|
|
19718
|
+
|
|
19636
19719
|
if (command === 'components' && (subcommand === 'lanes' || subcommand === 'lane')) {
|
|
19637
19720
|
await lanesComponentsCommand(args);
|
|
19638
19721
|
return;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const { execFileSync } = require('child_process');
|
|
6
|
+
|
|
7
|
+
function credentialRequest(text) {
|
|
8
|
+
const fields = {};
|
|
9
|
+
for (const line of String(text).split(/\r?\n/)) {
|
|
10
|
+
const split = line.indexOf('=');
|
|
11
|
+
if (split > 0) fields[line.slice(0, split)] = line.slice(split + 1);
|
|
12
|
+
}
|
|
13
|
+
return fields;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function matchesRepository(fields, repository) {
|
|
17
|
+
return fields.protocol === 'https' && fields.host === 'github.com' &&
|
|
18
|
+
String(fields.path || '').replace(/\.git$/, '') === repository;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function helperCommand(node, entry, accountId, baseUrl) {
|
|
22
|
+
const quote = s => "'" + String(s).replace(/'/g, "'\\''") + "'";
|
|
23
|
+
return '!' + [node, entry, 'builder', 'credential', '--account-id', accountId, '--base-url', baseUrl].map(quote).join(' ');
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function cloneRepository({ cloneUrl, directory, helper }) {
|
|
27
|
+
if (fs.existsSync(directory)) throw new Error('Choose a new directory for Builder Kit setup.');
|
|
28
|
+
const url = new URL(cloneUrl);
|
|
29
|
+
if (url.protocol !== 'https:' || url.hostname !== 'github.com' || url.username || url.password) {
|
|
30
|
+
throw new Error('Invalid Builder Kit repository URL.');
|
|
31
|
+
}
|
|
32
|
+
// Disable inherited credential stores for this operation; only our helper sees the issued token.
|
|
33
|
+
execFileSync('git', ['-c', 'credential.helper=', '-c', 'credential.helper=' + helper,
|
|
34
|
+
'-c', 'credential.useHttpPath=true', 'clone', '--', cloneUrl, directory],
|
|
35
|
+
{ stdio: 'inherit', env: { ...process.env, GIT_TERMINAL_PROMPT: '0' } });
|
|
36
|
+
const git = args => execFileSync('git', ['-C', directory, ...args], { stdio: 'pipe' });
|
|
37
|
+
git(['config', '--local', '--add', 'credential.helper', '']);
|
|
38
|
+
git(['config', '--local', '--add', 'credential.helper', helper]);
|
|
39
|
+
git(['config', '--local', 'credential.useHttpPath', 'true']);
|
|
40
|
+
return path.resolve(directory);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
module.exports = { credentialRequest, matchesRepository, helperCommand, cloneRepository };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@remits/remits-cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.170",
|
|
4
4
|
"description": "Local CLI for auth, component sync, and live test execution against Remits",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"private": false,
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
"files": [
|
|
13
13
|
"index.js",
|
|
14
14
|
"lib/sync-operation.js",
|
|
15
|
+
"lib/builder-kit.js",
|
|
15
16
|
"lib/local-ai.js",
|
|
16
17
|
"lib/websocket-retry.js",
|
|
17
18
|
"README.md",
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
## Table of Contents
|
|
10
10
|
|
|
11
|
+
- [Builder Kit and review proposals](#builder-kit-and-review-proposals)
|
|
11
12
|
- [Getting Started](#getting-started)
|
|
12
13
|
- [Authentication](#authentication)
|
|
13
14
|
- [Host vs Data Mode](#host-vs-data-mode)
|
|
@@ -21,6 +22,22 @@
|
|
|
21
22
|
- [Staging modes: workset vs full snapshot](#staging-modes-workset-vs-full-snapshot)
|
|
22
23
|
- [Prod banners and retryable failures](#prod-banners-and-retryable-failures)
|
|
23
24
|
|
|
25
|
+
## Builder Kit and review proposals
|
|
26
|
+
|
|
27
|
+
`remits-cli builder setup --account-id <owner> --directory <new-directory>` clones the owning account's
|
|
28
|
+
repository using your Remits builder sign-in. Add `--base-url` to use a local server. It installs a Git
|
|
29
|
+
credential helper, chooses your workspace, syncs guides and installs the Remits Builder Claude Code plugin.
|
|
30
|
+
Git credentials stay in memory, are restricted to that repository and expire within one hour; the next
|
|
31
|
+
issuance checks your current membership. Existing branch protections and account policies still apply.
|
|
32
|
+
|
|
33
|
+
After staging and testing, `remits-cli components propose --title "Describe the change"` creates or updates
|
|
34
|
+
a GitHub PR containing **every staged entry in your current lane**. `--branch` selects the base;
|
|
35
|
+
`--workspace` selects your lane. It preserves component sidecars, records staged hashes and includes a
|
|
36
|
+
verification envelope when available. `--json` returns the PR URL and branch. Landing policy can refuse it.
|
|
37
|
+
The command does not merge, sync, clear staging or commit your local checkout. Review and merge the PR,
|
|
38
|
+
then use the normal sync flow. Start a new workspace after a proposal is closed. If someone edits the PR
|
|
39
|
+
branch directly, reconcile that work before proposing again.
|
|
40
|
+
|
|
24
41
|
## Getting Started
|
|
25
42
|
|
|
26
43
|
### Authentication
|