convene-cli 1.4.1 → 1.4.3
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/dist/commands/init.js +105 -28
- package/dist/git.js +25 -0
- package/dist/index.js +1 -0
- package/dist/protocol.js +1 -1
- package/package.json +1 -1
package/dist/commands/init.js
CHANGED
|
@@ -8,6 +8,7 @@ exports.upsertMarkerBlock = upsertMarkerBlock;
|
|
|
8
8
|
exports.removeMarkerBlock = removeMarkerBlock;
|
|
9
9
|
exports.removeGitignoreGuard = removeGitignoreGuard;
|
|
10
10
|
exports.removeTomlBlock = removeTomlBlock;
|
|
11
|
+
exports.refreshDocs = refreshDocs;
|
|
11
12
|
exports.init = init;
|
|
12
13
|
/**
|
|
13
14
|
* `convene init` — one-command repo onboarding. IDEMPOTENT + merge-safe
|
|
@@ -520,10 +521,111 @@ async function adoptBestPractices(top, slug, opts) {
|
|
|
520
521
|
log('· reported adoption to the dashboard');
|
|
521
522
|
}
|
|
522
523
|
}
|
|
524
|
+
/**
|
|
525
|
+
* Re-render the managed COORDINATION blocks (CLAUDE.md + AGENTS.md) at the current
|
|
526
|
+
* template. Pure per file (P0-IDEMPOTENT). The two blocks intentionally diverge:
|
|
527
|
+
* CLAUDE.md (conveneBlock) omits the manual-deploy line (its PreToolUse hook gates
|
|
528
|
+
* deploys); AGENTS.md (conveneAgentsBlock) adds it for tools with no in-time gate.
|
|
529
|
+
* upsertMarkerBlock preserves everything OUTSIDE the markers.
|
|
530
|
+
*/
|
|
531
|
+
function writeCoordinationBlocks(top, slug, member, baseUrl) {
|
|
532
|
+
const fileBlocks = [
|
|
533
|
+
['CLAUDE.md', (0, protocol_1.conveneBlock)(slug, member, baseUrl)],
|
|
534
|
+
['AGENTS.md', (0, protocol_1.conveneAgentsBlock)(slug, member, baseUrl)],
|
|
535
|
+
];
|
|
536
|
+
for (const [fname, block] of fileBlocks) {
|
|
537
|
+
const file = node_path_1.default.join(top, fname);
|
|
538
|
+
const old = node_fs_1.default.existsSync(file) ? node_fs_1.default.readFileSync(file, 'utf8') : '';
|
|
539
|
+
const result = writeIfChanged(file, upsertMarkerBlock(old, block));
|
|
540
|
+
const note = result === 'created'
|
|
541
|
+
? 'created — Convene block added'
|
|
542
|
+
: result === 'updated'
|
|
543
|
+
? 'merged — your content preserved'
|
|
544
|
+
: 'unchanged';
|
|
545
|
+
log(`${result === 'unchanged' ? '·' : '✓'} ${fname} (${note})`);
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
/**
|
|
549
|
+
* Stage + commit ONLY the convene files (CONVENE_PATHS) as one isolated commit —
|
|
550
|
+
* never `git add -A`, so convene changes are never bundled into unrelated work.
|
|
551
|
+
* Shared by `convene init --commit` and `convene init --refresh-docs --commit`.
|
|
552
|
+
*/
|
|
553
|
+
function commitConveneFiles(top, message, label) {
|
|
554
|
+
const paths = exports.CONVENE_PATHS.filter((p) => node_fs_1.default.existsSync(node_path_1.default.join(top, p)));
|
|
555
|
+
if (!paths.length)
|
|
556
|
+
return;
|
|
557
|
+
// Decide up front whether anything under the managed paths is actually pending
|
|
558
|
+
// (staged/unstaged/untracked). This makes `--commit` deterministic and TRANSPARENT:
|
|
559
|
+
// a clean re-render says "already up to date" instead of a vague no-op, and a tree
|
|
560
|
+
// dirtied by an EARLIER `--refresh-docs` (without `--commit`) still gets committed
|
|
561
|
+
// — the gotcha that previously left changes stranded.
|
|
562
|
+
const pending = (0, git_1.gitPendingPaths)(paths, top);
|
|
563
|
+
if (!pending.length) {
|
|
564
|
+
log(`· ${label}: managed files already committed — nothing to commit.`);
|
|
565
|
+
return;
|
|
566
|
+
}
|
|
567
|
+
if (!(0, git_1.gitAddPaths)(paths, top)) {
|
|
568
|
+
log('⚠ could not stage the convene files — commit them manually.');
|
|
569
|
+
return;
|
|
570
|
+
}
|
|
571
|
+
const res = (0, git_1.gitCommit)(message, paths, top);
|
|
572
|
+
if (res.ok) {
|
|
573
|
+
log(`✓ committed ${label} as one isolated commit${res.sha ? ` (${res.sha})` : ''} — ${pending.length} convene file(s) staged, nothing else.`);
|
|
574
|
+
}
|
|
575
|
+
else {
|
|
576
|
+
// pending changes existed but the commit did not land — never silent.
|
|
577
|
+
log(`⚠ ${pending.length} convene file(s) are staged but the commit did not land — commit them manually (\`git commit\`).`);
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
/**
|
|
581
|
+
* `convene init --refresh-docs` — re-render the managed DOC surfaces (CLAUDE.md +
|
|
582
|
+
* AGENTS.md coordination blocks, the cross-agent rule files, and the MCP client
|
|
583
|
+
* configs) at the CURRENT CLI template, for a repo that is ALREADY on Convene.
|
|
584
|
+
*
|
|
585
|
+
* This is the propagation path init/setup lacked: `convene setup` on an already-
|
|
586
|
+
* onboarded repo only re-confirms identity, so improvements to the block templates
|
|
587
|
+
* (e.g. the connect-line in protocol.ts) never reached existing repos. Refresh fixes
|
|
588
|
+
* that with NO network/identity work — every template is a pure function of
|
|
589
|
+
* (slug, member, baseUrl), all read from local config — so it is byte-idempotent.
|
|
590
|
+
* Best-practice CONTENT is intentionally NOT touched here (that is `convene update`'s
|
|
591
|
+
* job: versioned + consented), and CONVENE_PROTOCOL.md is left as-is (write-if-absent
|
|
592
|
+
* / hand-enrichable), same as init.
|
|
593
|
+
*/
|
|
594
|
+
async function refreshDocs(opts) {
|
|
595
|
+
const top = (0, git_1.gitToplevel)();
|
|
596
|
+
if (!top)
|
|
597
|
+
(0, ctx_1.die)('not a git repository — run `convene init --refresh-docs` inside a repo');
|
|
598
|
+
const existing = (0, config_1.loadProjectConfig)(top);
|
|
599
|
+
if (!existing?.slug) {
|
|
600
|
+
(0, ctx_1.die)('this repo is not on Convene yet — run `convene setup` first; `--refresh-docs` only re-renders an already-onboarded repo.');
|
|
601
|
+
}
|
|
602
|
+
const cfg = (0, config_1.resolveConfig)();
|
|
603
|
+
const slug = existing.slug;
|
|
604
|
+
const member = cfg.member;
|
|
605
|
+
const baseUrl = cfg.baseUrl;
|
|
606
|
+
const skipAgentRules = opts.noAgentRules === true || opts.agentRules === false;
|
|
607
|
+
const skipMcp = opts.noMcp === true || opts.mcp === false;
|
|
608
|
+
log(`Refreshing Convene managed blocks for "${slug}" at the current template (no identity/network changes)…`);
|
|
609
|
+
writeCoordinationBlocks(top, slug, member, baseUrl);
|
|
610
|
+
if (!skipAgentRules)
|
|
611
|
+
writeAgentRules(top, slug, member, baseUrl);
|
|
612
|
+
if (!skipMcp)
|
|
613
|
+
writeMcpConfigs(top, baseUrl);
|
|
614
|
+
if (opts.commit)
|
|
615
|
+
commitConveneFiles(top, 'Refresh Convene managed blocks to current template', 'the refresh');
|
|
616
|
+
log('');
|
|
617
|
+
log('Done — managed blocks re-rendered. Your content outside the convene markers is untouched.');
|
|
618
|
+
log('(Best-practice content is managed separately — run `convene update` to take catalog changes.)');
|
|
619
|
+
}
|
|
523
620
|
async function init(opts) {
|
|
524
621
|
const top = (0, git_1.gitToplevel)();
|
|
525
622
|
if (!top)
|
|
526
623
|
(0, ctx_1.die)('not a git repository — run `convene init` inside a repo');
|
|
624
|
+
// `--refresh-docs` is a re-render of an already-onboarded repo's managed blocks —
|
|
625
|
+
// not onboarding. It needs no consent gate / identity / network, so short-circuit
|
|
626
|
+
// here, before all of that.
|
|
627
|
+
if (opts.refreshDocs)
|
|
628
|
+
return refreshDocs(opts);
|
|
527
629
|
// Consent gate: onboarding writes a footprint and registers per-prompt hooks — it
|
|
528
630
|
// must be a DELIBERATE choice, never an accidental side-effect. A human at a
|
|
529
631
|
// terminal (TTY) confirms simply by running it; an agent / CI (no TTY) must pass
|
|
@@ -658,21 +760,7 @@ async function init(opts) {
|
|
|
658
760
|
// gates deploys), AGENTS.md uses conveneAgentsBlock (adds the explicit
|
|
659
761
|
// `convene deploy` line for tools with no in-time gate). Each is PURE, so a
|
|
660
762
|
// re-run is byte-identical per file (P0-IDEMPOTENT).
|
|
661
|
-
|
|
662
|
-
['CLAUDE.md', (0, protocol_1.conveneBlock)(slug, member, baseUrl)],
|
|
663
|
-
['AGENTS.md', (0, protocol_1.conveneAgentsBlock)(slug, member, baseUrl)],
|
|
664
|
-
];
|
|
665
|
-
for (const [fname, block] of fileBlocks) {
|
|
666
|
-
const file = node_path_1.default.join(top, fname);
|
|
667
|
-
const old = node_fs_1.default.existsSync(file) ? node_fs_1.default.readFileSync(file, 'utf8') : '';
|
|
668
|
-
const result = writeIfChanged(file, upsertMarkerBlock(old, block));
|
|
669
|
-
const note = result === 'created'
|
|
670
|
-
? 'created — Convene block added'
|
|
671
|
-
: result === 'updated'
|
|
672
|
-
? 'merged — your content preserved'
|
|
673
|
-
: 'unchanged';
|
|
674
|
-
log(`${result === 'unchanged' ? '·' : '✓'} ${fname} (${note})`);
|
|
675
|
-
}
|
|
763
|
+
writeCoordinationBlocks(top, slug, member, baseUrl);
|
|
676
764
|
// 6. portable protocol doc — write only if ABSENT (mirrors the memory-seed
|
|
677
765
|
// pattern). The doc is hand-enrichable; unconditionally overwriting it with
|
|
678
766
|
// the generated stub would clobber any teammate's expanded protocol spec.
|
|
@@ -750,19 +838,8 @@ async function init(opts) {
|
|
|
750
838
|
// 8a. optional isolated commit — stage ONLY the convene files (never `git add -A`),
|
|
751
839
|
// so onboarding can never be bundled into unrelated work (the VAcontractorCo
|
|
752
840
|
// entangled-commit failure). Off by default; `--commit` opts in.
|
|
753
|
-
if (opts.commit)
|
|
754
|
-
|
|
755
|
-
if (paths.length && (0, git_1.gitAddPaths)(paths, top)) {
|
|
756
|
-
const res = (0, git_1.gitCommit)('Onboard onto Convene coordination bus', paths, top);
|
|
757
|
-
if (res.ok)
|
|
758
|
-
log(`✓ committed onboarding as one isolated commit${res.sha ? ` (${res.sha})` : ''} — only the convene files were staged.`);
|
|
759
|
-
else
|
|
760
|
-
log('· nothing committed (no staged changes).');
|
|
761
|
-
}
|
|
762
|
-
else if (paths.length) {
|
|
763
|
-
log('⚠ could not stage the convene files — commit them manually.');
|
|
764
|
-
}
|
|
765
|
-
}
|
|
841
|
+
if (opts.commit)
|
|
842
|
+
commitConveneFiles(top, 'Onboard onto Convene coordination bus', 'onboarding');
|
|
766
843
|
// 9. teammate one-liner
|
|
767
844
|
log('');
|
|
768
845
|
log(`Done. Project "${slug}" — dashboard: ${baseUrl}/p/${slug}`);
|
package/dist/git.js
CHANGED
|
@@ -26,6 +26,7 @@ exports.gitConfigUnsetLocal = gitConfigUnsetLocal;
|
|
|
26
26
|
exports.pathIsTracked = pathIsTracked;
|
|
27
27
|
exports.hasStagedChanges = hasStagedChanges;
|
|
28
28
|
exports.gitAddPaths = gitAddPaths;
|
|
29
|
+
exports.gitPendingPaths = gitPendingPaths;
|
|
29
30
|
exports.gitCommit = gitCommit;
|
|
30
31
|
exports.gitPathIsIgnored = gitPathIsIgnored;
|
|
31
32
|
/** Cross-platform git helpers. No shell strings — spawn git directly (P0-XPLAT). */
|
|
@@ -305,6 +306,30 @@ function gitAddPaths(paths, cwd = process.cwd()) {
|
|
|
305
306
|
return false;
|
|
306
307
|
}
|
|
307
308
|
}
|
|
309
|
+
/**
|
|
310
|
+
* The subset of `paths` that have PENDING changes (staged, unstaged, or untracked),
|
|
311
|
+
* via `git status --porcelain -- <paths>`. Lets a caller decide whether there is
|
|
312
|
+
* anything to commit BEFORE running `git commit` — so an isolated-commit helper can
|
|
313
|
+
* say "already up to date" plainly instead of relying on a non-zero `git commit`
|
|
314
|
+
* exit. Returns [] on any error / clean tree (never throws).
|
|
315
|
+
*/
|
|
316
|
+
function gitPendingPaths(paths, cwd = process.cwd()) {
|
|
317
|
+
if (paths.length === 0)
|
|
318
|
+
return [];
|
|
319
|
+
try {
|
|
320
|
+
const r = (0, node_child_process_1.spawnSync)('git', ['status', '--porcelain', '--', ...paths], { cwd, encoding: 'utf8', timeout: 5000 });
|
|
321
|
+
if (r.status !== 0 || !r.stdout)
|
|
322
|
+
return [];
|
|
323
|
+
// Porcelain v1 line: "XY <path>"; we only need the count/names, not the status.
|
|
324
|
+
return r.stdout
|
|
325
|
+
.split('\n')
|
|
326
|
+
.map((l) => l.slice(3).trim())
|
|
327
|
+
.filter(Boolean);
|
|
328
|
+
}
|
|
329
|
+
catch {
|
|
330
|
+
return [];
|
|
331
|
+
}
|
|
332
|
+
}
|
|
308
333
|
/**
|
|
309
334
|
* Commit ONLY the given pathspecs (`git commit -m <msg> -- <paths>`), leaving any
|
|
310
335
|
* other staged changes untouched — the isolated-commit guarantee. Returns the short
|
package/dist/index.js
CHANGED
|
@@ -263,6 +263,7 @@ program
|
|
|
263
263
|
.option('--yes', 'confirm onboarding non-interactively (required for agents/CI)')
|
|
264
264
|
.option('--commit', 'commit ONLY the convene files as one isolated commit (never `git add -A`)')
|
|
265
265
|
.option('--offline', 'write local files only (no API calls)')
|
|
266
|
+
.option('--refresh-docs', 're-render the managed CLAUDE.md/AGENTS.md blocks + agent rules + MCP configs at the current template (already-onboarded repos; no identity/network changes)')
|
|
266
267
|
.option('--tier <names>', 'best practices: comma-separated tiers to adopt (essentials,recommended,advanced)')
|
|
267
268
|
.option('--practice <id[=level]>', 'best practice to adopt (id or id=level; repeatable)', (v, acc) => (acc.push(v), acc), [])
|
|
268
269
|
.option('--all-practices', 'adopt every catalog best practice at its default level')
|
package/dist/protocol.js
CHANGED
|
@@ -31,7 +31,7 @@ function block(flavor, slug, member, baseUrl) {
|
|
|
31
31
|
`This repo is on **Convene** — a tool-agnostic AI development coordination bus — as project \`${slug}\`.`,
|
|
32
32
|
`Dashboard: ${baseUrl}/p/${slug}`,
|
|
33
33
|
'',
|
|
34
|
-
`> **
|
|
34
|
+
`> **Asked to get set up / "up and running" with Convene on this machine?** Run these three: \`npm i -g convene-cli@latest\` → \`convene setup\` (follow the prompts) → \`convene doctor\`. One time per machine; wires Claude Code **and** Codex. Already connected? \`convene doctor\` confirms it. Detail: ${baseUrl}/start.`,
|
|
35
35
|
'',
|
|
36
36
|
'Each turn you get a `<convene-channel>` block — a health line, open items addressed to you, and',
|
|
37
37
|
'recent activity. (Claude Code injects it via the `convene fetch` UserPromptSubmit hook; with other',
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "convene-cli",
|
|
3
|
-
"version": "1.4.
|
|
3
|
+
"version": "1.4.3",
|
|
4
4
|
"description": "Convene CLI — AI development coordination bus client + UserPromptSubmit hook. Install: npm i -g convene-cli; then `convene setup`.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"homepage": "https://dev.convene.live",
|