@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 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
- - L4799 Auth And Component Staging
13
- - L5435 Component Summaries, Status, And Sync Gates
14
- - L7759 Branches, Promotion, Commit, And Test Runs
15
- - L10072 Tokens, Tools, Verification, And Config
16
- - L11589 Service Dashboard And WebSocket Listener
17
- - L14099 Agent And Ticket Workflows
18
- - L18869 Help, Auto Update, And Command Dispatch
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
- console.log('Usage: remits-cli components <stage|status|lanes|entries|clear|sync|commit|promotion|branches|branch>');
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.169",
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