@oevery/rsp 3.1.0-beta.1 → 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/dist/cli.mjs CHANGED
@@ -1,22 +1,47 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
- ARCHIVES_DIR,
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-QLXIDVKK.mjs";
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, 2)}
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 all packaged Skills without changing files",
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-LAPR3TNI.mjs");
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-QLXIDVKK.mjs";
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,