@lmzhen/dsh-evolution-core 0.14.0 → 0.15.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/lib/index.js CHANGED
@@ -6075,6 +6075,211 @@ function filterUnreadSkillOps(ops, readNames) {
6075
6075
  return dropped;
6076
6076
  }
6077
6077
  //#endregion
6078
+ //#region lib/types/skill-row-cells.js
6079
+ /**
6080
+ * The cells one row shows, decided here and rendered by the client.
6081
+ *
6082
+ * Why it exists: until 0.14.1 a row's information architecture lived inside one JSX expression
6083
+ * (description + ' · ' + state + ' · ' + age), so which facts survived the browser's single-line
6084
+ * ellipsis was an accident of concatenation order — on a real library the skill row's age and
6085
+ * curation state were clipped away on EVERY row (measured 2026-09-28: 6 skills, descriptions
6086
+ * 49–61 characters, ~240px of line). A row now arrives as an ORDERED list of cells, each declaring
6087
+ * its slot, and the renderer lays them out: `aside` cells are right-aligned and never truncate, so a
6088
+ * decision fact cannot be eaten by a long description again.
6089
+ *
6090
+ * Invariants: no words live here. A cell carries either a locale key (`copy`, with the values its
6091
+ * template needs) or a verbatim fact (`literal` — numbers, hashes, recorded paths). Facts come from
6092
+ * the host; the dictionary owns every sentence and every number format, including the ones the panel
6093
+ * used to build itself (`row.delta.up`, `time.<unit>.one`, `versions.count`).
6094
+ * @module @lmzhen/dsh-evolution-core/skill-row-cells
6095
+ */
6096
+ /** The actions whose row carries an explanatory hover text. */
6097
+ const ACTION_NOTES = {
6098
+ delete: "action.delete.note",
6099
+ archive: "action.archive.note"
6100
+ };
6101
+ /** The actions whose bytes come from a support file rather than from SKILL.md. */
6102
+ const SUPPORT_ACTIONS$1 = ["support-write", "support-remove"];
6103
+ /**
6104
+ * The relative-time key for one bucket: a count of one is spelled on its own.
6105
+ * @param age - the bucket the host reported.
6106
+ * @returns the locale key, singular or plural.
6107
+ */
6108
+ function ageCopyKey(age) {
6109
+ if (age.unit === "now") return "time.now";
6110
+ return age.n === 1 ? "time." + age.unit + ".one" : "time." + age.unit;
6111
+ }
6112
+ /**
6113
+ * The state word one skill row carries, from the facts the listing reported.
6114
+ * @param skill - the row's facts.
6115
+ * @returns the locale key for its state.
6116
+ */
6117
+ function skillStateKey(skill) {
6118
+ if (skill.protectionUnknown) return "state.unknown";
6119
+ if (skill.protectedBy !== null) return "state.protected";
6120
+ return skill.managed ? "state.managed" : "state.foreign";
6121
+ }
6122
+ /** The hover text one action word needs, or nothing when it needs none. */
6123
+ function actionNote(actionKind) {
6124
+ const note = ACTION_NOTES[actionKind];
6125
+ return note === void 0 ? {} : { note };
6126
+ }
6127
+ /**
6128
+ * The cells of one version row: the facts on the title line, the summary (if any) under it.
6129
+ * @param row - the row's facts.
6130
+ * @returns both lines.
6131
+ */
6132
+ function versionRowCells(row) {
6133
+ const title = [
6134
+ {
6135
+ key: "v",
6136
+ copy: "row.version",
6137
+ values: { n: row.v },
6138
+ tone: "tertiary",
6139
+ slot: "meta"
6140
+ },
6141
+ {
6142
+ key: "action",
6143
+ copy: "action." + row.actionKind,
6144
+ tone: "primary",
6145
+ slot: "lead",
6146
+ ...actionNote(row.actionKind)
6147
+ },
6148
+ {
6149
+ key: "time",
6150
+ copy: ageCopyKey(row.age),
6151
+ values: { n: row.age.n },
6152
+ tone: "tertiary",
6153
+ slot: "meta"
6154
+ }
6155
+ ];
6156
+ if (row.path !== void 0) title.push({
6157
+ key: "path",
6158
+ literal: row.path,
6159
+ tone: "tertiary",
6160
+ slot: "meta",
6161
+ note: row.path
6162
+ });
6163
+ else if (SUPPORT_ACTIONS$1.includes(row.actionKind)) title.push({
6164
+ key: "path",
6165
+ copy: "path.unrecorded",
6166
+ tone: "tertiary",
6167
+ slot: "meta"
6168
+ });
6169
+ const delta = row.charsDelta;
6170
+ if (delta !== void 0 && delta !== 0) title.push({
6171
+ key: "delta",
6172
+ copy: delta > 0 ? "row.delta.up" : "row.delta.down",
6173
+ values: { n: Math.abs(delta) },
6174
+ tone: "tertiary",
6175
+ slot: "meta"
6176
+ });
6177
+ const meta = [];
6178
+ if (row.summary !== void 0 && row.summary !== "") meta.push({
6179
+ key: "summary",
6180
+ literal: row.summary,
6181
+ tone: "secondary",
6182
+ slot: "lead"
6183
+ });
6184
+ return {
6185
+ title,
6186
+ meta
6187
+ };
6188
+ }
6189
+ /**
6190
+ * The cells of one skill row: the name line, then the facts that describe it.
6191
+ *
6192
+ * The description is a `lead` cell (it is the one allowed to truncate, with the full text on hover),
6193
+ * while the version count and the last-changed time are `aside` cells — they survive any description.
6194
+ * The description is NOT pre-truncated in JavaScript: the browser's ellipsis already clips it at the
6195
+ * layout's real width, and a character cut on top of that only hides where the fact ends.
6196
+ * @param skill - the row's facts.
6197
+ * @returns both lines.
6198
+ */
6199
+ function skillRowCells(skill) {
6200
+ const title = [{
6201
+ key: "name",
6202
+ literal: skill.name,
6203
+ tone: "primary",
6204
+ slot: "lead",
6205
+ note: skill.name
6206
+ }, {
6207
+ key: "count",
6208
+ copy: "versions.count",
6209
+ values: { n: skill.versions },
6210
+ tone: "tertiary",
6211
+ slot: "aside"
6212
+ }];
6213
+ const meta = [{
6214
+ key: "description",
6215
+ literal: skill.description,
6216
+ tone: "tertiary",
6217
+ slot: "lead",
6218
+ note: skill.description
6219
+ }, {
6220
+ key: "state",
6221
+ copy: skillStateKey(skill),
6222
+ tone: "tertiary",
6223
+ slot: "meta"
6224
+ }];
6225
+ if (skill.age !== null) meta.push({
6226
+ key: "age",
6227
+ copy: ageCopyKey(skill.age),
6228
+ values: { n: skill.age.n },
6229
+ tone: "tertiary",
6230
+ slot: "aside"
6231
+ });
6232
+ return {
6233
+ title,
6234
+ meta
6235
+ };
6236
+ }
6237
+ //#endregion
6238
+ //#region lib/types/document-body.js
6239
+ /**
6240
+ * What the panel shows when it renders one version as a document.
6241
+ *
6242
+ * Two decisions, both made here so the preview and the rendered diff cannot drift apart:
6243
+ *
6244
+ * - FRONTMATTER IS NOT DOCUMENT TEXT. A SKILL.md opens with a YAML block; the renderer read its
6245
+ * closing `---` as a setext underline, so the metadata line became the document's biggest heading
6246
+ * and the real title sat below it (measured on the installed panel 2026-09-28). The block is
6247
+ * stripped for DISPLAY only: the raw view and the body route still carry every byte, and the
6248
+ * panel already shows the name and description on the row and in the left column.
6249
+ * - STRIPPING FAILS OPEN. Only a block that the family's own reader accepts is removed. A document
6250
+ * whose text merely starts with a thematic break, a block with no closing line, or a frontmatter
6251
+ * whose body is empty is returned UNCHANGED — showing a document's first line is always better
6252
+ * than showing nothing.
6253
+ *
6254
+ * `readingStats` exists for the other half of the reader's honesty: a preview that stops early has
6255
+ * to be able to say HOW much it is not showing.
6256
+ * @module @lmzhen/dsh-evolution-core/document-body
6257
+ */
6258
+ /**
6259
+ * The document a reader sees: the body without its leading frontmatter block.
6260
+ * @param content - the stored bytes of one version.
6261
+ * @returns the text to render; unchanged when there is no frontmatter the reader accepts.
6262
+ */
6263
+ function displayBodyOf(content) {
6264
+ const block = frontmatterBlock(content);
6265
+ if (block === null) return content;
6266
+ if (parseFrontmatter(content) === null) return content;
6267
+ return block.lines.slice(block.end + 1).join("\n").replace(/^\s*\n/, "");
6268
+ }
6269
+ /**
6270
+ * How much of a version the panel is showing.
6271
+ * @param full - the whole stored text.
6272
+ * @param shown - the part the route handed over.
6273
+ * @returns the counts, so the panel can say what it is not showing.
6274
+ */
6275
+ function readingStats(full, shown) {
6276
+ return {
6277
+ totalChars: full.length,
6278
+ shownChars: shown.length,
6279
+ truncated: shown.length < full.length
6280
+ };
6281
+ }
6282
+ //#endregion
6078
6283
  //#region lib/types/evidence.js
6079
6284
  /**
6080
6285
  * Which session frames are EVIDENCE, and which are bookkeeping.
@@ -11206,4 +11411,4 @@ function sessionAudited(ctx, sessionId, sessionScoped) {
11206
11411
  return false;
11207
11412
  }
11208
11413
  //#endregion
11209
- export { ALIVE_LOCK_TAKEOVER_MS, AUTHORING_DESCRIPTION_BAR, AUTHORING_SPLIT_LINE_CHARS, BASELINE_ACTION, CITATION_SUPPORT_DIRS, COMBINED_REVIEW_PLAN_PROMPT, COMBINED_REVIEW_PROMPT, COMPLETION_SKILL_REVIEW_PROMPT, CONTENT_SPLIT_HINT, COST_ASCII_TOKEN_HIGH, COST_ASCII_TOKEN_LOW, COST_CJK_TOKEN_HIGH, COST_CJK_TOKEN_LOW, CURATOR_DRY_RUN_BANNER, CURATOR_PROMPT, DEAD_LOCK_TAKEOVER_MS, DEDUP_MAX_PAIR_COMPARISONS, DEDUP_SIMILARITY_THRESHOLD, DEFAULT_ARCHIVE_AFTER_DAYS, DEFAULT_ARCHIVE_RETENTION_POLICY, DEFAULT_CITATION_POLICY, DEFAULT_CITATION_REF_BUDGET, DEFAULT_CONSOLIDATION_FAILURES, DEFAULT_CURATOR_BOOT_GRACE_SECONDS, DEFAULT_CURATOR_INTERVAL_HOURS, DEFAULT_CURATOR_MODEL, DEFAULT_CURATOR_REVIEW_MAX_TOKENS, DEFAULT_HEALTH_THRESHOLDS, DEFAULT_MAX_OPS_PER_PLAN, DEFAULT_MEMORY_CHAR_LIMIT, DEFAULT_MEMORY_REVIEW_MODEL, DEFAULT_MIN_IDLE_HOURS, DEFAULT_MUTATION_CAP, DEFAULT_REFERENCE_REWRITE_POLICY, DEFAULT_REVIEW_CONTEXT_MESSAGES, DEFAULT_REVIEW_MEMORY_INTERVAL, DEFAULT_REVIEW_MESSAGE_CHARS, DEFAULT_REVIEW_SKILL_INTERVAL, DEFAULT_REVIEW_TIMEOUT_MS, DEFAULT_SKILL_CONTENT_CHARS, DEFAULT_SKILL_LIMITS, DEFAULT_SKILL_REVIEW_COMPLETION_MIN_TOOL_CALLS, DEFAULT_SKILL_REVIEW_MODEL, DEFAULT_SKILL_REVIEW_TRIGGER, DEFAULT_SKILL_VERSION_KEEP, DEFAULT_STALE_AFTER_DAYS, DEFAULT_SUBSTANTIVE_MIN_AGENT_CHARS, DEFAULT_SUBSTANTIVE_MIN_TOOL_CALLS, DEFAULT_SUBSTANTIVE_MIN_USER_CHARS, DEFAULT_SUPPORT_FILE_CHAR_POLICY, DEFAULT_SUPPORT_READ_TOOL_NAMES, DEFAULT_THREAT_MAX_SCAN_CHARS, DEFAULT_USER_CHAR_LIMIT, DISPATCH_EVENT_TYPES, DRIFT_MAX_LINE_CHARS, DRIFT_SIGNALS_VERSION, DRIFT_SIGNAL_NOUNS, DSH_AUTHORING_STANDARDS, EMPTY_LOCK_TAKEOVER_MS, ENTRY_DELIMITER, EVENT_ARCHIVE_PREFIX, EVENT_LOG_RETAIN_ARCHIVES, EVENT_LOG_ROTATE_AT, EVENT_LOG_VERSION, EVOLUTION_ERRORS, EVOLUTION_WRITE_TOOLS, EvolutionGateSet, FAMILY_SESSION_TOOL_NAMES, FORBIDDEN_CONTROL_KEYS, HEALTH_STAMP_RE, HISTORY_DIR, HISTORY_INDEX_VERSION, HOOK_LINE_RE, INSTANCE_KEYS, KEEP_LINE_RE, LOCK_BODY_RE, LOCK_SUFFIX, LOCK_TEAR_TAKEOVER_MS, LOW_QUALITY_THRESHOLD, LostWriteLock, MAINTAIN_OUTPUT_INSTRUCTION, MAINTAIN_PROMPT, MAX_DESCRIPTION_LENGTH, MAX_RESTRUCTURE_MOVES, MAX_SKILL_CONTENT_CHARS, MAX_SKILL_FILE_BYTES, MAX_SKILL_NAME_LENGTH, MAX_SUPPORT_READ_PATHS, MAX_TIMER_DELAY_MS, MEMORY_GUIDANCE_SECTION_ORDER, MEMORY_REVIEW_PROMPT, MIN_STAMP_BODY_CHARS, MUTATIONS_FILE_VERSION, MemoryStore, NATIVE_CALL_EVENT, NATIVE_RESULT_EVENT, PARAM_ALIASES, PARAM_EXPOSURE, PARAM_GROUP_LABELS, PARAM_NAMESPACES, PATTERN_OVERLAP, PLATFORM_CATALOG_DESCRIPTION_DEFAULT, PLATFORM_ESTIMATE_CHARS_PER_TOKEN, POLICY_STAGE_DEFAULTS, PROMPT_BUNDLE, PROMPT_BUNDLE_ID, PROMPT_BUNDLE_VERSION, PROTECTED_BUILTIN_SKILLS, PTC_DISPATCH_EVENT, PTC_DISPATCH_START_EVENT, QUALITY_WEIGHTS, READ_REQUIRED_ACTIONS, RESTRUCTURE_TARGET_RE, RETENTION_FEEDBACK_KEEP_RATIO, RETENTION_FEEDBACK_MIN_CHARS, SKILLS_GUIDANCE, SKILLS_GUIDANCE_SECTION_ORDER, SKILL_ACTION_REQUIRED_FIELDS, SKILL_NAME_RE, SKILL_REVIEW_PLAN_PROMPT, SKILL_REVIEW_PROMPT, SNAPSHOT_EXTRA_NAME_RE, SUMMARY_DUPLICATE_HINT_THRESHOLD, SUPPORT_DIRS, SUPPRESSED_FILE_VERSION, SkillLibrary, TEXT_DIFF_MAX_CHARS, TEXT_DIFF_MAX_LINES, THREAT_EXEMPTION_HINT, TOKEN_ASCII_WEIGHT, TOKEN_CJK_WEIGHT, ToolDispatchNormalizer, ToolDispatchPayloadError, UPSTREAM_LIMIT_CHARS_PER_TOKEN, VERSION_SUMMARY_MAX_CHARS, advanceReview, affinity, allowRowCollisions, appendEvolutionEvent, applyCuratorLifecycleFields, applyCuratorMetaFields, applyReferenceRewrite, assertDispatchPayload, assertSkillsRootAliasRetired, assessStructureHealth, authoringFeedback, blobPath, bodyCost, buildCuratorRunReport, buildLearnPrompt, bumpPatch, bumpSupportRead, bumpUse, bumpView, callingScope, canonicalWriteId, claimInstance, clampedNumber, clearReviewChannel, collectReadSkillNames, composePresetComposition, computeDedupGroups, computeDriftSignals, computeLifecycleTransitions, computePrefixClusters, computeQualityScores, computeScopeView, contentHash, contentRetentionFeedback, countDispatches, createGateSet, daysSinceIso, decideTakeover, describeReferenceRewrite, duplicateHeadings, elapsedSince, emptyRecord, entryTarget, errorText, evaluateThreat, eventsFile, evidenceKindIndex, evolutionEventPayloadIssue, evolutionHome, evolutionIoAdapter, evolutionRoot, filterUnreadSkillOps, findDriftSignal, foldCuratorFields, foldToolDispatches, foldTurn, frontmatterBlock, frontmatterCatalogInvalid, getRecord, historyIndexFile, historyRoot, identity, idleDays, installParamSection, instanceClaimKey, instanceClaimedWriteSites, instanceHolder, isAbsent, isCommittedWarning, isDeprecatedParamId, isFileShapedPath, isMissingPath, isPresent, isProcessAlive, isProgramToolName, isReviewChannelSession, isSkillReadToolName, isSkillToolName, isUnknown, isUnreadWrite, latestActivityAt, latestVersionAt, lifecycleCandidate, listEventArchives, loadMutations, loadRowOverrides, loadSuppressedNames, loadUsage, loadVersionContent, loadVersions, makeSerialQueue, mapProbe, markAgentCreated, markReviewChannel, markerEntryName, memoryRoot, missingSupportPointers, mutateUsage, mutationsFile, narrowNameMatches, nearDuplicateSummaries, neutralizePromptVariables, newSkillLibrary, nextHistoryIndex, nodeEvolutionIo, normalizeFrontmatter, normalizeUsageRecord, normalizeVersionSummary, observeEvent, orderVersions, overlongLines, paramNamespace, paramSectionOverrides, parseCuratorNominations, parseEvolutionEvents, parseFrontmatter, parseHistoryIndex, parseLockBody, partitionVersions, pendingSelfCleanup, persistedWriteSite, persistedWriteSites, planReferenceRewrite, planRehoming, policyStageLimits, probeAbsent, probeList, probeMtime, probePresent, probeReason, probeUnknown, projectionText, readDispatchSignal, readEvolutionEvents, readEvolutionTimeline, readHistoryIndex, readNumberParam, readParam, recordMutation, recordVersions, redactSecrets, relatedSkillNames, releaseInstance, renameWithRetry, renderCuratorReportMarkdown, resolveCitations, resolveExecOrigins, resolveOrigins, resolveParamId, resolveRootConfig, resolveSkillsRoot, retainEventArchives, retirementReport, reviewPrompt, saveSuppressedNames, saveUsage, scanBodyHooks, scanContentThreats, scanMemoryThreats, scanThreats, scopedProbeReport, sessionAudited, sessionReadSkillNames, sessionSeesFamilyTools, skillReadNameOf, skillsRoot, supportFileReadOf, suppressedFile, sweepReviewChannelSessions, textDiffFacts, tokenLineFor, transactIo, transactTaskGuard, unhookedSupportPointers, updateSuppressedNames, usageFile, usageObserved, validateFrontmatter, validateRestructureTarget, valueOr, verifyPromptBundle, versionActionKind, versionSummaryPrompt, versionTarget, vocabulary, writeDurableTmp, yamlPlainScalarNeedsQuotes };
11414
+ export { ALIVE_LOCK_TAKEOVER_MS, AUTHORING_DESCRIPTION_BAR, AUTHORING_SPLIT_LINE_CHARS, BASELINE_ACTION, CITATION_SUPPORT_DIRS, COMBINED_REVIEW_PLAN_PROMPT, COMBINED_REVIEW_PROMPT, COMPLETION_SKILL_REVIEW_PROMPT, CONTENT_SPLIT_HINT, COST_ASCII_TOKEN_HIGH, COST_ASCII_TOKEN_LOW, COST_CJK_TOKEN_HIGH, COST_CJK_TOKEN_LOW, CURATOR_DRY_RUN_BANNER, CURATOR_PROMPT, DEAD_LOCK_TAKEOVER_MS, DEDUP_MAX_PAIR_COMPARISONS, DEDUP_SIMILARITY_THRESHOLD, DEFAULT_ARCHIVE_AFTER_DAYS, DEFAULT_ARCHIVE_RETENTION_POLICY, DEFAULT_CITATION_POLICY, DEFAULT_CITATION_REF_BUDGET, DEFAULT_CONSOLIDATION_FAILURES, DEFAULT_CURATOR_BOOT_GRACE_SECONDS, DEFAULT_CURATOR_INTERVAL_HOURS, DEFAULT_CURATOR_MODEL, DEFAULT_CURATOR_REVIEW_MAX_TOKENS, DEFAULT_HEALTH_THRESHOLDS, DEFAULT_MAX_OPS_PER_PLAN, DEFAULT_MEMORY_CHAR_LIMIT, DEFAULT_MEMORY_REVIEW_MODEL, DEFAULT_MIN_IDLE_HOURS, DEFAULT_MUTATION_CAP, DEFAULT_REFERENCE_REWRITE_POLICY, DEFAULT_REVIEW_CONTEXT_MESSAGES, DEFAULT_REVIEW_MEMORY_INTERVAL, DEFAULT_REVIEW_MESSAGE_CHARS, DEFAULT_REVIEW_SKILL_INTERVAL, DEFAULT_REVIEW_TIMEOUT_MS, DEFAULT_SKILL_CONTENT_CHARS, DEFAULT_SKILL_LIMITS, DEFAULT_SKILL_REVIEW_COMPLETION_MIN_TOOL_CALLS, DEFAULT_SKILL_REVIEW_MODEL, DEFAULT_SKILL_REVIEW_TRIGGER, DEFAULT_SKILL_VERSION_KEEP, DEFAULT_STALE_AFTER_DAYS, DEFAULT_SUBSTANTIVE_MIN_AGENT_CHARS, DEFAULT_SUBSTANTIVE_MIN_TOOL_CALLS, DEFAULT_SUBSTANTIVE_MIN_USER_CHARS, DEFAULT_SUPPORT_FILE_CHAR_POLICY, DEFAULT_SUPPORT_READ_TOOL_NAMES, DEFAULT_THREAT_MAX_SCAN_CHARS, DEFAULT_USER_CHAR_LIMIT, DISPATCH_EVENT_TYPES, DRIFT_MAX_LINE_CHARS, DRIFT_SIGNALS_VERSION, DRIFT_SIGNAL_NOUNS, DSH_AUTHORING_STANDARDS, EMPTY_LOCK_TAKEOVER_MS, ENTRY_DELIMITER, EVENT_ARCHIVE_PREFIX, EVENT_LOG_RETAIN_ARCHIVES, EVENT_LOG_ROTATE_AT, EVENT_LOG_VERSION, EVOLUTION_ERRORS, EVOLUTION_WRITE_TOOLS, EvolutionGateSet, FAMILY_SESSION_TOOL_NAMES, FORBIDDEN_CONTROL_KEYS, HEALTH_STAMP_RE, HISTORY_DIR, HISTORY_INDEX_VERSION, HOOK_LINE_RE, INSTANCE_KEYS, KEEP_LINE_RE, LOCK_BODY_RE, LOCK_SUFFIX, LOCK_TEAR_TAKEOVER_MS, LOW_QUALITY_THRESHOLD, LostWriteLock, MAINTAIN_OUTPUT_INSTRUCTION, MAINTAIN_PROMPT, MAX_DESCRIPTION_LENGTH, MAX_RESTRUCTURE_MOVES, MAX_SKILL_CONTENT_CHARS, MAX_SKILL_FILE_BYTES, MAX_SKILL_NAME_LENGTH, MAX_SUPPORT_READ_PATHS, MAX_TIMER_DELAY_MS, MEMORY_GUIDANCE_SECTION_ORDER, MEMORY_REVIEW_PROMPT, MIN_STAMP_BODY_CHARS, MUTATIONS_FILE_VERSION, MemoryStore, NATIVE_CALL_EVENT, NATIVE_RESULT_EVENT, PARAM_ALIASES, PARAM_EXPOSURE, PARAM_GROUP_LABELS, PARAM_NAMESPACES, PATTERN_OVERLAP, PLATFORM_CATALOG_DESCRIPTION_DEFAULT, PLATFORM_ESTIMATE_CHARS_PER_TOKEN, POLICY_STAGE_DEFAULTS, PROMPT_BUNDLE, PROMPT_BUNDLE_ID, PROMPT_BUNDLE_VERSION, PROTECTED_BUILTIN_SKILLS, PTC_DISPATCH_EVENT, PTC_DISPATCH_START_EVENT, QUALITY_WEIGHTS, READ_REQUIRED_ACTIONS, RESTRUCTURE_TARGET_RE, RETENTION_FEEDBACK_KEEP_RATIO, RETENTION_FEEDBACK_MIN_CHARS, SKILLS_GUIDANCE, SKILLS_GUIDANCE_SECTION_ORDER, SKILL_ACTION_REQUIRED_FIELDS, SKILL_NAME_RE, SKILL_REVIEW_PLAN_PROMPT, SKILL_REVIEW_PROMPT, SNAPSHOT_EXTRA_NAME_RE, SUMMARY_DUPLICATE_HINT_THRESHOLD, SUPPORT_DIRS, SUPPRESSED_FILE_VERSION, SkillLibrary, TEXT_DIFF_MAX_CHARS, TEXT_DIFF_MAX_LINES, THREAT_EXEMPTION_HINT, TOKEN_ASCII_WEIGHT, TOKEN_CJK_WEIGHT, ToolDispatchNormalizer, ToolDispatchPayloadError, UPSTREAM_LIMIT_CHARS_PER_TOKEN, VERSION_SUMMARY_MAX_CHARS, advanceReview, affinity, ageCopyKey, allowRowCollisions, appendEvolutionEvent, applyCuratorLifecycleFields, applyCuratorMetaFields, applyReferenceRewrite, assertDispatchPayload, assertSkillsRootAliasRetired, assessStructureHealth, authoringFeedback, blobPath, bodyCost, buildCuratorRunReport, buildLearnPrompt, bumpPatch, bumpSupportRead, bumpUse, bumpView, callingScope, canonicalWriteId, claimInstance, clampedNumber, clearReviewChannel, collectReadSkillNames, composePresetComposition, computeDedupGroups, computeDriftSignals, computeLifecycleTransitions, computePrefixClusters, computeQualityScores, computeScopeView, contentHash, contentRetentionFeedback, countDispatches, createGateSet, daysSinceIso, decideTakeover, describeReferenceRewrite, displayBodyOf, duplicateHeadings, elapsedSince, emptyRecord, entryTarget, errorText, evaluateThreat, eventsFile, evidenceKindIndex, evolutionEventPayloadIssue, evolutionHome, evolutionIoAdapter, evolutionRoot, filterUnreadSkillOps, findDriftSignal, foldCuratorFields, foldToolDispatches, foldTurn, frontmatterBlock, frontmatterCatalogInvalid, getRecord, historyIndexFile, historyRoot, identity, idleDays, installParamSection, instanceClaimKey, instanceClaimedWriteSites, instanceHolder, isAbsent, isCommittedWarning, isDeprecatedParamId, isFileShapedPath, isMissingPath, isPresent, isProcessAlive, isProgramToolName, isReviewChannelSession, isSkillReadToolName, isSkillToolName, isUnknown, isUnreadWrite, latestActivityAt, latestVersionAt, lifecycleCandidate, listEventArchives, loadMutations, loadRowOverrides, loadSuppressedNames, loadUsage, loadVersionContent, loadVersions, makeSerialQueue, mapProbe, markAgentCreated, markReviewChannel, markerEntryName, memoryRoot, missingSupportPointers, mutateUsage, mutationsFile, narrowNameMatches, nearDuplicateSummaries, neutralizePromptVariables, newSkillLibrary, nextHistoryIndex, nodeEvolutionIo, normalizeFrontmatter, normalizeUsageRecord, normalizeVersionSummary, observeEvent, orderVersions, overlongLines, paramNamespace, paramSectionOverrides, parseCuratorNominations, parseEvolutionEvents, parseFrontmatter, parseHistoryIndex, parseLockBody, partitionVersions, pendingSelfCleanup, persistedWriteSite, persistedWriteSites, planReferenceRewrite, planRehoming, policyStageLimits, probeAbsent, probeList, probeMtime, probePresent, probeReason, probeUnknown, projectionText, readDispatchSignal, readEvolutionEvents, readEvolutionTimeline, readHistoryIndex, readNumberParam, readParam, readingStats, recordMutation, recordVersions, redactSecrets, relatedSkillNames, releaseInstance, renameWithRetry, renderCuratorReportMarkdown, resolveCitations, resolveExecOrigins, resolveOrigins, resolveParamId, resolveRootConfig, resolveSkillsRoot, retainEventArchives, retirementReport, reviewPrompt, saveSuppressedNames, saveUsage, scanBodyHooks, scanContentThreats, scanMemoryThreats, scanThreats, scopedProbeReport, sessionAudited, sessionReadSkillNames, sessionSeesFamilyTools, skillReadNameOf, skillRowCells, skillStateKey, skillsRoot, supportFileReadOf, suppressedFile, sweepReviewChannelSessions, textDiffFacts, tokenLineFor, transactIo, transactTaskGuard, unhookedSupportPointers, updateSuppressedNames, usageFile, usageObserved, validateFrontmatter, validateRestructureTarget, valueOr, verifyPromptBundle, versionActionKind, versionRowCells, versionSummaryPrompt, versionTarget, vocabulary, writeDurableTmp, yamlPlainScalarNeedsQuotes };
@@ -0,0 +1,23 @@
1
+ /**
2
+ * The document a reader sees: the body without its leading frontmatter block.
3
+ * @param content - the stored bytes of one version.
4
+ * @returns the text to render; unchanged when there is no frontmatter the reader accepts.
5
+ */
6
+ export declare function displayBodyOf(content: string): string;
7
+ /** How much of one version the reader is looking at. */
8
+ export interface ReadingStats {
9
+ /** Characters in the stored version. */
10
+ readonly totalChars: number;
11
+ /** Characters the panel holds (the route's own bound). */
12
+ readonly shownChars: number;
13
+ /** Whether anything was left out. */
14
+ readonly truncated: boolean;
15
+ }
16
+ /**
17
+ * How much of a version the panel is showing.
18
+ * @param full - the whole stored text.
19
+ * @param shown - the part the route handed over.
20
+ * @returns the counts, so the panel can say what it is not showing.
21
+ */
22
+ export declare function readingStats(full: string, shown: string): ReadingStats;
23
+ //# sourceMappingURL=document-body.d.ts.map
@@ -53,6 +53,8 @@ export * from './scope.ts';
53
53
  export * from './skill-health.ts';
54
54
  export * from './signals.ts';
55
55
  export * from './skill-reads.ts';
56
+ export * from './skill-row-cells.ts';
57
+ export * from './document-body.ts';
56
58
  export * from './evidence.ts';
57
59
  export * from './drift-signals.ts';
58
60
  export * from './skill-history.ts';
@@ -0,0 +1,106 @@
1
+ /**
2
+ * The cells one row shows, decided here and rendered by the client.
3
+ *
4
+ * Why it exists: until 0.14.1 a row's information architecture lived inside one JSX expression
5
+ * (description + ' · ' + state + ' · ' + age), so which facts survived the browser's single-line
6
+ * ellipsis was an accident of concatenation order — on a real library the skill row's age and
7
+ * curation state were clipped away on EVERY row (measured 2026-09-28: 6 skills, descriptions
8
+ * 49–61 characters, ~240px of line). A row now arrives as an ORDERED list of cells, each declaring
9
+ * its slot, and the renderer lays them out: `aside` cells are right-aligned and never truncate, so a
10
+ * decision fact cannot be eaten by a long description again.
11
+ *
12
+ * Invariants: no words live here. A cell carries either a locale key (`copy`, with the values its
13
+ * template needs) or a verbatim fact (`literal` — numbers, hashes, recorded paths). Facts come from
14
+ * the host; the dictionary owns every sentence and every number format, including the ones the panel
15
+ * used to build itself (`row.delta.up`, `time.<unit>.one`, `versions.count`).
16
+ * @module @lmzhen/dsh-evolution-core/skill-row-cells
17
+ */
18
+ /** Where a cell sits in its row. `aside` is right-aligned and never truncated. */
19
+ export type CellSlot = 'lead' | 'meta' | 'aside';
20
+ /** The visual register a cell speaks in; the client maps it to a design token. */
21
+ export type CellTone = 'primary' | 'secondary' | 'tertiary';
22
+ /** What every cell carries, whichever kind it is. */
23
+ export interface RowCellBase {
24
+ /** Stable identity, for the renderer's key and for a spec to name one cell. */
25
+ readonly key: string;
26
+ /** Where it sits. */
27
+ readonly slot: CellSlot;
28
+ /** Which register it speaks in. */
29
+ readonly tone: CellTone;
30
+ /** Hover text (a locale key) when the row would otherwise hide the full value. */
31
+ readonly note?: string;
32
+ }
33
+ /** A sentence: the locale key plus the values its template interpolates. */
34
+ export interface CopyCell extends RowCellBase {
35
+ readonly copy: string;
36
+ readonly values?: Readonly<Record<string, string | number>>;
37
+ }
38
+ /** A fact shown verbatim (a version number, a path, a summary the model wrote). */
39
+ export interface LiteralCell extends RowCellBase {
40
+ readonly literal: string;
41
+ }
42
+ /** One cell. Narrow with `'copy' in cell`. */
43
+ export type RowCell = CopyCell | LiteralCell;
44
+ /** The lines one row can show: a title line, and a meta line under it. */
45
+ export interface RowCells {
46
+ readonly title: readonly RowCell[];
47
+ readonly meta: readonly RowCell[];
48
+ }
49
+ /** The facts a version row needs. The client's `VersionRow` satisfies this structurally. */
50
+ export interface VersionRowFacts {
51
+ readonly v: number;
52
+ readonly actionKind: string;
53
+ readonly age: {
54
+ readonly unit: string;
55
+ readonly n: number;
56
+ };
57
+ readonly charsDelta?: number;
58
+ readonly path?: string;
59
+ readonly summary?: string;
60
+ }
61
+ /** The facts a skill row needs. The client's `SkillRow` satisfies this structurally. */
62
+ export interface SkillRowFacts {
63
+ readonly name: string;
64
+ readonly versions: number;
65
+ readonly description: string;
66
+ readonly managed: boolean;
67
+ readonly protectedBy: string | null;
68
+ readonly protectionUnknown: boolean;
69
+ readonly age: {
70
+ readonly unit: string;
71
+ readonly n: number;
72
+ } | null;
73
+ }
74
+ /**
75
+ * The relative-time key for one bucket: a count of one is spelled on its own.
76
+ * @param age - the bucket the host reported.
77
+ * @returns the locale key, singular or plural.
78
+ */
79
+ export declare function ageCopyKey(age: {
80
+ readonly unit: string;
81
+ readonly n: number;
82
+ }): string;
83
+ /**
84
+ * The state word one skill row carries, from the facts the listing reported.
85
+ * @param skill - the row's facts.
86
+ * @returns the locale key for its state.
87
+ */
88
+ export declare function skillStateKey(skill: SkillRowFacts): string;
89
+ /**
90
+ * The cells of one version row: the facts on the title line, the summary (if any) under it.
91
+ * @param row - the row's facts.
92
+ * @returns both lines.
93
+ */
94
+ export declare function versionRowCells(row: VersionRowFacts): RowCells;
95
+ /**
96
+ * The cells of one skill row: the name line, then the facts that describe it.
97
+ *
98
+ * The description is a `lead` cell (it is the one allowed to truncate, with the full text on hover),
99
+ * while the version count and the last-changed time are `aside` cells — they survive any description.
100
+ * The description is NOT pre-truncated in JavaScript: the browser's ellipsis already clips it at the
101
+ * layout's real width, and a character cut on top of that only hides where the fact ends.
102
+ * @param skill - the row's facts.
103
+ * @returns both lines.
104
+ */
105
+ export declare function skillRowCells(skill: SkillRowFacts): RowCells;
106
+ //# sourceMappingURL=skill-row-cells.d.ts.map
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@lmzhen/dsh-evolution-core",
3
3
  "description": "Shared stores, prompts, signals and lifecycle logic for the dsh-evolution plugin family (community build)",
4
- "version": "0.14.0",
4
+ "version": "0.15.0",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },