@rness/cli 0.13.0 → 0.14.0
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 +50 -11
- package/dist/bin/rness.js +1 -1
- package/dist/{chunk-4VTYSPZW.js → chunk-AXTFDXN2.js} +566 -386
- package/dist/chunk-AXTFDXN2.js.map +1 -0
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-4VTYSPZW.js.map +0 -1
|
@@ -486,7 +486,7 @@ function parseRepoSpec(spec, org, host) {
|
|
|
486
486
|
}
|
|
487
487
|
|
|
488
488
|
// src/version.ts
|
|
489
|
-
var VERSION = "0.
|
|
489
|
+
var VERSION = "0.14.0";
|
|
490
490
|
|
|
491
491
|
// src/core/pm.ts
|
|
492
492
|
import { execFile as execFile2 } from "child_process";
|
|
@@ -523,6 +523,12 @@ function rnessRunner(pm, version) {
|
|
|
523
523
|
return "yarn dlx @rness/cli";
|
|
524
524
|
return "npx @rness/cli";
|
|
525
525
|
}
|
|
526
|
+
function localRunner(pm) {
|
|
527
|
+
if (pm === "pnpm") return "pnpm";
|
|
528
|
+
if (pm === "yarn") return "yarn";
|
|
529
|
+
if (pm === "bun") return "bunx";
|
|
530
|
+
return "npx";
|
|
531
|
+
}
|
|
526
532
|
function rnessCommand(env = process.env) {
|
|
527
533
|
const agent = env["npm_config_user_agent"] ?? "";
|
|
528
534
|
if (agent === "") return "rness";
|
|
@@ -3211,6 +3217,54 @@ function reportError(e) {
|
|
|
3211
3217
|
return 1;
|
|
3212
3218
|
}
|
|
3213
3219
|
|
|
3220
|
+
// src/core/delegate.ts
|
|
3221
|
+
import { readFile as readFile6 } from "fs/promises";
|
|
3222
|
+
import { join as join10 } from "path";
|
|
3223
|
+
var DEFAULT_BIN = "dist/bin/rness.js";
|
|
3224
|
+
var PINNED_BIN = `node_modules/@rness/cli/${DEFAULT_BIN}`;
|
|
3225
|
+
async function readPinnedCli(rnessDir) {
|
|
3226
|
+
const dir = join10(rnessDir, "node_modules", "@rness", "cli");
|
|
3227
|
+
let pkg;
|
|
3228
|
+
try {
|
|
3229
|
+
pkg = JSON.parse(await readFile6(join10(dir, "package.json"), "utf8"));
|
|
3230
|
+
} catch {
|
|
3231
|
+
return null;
|
|
3232
|
+
}
|
|
3233
|
+
const declared2 = pkg.bin;
|
|
3234
|
+
let bin = DEFAULT_BIN;
|
|
3235
|
+
if (typeof declared2 === "string") bin = declared2;
|
|
3236
|
+
else if (declared2 !== null && typeof declared2 === "object") {
|
|
3237
|
+
const named = declared2["rness"];
|
|
3238
|
+
if (typeof named === "string") bin = named;
|
|
3239
|
+
}
|
|
3240
|
+
return {
|
|
3241
|
+
dir,
|
|
3242
|
+
bin,
|
|
3243
|
+
version: typeof pkg.version === "string" ? pkg.version : null
|
|
3244
|
+
};
|
|
3245
|
+
}
|
|
3246
|
+
async function pinnedBinPath(rnessDir) {
|
|
3247
|
+
const pinned = await readPinnedCli(rnessDir);
|
|
3248
|
+
if (pinned === null) return null;
|
|
3249
|
+
return join10(pinned.dir, ...pinned.bin.split("/"));
|
|
3250
|
+
}
|
|
3251
|
+
async function findDelegate(cwd, ownVersion) {
|
|
3252
|
+
let root;
|
|
3253
|
+
let rnessDir;
|
|
3254
|
+
try {
|
|
3255
|
+
const ws = await findWorkspace(cwd);
|
|
3256
|
+
root = ws.root;
|
|
3257
|
+
rnessDir = ws.rnessDir;
|
|
3258
|
+
} catch {
|
|
3259
|
+
return null;
|
|
3260
|
+
}
|
|
3261
|
+
const pinned = await readPinnedCli(rnessDir);
|
|
3262
|
+
if (pinned === null) return null;
|
|
3263
|
+
const { version } = pinned;
|
|
3264
|
+
if (version === null || version === ownVersion) return null;
|
|
3265
|
+
return { entry: join10(pinned.dir, "dist", "index.js"), version, root };
|
|
3266
|
+
}
|
|
3267
|
+
|
|
3214
3268
|
// src/core/block.ts
|
|
3215
3269
|
import { createHash as createHash2 } from "crypto";
|
|
3216
3270
|
var BEGIN = "<!-- BEGIN rness -->";
|
|
@@ -3275,7 +3329,7 @@ function isCurrentBlock(blockLines, freshHash) {
|
|
|
3275
3329
|
}
|
|
3276
3330
|
|
|
3277
3331
|
// src/core/merge.ts
|
|
3278
|
-
import { join as
|
|
3332
|
+
import { join as join11 } from "path";
|
|
3279
3333
|
function findBlock(lines) {
|
|
3280
3334
|
const begins = [];
|
|
3281
3335
|
const ends = [];
|
|
@@ -3334,7 +3388,7 @@ function claudeMdAtRoot(existing, block) {
|
|
|
3334
3388
|
return merged.ok ? { ...merged, changed: merged.text !== existing } : merged;
|
|
3335
3389
|
}
|
|
3336
3390
|
async function ensureClaudeMd(dir) {
|
|
3337
|
-
const file =
|
|
3391
|
+
const file = join11(dir, "CLAUDE.md");
|
|
3338
3392
|
if (await isSymlink(file)) return "unchanged";
|
|
3339
3393
|
const existing = await readOrNull(file);
|
|
3340
3394
|
if (existing === null) {
|
|
@@ -3349,14 +3403,222 @@ async function ensureClaudeMd(dir) {
|
|
|
3349
3403
|
}
|
|
3350
3404
|
|
|
3351
3405
|
// src/commands/sync.ts
|
|
3352
|
-
import { join as
|
|
3406
|
+
import { join as join14 } from "path";
|
|
3353
3407
|
|
|
3354
3408
|
// src/core/agent-targets.ts
|
|
3355
3409
|
import { mkdir as mkdir2 } from "fs/promises";
|
|
3356
|
-
import { dirname as dirname4, join as
|
|
3410
|
+
import { dirname as dirname4, join as join13 } from "path";
|
|
3411
|
+
|
|
3412
|
+
// src/core/claude-skills.ts
|
|
3413
|
+
var PLUGIN = ".claude/skills/rness";
|
|
3414
|
+
var PLUGIN_JSON = `${JSON.stringify(
|
|
3415
|
+
{
|
|
3416
|
+
name: "rness",
|
|
3417
|
+
description: "The rness workspace in Claude Code: /rness:status, /rness:adr, /rness:spec, /rness:plan, /rness:done."
|
|
3418
|
+
},
|
|
3419
|
+
null,
|
|
3420
|
+
2
|
|
3421
|
+
)}
|
|
3422
|
+
`;
|
|
3423
|
+
function statusSkill(rness, pm) {
|
|
3424
|
+
const command = `node "\${CLAUDE_PROJECT_DIR}/${rness}/${PINNED_BIN}" status --cwd "\${CLAUDE_PROJECT_DIR}"`;
|
|
3425
|
+
return `---
|
|
3426
|
+
name: status
|
|
3427
|
+
description: The status of every decision, specification, plan and other tracked document of the rness workspace, one table per directory. Read-only.
|
|
3428
|
+
argument-hint: '[tab]'
|
|
3429
|
+
disable-model-invocation: true
|
|
3430
|
+
allowed-tools: Bash(${command})
|
|
3431
|
+
---
|
|
3432
|
+
|
|
3433
|
+
!\`${command}\`
|
|
3434
|
+
|
|
3435
|
+
Show the output above to the user as it is: the heading and the tables,
|
|
3436
|
+
nothing added, nothing summarised, no other tool. Arguments: \`$ARGUMENTS\`.
|
|
3437
|
+
When they name a tab, show only that tab's section. If the output says the
|
|
3438
|
+
module cannot be found, say instead that ${rness} is not installed next to
|
|
3439
|
+
this repository.
|
|
3440
|
+
|
|
3441
|
+
End with this line: _For the view with tabs and scrolling: here, Ctrl+Z,
|
|
3442
|
+
then \`npx @rness/cli status\` (q to close), then \`fg\`; or in another
|
|
3443
|
+
terminal, from the workspace's \`.rness/\`: \`${localRunner(pm)} rness status\`._
|
|
3444
|
+
`;
|
|
3445
|
+
}
|
|
3446
|
+
var LIFECYCLE2 = [
|
|
3447
|
+
{
|
|
3448
|
+
name: "adr",
|
|
3449
|
+
description: "Record a decision of the rness workspace as an ADR in .rness/adr/ \u2014 a choice expensive to reverse or that creates a lasting constraint. Use when the developer asks for an ADR, or when the conversation reaches such a decision.",
|
|
3450
|
+
hint: "[subject | NNNN]",
|
|
3451
|
+
tab: "adr",
|
|
3452
|
+
body: (rness) => `You record a decision of this workspace as an ADR in \`${rness}/adr/\`. The table
|
|
3453
|
+
above lists the existing ADRs, newest first. Arguments: \`$ARGUMENTS\`.
|
|
3454
|
+
|
|
3455
|
+
Before writing:
|
|
3456
|
+
|
|
3457
|
+
1. If the developer did not ask for an ADR in so many words, propose one in
|
|
3458
|
+
a single line \u2014 its title, and why the choice is hard to reverse \u2014 and
|
|
3459
|
+
wait for a yes.
|
|
3460
|
+
2. Read \`${rness}/CONVENTIONS.md\` and \`${rness}/adr/0000-template.md\`: they hold the
|
|
3461
|
+
rules and the sections; this skill is only the procedure.
|
|
3462
|
+
3. Arguments naming an ADR (\`NNNN\`): reopen that file. An \`Accepted\` ADR is
|
|
3463
|
+
never edited: offer a new ADR that supersedes it.
|
|
3464
|
+
4. Otherwise the subject is the arguments, else the decision just
|
|
3465
|
+
discussed. Context, alternatives or consequences missing from the
|
|
3466
|
+
conversation: ask for them, one question at a time. Never invent them.
|
|
3467
|
+
|
|
3468
|
+
Writing:
|
|
3469
|
+
|
|
3470
|
+
- \`${rness}/adr/NNNN-<slug>.md\`, NNNN the highest number above plus one.
|
|
3471
|
+
- The template's front matter and sections, filled in, its guidance lines
|
|
3472
|
+
removed: \`date\` today, \`status: Proposed\`, \`repo\` the repositories under
|
|
3473
|
+
\`org/\` it affects.
|
|
3474
|
+
- An ADR it replaces is named in Context. That one becomes \`Superseded\`,
|
|
3475
|
+
with \`superseded_by:\`, only once the new ADR is \`Accepted\`.
|
|
3476
|
+
- The rness hook checks every edit under \`${rness}/\`: fix what it reports.
|
|
3477
|
+
|
|
3478
|
+
After writing: give the path and the Decision section, and say the ADR
|
|
3479
|
+
stays \`Proposed\` until the developer accepts it. Change a status only when
|
|
3480
|
+
the developer says so. Do not commit.
|
|
3481
|
+
`
|
|
3482
|
+
},
|
|
3483
|
+
{
|
|
3484
|
+
name: "spec",
|
|
3485
|
+
description: "Write a specification of the rness workspace in .rness/specs/ \u2014 the outcome wanted and its scope, before any plan. Use when the developer asks for a spec, or when agreed work is too large to start without one.",
|
|
3486
|
+
hint: "[subject | NNNN]",
|
|
3487
|
+
tab: "specs",
|
|
3488
|
+
body: (rness) => `You write a specification of this workspace in \`${rness}/specs/\`. The table above
|
|
3489
|
+
lists the existing ones, newest first. Arguments: \`$ARGUMENTS\`.
|
|
3490
|
+
|
|
3491
|
+
Before writing:
|
|
3492
|
+
|
|
3493
|
+
1. If the developer did not ask for a specification in so many words,
|
|
3494
|
+
propose one in a single line and wait for a yes.
|
|
3495
|
+
2. Read \`${rness}/CONVENTIONS.md\`, then the most recent specification above: match
|
|
3496
|
+
its front matter, sections and tone.
|
|
3497
|
+
3. Arguments naming a specification (\`NNNN\`): reopen it. One that is
|
|
3498
|
+
\`Implemented\`, \`Superseded\` or \`Rejected\` is not edited: offer a new one.
|
|
3499
|
+
4. Otherwise the subject is the arguments, else the work just discussed.
|
|
3500
|
+
The problem, what is in and out of scope, the ADRs it rests on: ask what
|
|
3501
|
+
the conversation does not say, one question at a time.
|
|
3502
|
+
|
|
3503
|
+
Writing:
|
|
3504
|
+
|
|
3505
|
+
- \`${rness}/specs/NNNN-<slug>.md\`, NNNN the highest number above plus one.
|
|
3506
|
+
- \`date\` and \`updated\` today, \`status: Draft\`, \`repo\`, and \`adr:\` linking
|
|
3507
|
+
the decisions it rests on \u2014 or the rationale in the body when none does.
|
|
3508
|
+
- No specification yet to follow: Summary, Scope, Out of scope,
|
|
3509
|
+
Alternatives considered, To verify, Tests.
|
|
3510
|
+
- What was checked in this session (a document read, a command run) is
|
|
3511
|
+
written as verified, with the date; everything else as a proposal or an
|
|
3512
|
+
open question.
|
|
3513
|
+
- The rness hook checks every edit under \`${rness}/\`: fix what it reports.
|
|
3514
|
+
|
|
3515
|
+
After writing: give the path and the summary. It stays \`Draft\` until the
|
|
3516
|
+
developer moves it (\`Proposed\` for review, \`Approved\` to plan it). No plan
|
|
3517
|
+
here: \`/rness:plan NNNN\` once approved. Do not commit.
|
|
3518
|
+
`
|
|
3519
|
+
},
|
|
3520
|
+
{
|
|
3521
|
+
name: "plan",
|
|
3522
|
+
description: "Turn an approved specification of the rness workspace into a plan in .rness/plans/ \u2014 ordered tasks, each with the command that proves it done. Use when the developer asks for a plan, or when a specification has just been approved.",
|
|
3523
|
+
hint: "<spec NNNN>",
|
|
3524
|
+
tab: "plans",
|
|
3525
|
+
body: (rness) => `You turn a specification into a plan in \`${rness}/plans/\`. The table above lists
|
|
3526
|
+
the existing plans, newest first. Arguments, the specification:
|
|
3527
|
+
\`$ARGUMENTS\`.
|
|
3528
|
+
|
|
3529
|
+
Before writing:
|
|
3530
|
+
|
|
3531
|
+
1. If the developer did not ask for a plan in so many words, propose one in
|
|
3532
|
+
a single line and wait for a yes.
|
|
3533
|
+
2. No specification named: ask which. Read it, \`${rness}/CONVENTIONS.md\`, and the
|
|
3534
|
+
most recent plan above: match its front matter and sections.
|
|
3535
|
+
3. A specification that is not \`Approved\`: say so, and plan it only if the
|
|
3536
|
+
developer confirms. A plan of it that is neither \`Completed\` nor
|
|
3537
|
+
\`Abandoned\`: reopen it rather than write a second.
|
|
3538
|
+
4. Read the code and the repositories the specification touches: every
|
|
3539
|
+
task names real files and real commands.
|
|
3540
|
+
|
|
3541
|
+
Writing:
|
|
3542
|
+
|
|
3543
|
+
- \`${rness}/plans/NNNN-<slug>.md\`, NNNN the highest plan number above plus one \u2014
|
|
3544
|
+
not the specification's.
|
|
3545
|
+
- \`date\` and \`updated\` today, \`status: Draft\`, \`repo\`, \`spec:\` linking the
|
|
3546
|
+
specification.
|
|
3547
|
+
- Tasks in order, as checkboxes. Each gives the files, what changes, and
|
|
3548
|
+
the command that proves it (a test, a build, a run). The last tasks:
|
|
3549
|
+
the documentation the work makes inaccurate, then the release when the
|
|
3550
|
+
repository has one.
|
|
3551
|
+
- Where the plan decides something the specification leaves open, a
|
|
3552
|
+
section says so.
|
|
3553
|
+
- The rness hook checks every edit under \`${rness}/\`: fix what it reports.
|
|
3554
|
+
|
|
3555
|
+
After writing: give the path and the list of tasks. It becomes \`Ready\` when
|
|
3556
|
+
the developer agrees. Do not commit.
|
|
3557
|
+
`
|
|
3558
|
+
},
|
|
3559
|
+
{
|
|
3560
|
+
name: "done",
|
|
3561
|
+
description: "Close a piece of work of the rness workspace \u2014 check each task of its plan on evidence, then move the plan and its specification to their final status and correct the documents the work made inaccurate. Use when the developer says the work is done, or when the last task of a plan passes.",
|
|
3562
|
+
hint: "[plan NNNN]",
|
|
3563
|
+
tab: "plans",
|
|
3564
|
+
body: (rness) => `You close a piece of work: its plan in \`${rness}/plans/\`, its specification, and
|
|
3565
|
+
what they made inaccurate. The table above lists the plans, newest first.
|
|
3566
|
+
Arguments: \`$ARGUMENTS\`.
|
|
3567
|
+
|
|
3568
|
+
1. The plan: the one named, else the one \`In progress\`. Several or none:
|
|
3569
|
+
ask.
|
|
3570
|
+
2. If the developer did not ask to close it in so many words, propose it in
|
|
3571
|
+
a single line and wait for a yes.
|
|
3572
|
+
3. Read the plan, its specification and \`${rness}/CONVENTIONS.md\`.
|
|
3573
|
+
4. Evidence first. For each task, what shows it done: a test, a build, a
|
|
3574
|
+
command's output in this session. A task without evidence: run its
|
|
3575
|
+
check now, or report it. Never mark a task done on belief.
|
|
3576
|
+
5. All tasks proven:
|
|
3577
|
+
- the plan: \`status: Completed\`, \`updated\` today, the checkboxes of the
|
|
3578
|
+
proven tasks ticked, and a section \`Verification (YYYY-MM-DD)\` \u2014 what
|
|
3579
|
+
ran, what it showed, what could not run and why;
|
|
3580
|
+
- the specification: \`Implemented\` once every plan of it is
|
|
3581
|
+
\`Completed\`; \`updated\` today;
|
|
3582
|
+
- the smallest set of documents the work makes inaccurate: \`${rness}/docs/\`,
|
|
3583
|
+
the READMEs of the repositories it changed.
|
|
3584
|
+
6. A task not proven: the plan stays \`In progress\` \u2014 or \`Blocked\`, the
|
|
3585
|
+
blocker written in it. Say what remains.
|
|
3586
|
+
7. The rness hook checks every edit under \`${rness}/\`: fix what it reports.
|
|
3587
|
+
|
|
3588
|
+
After: list the files changed and the statuses moved. Do not commit.
|
|
3589
|
+
`
|
|
3590
|
+
}
|
|
3591
|
+
];
|
|
3592
|
+
function lifecycleSkill(rness, s) {
|
|
3593
|
+
const command = `node "\${CLAUDE_PROJECT_DIR}/${rness}/${PINNED_BIN}" status ${s.tab} --cwd "\${CLAUDE_PROJECT_DIR}"`;
|
|
3594
|
+
return `---
|
|
3595
|
+
name: ${s.name}
|
|
3596
|
+
description: ${s.description}
|
|
3597
|
+
argument-hint: '${s.hint}'
|
|
3598
|
+
allowed-tools: Bash(${command})
|
|
3599
|
+
---
|
|
3600
|
+
|
|
3601
|
+
!\`${command}\`
|
|
3602
|
+
|
|
3603
|
+
${s.body(rness)}`;
|
|
3604
|
+
}
|
|
3605
|
+
function pluginFiles(rness, at, ctx) {
|
|
3606
|
+
return [
|
|
3607
|
+
{ file: `${PLUGIN}/.claude-plugin/plugin.json`, at, content: PLUGIN_JSON },
|
|
3608
|
+
{
|
|
3609
|
+
file: `${PLUGIN}/skills/status/SKILL.md`,
|
|
3610
|
+
at,
|
|
3611
|
+
content: statusSkill(rness, ctx.packageManager)
|
|
3612
|
+
},
|
|
3613
|
+
...LIFECYCLE2.map((s) => ({
|
|
3614
|
+
file: `${PLUGIN}/skills/${s.name}/SKILL.md`,
|
|
3615
|
+
at,
|
|
3616
|
+
content: lifecycleSkill(rness, s)
|
|
3617
|
+
}))
|
|
3618
|
+
];
|
|
3619
|
+
}
|
|
3357
3620
|
|
|
3358
3621
|
// src/core/agents.ts
|
|
3359
|
-
var PINNED_BIN = "node_modules/@rness/cli/dist/bin/rness.js";
|
|
3360
3622
|
function hookLine(rness, event) {
|
|
3361
3623
|
const run3 = `f="$CLAUDE_PROJECT_DIR/${rness}/${PINNED_BIN}"; if [ -f "$f" ]; then node "$f" hook ${event};`;
|
|
3362
3624
|
if (event !== "session-start") return `${run3} fi`;
|
|
@@ -3409,53 +3671,11 @@ function hooks(rness) {
|
|
|
3409
3671
|
}
|
|
3410
3672
|
];
|
|
3411
3673
|
}
|
|
3412
|
-
var PLUGIN = ".claude/skills/rness";
|
|
3413
|
-
var PLUGIN_JSON = `${JSON.stringify(
|
|
3414
|
-
{
|
|
3415
|
-
name: "rness",
|
|
3416
|
-
description: "The rness workspace in Claude Code: /rness:status."
|
|
3417
|
-
},
|
|
3418
|
-
null,
|
|
3419
|
-
2
|
|
3420
|
-
)}
|
|
3421
|
-
`;
|
|
3422
|
-
function statusSkill(rness) {
|
|
3423
|
-
const command = `node "\${CLAUDE_PROJECT_DIR}/${rness}/${PINNED_BIN}" status --cwd "\${CLAUDE_PROJECT_DIR}"`;
|
|
3424
|
-
return `---
|
|
3425
|
-
name: status
|
|
3426
|
-
description: The status of every decision, specification, plan and other tracked document of the rness workspace, one table per directory. Read-only.
|
|
3427
|
-
argument-hint: '[tab]'
|
|
3428
|
-
disable-model-invocation: true
|
|
3429
|
-
allowed-tools: Bash(${command})
|
|
3430
|
-
---
|
|
3431
|
-
|
|
3432
|
-
!\`${command}\`
|
|
3433
|
-
|
|
3434
|
-
Show the output above to the user as it is: the heading and the tables,
|
|
3435
|
-
nothing added, nothing summarised, no other tool. Arguments: \`$ARGUMENTS\`.
|
|
3436
|
-
When they name a tab, show only that tab's section. If the output says the
|
|
3437
|
-
module cannot be found, say instead that ${rness} is not installed next to
|
|
3438
|
-
this repository.
|
|
3439
|
-
|
|
3440
|
-
End with this line: _For the view with tabs and scrolling: Ctrl+Z, then
|
|
3441
|
-
\`npx @rness/cli status\` (q to close), then \`fg\`._
|
|
3442
|
-
`;
|
|
3443
|
-
}
|
|
3444
|
-
function plugin(rness, at) {
|
|
3445
|
-
return [
|
|
3446
|
-
{ file: `${PLUGIN}/.claude-plugin/plugin.json`, at, content: PLUGIN_JSON },
|
|
3447
|
-
{
|
|
3448
|
-
file: `${PLUGIN}/skills/status/SKILL.md`,
|
|
3449
|
-
at,
|
|
3450
|
-
content: statusSkill(rness)
|
|
3451
|
-
}
|
|
3452
|
-
];
|
|
3453
|
-
}
|
|
3454
3674
|
var TARGETS = {
|
|
3455
3675
|
claude: {
|
|
3456
3676
|
name: "claude",
|
|
3457
3677
|
label: "Claude Code",
|
|
3458
|
-
files: [
|
|
3678
|
+
files: (ctx) => [
|
|
3459
3679
|
{
|
|
3460
3680
|
file: ".claude/settings.json",
|
|
3461
3681
|
at: "clones",
|
|
@@ -3491,7 +3711,7 @@ var TARGETS = {
|
|
|
3491
3711
|
}
|
|
3492
3712
|
]
|
|
3493
3713
|
},
|
|
3494
|
-
...
|
|
3714
|
+
...pluginFiles("../../.rness", "clones", ctx),
|
|
3495
3715
|
// A session opened at the workspace root reads this file, one opened
|
|
3496
3716
|
// in a clone does not (spec 0011 §1): the hooks only, `.rness` inside.
|
|
3497
3717
|
{
|
|
@@ -3499,7 +3719,7 @@ var TARGETS = {
|
|
|
3499
3719
|
at: "root",
|
|
3500
3720
|
guarantees: hooks(".rness")
|
|
3501
3721
|
},
|
|
3502
|
-
...
|
|
3722
|
+
...pluginFiles(".rness", "root", ctx)
|
|
3503
3723
|
]
|
|
3504
3724
|
}
|
|
3505
3725
|
};
|
|
@@ -3613,30 +3833,288 @@ function describeGuarantee(g) {
|
|
|
3613
3833
|
return `${g.path.join(".")} lacks ${what}`;
|
|
3614
3834
|
}
|
|
3615
3835
|
|
|
3836
|
+
// src/core/pinned.ts
|
|
3837
|
+
import { execFile as execFile3 } from "child_process";
|
|
3838
|
+
import { readFile as readFile7 } from "fs/promises";
|
|
3839
|
+
import { basename as basename3, join as join12 } from "path";
|
|
3840
|
+
import { promisify as promisify3 } from "util";
|
|
3841
|
+
var execFileP3 = promisify3(execFile3);
|
|
3842
|
+
var PACKAGE = "@rness/cli";
|
|
3843
|
+
var EXACT_VERSION = /^\d+\.\d+\.\d+(-[0-9A-Za-z.-]+)?$/;
|
|
3844
|
+
function compareVersions(a, b) {
|
|
3845
|
+
const split = (v) => {
|
|
3846
|
+
const dash = v.indexOf("-");
|
|
3847
|
+
const core = dash === -1 ? v : v.slice(0, dash);
|
|
3848
|
+
return [core.split(".").map(Number), dash === -1 ? null : v.slice(dash + 1)];
|
|
3849
|
+
};
|
|
3850
|
+
const [coreA, preA] = split(a);
|
|
3851
|
+
const [coreB, preB] = split(b);
|
|
3852
|
+
for (let i = 0; i < 3; i += 1) {
|
|
3853
|
+
const diff = (coreA[i] ?? 0) - (coreB[i] ?? 0);
|
|
3854
|
+
if (diff !== 0) return diff;
|
|
3855
|
+
}
|
|
3856
|
+
if (preA === preB) return 0;
|
|
3857
|
+
if (preA === null) return 1;
|
|
3858
|
+
if (preB === null) return -1;
|
|
3859
|
+
return preA.localeCompare(preB, "en", { numeric: true });
|
|
3860
|
+
}
|
|
3861
|
+
async function readPackageJson(rnessDir) {
|
|
3862
|
+
try {
|
|
3863
|
+
const parsed = JSON.parse(
|
|
3864
|
+
await readFile7(join12(rnessDir, "package.json"), "utf8")
|
|
3865
|
+
);
|
|
3866
|
+
return parsed !== null && typeof parsed === "object" ? parsed : null;
|
|
3867
|
+
} catch {
|
|
3868
|
+
return null;
|
|
3869
|
+
}
|
|
3870
|
+
}
|
|
3871
|
+
async function readPin(rnessDir) {
|
|
3872
|
+
const pkg = await readPackageJson(rnessDir);
|
|
3873
|
+
if (pkg === null) return null;
|
|
3874
|
+
for (const field of ["devDependencies", "dependencies"]) {
|
|
3875
|
+
const deps = pkg[field];
|
|
3876
|
+
if (deps === null || typeof deps !== "object") continue;
|
|
3877
|
+
const spec = deps[PACKAGE];
|
|
3878
|
+
if (typeof spec === "string") return { spec, field };
|
|
3879
|
+
}
|
|
3880
|
+
return null;
|
|
3881
|
+
}
|
|
3882
|
+
async function writePin(rnessDir, from, to) {
|
|
3883
|
+
const file = join12(rnessDir, "package.json");
|
|
3884
|
+
const text = await readFile7(file, "utf8");
|
|
3885
|
+
const entry = new RegExp(
|
|
3886
|
+
`("${PACKAGE}"\\s*:\\s*")${from.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}(")`
|
|
3887
|
+
);
|
|
3888
|
+
if (!entry.test(text))
|
|
3889
|
+
throw new Error(`"${PACKAGE}": "${from}" not found in package.json`);
|
|
3890
|
+
await writeFileAtomic(file, text.replace(entry, `$1${to}$2`));
|
|
3891
|
+
}
|
|
3892
|
+
var LOCKFILES = [
|
|
3893
|
+
["pnpm-lock.yaml", "pnpm"],
|
|
3894
|
+
["yarn.lock", "yarn"],
|
|
3895
|
+
["bun.lock", "bun"],
|
|
3896
|
+
["bun.lockb", "bun"],
|
|
3897
|
+
["package-lock.json", "npm"]
|
|
3898
|
+
];
|
|
3899
|
+
async function workspacePackageManager(rnessDir) {
|
|
3900
|
+
const declared2 = (await readPackageJson(rnessDir))?.["packageManager"];
|
|
3901
|
+
if (typeof declared2 === "string") {
|
|
3902
|
+
const name = declared2.split("@")[0] ?? "";
|
|
3903
|
+
if (isPackageManager(name)) return name;
|
|
3904
|
+
}
|
|
3905
|
+
for (const [lockfile, pm] of LOCKFILES)
|
|
3906
|
+
if (await exists(join12(rnessDir, lockfile))) return pm;
|
|
3907
|
+
return "npm";
|
|
3908
|
+
}
|
|
3909
|
+
async function hasLockfile(rnessDir, pm) {
|
|
3910
|
+
for (const [lockfile, owner] of LOCKFILES)
|
|
3911
|
+
if (owner === pm && await exists(join12(rnessDir, lockfile))) return true;
|
|
3912
|
+
return false;
|
|
3913
|
+
}
|
|
3914
|
+
async function pinDrift(rnessDir) {
|
|
3915
|
+
const pin = await readPin(rnessDir);
|
|
3916
|
+
if (pin === null || !EXACT_VERSION.test(pin.spec)) return null;
|
|
3917
|
+
const installed = (await readPinnedCli(rnessDir))?.version ?? null;
|
|
3918
|
+
return installed === pin.spec ? null : { pin: pin.spec, installed };
|
|
3919
|
+
}
|
|
3920
|
+
async function driftWarning(cwd) {
|
|
3921
|
+
let root;
|
|
3922
|
+
let rnessDir;
|
|
3923
|
+
try {
|
|
3924
|
+
const ws = await findWorkspace(cwd);
|
|
3925
|
+
root = ws.root;
|
|
3926
|
+
rnessDir = ws.rnessDir;
|
|
3927
|
+
} catch {
|
|
3928
|
+
return null;
|
|
3929
|
+
}
|
|
3930
|
+
const drift = await pinDrift(rnessDir);
|
|
3931
|
+
if (drift === null) return null;
|
|
3932
|
+
const pm = await workspacePackageManager(rnessDir);
|
|
3933
|
+
return warn(
|
|
3934
|
+
`${basename3(root)}/.rness pins @rness/cli ${drift.pin} but ${drift.installed ?? "nothing"} is installed \u2014 run ${pm} install in .rness`
|
|
3935
|
+
);
|
|
3936
|
+
}
|
|
3937
|
+
var CHILD_DEADLINE_MS = 12e4;
|
|
3938
|
+
function childEnv(env = process.env) {
|
|
3939
|
+
return {
|
|
3940
|
+
...env,
|
|
3941
|
+
GIT_SSH_COMMAND: `${env["GIT_SSH_COMMAND"] ?? "ssh"} -o BatchMode=yes`,
|
|
3942
|
+
GIT_TERMINAL_PROMPT: "0"
|
|
3943
|
+
};
|
|
3944
|
+
}
|
|
3945
|
+
async function ensureInstalled(rnessDir, opts = {}) {
|
|
3946
|
+
const drift = await pinDrift(rnessDir);
|
|
3947
|
+
if (drift === null) return null;
|
|
3948
|
+
const env = opts.env ?? process.env;
|
|
3949
|
+
if (env["RNESS_NO_INSTALL"] === "1")
|
|
3950
|
+
return { installed: false, pin: drift.pin, reason: "RNESS_NO_INSTALL=1" };
|
|
3951
|
+
const pm = await workspacePackageManager(rnessDir);
|
|
3952
|
+
const frozen = await hasLockfile(rnessDir, pm);
|
|
3953
|
+
const install = opts.install ?? installDependencies;
|
|
3954
|
+
opts.announce?.(drift.pin);
|
|
3955
|
+
try {
|
|
3956
|
+
await install(pm, rnessDir, { frozen });
|
|
3957
|
+
return { installed: true, pin: drift.pin, reason: null };
|
|
3958
|
+
} catch (e) {
|
|
3959
|
+
return {
|
|
3960
|
+
installed: false,
|
|
3961
|
+
pin: drift.pin,
|
|
3962
|
+
reason: e instanceof Error ? e.message : String(e)
|
|
3963
|
+
};
|
|
3964
|
+
}
|
|
3965
|
+
}
|
|
3966
|
+
async function runPinnedSync(root) {
|
|
3967
|
+
const installed = await readPinnedCli(join12(root, ".rness"));
|
|
3968
|
+
if (installed === null) return null;
|
|
3969
|
+
const pinned = join12(installed.dir, ...installed.bin.split("/"));
|
|
3970
|
+
if (!await exists(pinned))
|
|
3971
|
+
return {
|
|
3972
|
+
code: 1,
|
|
3973
|
+
stdout: "",
|
|
3974
|
+
stderr: `@rness/cli in .rness is not installed correctly (missing ${installed.bin}); reinstall in .rness/
|
|
3975
|
+
`
|
|
3976
|
+
};
|
|
3977
|
+
try {
|
|
3978
|
+
const { stdout, stderr } = await execFileP3(
|
|
3979
|
+
process.execPath,
|
|
3980
|
+
[pinned, "sync", "--yes"],
|
|
3981
|
+
{
|
|
3982
|
+
cwd: root,
|
|
3983
|
+
maxBuffer: 16 * 1024 * 1024,
|
|
3984
|
+
env: childEnv(),
|
|
3985
|
+
timeout: CHILD_DEADLINE_MS,
|
|
3986
|
+
killSignal: "SIGKILL"
|
|
3987
|
+
}
|
|
3988
|
+
);
|
|
3989
|
+
return { code: 0, stdout, stderr };
|
|
3990
|
+
} catch (e) {
|
|
3991
|
+
const err = e;
|
|
3992
|
+
const deadline = err.killed === true ? `rness sync in .rness did not finish within ${CHILD_DEADLINE_MS / 1e3}s and was stopped
|
|
3993
|
+
` : "";
|
|
3994
|
+
return {
|
|
3995
|
+
code: typeof err.code === "number" ? err.code : 1,
|
|
3996
|
+
stdout: err.stdout ?? "",
|
|
3997
|
+
stderr: `${err.stderr ?? ""}${deadline}`
|
|
3998
|
+
};
|
|
3999
|
+
}
|
|
4000
|
+
}
|
|
4001
|
+
var SYNC_VERBS = ["updated", "unchanged", "stale"];
|
|
4002
|
+
function counted(noun, counts) {
|
|
4003
|
+
const total = [...counts.values()].reduce((a, b) => a + b, 0);
|
|
4004
|
+
const detail = SYNC_VERBS.filter((verb) => counts.has(verb)).map((verb) => `${counts.get(verb) ?? 0} ${verb}`).join(", ");
|
|
4005
|
+
return `${total} ${noun}${total === 1 ? "" : "s"}${detail === "" ? "" : `: ${detail}`}`;
|
|
4006
|
+
}
|
|
4007
|
+
function summariseSync(stdout) {
|
|
4008
|
+
const blocks = /* @__PURE__ */ new Map();
|
|
4009
|
+
const agentFiles = /* @__PURE__ */ new Map();
|
|
4010
|
+
const others = [];
|
|
4011
|
+
for (const line3 of stdout.split("\n")) {
|
|
4012
|
+
if (line3.trim() === "") continue;
|
|
4013
|
+
const m = /^(updated|unchanged|stale)\s+(\S+)/.exec(line3);
|
|
4014
|
+
if (m === null) {
|
|
4015
|
+
others.push(line3);
|
|
4016
|
+
continue;
|
|
4017
|
+
}
|
|
4018
|
+
const [, verb = "", path = ""] = m;
|
|
4019
|
+
const counts = /(^|\/)(AGENTS|CLAUDE)\.md$/.test(path) ? blocks : agentFiles;
|
|
4020
|
+
counts.set(verb, (counts.get(verb) ?? 0) + 1);
|
|
4021
|
+
}
|
|
4022
|
+
return {
|
|
4023
|
+
summary: [
|
|
4024
|
+
counted("block", blocks),
|
|
4025
|
+
...agentFiles.size > 0 ? [counted("agent file", agentFiles)] : []
|
|
4026
|
+
].join("; "),
|
|
4027
|
+
others
|
|
4028
|
+
};
|
|
4029
|
+
}
|
|
4030
|
+
function syncOutcome(result, opts = {}) {
|
|
4031
|
+
const { others } = summariseSync(result.stdout);
|
|
4032
|
+
const wrote = /^(updated|unchanged|stale)\s/m.test(result.stdout);
|
|
4033
|
+
const stderr = result.stderr.split("\n").map((l) => l.trimEnd()).filter((l) => l.trim() !== "");
|
|
4034
|
+
const hints = wrote ? [...others, ...stderr] : others;
|
|
4035
|
+
if (opts.sshWorks === true && /Permission denied \(publickey\)/.test(result.stderr))
|
|
4036
|
+
hints.push(...agentHintLines());
|
|
4037
|
+
return {
|
|
4038
|
+
code: wrote ? 0 : result.code,
|
|
4039
|
+
hints,
|
|
4040
|
+
errors: wrote ? [] : stderr
|
|
4041
|
+
};
|
|
4042
|
+
}
|
|
4043
|
+
async function syncPinned(root, shown, fallback) {
|
|
4044
|
+
const rnessDir = join12(root, ".rness");
|
|
4045
|
+
const installed = await readPinnedCli(rnessDir);
|
|
4046
|
+
if (installed === null) {
|
|
4047
|
+
if (fallback !== void 0) return fallback();
|
|
4048
|
+
process.stderr.write(
|
|
4049
|
+
`@rness/cli is not installed in ${shown}/.rness; install in .rness/, then ${rnessCommand()} sync
|
|
4050
|
+
`
|
|
4051
|
+
);
|
|
4052
|
+
return 1;
|
|
4053
|
+
}
|
|
4054
|
+
const pinned = join12(installed.dir, ...installed.bin.split("/"));
|
|
4055
|
+
if (!await exists(pinned)) {
|
|
4056
|
+
process.stderr.write(
|
|
4057
|
+
`@rness/cli in ${shown}/.rness is not installed correctly (missing ${installed.bin}); reinstall in .rness/
|
|
4058
|
+
`
|
|
4059
|
+
);
|
|
4060
|
+
return 1;
|
|
4061
|
+
}
|
|
4062
|
+
try {
|
|
4063
|
+
const { stdout, stderr } = await execFileP3(
|
|
4064
|
+
process.execPath,
|
|
4065
|
+
[pinned, "sync", "--yes"],
|
|
4066
|
+
{
|
|
4067
|
+
cwd: root,
|
|
4068
|
+
maxBuffer: 16 * 1024 * 1024,
|
|
4069
|
+
env: childEnv(),
|
|
4070
|
+
timeout: CHILD_DEADLINE_MS,
|
|
4071
|
+
killSignal: "SIGKILL"
|
|
4072
|
+
}
|
|
4073
|
+
);
|
|
4074
|
+
process.stdout.write(stdout);
|
|
4075
|
+
if (stderr !== "") process.stderr.write(stderr);
|
|
4076
|
+
return 0;
|
|
4077
|
+
} catch (e) {
|
|
4078
|
+
const err = e;
|
|
4079
|
+
if (err.stdout !== void 0 && err.stdout !== "")
|
|
4080
|
+
process.stdout.write(err.stdout);
|
|
4081
|
+
if (err.stderr !== void 0 && err.stderr !== "")
|
|
4082
|
+
process.stderr.write(err.stderr);
|
|
4083
|
+
return typeof err.code === "number" ? err.code : 1;
|
|
4084
|
+
}
|
|
4085
|
+
}
|
|
4086
|
+
|
|
3616
4087
|
// src/core/agent-targets.ts
|
|
3617
4088
|
function wholeDiff(existing, content) {
|
|
3618
4089
|
if (existing === content) return null;
|
|
3619
4090
|
return existing === null ? "missing" : "differs from what rness writes";
|
|
3620
4091
|
}
|
|
4092
|
+
async function contextOf(root) {
|
|
4093
|
+
return {
|
|
4094
|
+
packageManager: await workspacePackageManager(join13(root, ".rness"))
|
|
4095
|
+
};
|
|
4096
|
+
}
|
|
4097
|
+
var PATHS_ONLY = { packageManager: "npm" };
|
|
3621
4098
|
async function filesOf(root, manifest, targets) {
|
|
3622
4099
|
const files = [];
|
|
3623
|
-
if (!await exists(
|
|
4100
|
+
if (!await exists(join13(root, "org"))) return files;
|
|
4101
|
+
const ctx = await contextOf(root);
|
|
3624
4102
|
for (const target2 of targets)
|
|
3625
|
-
for (const owned of target2.files)
|
|
4103
|
+
for (const owned of target2.files(ctx))
|
|
3626
4104
|
if (owned.at === "root")
|
|
3627
4105
|
files.push({
|
|
3628
4106
|
...owned,
|
|
3629
|
-
file:
|
|
4107
|
+
file: join13(root, ...owned.file.split("/")),
|
|
3630
4108
|
label: owned.file
|
|
3631
4109
|
});
|
|
3632
4110
|
for (const repo of Object.keys(manifest.repos)) {
|
|
3633
|
-
if (!await exists(
|
|
4111
|
+
if (!await exists(join13(root, "org", repo))) continue;
|
|
3634
4112
|
for (const target2 of targets)
|
|
3635
|
-
for (const owned of target2.files)
|
|
4113
|
+
for (const owned of target2.files(ctx))
|
|
3636
4114
|
if (owned.at === "clones")
|
|
3637
4115
|
files.push({
|
|
3638
4116
|
...owned,
|
|
3639
|
-
file:
|
|
4117
|
+
file: join13(root, "org", repo, ...owned.file.split("/")),
|
|
3640
4118
|
label: `org/${repo}/${owned.file}`
|
|
3641
4119
|
});
|
|
3642
4120
|
}
|
|
@@ -3652,7 +4130,7 @@ function writtenFiles(manifest) {
|
|
|
3652
4130
|
return [
|
|
3653
4131
|
...BLOCK_FILES,
|
|
3654
4132
|
...declared(manifest).flatMap(
|
|
3655
|
-
(t) => t.files.filter((f) => f.at === "clones").map((f) => f.file)
|
|
4133
|
+
(t) => t.files(PATHS_ONLY).filter((f) => f.at === "clones").map((f) => f.file)
|
|
3656
4134
|
)
|
|
3657
4135
|
];
|
|
3658
4136
|
}
|
|
@@ -3960,7 +4438,7 @@ function targetsOf(manifest, root, only) {
|
|
|
3960
4438
|
const segments = entry.path.split("/");
|
|
3961
4439
|
targets.push({
|
|
3962
4440
|
scope: name,
|
|
3963
|
-
dir:
|
|
4441
|
+
dir: join14(root, ...segments),
|
|
3964
4442
|
depth: segments.length,
|
|
3965
4443
|
label: `${entry.path}/AGENTS.md`
|
|
3966
4444
|
});
|
|
@@ -4119,7 +4597,7 @@ async function syncCommand(opts, deps = {}) {
|
|
|
4119
4597
|
try {
|
|
4120
4598
|
const notCloned = /* @__PURE__ */ new Set();
|
|
4121
4599
|
for (const [name, repo] of Object.entries(manifest.repos)) {
|
|
4122
|
-
const dir =
|
|
4600
|
+
const dir = join14(ws.root, "org", name);
|
|
4123
4601
|
const label = `org/${name}`;
|
|
4124
4602
|
if (!await exists(dir)) {
|
|
4125
4603
|
if (!toClone.has(name)) {
|
|
@@ -4171,7 +4649,7 @@ async function syncCommand(opts, deps = {}) {
|
|
|
4171
4649
|
lines.push(
|
|
4172
4650
|
`not in rness.json: ${undeclared.join(", ")} (${rnessCommand()} add <name> declares it)`
|
|
4173
4651
|
);
|
|
4174
|
-
if (!await exists(
|
|
4652
|
+
if (!await exists(join14(ws.root, "org"))) {
|
|
4175
4653
|
lines.push(["skipped", "blocks (no org/ directory here)"]);
|
|
4176
4654
|
} else {
|
|
4177
4655
|
let differences = 0;
|
|
@@ -4183,7 +4661,7 @@ async function syncCommand(opts, deps = {}) {
|
|
|
4183
4661
|
continue;
|
|
4184
4662
|
}
|
|
4185
4663
|
const [agentsLinked, claudeLinked] = await Promise.all(
|
|
4186
|
-
BLOCK_FILES.map((f) => isSymlink(
|
|
4664
|
+
BLOCK_FILES.map((f) => isSymlink(join14(t.dir, f)))
|
|
4187
4665
|
);
|
|
4188
4666
|
const atRoot = t.scope === null;
|
|
4189
4667
|
if (!atRoot && (agentsLinked === true || claudeLinked === true)) {
|
|
@@ -4206,7 +4684,7 @@ async function syncCommand(opts, deps = {}) {
|
|
|
4206
4684
|
`${t.label}: block is ${Math.round(block.bytes / 1024)} KB (over 32 KB)`
|
|
4207
4685
|
);
|
|
4208
4686
|
}
|
|
4209
|
-
const agents = agentsLinked === true ? "skipped" : await syncBlockFile(
|
|
4687
|
+
const agents = agentsLinked === true ? "skipped" : await syncBlockFile(join14(t.dir, "AGENTS.md"), block, check);
|
|
4210
4688
|
if (typeof agents === "object") {
|
|
4211
4689
|
problems.push(`${t.label}: ${agents.error}`);
|
|
4212
4690
|
continue;
|
|
@@ -4221,7 +4699,7 @@ async function syncCommand(opts, deps = {}) {
|
|
|
4221
4699
|
}
|
|
4222
4700
|
if (claudeLinked === true) continue;
|
|
4223
4701
|
const claude = await syncBlockFile(
|
|
4224
|
-
|
|
4702
|
+
join14(t.dir, "CLAUDE.md"),
|
|
4225
4703
|
block,
|
|
4226
4704
|
check,
|
|
4227
4705
|
true
|
|
@@ -4278,7 +4756,7 @@ async function syncCommand(opts, deps = {}) {
|
|
|
4278
4756
|
}
|
|
4279
4757
|
|
|
4280
4758
|
// src/commands/add.ts
|
|
4281
|
-
import { basename as
|
|
4759
|
+
import { basename as basename4, join as join15 } from "path";
|
|
4282
4760
|
function printDeclared(ui, result, already) {
|
|
4283
4761
|
for (const name of result.declared) {
|
|
4284
4762
|
if (already.has(name)) continue;
|
|
@@ -4313,7 +4791,7 @@ async function addCommand(spec, opts, deps = {}) {
|
|
|
4313
4791
|
}
|
|
4314
4792
|
if (parsed.name === CONTEXT_REPO) {
|
|
4315
4793
|
process.stderr.write(
|
|
4316
|
-
`${CONTEXT_REPO} is the workspace context, not a member repository \u2014 it is already cloned at ${
|
|
4794
|
+
`${CONTEXT_REPO} is the workspace context, not a member repository \u2014 it is already cloned at ${basename4(ws.root)}/${CONTEXT_REPO}
|
|
4317
4795
|
`
|
|
4318
4796
|
);
|
|
4319
4797
|
return 2;
|
|
@@ -4371,7 +4849,7 @@ async function addCommand(spec, opts, deps = {}) {
|
|
|
4371
4849
|
}
|
|
4372
4850
|
parsed = parseRepoSpec(spec, org, host);
|
|
4373
4851
|
const scopes = (opts.scopes ?? "").split(",").map((s) => s.trim()).filter((s) => s !== "");
|
|
4374
|
-
const dir =
|
|
4852
|
+
const dir = join15(ws.root, "org", parsed.name);
|
|
4375
4853
|
const present = await exists(dir);
|
|
4376
4854
|
if (interactive) {
|
|
4377
4855
|
const { confirm, isCancel } = await terminal.prompts();
|
|
@@ -4487,66 +4965,19 @@ async function contextCommand(opts) {
|
|
|
4487
4965
|
manifest,
|
|
4488
4966
|
scope
|
|
4489
4967
|
});
|
|
4490
|
-
process.stdout.write(
|
|
4491
|
-
opts.json ? `${JSON.stringify(ctx, null, 2)}
|
|
4492
|
-
` : renderMarkdown(ctx)
|
|
4493
|
-
);
|
|
4494
|
-
return 0;
|
|
4495
|
-
} catch (e) {
|
|
4496
|
-
return reportError(e);
|
|
4497
|
-
}
|
|
4498
|
-
}
|
|
4499
|
-
|
|
4500
|
-
// src/core/delegate.ts
|
|
4501
|
-
import { readFile as readFile6 } from "fs/promises";
|
|
4502
|
-
import { join as join14 } from "path";
|
|
4503
|
-
var DEFAULT_BIN = "dist/bin/rness.js";
|
|
4504
|
-
async function readPinnedCli(rnessDir) {
|
|
4505
|
-
const dir = join14(rnessDir, "node_modules", "@rness", "cli");
|
|
4506
|
-
let pkg;
|
|
4507
|
-
try {
|
|
4508
|
-
pkg = JSON.parse(await readFile6(join14(dir, "package.json"), "utf8"));
|
|
4509
|
-
} catch {
|
|
4510
|
-
return null;
|
|
4511
|
-
}
|
|
4512
|
-
const declared2 = pkg.bin;
|
|
4513
|
-
let bin = DEFAULT_BIN;
|
|
4514
|
-
if (typeof declared2 === "string") bin = declared2;
|
|
4515
|
-
else if (declared2 !== null && typeof declared2 === "object") {
|
|
4516
|
-
const named = declared2["rness"];
|
|
4517
|
-
if (typeof named === "string") bin = named;
|
|
4518
|
-
}
|
|
4519
|
-
return {
|
|
4520
|
-
dir,
|
|
4521
|
-
bin,
|
|
4522
|
-
version: typeof pkg.version === "string" ? pkg.version : null
|
|
4523
|
-
};
|
|
4524
|
-
}
|
|
4525
|
-
async function pinnedBinPath(rnessDir) {
|
|
4526
|
-
const pinned = await readPinnedCli(rnessDir);
|
|
4527
|
-
if (pinned === null) return null;
|
|
4528
|
-
return join14(pinned.dir, ...pinned.bin.split("/"));
|
|
4529
|
-
}
|
|
4530
|
-
async function findDelegate(cwd, ownVersion) {
|
|
4531
|
-
let root;
|
|
4532
|
-
let rnessDir;
|
|
4533
|
-
try {
|
|
4534
|
-
const ws = await findWorkspace(cwd);
|
|
4535
|
-
root = ws.root;
|
|
4536
|
-
rnessDir = ws.rnessDir;
|
|
4537
|
-
} catch {
|
|
4538
|
-
return null;
|
|
4968
|
+
process.stdout.write(
|
|
4969
|
+
opts.json ? `${JSON.stringify(ctx, null, 2)}
|
|
4970
|
+
` : renderMarkdown(ctx)
|
|
4971
|
+
);
|
|
4972
|
+
return 0;
|
|
4973
|
+
} catch (e) {
|
|
4974
|
+
return reportError(e);
|
|
4539
4975
|
}
|
|
4540
|
-
const pinned = await readPinnedCli(rnessDir);
|
|
4541
|
-
if (pinned === null) return null;
|
|
4542
|
-
const { version } = pinned;
|
|
4543
|
-
if (version === null || version === ownVersion) return null;
|
|
4544
|
-
return { entry: join14(pinned.dir, "dist", "index.js"), version, root };
|
|
4545
4976
|
}
|
|
4546
4977
|
|
|
4547
4978
|
// src/core/scaffold.ts
|
|
4548
4979
|
import { statSync } from "fs";
|
|
4549
|
-
import { dirname as dirname5, join as
|
|
4980
|
+
import { dirname as dirname5, join as join16 } from "path";
|
|
4550
4981
|
import { fileURLToPath } from "url";
|
|
4551
4982
|
var SCAFFOLD_FILES = [
|
|
4552
4983
|
"AGENTS.md",
|
|
@@ -4570,9 +5001,9 @@ var SCAFFOLD_FILES = [
|
|
|
4570
5001
|
function scaffoldDir() {
|
|
4571
5002
|
let dir = dirname5(fileURLToPath(import.meta.url));
|
|
4572
5003
|
for (let i = 0; i < 4; i += 1) {
|
|
4573
|
-
const candidate =
|
|
5004
|
+
const candidate = join16(dir, "scaffold");
|
|
4574
5005
|
try {
|
|
4575
|
-
if (statSync(
|
|
5006
|
+
if (statSync(join16(candidate, "rness.json")).isFile()) return candidate;
|
|
4576
5007
|
} catch {
|
|
4577
5008
|
}
|
|
4578
5009
|
dir = dirname5(dir);
|
|
@@ -4581,15 +5012,15 @@ function scaffoldDir() {
|
|
|
4581
5012
|
}
|
|
4582
5013
|
|
|
4583
5014
|
// src/core/scaffold-copy.ts
|
|
4584
|
-
import { chmod as chmod2, mkdir as mkdir3, readFile as
|
|
4585
|
-
import { dirname as dirname6, join as
|
|
5015
|
+
import { chmod as chmod2, mkdir as mkdir3, readFile as readFile8, stat as stat2, writeFile as writeFile2 } from "fs/promises";
|
|
5016
|
+
import { dirname as dirname6, join as join17 } from "path";
|
|
4586
5017
|
var TOKENISED = /* @__PURE__ */ new Set(["package.json"]);
|
|
4587
5018
|
async function renderScaffold(source, tokens) {
|
|
4588
5019
|
const files = [];
|
|
4589
5020
|
for (const rel of SCAFFOLD_FILES) {
|
|
4590
5021
|
if (rel === "rness.json") continue;
|
|
4591
|
-
const from =
|
|
4592
|
-
let content = await
|
|
5022
|
+
const from = join17(source, ...rel.split("/"));
|
|
5023
|
+
let content = await readFile8(from, "utf8");
|
|
4593
5024
|
if (TOKENISED.has(rel)) {
|
|
4594
5025
|
content = content.replaceAll("__RNESS_VERSION__", tokens.version).replaceAll("__RNESS_PM__", tokens.packageManager);
|
|
4595
5026
|
}
|
|
@@ -4603,7 +5034,7 @@ async function renderScaffold(source, tokens) {
|
|
|
4603
5034
|
}
|
|
4604
5035
|
async function copyScaffold(dest, tokens) {
|
|
4605
5036
|
for (const file of await renderScaffold(scaffoldDir(), tokens)) {
|
|
4606
|
-
const to =
|
|
5037
|
+
const to = join17(dest, ...file.path.split("/"));
|
|
4607
5038
|
await mkdir3(dirname6(to), { recursive: true });
|
|
4608
5039
|
await writeFile2(to, file.content, "utf8");
|
|
4609
5040
|
if (file.executable) await chmod2(to, 493);
|
|
@@ -4615,16 +5046,16 @@ import { spawn as spawn3 } from "child_process";
|
|
|
4615
5046
|
import { realpath } from "fs/promises";
|
|
4616
5047
|
|
|
4617
5048
|
// src/core/setup-git.ts
|
|
4618
|
-
import { execFile as
|
|
4619
|
-
import { promisify as
|
|
4620
|
-
var
|
|
5049
|
+
import { execFile as execFile4 } from "child_process";
|
|
5050
|
+
import { promisify as promisify4 } from "util";
|
|
5051
|
+
var execFileP4 = promisify4(execFile4);
|
|
4621
5052
|
var KEY = "credential.https://github.com.helper";
|
|
4622
5053
|
function helperValue(node, bin) {
|
|
4623
5054
|
return `!'${node}' '${bin}' git-credential`;
|
|
4624
5055
|
}
|
|
4625
5056
|
var isOurs = (value) => /^!'[^']+' '[^']*rness[^']*' git-credential$/.test(value);
|
|
4626
5057
|
async function config(args) {
|
|
4627
|
-
const { stdout } = await
|
|
5058
|
+
const { stdout } = await execFileP4("git", ["config", "--global", ...args]);
|
|
4628
5059
|
return stdout;
|
|
4629
5060
|
}
|
|
4630
5061
|
async function values() {
|
|
@@ -4802,257 +5233,6 @@ async function askProvider(p) {
|
|
|
4802
5233
|
import { mkdir as mkdir4, readdir as readdir3, rm as rm5, stat as stat3 } from "fs/promises";
|
|
4803
5234
|
import { dirname as dirname8, join as join19, relative as relative2 } from "path";
|
|
4804
5235
|
|
|
4805
|
-
// src/core/pinned.ts
|
|
4806
|
-
import { execFile as execFile4 } from "child_process";
|
|
4807
|
-
import { readFile as readFile8 } from "fs/promises";
|
|
4808
|
-
import { basename as basename4, join as join17 } from "path";
|
|
4809
|
-
import { promisify as promisify4 } from "util";
|
|
4810
|
-
var execFileP4 = promisify4(execFile4);
|
|
4811
|
-
var PACKAGE = "@rness/cli";
|
|
4812
|
-
var EXACT_VERSION = /^\d+\.\d+\.\d+(-[0-9A-Za-z.-]+)?$/;
|
|
4813
|
-
function compareVersions(a, b) {
|
|
4814
|
-
const split = (v) => {
|
|
4815
|
-
const dash = v.indexOf("-");
|
|
4816
|
-
const core = dash === -1 ? v : v.slice(0, dash);
|
|
4817
|
-
return [core.split(".").map(Number), dash === -1 ? null : v.slice(dash + 1)];
|
|
4818
|
-
};
|
|
4819
|
-
const [coreA, preA] = split(a);
|
|
4820
|
-
const [coreB, preB] = split(b);
|
|
4821
|
-
for (let i = 0; i < 3; i += 1) {
|
|
4822
|
-
const diff = (coreA[i] ?? 0) - (coreB[i] ?? 0);
|
|
4823
|
-
if (diff !== 0) return diff;
|
|
4824
|
-
}
|
|
4825
|
-
if (preA === preB) return 0;
|
|
4826
|
-
if (preA === null) return 1;
|
|
4827
|
-
if (preB === null) return -1;
|
|
4828
|
-
return preA.localeCompare(preB, "en", { numeric: true });
|
|
4829
|
-
}
|
|
4830
|
-
async function readPackageJson(rnessDir) {
|
|
4831
|
-
try {
|
|
4832
|
-
const parsed = JSON.parse(
|
|
4833
|
-
await readFile8(join17(rnessDir, "package.json"), "utf8")
|
|
4834
|
-
);
|
|
4835
|
-
return parsed !== null && typeof parsed === "object" ? parsed : null;
|
|
4836
|
-
} catch {
|
|
4837
|
-
return null;
|
|
4838
|
-
}
|
|
4839
|
-
}
|
|
4840
|
-
async function readPin(rnessDir) {
|
|
4841
|
-
const pkg = await readPackageJson(rnessDir);
|
|
4842
|
-
if (pkg === null) return null;
|
|
4843
|
-
for (const field of ["devDependencies", "dependencies"]) {
|
|
4844
|
-
const deps = pkg[field];
|
|
4845
|
-
if (deps === null || typeof deps !== "object") continue;
|
|
4846
|
-
const spec = deps[PACKAGE];
|
|
4847
|
-
if (typeof spec === "string") return { spec, field };
|
|
4848
|
-
}
|
|
4849
|
-
return null;
|
|
4850
|
-
}
|
|
4851
|
-
async function writePin(rnessDir, from, to) {
|
|
4852
|
-
const file = join17(rnessDir, "package.json");
|
|
4853
|
-
const text = await readFile8(file, "utf8");
|
|
4854
|
-
const entry = new RegExp(
|
|
4855
|
-
`("${PACKAGE}"\\s*:\\s*")${from.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}(")`
|
|
4856
|
-
);
|
|
4857
|
-
if (!entry.test(text))
|
|
4858
|
-
throw new Error(`"${PACKAGE}": "${from}" not found in package.json`);
|
|
4859
|
-
await writeFileAtomic(file, text.replace(entry, `$1${to}$2`));
|
|
4860
|
-
}
|
|
4861
|
-
var LOCKFILES = [
|
|
4862
|
-
["pnpm-lock.yaml", "pnpm"],
|
|
4863
|
-
["yarn.lock", "yarn"],
|
|
4864
|
-
["bun.lock", "bun"],
|
|
4865
|
-
["bun.lockb", "bun"],
|
|
4866
|
-
["package-lock.json", "npm"]
|
|
4867
|
-
];
|
|
4868
|
-
async function workspacePackageManager(rnessDir) {
|
|
4869
|
-
const declared2 = (await readPackageJson(rnessDir))?.["packageManager"];
|
|
4870
|
-
if (typeof declared2 === "string") {
|
|
4871
|
-
const name = declared2.split("@")[0] ?? "";
|
|
4872
|
-
if (isPackageManager(name)) return name;
|
|
4873
|
-
}
|
|
4874
|
-
for (const [lockfile, pm] of LOCKFILES)
|
|
4875
|
-
if (await exists(join17(rnessDir, lockfile))) return pm;
|
|
4876
|
-
return "npm";
|
|
4877
|
-
}
|
|
4878
|
-
async function hasLockfile(rnessDir, pm) {
|
|
4879
|
-
for (const [lockfile, owner] of LOCKFILES)
|
|
4880
|
-
if (owner === pm && await exists(join17(rnessDir, lockfile))) return true;
|
|
4881
|
-
return false;
|
|
4882
|
-
}
|
|
4883
|
-
async function pinDrift(rnessDir) {
|
|
4884
|
-
const pin = await readPin(rnessDir);
|
|
4885
|
-
if (pin === null || !EXACT_VERSION.test(pin.spec)) return null;
|
|
4886
|
-
const installed = (await readPinnedCli(rnessDir))?.version ?? null;
|
|
4887
|
-
return installed === pin.spec ? null : { pin: pin.spec, installed };
|
|
4888
|
-
}
|
|
4889
|
-
async function driftWarning(cwd) {
|
|
4890
|
-
let root;
|
|
4891
|
-
let rnessDir;
|
|
4892
|
-
try {
|
|
4893
|
-
const ws = await findWorkspace(cwd);
|
|
4894
|
-
root = ws.root;
|
|
4895
|
-
rnessDir = ws.rnessDir;
|
|
4896
|
-
} catch {
|
|
4897
|
-
return null;
|
|
4898
|
-
}
|
|
4899
|
-
const drift = await pinDrift(rnessDir);
|
|
4900
|
-
if (drift === null) return null;
|
|
4901
|
-
const pm = await workspacePackageManager(rnessDir);
|
|
4902
|
-
return warn(
|
|
4903
|
-
`${basename4(root)}/.rness pins @rness/cli ${drift.pin} but ${drift.installed ?? "nothing"} is installed \u2014 run ${pm} install in .rness`
|
|
4904
|
-
);
|
|
4905
|
-
}
|
|
4906
|
-
var CHILD_DEADLINE_MS = 12e4;
|
|
4907
|
-
function childEnv(env = process.env) {
|
|
4908
|
-
return {
|
|
4909
|
-
...env,
|
|
4910
|
-
GIT_SSH_COMMAND: `${env["GIT_SSH_COMMAND"] ?? "ssh"} -o BatchMode=yes`,
|
|
4911
|
-
GIT_TERMINAL_PROMPT: "0"
|
|
4912
|
-
};
|
|
4913
|
-
}
|
|
4914
|
-
async function ensureInstalled(rnessDir, opts = {}) {
|
|
4915
|
-
const drift = await pinDrift(rnessDir);
|
|
4916
|
-
if (drift === null) return null;
|
|
4917
|
-
const env = opts.env ?? process.env;
|
|
4918
|
-
if (env["RNESS_NO_INSTALL"] === "1")
|
|
4919
|
-
return { installed: false, pin: drift.pin, reason: "RNESS_NO_INSTALL=1" };
|
|
4920
|
-
const pm = await workspacePackageManager(rnessDir);
|
|
4921
|
-
const frozen = await hasLockfile(rnessDir, pm);
|
|
4922
|
-
const install = opts.install ?? installDependencies;
|
|
4923
|
-
opts.announce?.(drift.pin);
|
|
4924
|
-
try {
|
|
4925
|
-
await install(pm, rnessDir, { frozen });
|
|
4926
|
-
return { installed: true, pin: drift.pin, reason: null };
|
|
4927
|
-
} catch (e) {
|
|
4928
|
-
return {
|
|
4929
|
-
installed: false,
|
|
4930
|
-
pin: drift.pin,
|
|
4931
|
-
reason: e instanceof Error ? e.message : String(e)
|
|
4932
|
-
};
|
|
4933
|
-
}
|
|
4934
|
-
}
|
|
4935
|
-
async function runPinnedSync(root) {
|
|
4936
|
-
const installed = await readPinnedCli(join17(root, ".rness"));
|
|
4937
|
-
if (installed === null) return null;
|
|
4938
|
-
const pinned = join17(installed.dir, ...installed.bin.split("/"));
|
|
4939
|
-
if (!await exists(pinned))
|
|
4940
|
-
return {
|
|
4941
|
-
code: 1,
|
|
4942
|
-
stdout: "",
|
|
4943
|
-
stderr: `@rness/cli in .rness is not installed correctly (missing ${installed.bin}); reinstall in .rness/
|
|
4944
|
-
`
|
|
4945
|
-
};
|
|
4946
|
-
try {
|
|
4947
|
-
const { stdout, stderr } = await execFileP4(
|
|
4948
|
-
process.execPath,
|
|
4949
|
-
[pinned, "sync", "--yes"],
|
|
4950
|
-
{
|
|
4951
|
-
cwd: root,
|
|
4952
|
-
maxBuffer: 16 * 1024 * 1024,
|
|
4953
|
-
env: childEnv(),
|
|
4954
|
-
timeout: CHILD_DEADLINE_MS,
|
|
4955
|
-
killSignal: "SIGKILL"
|
|
4956
|
-
}
|
|
4957
|
-
);
|
|
4958
|
-
return { code: 0, stdout, stderr };
|
|
4959
|
-
} catch (e) {
|
|
4960
|
-
const err = e;
|
|
4961
|
-
const deadline = err.killed === true ? `rness sync in .rness did not finish within ${CHILD_DEADLINE_MS / 1e3}s and was stopped
|
|
4962
|
-
` : "";
|
|
4963
|
-
return {
|
|
4964
|
-
code: typeof err.code === "number" ? err.code : 1,
|
|
4965
|
-
stdout: err.stdout ?? "",
|
|
4966
|
-
stderr: `${err.stderr ?? ""}${deadline}`
|
|
4967
|
-
};
|
|
4968
|
-
}
|
|
4969
|
-
}
|
|
4970
|
-
var SYNC_VERBS = ["updated", "unchanged", "stale"];
|
|
4971
|
-
function counted(noun, counts) {
|
|
4972
|
-
const total = [...counts.values()].reduce((a, b) => a + b, 0);
|
|
4973
|
-
const detail = SYNC_VERBS.filter((verb) => counts.has(verb)).map((verb) => `${counts.get(verb) ?? 0} ${verb}`).join(", ");
|
|
4974
|
-
return `${total} ${noun}${total === 1 ? "" : "s"}${detail === "" ? "" : `: ${detail}`}`;
|
|
4975
|
-
}
|
|
4976
|
-
function summariseSync(stdout) {
|
|
4977
|
-
const blocks = /* @__PURE__ */ new Map();
|
|
4978
|
-
const agentFiles = /* @__PURE__ */ new Map();
|
|
4979
|
-
const others = [];
|
|
4980
|
-
for (const line3 of stdout.split("\n")) {
|
|
4981
|
-
if (line3.trim() === "") continue;
|
|
4982
|
-
const m = /^(updated|unchanged|stale)\s+(\S+)/.exec(line3);
|
|
4983
|
-
if (m === null) {
|
|
4984
|
-
others.push(line3);
|
|
4985
|
-
continue;
|
|
4986
|
-
}
|
|
4987
|
-
const [, verb = "", path = ""] = m;
|
|
4988
|
-
const counts = /(^|\/)(AGENTS|CLAUDE)\.md$/.test(path) ? blocks : agentFiles;
|
|
4989
|
-
counts.set(verb, (counts.get(verb) ?? 0) + 1);
|
|
4990
|
-
}
|
|
4991
|
-
return {
|
|
4992
|
-
summary: [
|
|
4993
|
-
counted("block", blocks),
|
|
4994
|
-
...agentFiles.size > 0 ? [counted("agent file", agentFiles)] : []
|
|
4995
|
-
].join("; "),
|
|
4996
|
-
others
|
|
4997
|
-
};
|
|
4998
|
-
}
|
|
4999
|
-
function syncOutcome(result, opts = {}) {
|
|
5000
|
-
const { others } = summariseSync(result.stdout);
|
|
5001
|
-
const wrote = /^(updated|unchanged|stale)\s/m.test(result.stdout);
|
|
5002
|
-
const stderr = result.stderr.split("\n").map((l) => l.trimEnd()).filter((l) => l.trim() !== "");
|
|
5003
|
-
const hints = wrote ? [...others, ...stderr] : others;
|
|
5004
|
-
if (opts.sshWorks === true && /Permission denied \(publickey\)/.test(result.stderr))
|
|
5005
|
-
hints.push(...agentHintLines());
|
|
5006
|
-
return {
|
|
5007
|
-
code: wrote ? 0 : result.code,
|
|
5008
|
-
hints,
|
|
5009
|
-
errors: wrote ? [] : stderr
|
|
5010
|
-
};
|
|
5011
|
-
}
|
|
5012
|
-
async function syncPinned(root, shown, fallback) {
|
|
5013
|
-
const rnessDir = join17(root, ".rness");
|
|
5014
|
-
const installed = await readPinnedCli(rnessDir);
|
|
5015
|
-
if (installed === null) {
|
|
5016
|
-
if (fallback !== void 0) return fallback();
|
|
5017
|
-
process.stderr.write(
|
|
5018
|
-
`@rness/cli is not installed in ${shown}/.rness; install in .rness/, then ${rnessCommand()} sync
|
|
5019
|
-
`
|
|
5020
|
-
);
|
|
5021
|
-
return 1;
|
|
5022
|
-
}
|
|
5023
|
-
const pinned = join17(installed.dir, ...installed.bin.split("/"));
|
|
5024
|
-
if (!await exists(pinned)) {
|
|
5025
|
-
process.stderr.write(
|
|
5026
|
-
`@rness/cli in ${shown}/.rness is not installed correctly (missing ${installed.bin}); reinstall in .rness/
|
|
5027
|
-
`
|
|
5028
|
-
);
|
|
5029
|
-
return 1;
|
|
5030
|
-
}
|
|
5031
|
-
try {
|
|
5032
|
-
const { stdout, stderr } = await execFileP4(
|
|
5033
|
-
process.execPath,
|
|
5034
|
-
[pinned, "sync", "--yes"],
|
|
5035
|
-
{
|
|
5036
|
-
cwd: root,
|
|
5037
|
-
maxBuffer: 16 * 1024 * 1024,
|
|
5038
|
-
env: childEnv(),
|
|
5039
|
-
timeout: CHILD_DEADLINE_MS,
|
|
5040
|
-
killSignal: "SIGKILL"
|
|
5041
|
-
}
|
|
5042
|
-
);
|
|
5043
|
-
process.stdout.write(stdout);
|
|
5044
|
-
if (stderr !== "") process.stderr.write(stderr);
|
|
5045
|
-
return 0;
|
|
5046
|
-
} catch (e) {
|
|
5047
|
-
const err = e;
|
|
5048
|
-
if (err.stdout !== void 0 && err.stdout !== "")
|
|
5049
|
-
process.stdout.write(err.stdout);
|
|
5050
|
-
if (err.stderr !== void 0 && err.stderr !== "")
|
|
5051
|
-
process.stderr.write(err.stderr);
|
|
5052
|
-
return typeof err.code === "number" ? err.code : 1;
|
|
5053
|
-
}
|
|
5054
|
-
}
|
|
5055
|
-
|
|
5056
5236
|
// src/core/scaffold-git.ts
|
|
5057
5237
|
import { execFile as execFile5 } from "child_process";
|
|
5058
5238
|
import { mkdtemp, realpath as realpath2, rm as rm4, writeFile as writeFile3 } from "fs/promises";
|
|
@@ -8353,6 +8533,7 @@ export {
|
|
|
8353
8533
|
defaultTransport,
|
|
8354
8534
|
findWorkspace,
|
|
8355
8535
|
reportError,
|
|
8536
|
+
findDelegate,
|
|
8356
8537
|
BEGIN,
|
|
8357
8538
|
END,
|
|
8358
8539
|
BLOCK_SIZE_WARNING,
|
|
@@ -8367,7 +8548,6 @@ export {
|
|
|
8367
8548
|
addCommand,
|
|
8368
8549
|
renderMarkdown,
|
|
8369
8550
|
contextCommand,
|
|
8370
|
-
findDelegate,
|
|
8371
8551
|
SCAFFOLD_FILES,
|
|
8372
8552
|
scaffoldDir,
|
|
8373
8553
|
copyScaffold,
|
|
@@ -8381,4 +8561,4 @@ export {
|
|
|
8381
8561
|
OWN_COMMANDS,
|
|
8382
8562
|
catchUp
|
|
8383
8563
|
};
|
|
8384
|
-
//# sourceMappingURL=chunk-
|
|
8564
|
+
//# sourceMappingURL=chunk-AXTFDXN2.js.map
|