projecta-rrr 1.24.4 → 1.24.5
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/AGENTS.md +1 -1
- package/CHANGELOG.md +10 -0
- package/commands/rrr/provision-coordinator.md +7 -2
- package/package.json +1 -1
- package/rrr/lib/team-mode/manager.js +156 -7
- package/scripts/rrr-team-mode.js +10 -2
package/AGENTS.md
CHANGED
|
@@ -96,4 +96,4 @@ The RRR loop follows five steps:
|
|
|
96
96
|
- Use `$rrr-help` for full skill catalogue
|
|
97
97
|
- Trigger phrases are case-sensitive: `$rrr-plan-phase` not `$rrr-PlanPhase`
|
|
98
98
|
|
|
99
|
-
<!-- generated: 2026-05-
|
|
99
|
+
<!-- generated: 2026-05-13T01:06:46.790Z | source: commands/rrr/*.md | count: 59 skills -->
|
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,16 @@ All notable changes to RRR will be documented in this file.
|
|
|
4
4
|
|
|
5
5
|
Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
|
|
6
6
|
|
|
7
|
+
## [1.24.5] - 2026-05-13
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
- **Coordinator auth modes** — `$rrr-provision-coordinator` now writes an `auth` block with `mode: claude-code-subscription` (default) or `mode: anthropic-api-key`. Subscription mode uses `~/.claude/.credentials.json` injected via the Cloudflare Secret `CLAUDE_CREDENTIALS_JSON`, eliminating the need for `ANTHROPIC_API_KEY` on the coordinator.
|
|
11
|
+
- **Cloudflare AI Gateway option** — when `--auth-mode anthropic-api-key`, optional `--ai-gateway-account-id <id> --ai-gateway-id <id> [--ai-gateway-authenticated]` flags wire `ANTHROPIC_BASE_URL` to a gateway URL and add `CF_AI_GATEWAY_TOKEN` to required secrets when authenticated.
|
|
12
|
+
|
|
13
|
+
### Changed
|
|
14
|
+
- **Coordinator README** — generated README now includes the sandbox boot snippet that writes `CLAUDE_CREDENTIALS_JSON` to `~/.claude/.credentials.json`, and only documents AI Gateway when API-key mode is selected.
|
|
15
|
+
- **`$rrr-coordinator-status`** — checks for `~/.claude/.credentials.json` or `CLAUDE_CREDENTIALS_JSON` env when subscription mode is active; falls back to API key / AI Gateway env checks otherwise.
|
|
16
|
+
|
|
7
17
|
## [1.24.4] - 2026-05-12
|
|
8
18
|
|
|
9
19
|
### Fixed
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: rrr:provision-coordinator
|
|
3
3
|
description: Create the Cloudflare coordinator contract for RRR team mode integration review
|
|
4
|
-
argument-hint: "[--provider cloudflare-sandbox] [--name <coordinator-name>]"
|
|
4
|
+
argument-hint: "[--auth-mode claude-code-subscription|anthropic-api-key] [--ai-gateway-account-id <id> --ai-gateway-id <id> [--ai-gateway-authenticated]] [--provider cloudflare-sandbox] [--name <coordinator-name>]"
|
|
5
5
|
allowed-tools:
|
|
6
6
|
- Read
|
|
7
7
|
- Write
|
|
@@ -32,8 +32,13 @@ Prepare the repo's coordinator contract so a reusable Cloudflare Claude Code/San
|
|
|
32
32
|
|
|
33
33
|
</process>
|
|
34
34
|
|
|
35
|
+
<auth_modes>
|
|
36
|
+
- `claude-code-subscription` (default) — coordinator runs Claude Code authenticated by an Anthropic subscription. Store the contents of `~/.claude/.credentials.json` as the Cloudflare Secret `CLAUDE_CREDENTIALS_JSON`; sandbox boot writes it to disk so Claude Code resumes the session. No `ANTHROPIC_API_KEY` required.
|
|
37
|
+
- `anthropic-api-key` — coordinator uses `ANTHROPIC_API_KEY` (per-token billing). Pair with `--ai-gateway-account-id <id> --ai-gateway-id <id>` to route Anthropic traffic through Cloudflare AI Gateway for caching, rate limits, and observability. Add `--ai-gateway-authenticated` if the gateway requires `cf-aig-authorization: Bearer $CF_AI_GATEWAY_TOKEN`.
|
|
38
|
+
</auth_modes>
|
|
39
|
+
|
|
35
40
|
<constraints>
|
|
36
41
|
- Coordinator is report-first; never auto-merge to the base branch.
|
|
37
42
|
- Developer work remains in team Sprites and team branches.
|
|
38
|
-
- Do not store secrets in planning files.
|
|
43
|
+
- Do not store secrets in planning files — `CLAUDE_CREDENTIALS_JSON` and AI Gateway tokens belong in Cloudflare Secrets.
|
|
39
44
|
</constraints>
|
package/package.json
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const fs = require('fs');
|
|
4
|
+
const os = require('os');
|
|
4
5
|
const path = require('path');
|
|
5
6
|
const { execFileSync } = require('child_process');
|
|
6
7
|
const { resolvePlanningContext, requireTeamName } = require('./state-router');
|
|
@@ -514,6 +515,61 @@ function coordinatorConfigPath(projectRoot) {
|
|
|
514
515
|
return path.join(projectRoot, '.planning', 'coordinator', 'COORDINATOR.json');
|
|
515
516
|
}
|
|
516
517
|
|
|
518
|
+
function buildAiGatewayBlock(opts) {
|
|
519
|
+
const accountId = opts.aiGatewayAccountId || opts.cfAccountId || null;
|
|
520
|
+
const gatewayId = opts.aiGatewayId || null;
|
|
521
|
+
if (!accountId || !gatewayId) return null;
|
|
522
|
+
const authenticated = opts.aiGatewayAuthenticated === true || opts.aiGatewayAuthenticated === 'true';
|
|
523
|
+
const baseUrl = `https://gateway.ai.cloudflare.com/v1/${accountId}/${gatewayId}/anthropic`;
|
|
524
|
+
return {
|
|
525
|
+
provider: 'cloudflare-ai-gateway',
|
|
526
|
+
account_id: accountId,
|
|
527
|
+
gateway_id: gatewayId,
|
|
528
|
+
anthropic_base_url: baseUrl,
|
|
529
|
+
authenticated,
|
|
530
|
+
runtime_env: { ANTHROPIC_BASE_URL: baseUrl },
|
|
531
|
+
notes: [
|
|
532
|
+
'Only used when auth_mode = anthropic-api-key.',
|
|
533
|
+
'Set ANTHROPIC_BASE_URL to route Anthropic API calls through the gateway.',
|
|
534
|
+
authenticated
|
|
535
|
+
? 'Authenticated gateway: send `cf-aig-authorization: Bearer $CF_AI_GATEWAY_TOKEN` header on every request.'
|
|
536
|
+
: 'Unauthenticated gateway: ANTHROPIC_API_KEY is the only credential; gateway URL is the access boundary.'
|
|
537
|
+
]
|
|
538
|
+
};
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
function buildAuthBlock(opts) {
|
|
542
|
+
const mode = opts.authMode || 'claude-code-subscription';
|
|
543
|
+
if (mode === 'claude-code-subscription') {
|
|
544
|
+
return {
|
|
545
|
+
mode,
|
|
546
|
+
description: 'Coordinator uses Claude Code with an Anthropic subscription (Max/Pro). No ANTHROPIC_API_KEY required.',
|
|
547
|
+
credentials_path: '~/.claude/.credentials.json',
|
|
548
|
+
injection: [
|
|
549
|
+
'Persist the credentials file once (after a one-time `claude login`).',
|
|
550
|
+
'For a Cloudflare sandbox: write the stored credentials JSON to ~/.claude/.credentials.json on container start (from a CF Secret, KV, or D1 row).',
|
|
551
|
+
'For a Sprite: run `claude login` once interactively, then `sprite checkpoint create` to capture the authenticated state.'
|
|
552
|
+
],
|
|
553
|
+
required_secrets: ['GITHUB_TOKEN', 'CLAUDE_CREDENTIALS_JSON'],
|
|
554
|
+
notes: [
|
|
555
|
+
'CLAUDE_CREDENTIALS_JSON holds the contents of ~/.claude/.credentials.json — store as a CF Secret, not in repo.',
|
|
556
|
+
'Subscription billing applies; no per-token API cost.'
|
|
557
|
+
]
|
|
558
|
+
};
|
|
559
|
+
}
|
|
560
|
+
if (mode === 'anthropic-api-key') {
|
|
561
|
+
return {
|
|
562
|
+
mode,
|
|
563
|
+
description: 'Coordinator authenticates Claude Code with ANTHROPIC_API_KEY (per-token billing).',
|
|
564
|
+
required_secrets: ['ANTHROPIC_API_KEY', 'GITHUB_TOKEN'],
|
|
565
|
+
notes: [
|
|
566
|
+
'Optional: pair with Cloudflare AI Gateway via --ai-gateway-account-id/--ai-gateway-id for caching, rate limits, and observability.'
|
|
567
|
+
]
|
|
568
|
+
};
|
|
569
|
+
}
|
|
570
|
+
throw new Error(`unknown auth_mode: ${mode}`);
|
|
571
|
+
}
|
|
572
|
+
|
|
517
573
|
function writeCoordinatorProvision(options) {
|
|
518
574
|
const opts = options || {};
|
|
519
575
|
const projectRoot = opts.projectRoot || process.cwd();
|
|
@@ -521,8 +577,13 @@ function writeCoordinatorProvision(options) {
|
|
|
521
577
|
const runtime = readRuntimeManifest(projectRoot);
|
|
522
578
|
const dir = path.join(projectRoot, '.planning', 'coordinator');
|
|
523
579
|
ensureDir(dir);
|
|
580
|
+
const auth = buildAuthBlock(opts);
|
|
581
|
+
const aiGateway = auth.mode === 'anthropic-api-key' ? buildAiGatewayBlock(opts) : null;
|
|
582
|
+
const requiredSecrets = [...auth.required_secrets];
|
|
583
|
+
if (aiGateway && aiGateway.authenticated) requiredSecrets.push('CF_AI_GATEWAY_TOKEN');
|
|
584
|
+
|
|
524
585
|
const config = {
|
|
525
|
-
schema_version:
|
|
586
|
+
schema_version: 2,
|
|
526
587
|
provider: opts.provider || 'cloudflare-sandbox',
|
|
527
588
|
name: opts.name || `rrr-coordinator-${repoNameFor(teamConfig).toLowerCase()}`,
|
|
528
589
|
generated_at: new Date().toISOString(),
|
|
@@ -532,7 +593,9 @@ function writeCoordinatorProvision(options) {
|
|
|
532
593
|
integration_branch: teamConfig.github.integration_branch,
|
|
533
594
|
runtime_manifest: path.relative(projectRoot, runtimeManifestPath(projectRoot)),
|
|
534
595
|
report_first: true,
|
|
535
|
-
|
|
596
|
+
auth,
|
|
597
|
+
ai_gateway: aiGateway,
|
|
598
|
+
required_secrets: requiredSecrets,
|
|
536
599
|
responsibilities: [
|
|
537
600
|
'clone repository into ephemeral sandbox',
|
|
538
601
|
'merge team branches into integration branch',
|
|
@@ -542,6 +605,7 @@ function writeCoordinatorProvision(options) {
|
|
|
542
605
|
]
|
|
543
606
|
};
|
|
544
607
|
writeJson(coordinatorConfigPath(projectRoot), config);
|
|
608
|
+
|
|
545
609
|
const readme = [
|
|
546
610
|
`# ${config.name}`,
|
|
547
611
|
'',
|
|
@@ -554,11 +618,67 @@ function writeCoordinatorProvision(options) {
|
|
|
554
618
|
`Base branch: ${config.base_branch}`,
|
|
555
619
|
`Integration branch: ${config.integration_branch}`,
|
|
556
620
|
`Runtime manifest: ${config.runtime_manifest}`,
|
|
621
|
+
'',
|
|
622
|
+
'## Auth',
|
|
623
|
+
'',
|
|
624
|
+
`Mode: \`${auth.mode}\``,
|
|
625
|
+
'',
|
|
626
|
+
auth.description
|
|
627
|
+
];
|
|
628
|
+
|
|
629
|
+
if (auth.mode === 'claude-code-subscription') {
|
|
630
|
+
readme.push(
|
|
631
|
+
'',
|
|
632
|
+
'### Credentials injection',
|
|
633
|
+
'',
|
|
634
|
+
...auth.injection.map(line => `- ${line}`),
|
|
635
|
+
'',
|
|
636
|
+
'Cloudflare sandbox boot snippet:',
|
|
637
|
+
'',
|
|
638
|
+
'```bash',
|
|
639
|
+
'mkdir -p ~/.claude',
|
|
640
|
+
'printf "%s" "$CLAUDE_CREDENTIALS_JSON" > ~/.claude/.credentials.json',
|
|
641
|
+
'chmod 600 ~/.claude/.credentials.json',
|
|
642
|
+
'claude --version # verifies authenticated',
|
|
643
|
+
'```'
|
|
644
|
+
);
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
readme.push(
|
|
557
648
|
'',
|
|
558
649
|
'## Required Secrets',
|
|
559
650
|
'',
|
|
560
|
-
|
|
561
|
-
|
|
651
|
+
...requiredSecrets.map(s => `- \`${s}\``)
|
|
652
|
+
);
|
|
653
|
+
|
|
654
|
+
if (aiGateway) {
|
|
655
|
+
readme.push(
|
|
656
|
+
'',
|
|
657
|
+
'## Cloudflare AI Gateway (optional)',
|
|
658
|
+
'',
|
|
659
|
+
`Account: ${aiGateway.account_id}`,
|
|
660
|
+
`Gateway: ${aiGateway.gateway_id}`,
|
|
661
|
+
`Anthropic base URL: ${aiGateway.anthropic_base_url}`,
|
|
662
|
+
`Authenticated: ${aiGateway.authenticated ? 'yes' : 'no'}`,
|
|
663
|
+
'',
|
|
664
|
+
'```bash',
|
|
665
|
+
`export ANTHROPIC_BASE_URL="${aiGateway.anthropic_base_url}"`,
|
|
666
|
+
'export ANTHROPIC_API_KEY="$ANTHROPIC_API_KEY"',
|
|
667
|
+
aiGateway.authenticated
|
|
668
|
+
? '# header: cf-aig-authorization: Bearer $CF_AI_GATEWAY_TOKEN'
|
|
669
|
+
: '# unauthenticated gateway — URL is the access boundary',
|
|
670
|
+
'```'
|
|
671
|
+
);
|
|
672
|
+
} else if (auth.mode === 'anthropic-api-key') {
|
|
673
|
+
readme.push(
|
|
674
|
+
'',
|
|
675
|
+
'## Cloudflare AI Gateway',
|
|
676
|
+
'',
|
|
677
|
+
'Not configured. Re-run with `--ai-gateway-account-id <id> --ai-gateway-id <id>` to route Anthropic API traffic through Cloudflare AI Gateway.'
|
|
678
|
+
);
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
readme.push(
|
|
562
682
|
'',
|
|
563
683
|
'## Execution Contract',
|
|
564
684
|
'',
|
|
@@ -566,8 +686,9 @@ function writeCoordinatorProvision(options) {
|
|
|
566
686
|
'- GitHub remains the source of truth for branches, PRs, reviews, and checks.',
|
|
567
687
|
'- Coordinator is report-first: it writes reports and recommendations only; humans approve final merges.',
|
|
568
688
|
'- Developer work stays in Sprites/team branches.'
|
|
569
|
-
|
|
570
|
-
|
|
689
|
+
);
|
|
690
|
+
|
|
691
|
+
atomicWrite(path.join(dir, 'README.md'), `${readme.join('\n')}\n`);
|
|
571
692
|
return { config, runtime, dir };
|
|
572
693
|
}
|
|
573
694
|
|
|
@@ -579,8 +700,36 @@ function readCoordinatorStatus(projectRoot) {
|
|
|
579
700
|
checks.push({ name: 'runtime manifest', ok: fs.existsSync(runtimeManifestPath(root)), detail: path.relative(root, runtimeManifestPath(root)) });
|
|
580
701
|
const wrangler = execCapture('npx', ['wrangler', '--version'], { cwd: root });
|
|
581
702
|
checks.push({ name: 'wrangler available', ok: wrangler.ok, detail: wrangler.output || 'not available' });
|
|
582
|
-
checks.push({ name: 'ANTHROPIC_API_KEY present', ok: !!process.env.ANTHROPIC_API_KEY, detail: process.env.ANTHROPIC_API_KEY ? 'present' : 'missing locally' });
|
|
583
703
|
checks.push({ name: 'GITHUB_TOKEN present', ok: !!process.env.GITHUB_TOKEN, detail: process.env.GITHUB_TOKEN ? 'present' : 'missing locally' });
|
|
704
|
+
|
|
705
|
+
const authMode = config && config.auth ? config.auth.mode : (config && config.ai_gateway ? 'anthropic-api-key' : 'claude-code-subscription');
|
|
706
|
+
if (authMode === 'claude-code-subscription') {
|
|
707
|
+
const credsPath = path.join(os.homedir(), '.claude', '.credentials.json');
|
|
708
|
+
const localCreds = fs.existsSync(credsPath);
|
|
709
|
+
checks.push({
|
|
710
|
+
name: 'Claude Code subscription credentials',
|
|
711
|
+
ok: localCreds || !!process.env.CLAUDE_CREDENTIALS_JSON,
|
|
712
|
+
detail: localCreds ? credsPath : (process.env.CLAUDE_CREDENTIALS_JSON ? 'CLAUDE_CREDENTIALS_JSON env present' : 'missing locally (run `claude login` or set CLAUDE_CREDENTIALS_JSON)')
|
|
713
|
+
});
|
|
714
|
+
} else {
|
|
715
|
+
checks.push({ name: 'ANTHROPIC_API_KEY present', ok: !!process.env.ANTHROPIC_API_KEY, detail: process.env.ANTHROPIC_API_KEY ? 'present' : 'missing locally' });
|
|
716
|
+
if (config && config.ai_gateway) {
|
|
717
|
+
const expectedBase = config.ai_gateway.anthropic_base_url;
|
|
718
|
+
const baseUrl = process.env.ANTHROPIC_BASE_URL;
|
|
719
|
+
checks.push({
|
|
720
|
+
name: 'ANTHROPIC_BASE_URL routes to AI Gateway',
|
|
721
|
+
ok: baseUrl === expectedBase,
|
|
722
|
+
detail: baseUrl ? (baseUrl === expectedBase ? expectedBase : `mismatch: ${baseUrl}`) : `missing locally (expected ${expectedBase})`
|
|
723
|
+
});
|
|
724
|
+
if (config.ai_gateway.authenticated) {
|
|
725
|
+
checks.push({
|
|
726
|
+
name: 'CF_AI_GATEWAY_TOKEN present',
|
|
727
|
+
ok: !!process.env.CF_AI_GATEWAY_TOKEN,
|
|
728
|
+
detail: process.env.CF_AI_GATEWAY_TOKEN ? 'present' : 'missing locally (authenticated gateway requires it)'
|
|
729
|
+
});
|
|
730
|
+
}
|
|
731
|
+
}
|
|
732
|
+
}
|
|
584
733
|
return { config, checks };
|
|
585
734
|
}
|
|
586
735
|
|
package/scripts/rrr-team-mode.js
CHANGED
|
@@ -73,7 +73,7 @@ Usage:
|
|
|
73
73
|
node scripts/rrr-team-mode.js runtime-init
|
|
74
74
|
node scripts/rrr-team-mode.js provision-sprites [--apply] [--teams team-runtime]
|
|
75
75
|
node scripts/rrr-team-mode.js sprite-status [--live]
|
|
76
|
-
node scripts/rrr-team-mode.js provision-coordinator
|
|
76
|
+
node scripts/rrr-team-mode.js provision-coordinator [--auth-mode claude-code-subscription|anthropic-api-key] [--ai-gateway-account-id <id> --ai-gateway-id <id> [--ai-gateway-authenticated]]
|
|
77
77
|
node scripts/rrr-team-mode.js coordinator-status
|
|
78
78
|
|
|
79
79
|
Notes:
|
|
@@ -224,10 +224,18 @@ function main() {
|
|
|
224
224
|
const result = writeCoordinatorProvision({
|
|
225
225
|
projectRoot,
|
|
226
226
|
provider: args.provider,
|
|
227
|
-
name: args.name
|
|
227
|
+
name: args.name,
|
|
228
|
+
authMode: args['auth-mode'] || args.authMode,
|
|
229
|
+
aiGatewayAccountId: args['ai-gateway-account-id'] || args['cf-account-id'],
|
|
230
|
+
aiGatewayId: args['ai-gateway-id'],
|
|
231
|
+
aiGatewayAuthenticated: args['ai-gateway-authenticated'] === true || args['ai-gateway-authenticated'] === 'true'
|
|
228
232
|
});
|
|
229
233
|
console.log(`Wrote ${path.relative(projectRoot, path.join(result.dir, 'COORDINATOR.json'))}`);
|
|
230
234
|
console.log(`Wrote ${path.relative(projectRoot, path.join(result.dir, 'README.md'))}`);
|
|
235
|
+
console.log(`Auth mode: ${result.config.auth.mode}`);
|
|
236
|
+
if (result.config.ai_gateway) {
|
|
237
|
+
console.log(`AI Gateway: ${result.config.ai_gateway.anthropic_base_url}`);
|
|
238
|
+
}
|
|
231
239
|
return;
|
|
232
240
|
}
|
|
233
241
|
|