@oevery/rsp 3.1.0-beta.0 → 3.1.0-beta.2
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 +77 -74
- package/README.zh-CN.md +71 -53
- package/dist/chunk-4K53353L.mjs +322 -0
- package/dist/{chunk-QLXIDVKK.mjs → chunk-EALHA3ZS.mjs} +99 -1038
- package/dist/chunk-JOMFFQRG.mjs +99 -0
- package/dist/chunk-OTJFL6XH.mjs +1022 -0
- package/dist/cli.mjs +95 -264
- package/dist/{entry-LAPR3TNI.mjs → entry-N7WLWGTI.mjs} +8 -92
- package/dist/entry-UWUX3HM7.mjs +174 -0
- package/package.json +13 -11
- package/rules/rsp-rules.md +10 -12
- package/skills/rsp/SKILL.md +45 -172
- package/skills/rsp/references/conflict-handling.md +11 -0
- package/skills/rsp/references/durable-review.md +17 -0
- package/skills/rsp/references/groups-dependencies.md +11 -0
- package/skills/rsp/references/managed-routing.md +45 -0
- package/skills/rsp/references/setup-repair.md +11 -0
- package/skills/rsp-address-review/SKILL.md +5 -5
- package/skills/rsp-codebase-audit/SKILL.md +69 -0
- package/skills/rsp-codebase-audit/references/structural-lenses.md +35 -0
- package/skills/rsp-commit/SKILL.md +42 -0
- package/skills/rsp-design/SKILL.md +14 -9
- package/skills/rsp-manage/SKILL.md +24 -25
- package/skills/rsp-release-docs/SKILL.md +36 -81
- package/skills/rsp-release-docs/references/evidence-and-surfaces.md +21 -0
- package/skills/rsp-release-docs/references/output-contracts.md +0 -18
- package/skills/rsp-release-docs/references/publication-lifecycle.md +24 -0
- package/skills/rsp-shape/SKILL.md +19 -17
- package/skills/rsp-shape/references/complex-shaping.md +2 -2
package/dist/cli.mjs
CHANGED
|
@@ -1,22 +1,47 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
|
-
|
|
3
|
+
inspectPackagedSkillInventory,
|
|
4
|
+
installPackagedSkills,
|
|
5
|
+
printPackagedSkillInventory,
|
|
6
|
+
printSkillInstallResult
|
|
7
|
+
} from "./chunk-4K53353L.mjs";
|
|
8
|
+
import {
|
|
4
9
|
ArchiveHistoryError,
|
|
10
|
+
GROUP_BRIEF_FILENAME,
|
|
11
|
+
HISTORY_DEFAULT_LIMIT,
|
|
12
|
+
HISTORY_MAX_LIMIT,
|
|
13
|
+
WorkRefError,
|
|
14
|
+
generateGroupBriefContent,
|
|
15
|
+
hasArchivedGroupBrief,
|
|
16
|
+
historyInspectionComplete,
|
|
17
|
+
inspectArchiveHistory,
|
|
18
|
+
inspectArchiveTree,
|
|
19
|
+
inspectChangeDependencies,
|
|
20
|
+
inspectChangeGroups,
|
|
21
|
+
inspectFocusTree,
|
|
22
|
+
inspectProjectStatus,
|
|
23
|
+
inspectWorkTree,
|
|
24
|
+
projectDependencyForest,
|
|
25
|
+
queryArchiveHistory,
|
|
26
|
+
readArchiveHistoryDetail,
|
|
27
|
+
resolveArchiveDirectory,
|
|
28
|
+
resolveExecutableChange,
|
|
29
|
+
resolveFocusMarkerPath,
|
|
30
|
+
resolveWorkRef,
|
|
31
|
+
selectArchiveHistoryRecord
|
|
32
|
+
} from "./chunk-EALHA3ZS.mjs";
|
|
33
|
+
import {
|
|
34
|
+
ARCHIVES_DIR,
|
|
5
35
|
CHANGES_DIR,
|
|
6
36
|
CONFIG_PATH,
|
|
7
37
|
DEFAULT_DECISION_RECORDS_PATH,
|
|
8
38
|
FOCUS_DIR,
|
|
9
|
-
GROUP_BRIEF_FILENAME,
|
|
10
|
-
HISTORY_DEFAULT_LIMIT,
|
|
11
|
-
HISTORY_MAX_LIMIT,
|
|
12
39
|
LOCK_PATH,
|
|
13
|
-
ManagedPathError,
|
|
14
40
|
OBSOLETE_RSP_RULES_PATH,
|
|
15
41
|
PKG_ROOT,
|
|
16
42
|
RSP_DIR,
|
|
17
43
|
RSP_RULES_PATH,
|
|
18
44
|
VALID_KINDS,
|
|
19
|
-
WorkRefError,
|
|
20
45
|
buildDurableReviewGuidance,
|
|
21
46
|
cleanupEmptyParentDirs,
|
|
22
47
|
clearConfigCache,
|
|
@@ -31,53 +56,35 @@ import {
|
|
|
31
56
|
extractSection,
|
|
32
57
|
generateChangeContent,
|
|
33
58
|
generateDesignContent,
|
|
34
|
-
generateGroupBriefContent,
|
|
35
59
|
generateSpecContent,
|
|
36
60
|
getDurableReviewCandidateTargets,
|
|
37
61
|
getVersion,
|
|
38
62
|
guardRspInitialized,
|
|
39
|
-
hasArchivedGroupBrief,
|
|
40
63
|
hasMeaningfulBlockers,
|
|
41
64
|
hasRspAgentsBlock,
|
|
42
|
-
historyInspectionComplete,
|
|
43
|
-
inspectArchiveHistory,
|
|
44
|
-
inspectArchiveTree,
|
|
45
|
-
inspectChangeDependencies,
|
|
46
|
-
inspectChangeGroups,
|
|
47
|
-
inspectFocusTree,
|
|
48
65
|
inspectManagedDirectory,
|
|
49
66
|
inspectManagedFile,
|
|
50
67
|
inspectManagedFileTree,
|
|
51
|
-
inspectProjectStatus,
|
|
52
68
|
inspectRspConfig,
|
|
53
69
|
inspectUnsupportedRules,
|
|
54
|
-
inspectWorkTree,
|
|
55
70
|
isValidSpecName,
|
|
56
71
|
loadRspConfig,
|
|
57
72
|
normalizeLogicalPath,
|
|
58
73
|
parseFrontmatter,
|
|
59
74
|
parseScenarios,
|
|
60
75
|
pc,
|
|
61
|
-
projectDependencyForest,
|
|
62
|
-
queryArchiveHistory,
|
|
63
|
-
readArchiveHistoryDetail,
|
|
64
76
|
recordRuntimeDiagnostic,
|
|
65
77
|
requireManagedDirectory,
|
|
66
|
-
resolveArchiveDirectory,
|
|
67
78
|
resolveDecisionRecordsPath,
|
|
68
|
-
resolveExecutableChange,
|
|
69
|
-
resolveFocusMarkerPath,
|
|
70
79
|
resolveKinds,
|
|
71
80
|
resolveManagedDirectoryChain,
|
|
72
81
|
resolveRequiredSections,
|
|
73
|
-
resolveWorkRef,
|
|
74
|
-
selectArchiveHistoryRecord,
|
|
75
82
|
toErrorMessage,
|
|
76
83
|
upsertRspAgentsBlock,
|
|
77
84
|
validateDecisionRecordsFilesystemPath,
|
|
78
85
|
walkMarkdownFiles,
|
|
79
86
|
writeManagedFile
|
|
80
|
-
} from "./chunk-
|
|
87
|
+
} from "./chunk-OTJFL6XH.mjs";
|
|
81
88
|
|
|
82
89
|
// src/cli.ts
|
|
83
90
|
import { resolve } from "path";
|
|
@@ -1923,7 +1930,14 @@ function generateConfigTemplate() {
|
|
|
1923
1930
|
# kinds: ${VALID_KINDS.join(", ")}
|
|
1924
1931
|
#
|
|
1925
1932
|
# kinds:
|
|
1926
|
-
${fmtList(VALID_KINDS,
|
|
1933
|
+
${fmtList(VALID_KINDS, 0)}
|
|
1934
|
+
|
|
1935
|
+
# New projects default to automatic Manage routing with lifecycle-only closeout.
|
|
1936
|
+
# Use activation: explicit to require a named managed request.
|
|
1937
|
+
# closeout accepts manual, lifecycle, or local; local may authorize an eligible local commit but never push or publication.
|
|
1938
|
+
manage:
|
|
1939
|
+
activation: auto
|
|
1940
|
+
closeout: lifecycle
|
|
1927
1941
|
|
|
1928
1942
|
# Decision Records default to .rsp/specs/decisions.
|
|
1929
1943
|
# Set exactly one project-relative authoritative directory when the Host Project already owns Decision Records elsewhere.
|
|
@@ -2348,239 +2362,6 @@ function formatArchiveReady2(value) {
|
|
|
2348
2362
|
}
|
|
2349
2363
|
}
|
|
2350
2364
|
|
|
2351
|
-
// src/commands/skills.ts
|
|
2352
|
-
import { randomUUID } from "crypto";
|
|
2353
|
-
import { lstatSync } from "fs";
|
|
2354
|
-
import { chmod, copyFile, mkdir as mkdir9, readdir as readdir2, readFile as readFile11, rename as rename3, rm as rm2 } from "fs/promises";
|
|
2355
|
-
import { dirname as dirname4, join as join9, relative as relative4 } from "path";
|
|
2356
|
-
function unsupportedEntry(path, label) {
|
|
2357
|
-
return new ManagedPathError(path, `unsupported entry in the ${label} tree: ${path}`);
|
|
2358
|
-
}
|
|
2359
|
-
function inspectDirectoryIdentity(path, label) {
|
|
2360
|
-
const inspection = inspectManagedDirectory(path, label);
|
|
2361
|
-
if (inspection.issue)
|
|
2362
|
-
throw inspection.issue;
|
|
2363
|
-
const stats = lstatSync(path);
|
|
2364
|
-
return { path, dev: stats.dev, ino: stats.ino };
|
|
2365
|
-
}
|
|
2366
|
-
function assertDirectoryIdentities(identities, label) {
|
|
2367
|
-
for (const identity of identities) {
|
|
2368
|
-
const current = inspectDirectoryIdentity(identity.path, label);
|
|
2369
|
-
if (current.dev !== identity.dev || current.ino !== identity.ino)
|
|
2370
|
-
throw new ManagedPathError(identity.path, `${label} changed after validation: ${identity.path}`);
|
|
2371
|
-
}
|
|
2372
|
-
}
|
|
2373
|
-
async function prepareTargetRoot(projectRoot, targetRoot) {
|
|
2374
|
-
const projectIdentity = inspectDirectoryIdentity(projectRoot, "project Skills root");
|
|
2375
|
-
const agentsRoot = join9(projectRoot, ".agents");
|
|
2376
|
-
const identities = [projectIdentity];
|
|
2377
|
-
assertDirectoryIdentities(identities, "project Skills root");
|
|
2378
|
-
await mkdir9(agentsRoot).catch((error) => {
|
|
2379
|
-
if (error.code !== "EEXIST")
|
|
2380
|
-
throw error;
|
|
2381
|
-
});
|
|
2382
|
-
assertDirectoryIdentities(identities, "project Skills root");
|
|
2383
|
-
identities.push(inspectDirectoryIdentity(agentsRoot, "project Skills root"));
|
|
2384
|
-
assertDirectoryIdentities(identities, "project Skills root");
|
|
2385
|
-
await mkdir9(targetRoot).catch((error) => {
|
|
2386
|
-
if (error.code !== "EEXIST")
|
|
2387
|
-
throw error;
|
|
2388
|
-
});
|
|
2389
|
-
assertDirectoryIdentities(identities, "project Skills root");
|
|
2390
|
-
identities.push(inspectDirectoryIdentity(targetRoot, "project Skills root"));
|
|
2391
|
-
return identities;
|
|
2392
|
-
}
|
|
2393
|
-
async function inspectPackagedSkills(packageRoot) {
|
|
2394
|
-
const skillsRoot = join9(packageRoot, "skills");
|
|
2395
|
-
const rootInspection = inspectManagedDirectory(skillsRoot, "packaged Skills root");
|
|
2396
|
-
if (rootInspection.issue)
|
|
2397
|
-
throw rootInspection.issue;
|
|
2398
|
-
const entries = await readdir2(skillsRoot, { withFileTypes: true });
|
|
2399
|
-
const skills = [];
|
|
2400
|
-
for (const entry of entries.sort((a, b) => a.name.localeCompare(b.name))) {
|
|
2401
|
-
if (entry.name.startsWith("."))
|
|
2402
|
-
continue;
|
|
2403
|
-
const root = join9(skillsRoot, entry.name);
|
|
2404
|
-
if (!entry.isDirectory())
|
|
2405
|
-
throw unsupportedEntry(root, "packaged Skills");
|
|
2406
|
-
const inspection = await inspectManagedFileTree(root, `packaged Skill ${entry.name}`);
|
|
2407
|
-
if (inspection.issues.length > 0)
|
|
2408
|
-
throw inspection.issues[0];
|
|
2409
|
-
skills.push({
|
|
2410
|
-
name: entry.name,
|
|
2411
|
-
root,
|
|
2412
|
-
files: inspection.files.map((path) => relative4(root, path))
|
|
2413
|
-
});
|
|
2414
|
-
}
|
|
2415
|
-
return skills;
|
|
2416
|
-
}
|
|
2417
|
-
function inspectTarget(path, name) {
|
|
2418
|
-
try {
|
|
2419
|
-
const stats = lstatSync(path);
|
|
2420
|
-
if (stats.isDirectory())
|
|
2421
|
-
return "directory";
|
|
2422
|
-
throw unsupportedEntry(path, `installed Skill ${name}`);
|
|
2423
|
-
} catch (error) {
|
|
2424
|
-
if (error.code === "ENOENT")
|
|
2425
|
-
return "missing";
|
|
2426
|
-
throw error;
|
|
2427
|
-
}
|
|
2428
|
-
}
|
|
2429
|
-
async function treesEqual(source, targetRoot) {
|
|
2430
|
-
const target = await inspectManagedFileTree(targetRoot, `installed Skill ${source.name}`);
|
|
2431
|
-
if (target.issues.length > 0)
|
|
2432
|
-
throw target.issues[0];
|
|
2433
|
-
const targetFiles = target.files.map((path) => relative4(targetRoot, path));
|
|
2434
|
-
if (source.files.length !== targetFiles.length || source.files.some((path, index) => path !== targetFiles[index]))
|
|
2435
|
-
return false;
|
|
2436
|
-
for (const path of source.files) {
|
|
2437
|
-
const sourcePath = join9(source.root, path);
|
|
2438
|
-
const targetPath = join9(targetRoot, path);
|
|
2439
|
-
const [sourceStats, targetStats] = [lstatSync(sourcePath), lstatSync(targetPath)];
|
|
2440
|
-
if (!sourceStats.isFile() || !targetStats.isFile())
|
|
2441
|
-
throw unsupportedEntry(!sourceStats.isFile() ? sourcePath : targetPath, `Skill ${source.name}`);
|
|
2442
|
-
if ((sourceStats.mode & 511) !== (targetStats.mode & 511))
|
|
2443
|
-
return false;
|
|
2444
|
-
const [sourceContent, targetContent] = await Promise.all([readFile11(sourcePath), readFile11(targetPath)]);
|
|
2445
|
-
if (!sourceContent.equals(targetContent))
|
|
2446
|
-
return false;
|
|
2447
|
-
}
|
|
2448
|
-
return true;
|
|
2449
|
-
}
|
|
2450
|
-
async function copySkillTree(source, targetRoot) {
|
|
2451
|
-
await mkdir9(targetRoot, { recursive: true });
|
|
2452
|
-
for (const path of source.files) {
|
|
2453
|
-
const sourcePath = join9(source.root, path);
|
|
2454
|
-
const targetPath = join9(targetRoot, path);
|
|
2455
|
-
const stats = lstatSync(sourcePath);
|
|
2456
|
-
if (!stats.isFile())
|
|
2457
|
-
throw unsupportedEntry(sourcePath, `packaged Skill ${source.name}`);
|
|
2458
|
-
await mkdir9(dirname4(targetPath), { recursive: true });
|
|
2459
|
-
await copyFile(sourcePath, targetPath);
|
|
2460
|
-
await chmod(targetPath, stats.mode & 511);
|
|
2461
|
-
}
|
|
2462
|
-
}
|
|
2463
|
-
async function installPackagedSkills(args = {}, options = {}) {
|
|
2464
|
-
const packageRoot = options.packageRoot ?? PKG_ROOT;
|
|
2465
|
-
const projectRoot = options.projectRoot ?? process.cwd();
|
|
2466
|
-
const renamePath = options.renamePath ?? rename3;
|
|
2467
|
-
const skills = await inspectPackagedSkills(packageRoot);
|
|
2468
|
-
const targetRoot = resolveManagedDirectoryChain(projectRoot, [".agents", "skills"], "project Skills root");
|
|
2469
|
-
const result = { installed: [], unchanged: [], replaced: [] };
|
|
2470
|
-
const conflicts = [];
|
|
2471
|
-
const targetTreeIdentities = /* @__PURE__ */ new Map();
|
|
2472
|
-
for (const skill of skills) {
|
|
2473
|
-
const target = join9(targetRoot, skill.name);
|
|
2474
|
-
if (inspectTarget(target, skill.name) === "missing") {
|
|
2475
|
-
result.installed.push(skill.name);
|
|
2476
|
-
continue;
|
|
2477
|
-
}
|
|
2478
|
-
const targetIdentity = inspectDirectoryIdentity(target, `installed Skill ${skill.name}`);
|
|
2479
|
-
if (await treesEqual(skill, target)) {
|
|
2480
|
-
result.unchanged.push(skill.name);
|
|
2481
|
-
continue;
|
|
2482
|
-
}
|
|
2483
|
-
assertDirectoryIdentities([targetIdentity], `installed Skill ${skill.name}`);
|
|
2484
|
-
if (args.force) {
|
|
2485
|
-
result.replaced.push(skill.name);
|
|
2486
|
-
targetTreeIdentities.set(skill.name, targetIdentity);
|
|
2487
|
-
} else {
|
|
2488
|
-
conflicts.push(skill.name);
|
|
2489
|
-
}
|
|
2490
|
-
}
|
|
2491
|
-
if (conflicts.length > 0)
|
|
2492
|
-
throw new Error(`conflicting packaged Skills: ${conflicts.join(", ")}; rerun with --force to replace only these package-owned directories`);
|
|
2493
|
-
if (args.dryRun)
|
|
2494
|
-
return result;
|
|
2495
|
-
await options.onMutationStep?.({ phase: "before-target-root-mutation", targetRoot });
|
|
2496
|
-
const targetIdentities = await prepareTargetRoot(projectRoot, targetRoot);
|
|
2497
|
-
const stagingRoot = join9(targetRoot, `.rsp-skills-install-${randomUUID()}`);
|
|
2498
|
-
const nextRoot = join9(stagingRoot, "next");
|
|
2499
|
-
const previousRoot = join9(stagingRoot, "previous");
|
|
2500
|
-
const failedRoot = join9(stagingRoot, "failed");
|
|
2501
|
-
const movedPrevious = [];
|
|
2502
|
-
const activated = [];
|
|
2503
|
-
let removeStaging = true;
|
|
2504
|
-
try {
|
|
2505
|
-
assertDirectoryIdentities(targetIdentities, "project Skills root");
|
|
2506
|
-
await mkdir9(nextRoot, { recursive: true });
|
|
2507
|
-
await mkdir9(previousRoot);
|
|
2508
|
-
await mkdir9(failedRoot);
|
|
2509
|
-
for (const skill of skills) {
|
|
2510
|
-
if (result.unchanged.includes(skill.name))
|
|
2511
|
-
continue;
|
|
2512
|
-
await copySkillTree(skill, join9(nextRoot, skill.name));
|
|
2513
|
-
}
|
|
2514
|
-
for (const name of result.installed) {
|
|
2515
|
-
const target = join9(targetRoot, name);
|
|
2516
|
-
if (inspectTarget(target, name) !== "missing")
|
|
2517
|
-
throw new ManagedPathError(target, `installed Skill changed after preflight: ${target}`);
|
|
2518
|
-
}
|
|
2519
|
-
for (const name of result.replaced) {
|
|
2520
|
-
assertDirectoryIdentities([targetTreeIdentities.get(name)], `installed Skill ${name}`);
|
|
2521
|
-
}
|
|
2522
|
-
for (const name of result.replaced) {
|
|
2523
|
-
assertDirectoryIdentities(targetIdentities, "project Skills root");
|
|
2524
|
-
assertDirectoryIdentities([targetTreeIdentities.get(name)], `installed Skill ${name}`);
|
|
2525
|
-
await renamePath(join9(targetRoot, name), join9(previousRoot, name));
|
|
2526
|
-
movedPrevious.push(name);
|
|
2527
|
-
}
|
|
2528
|
-
for (const name of [...result.installed, ...result.replaced].sort()) {
|
|
2529
|
-
const target = join9(targetRoot, name);
|
|
2530
|
-
assertDirectoryIdentities(targetIdentities, "project Skills root");
|
|
2531
|
-
await options.onMutationStep?.({ phase: "before-activate", name, target });
|
|
2532
|
-
assertDirectoryIdentities(targetIdentities, "project Skills root");
|
|
2533
|
-
if (inspectTarget(target, name) !== "missing")
|
|
2534
|
-
throw new ManagedPathError(target, `installed Skill changed after preflight: ${target}`);
|
|
2535
|
-
await renamePath(join9(nextRoot, name), target);
|
|
2536
|
-
activated.push(name);
|
|
2537
|
-
}
|
|
2538
|
-
} catch (error) {
|
|
2539
|
-
const rollbackErrors = [];
|
|
2540
|
-
for (const name of activated.reverse()) {
|
|
2541
|
-
const target = join9(targetRoot, name);
|
|
2542
|
-
try {
|
|
2543
|
-
assertDirectoryIdentities(targetIdentities, "project Skills root");
|
|
2544
|
-
if (inspectTarget(target, name) === "directory")
|
|
2545
|
-
await renamePath(target, join9(failedRoot, name));
|
|
2546
|
-
} catch (rollbackError) {
|
|
2547
|
-
rollbackErrors.push(rollbackError instanceof Error ? rollbackError.message : String(rollbackError));
|
|
2548
|
-
}
|
|
2549
|
-
}
|
|
2550
|
-
for (const name of movedPrevious.reverse()) {
|
|
2551
|
-
const target = join9(targetRoot, name);
|
|
2552
|
-
const previous = join9(previousRoot, name);
|
|
2553
|
-
try {
|
|
2554
|
-
assertDirectoryIdentities(targetIdentities, "project Skills root");
|
|
2555
|
-
await options.onMutationStep?.({ phase: "before-rollback-restore", name, target, previous });
|
|
2556
|
-
assertDirectoryIdentities(targetIdentities, "project Skills root");
|
|
2557
|
-
if (inspectTarget(target, name) !== "missing")
|
|
2558
|
-
throw new ManagedPathError(target, `cannot restore installed Skill because the target is occupied: ${target}`);
|
|
2559
|
-
await renamePath(previous, target);
|
|
2560
|
-
} catch (rollbackError) {
|
|
2561
|
-
rollbackErrors.push(rollbackError instanceof Error ? rollbackError.message : String(rollbackError));
|
|
2562
|
-
}
|
|
2563
|
-
}
|
|
2564
|
-
if (rollbackErrors.length > 0) {
|
|
2565
|
-
removeStaging = false;
|
|
2566
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
2567
|
-
throw new Error(`${message}; rollback incomplete; recover original Skills from ${previousRoot}; ${rollbackErrors.join("; ")}`);
|
|
2568
|
-
}
|
|
2569
|
-
throw error;
|
|
2570
|
-
} finally {
|
|
2571
|
-
if (removeStaging)
|
|
2572
|
-
await rm2(stagingRoot, { recursive: true, force: true });
|
|
2573
|
-
}
|
|
2574
|
-
return result;
|
|
2575
|
-
}
|
|
2576
|
-
function printSkillInstallResult(result, dryRun = false) {
|
|
2577
|
-
const prefix = dryRun ? "would be " : "";
|
|
2578
|
-
for (const status of ["installed", "unchanged", "replaced"]) {
|
|
2579
|
-
if (result[status].length > 0)
|
|
2580
|
-
console.log(` ${prefix}${status}: ${result[status].join(", ")}`);
|
|
2581
|
-
}
|
|
2582
|
-
}
|
|
2583
|
-
|
|
2584
2365
|
// src/status/derive.ts
|
|
2585
2366
|
function deriveStatusView(snapshot, options = {}) {
|
|
2586
2367
|
const query = {
|
|
@@ -2601,6 +2382,7 @@ function deriveStatusView(snapshot, options = {}) {
|
|
|
2601
2382
|
const ok = snapshot.diagnostics.every((diagnostic) => diagnostic.severity !== "error");
|
|
2602
2383
|
const nextActions = ok ? buildStatusNextActions(snapshot.focused.length, snapshot.records.map((record) => record.output), snapshot.groups, filtered) : ["Run: rsp doctor"];
|
|
2603
2384
|
return {
|
|
2385
|
+
manage: snapshot.manage,
|
|
2604
2386
|
query,
|
|
2605
2387
|
focused: snapshot.focused,
|
|
2606
2388
|
records,
|
|
@@ -2696,6 +2478,8 @@ function printStatusPlain(view) {
|
|
|
2696
2478
|
console.log();
|
|
2697
2479
|
console.log(` ${pc.bold("RSP status")}`);
|
|
2698
2480
|
console.log();
|
|
2481
|
+
console.log(` ${pc.bold("Manage:")} activation ${view.manage.activation} \xB7 closeout ${view.manage.closeout}`);
|
|
2482
|
+
console.log();
|
|
2699
2483
|
for (const diagnostic of view.diagnostics) {
|
|
2700
2484
|
const label = diagnostic.change ?? diagnostic.path;
|
|
2701
2485
|
console.log(` ${pc.red("\u2717")} ${label ? `${label} \u2014 ` : ""}${diagnostic.message}`);
|
|
@@ -2813,6 +2597,7 @@ function toStatusJson(view) {
|
|
|
2813
2597
|
return {
|
|
2814
2598
|
command: "status",
|
|
2815
2599
|
ok: view.ok,
|
|
2600
|
+
manage: view.manage,
|
|
2816
2601
|
filters: view.query,
|
|
2817
2602
|
focused: view.focused,
|
|
2818
2603
|
records: view.records.map((record) => record.output),
|
|
@@ -2829,6 +2614,7 @@ function toStatusJsonError(error, options) {
|
|
|
2829
2614
|
return {
|
|
2830
2615
|
command: "status",
|
|
2831
2616
|
ok: false,
|
|
2617
|
+
manage: { activation: "explicit", closeout: "manual" },
|
|
2832
2618
|
filters: {
|
|
2833
2619
|
focused: options.focused,
|
|
2834
2620
|
blocked: options.blocked,
|
|
@@ -2878,6 +2664,9 @@ function isInteractiveTerminal(environment) {
|
|
|
2878
2664
|
function shouldAutoLaunchUi(args, environment) {
|
|
2879
2665
|
return args.length === 0 && isInteractiveTerminal(environment) && (environment.ci === void 0 || environment.ci === "false");
|
|
2880
2666
|
}
|
|
2667
|
+
function shouldLaunchSkillsUi(args, environment) {
|
|
2668
|
+
return args.length === 1 && args[0] === "skills" && isInteractiveTerminal(environment) && (environment.ci === void 0 || environment.ci === "false");
|
|
2669
|
+
}
|
|
2881
2670
|
function validateUiArgs(args) {
|
|
2882
2671
|
let lang = "auto";
|
|
2883
2672
|
for (let index = 0; index < args.length; index += 1) {
|
|
@@ -3194,9 +2983,14 @@ var skillsInstallCommand = defineCommand({
|
|
|
3194
2983
|
description: "Install this package's bundled Skills into .agents/skills"
|
|
3195
2984
|
},
|
|
3196
2985
|
args: {
|
|
2986
|
+
"name": {
|
|
2987
|
+
type: "positional",
|
|
2988
|
+
description: "Exact packaged Skill name (default: lifecycle suite)",
|
|
2989
|
+
required: false
|
|
2990
|
+
},
|
|
3197
2991
|
"dry-run": {
|
|
3198
2992
|
type: "boolean",
|
|
3199
|
-
description: "Preflight
|
|
2993
|
+
description: "Preflight selected packaged Skills without changing files",
|
|
3200
2994
|
default: false
|
|
3201
2995
|
},
|
|
3202
2996
|
"force": {
|
|
@@ -3206,20 +3000,44 @@ var skillsInstallCommand = defineCommand({
|
|
|
3206
3000
|
}
|
|
3207
3001
|
},
|
|
3208
3002
|
async run({ args }) {
|
|
3003
|
+
if (args._.length > 1)
|
|
3004
|
+
throw new Error("rsp skills install accepts at most one Skill name");
|
|
3209
3005
|
const result = await installPackagedSkills({
|
|
3210
3006
|
dryRun: Boolean(args["dry-run"]),
|
|
3211
|
-
force: Boolean(args.force)
|
|
3007
|
+
force: Boolean(args.force),
|
|
3008
|
+
names: args.name ? [args.name] : void 0
|
|
3212
3009
|
});
|
|
3213
3010
|
printSkillInstallResult(result, Boolean(args["dry-run"]));
|
|
3214
3011
|
}
|
|
3215
3012
|
});
|
|
3013
|
+
var skillsListCommand = defineCommand({
|
|
3014
|
+
meta: {
|
|
3015
|
+
name: "list",
|
|
3016
|
+
description: "List package-bundled Skills and their project status"
|
|
3017
|
+
},
|
|
3018
|
+
args: {
|
|
3019
|
+
json: {
|
|
3020
|
+
type: "boolean",
|
|
3021
|
+
description: "Print machine-readable JSON output",
|
|
3022
|
+
default: false
|
|
3023
|
+
}
|
|
3024
|
+
},
|
|
3025
|
+
async run({ args }) {
|
|
3026
|
+
const inventory = await inspectPackagedSkillInventory();
|
|
3027
|
+
if (args.json)
|
|
3028
|
+
emitJson(inventory);
|
|
3029
|
+
else
|
|
3030
|
+
printPackagedSkillInventory(inventory);
|
|
3031
|
+
}
|
|
3032
|
+
});
|
|
3216
3033
|
var skillsCommand = defineCommand({
|
|
3217
3034
|
meta: {
|
|
3218
3035
|
name: "skills",
|
|
3219
3036
|
description: "Manage package-bundled project Skills"
|
|
3220
3037
|
},
|
|
3221
3038
|
subCommands: {
|
|
3222
|
-
install: skillsInstallCommand
|
|
3039
|
+
install: skillsInstallCommand,
|
|
3040
|
+
list: skillsListCommand
|
|
3223
3041
|
}
|
|
3224
3042
|
});
|
|
3225
3043
|
var doctorCommand = defineCommand({
|
|
@@ -3391,6 +3209,19 @@ async function runCli(rawArgs = process.argv.slice(2)) {
|
|
|
3391
3209
|
ci: process.env.CI
|
|
3392
3210
|
};
|
|
3393
3211
|
const explicitUi = rawArgs[0] === "ui";
|
|
3212
|
+
if (shouldLaunchSkillsUi(rawArgs, terminalEnvironment)) {
|
|
3213
|
+
const { resolveUiLocale } = await import("./locale-HT44UIUP.mjs");
|
|
3214
|
+
const locale = resolveUiLocale("auto", process.env.RSP_UI_LANG, process.env.LC_ALL ?? process.env.LC_MESSAGES ?? process.env.LANG ?? new Intl.DateTimeFormat().resolvedOptions().locale);
|
|
3215
|
+
const { runSkillsTui } = await import("./entry-UWUX3HM7.mjs");
|
|
3216
|
+
const selection = await runSkillsTui(locale);
|
|
3217
|
+
if (selection.kind === "confirmed") {
|
|
3218
|
+
const result = await installPackagedSkills({ names: selection.names, force: selection.force });
|
|
3219
|
+
printSkillInstallResult(result);
|
|
3220
|
+
} else if (selection.kind === "error") {
|
|
3221
|
+
process.exitCode = 1;
|
|
3222
|
+
}
|
|
3223
|
+
return;
|
|
3224
|
+
}
|
|
3394
3225
|
if (explicitUi || shouldAutoLaunchUi(rawArgs, terminalEnvironment)) {
|
|
3395
3226
|
const { lang } = validateUiArgs(explicitUi ? rawArgs.slice(1) : []);
|
|
3396
3227
|
if (!isInteractiveTerminal(terminalEnvironment)) {
|
|
@@ -3398,8 +3229,8 @@ async function runCli(rawArgs = process.argv.slice(2)) {
|
|
|
3398
3229
|
throw new Error("rsp ui requires an interactive terminal; use rsp status or rsp status --json instead");
|
|
3399
3230
|
} else {
|
|
3400
3231
|
const { resolveUiLocale } = await import("./locale-HT44UIUP.mjs");
|
|
3401
|
-
const locale = resolveUiLocale(lang, process.env.RSP_UI_LANG, process.env.LC_ALL ?? process.env.LC_MESSAGES ?? process.env.LANG ?? Intl.DateTimeFormat().resolvedOptions().locale);
|
|
3402
|
-
const { runTui } = await import("./entry-
|
|
3232
|
+
const locale = resolveUiLocale(lang, process.env.RSP_UI_LANG, process.env.LC_ALL ?? process.env.LC_MESSAGES ?? process.env.LANG ?? new Intl.DateTimeFormat().resolvedOptions().locale);
|
|
3233
|
+
const { runTui } = await import("./entry-N7WLWGTI.mjs");
|
|
3403
3234
|
const exitCode = await runTui(locale);
|
|
3404
3235
|
if (exitCode !== 0)
|
|
3405
3236
|
process.exitCode = exitCode;
|
|
@@ -7,7 +7,14 @@ import {
|
|
|
7
7
|
projectDependencyForest,
|
|
8
8
|
queryArchiveHistory,
|
|
9
9
|
readArchiveHistoryDetail
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-EALHA3ZS.mjs";
|
|
11
|
+
import {
|
|
12
|
+
displayWidth,
|
|
13
|
+
openTerminalSession,
|
|
14
|
+
truncateDisplay,
|
|
15
|
+
wrapDisplay
|
|
16
|
+
} from "./chunk-JOMFFQRG.mjs";
|
|
17
|
+
import "./chunk-OTJFL6XH.mjs";
|
|
11
18
|
|
|
12
19
|
// src/tui/entry.tsx
|
|
13
20
|
import process from "process";
|
|
@@ -18,81 +25,6 @@ import React from "react";
|
|
|
18
25
|
import { Box, Text, useApp, useInput, useStdout } from "ink";
|
|
19
26
|
import { useCallback, useEffect, useReducer, useRef } from "react";
|
|
20
27
|
|
|
21
|
-
// src/tui/display.ts
|
|
22
|
-
var segmenter = new Intl.Segmenter(void 0, { granularity: "grapheme" });
|
|
23
|
-
function isWide(codePoint) {
|
|
24
|
-
return codePoint >= 4352 && (codePoint <= 4447 || codePoint === 9001 || codePoint === 9002 || codePoint >= 11904 && codePoint <= 42191 && codePoint !== 12351 || codePoint >= 44032 && codePoint <= 55203 || codePoint >= 63744 && codePoint <= 64255 || codePoint >= 65040 && codePoint <= 65049 || codePoint >= 65072 && codePoint <= 65135 || codePoint >= 65280 && codePoint <= 65376 || codePoint >= 65504 && codePoint <= 65510 || codePoint >= 127744 && codePoint <= 129791 || codePoint >= 131072 && codePoint <= 262141);
|
|
25
|
-
}
|
|
26
|
-
function displayWidth(value) {
|
|
27
|
-
let width = 0;
|
|
28
|
-
for (const { segment } of segmenter.segment(value)) {
|
|
29
|
-
const codePoint = segment.codePointAt(0) ?? 0;
|
|
30
|
-
if (/^\p{Mark}$/u.test(segment) || codePoint === 8205)
|
|
31
|
-
continue;
|
|
32
|
-
width += isWide(codePoint) ? 2 : 1;
|
|
33
|
-
}
|
|
34
|
-
return width;
|
|
35
|
-
}
|
|
36
|
-
function truncateDisplay(value, maxWidth) {
|
|
37
|
-
if (displayWidth(value) <= maxWidth)
|
|
38
|
-
return value;
|
|
39
|
-
if (maxWidth <= 1)
|
|
40
|
-
return "\u2026".slice(0, maxWidth);
|
|
41
|
-
let result = "";
|
|
42
|
-
for (const { segment } of segmenter.segment(value)) {
|
|
43
|
-
if (displayWidth(result + segment) > maxWidth - 1)
|
|
44
|
-
break;
|
|
45
|
-
result += segment;
|
|
46
|
-
}
|
|
47
|
-
return `${result}\u2026`;
|
|
48
|
-
}
|
|
49
|
-
function wrapDisplay(value, maxWidth, firstPrefix = "", continuationPrefix = firstPrefix) {
|
|
50
|
-
const width = Math.max(1, maxWidth);
|
|
51
|
-
if (displayWidth(firstPrefix) >= width)
|
|
52
|
-
return [truncateDisplay(`${firstPrefix}${value}`, width)];
|
|
53
|
-
const lines = [];
|
|
54
|
-
let prefix = firstPrefix;
|
|
55
|
-
let line = prefix;
|
|
56
|
-
const pushLine = () => {
|
|
57
|
-
lines.push(line);
|
|
58
|
-
prefix = continuationPrefix;
|
|
59
|
-
line = prefix;
|
|
60
|
-
};
|
|
61
|
-
const appendUnbroken = (token) => {
|
|
62
|
-
for (const { segment } of segmenter.segment(token)) {
|
|
63
|
-
if (displayWidth(line + segment) > width && line !== prefix)
|
|
64
|
-
pushLine();
|
|
65
|
-
if (displayWidth(line + segment) > width) {
|
|
66
|
-
lines.push(truncateDisplay(line + segment, width));
|
|
67
|
-
prefix = continuationPrefix;
|
|
68
|
-
line = prefix;
|
|
69
|
-
continue;
|
|
70
|
-
}
|
|
71
|
-
line += segment;
|
|
72
|
-
}
|
|
73
|
-
};
|
|
74
|
-
let pendingWhitespace = "";
|
|
75
|
-
for (const token of value.split(/(\s+)/u).filter(Boolean)) {
|
|
76
|
-
if (token.trim().length === 0) {
|
|
77
|
-
if (line !== prefix)
|
|
78
|
-
pendingWhitespace += token;
|
|
79
|
-
continue;
|
|
80
|
-
}
|
|
81
|
-
const separator = line === prefix ? "" : pendingWhitespace;
|
|
82
|
-
if (displayWidth(line + separator + token) <= width) {
|
|
83
|
-
line += `${separator}${token}`;
|
|
84
|
-
} else {
|
|
85
|
-
if (line !== prefix && separator)
|
|
86
|
-
pushLine();
|
|
87
|
-
appendUnbroken(token);
|
|
88
|
-
}
|
|
89
|
-
pendingWhitespace = "";
|
|
90
|
-
}
|
|
91
|
-
if (line !== prefix || lines.length === 0)
|
|
92
|
-
lines.push(line);
|
|
93
|
-
return lines;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
28
|
// src/tui/history-display.ts
|
|
97
29
|
function formatHistoryRow(record, width) {
|
|
98
30
|
const boundedWidth = Math.max(1, width);
|
|
@@ -884,22 +816,6 @@ var catalogs = {
|
|
|
884
816
|
"zh-CN": zhCN
|
|
885
817
|
};
|
|
886
818
|
|
|
887
|
-
// src/tui/terminal.ts
|
|
888
|
-
function openTerminalSession(stdout, options) {
|
|
889
|
-
let cleaned = false;
|
|
890
|
-
if (!options.screenReader)
|
|
891
|
-
stdout.write("\x1B[?1049h\x1B[?25l");
|
|
892
|
-
return {
|
|
893
|
-
cleanup() {
|
|
894
|
-
if (cleaned)
|
|
895
|
-
return;
|
|
896
|
-
cleaned = true;
|
|
897
|
-
if (!options.screenReader)
|
|
898
|
-
stdout.write("\x1B[?25h\x1B[?1049l");
|
|
899
|
-
}
|
|
900
|
-
};
|
|
901
|
-
}
|
|
902
|
-
|
|
903
819
|
// src/tui/entry.tsx
|
|
904
820
|
var signalExitCodes = {
|
|
905
821
|
SIGHUP: 129,
|