@lmzhen/dsh-evolution-core 0.13.6 → 0.14.1

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
@@ -6489,25 +6489,67 @@ function versionTarget(action) {
6489
6489
  return "other";
6490
6490
  }
6491
6491
  /**
6492
+ * Which artifact one INDEX ENTRY holds.
6493
+ *
6494
+ * {@link versionTarget} reads the ACTION, which is enough for the entries a write mints under its own
6495
+ * label and is NOT enough for a {@link BASELINE_ACTION}: a baseline minted for a support write holds
6496
+ * that FILE's previous bytes while its action says only "this is what was there". Two facts recover
6497
+ * the artifact:
6498
+ *
6499
+ * - `path` is written exactly when the bytes come from a support file, on BOTH entries one support
6500
+ * write can mint, so it decides on its own;
6501
+ * - an entry recorded before `path` existed has none, and the link is the evidence left: a support
6502
+ * write names the content it replaced through `beforeHash`, so a baseline that a support write
6503
+ * names as its predecessor holds that file's bytes.
6504
+ *
6505
+ * The inference runs only for a baseline. Every other entry keeps the action's verdict, which is also
6506
+ * the fail-closed one for an action this module does not know.
6507
+ * @param entry - one entry of a skill's index.
6508
+ * @param index - the index the entry came from: the legacy link is only readable across the whole
6509
+ * index. Omitting it answers from `path` and the action alone.
6510
+ * @returns the artifact class; `other` when nothing attributes the bytes.
6511
+ */
6512
+ function entryTarget(entry, index = []) {
6513
+ if (entry.path !== void 0) return "support";
6514
+ if (entry.action !== "baseline") return versionTarget(entry.action);
6515
+ return index.some((candidate) => SUPPORT_ACTIONS.includes(candidate.action) && candidate.beforeHash === entry.hash) ? "support" : "other";
6516
+ }
6517
+ /**
6492
6518
  * Split one index into the skill body's chain and the support files' versions.
6493
6519
  *
6494
6520
  * Both share ONE index, so a skill that ever wrote a support file has two chains and
6495
6521
  * {@link orderVersions} cannot account for every entry (it falls back to the stored order). Splitting
6496
6522
  * first lets each group rebuild its own order, and keeps the body's chain intact by leaving every
6497
- * entry the index cannot classify in it — a `baseline` predecessor is usually the body's first link.
6523
+ * entry whose artifact nothing attributes in it — a `baseline` predecessor is usually the body's
6524
+ * first link, and only the support-file baselines {@link entryTarget} recovers leave it.
6498
6525
  * @param versions - the stored index, oldest first as recorded.
6499
6526
  * @returns the two groups, each in content order when its chain is complete.
6500
6527
  */
6501
6528
  function partitionVersions(versions) {
6502
6529
  const content = [];
6503
6530
  const support = [];
6504
- for (const entry of versions) if (versionTarget(entry.action) === "support") support.push(entry);
6531
+ for (const entry of versions) if (entryTarget(entry, versions) === "support") support.push(entry);
6505
6532
  else content.push(entry);
6506
6533
  return {
6507
6534
  content: orderVersions(content),
6508
6535
  support: orderVersions(support)
6509
6536
  };
6510
6537
  }
6538
+ /**
6539
+ * When this skill's content last changed: the newest `at` across BOTH chains, or null when the index
6540
+ * holds nothing.
6541
+ *
6542
+ * The stored array is APPEND order and two writers of one skill can interleave, so the answer is the
6543
+ * maximum timestamp rather than the tail. Every `at` this family writes is the same ISO-8601 UTC
6544
+ * form, so comparing the strings is comparing the instants.
6545
+ * @param versions - every entry the index holds, in any order.
6546
+ * @returns the newest timestamp, or null when there is none to report.
6547
+ */
6548
+ function latestVersionAt(versions) {
6549
+ let newest = null;
6550
+ for (const entry of versions) if (newest === null || entry.at > newest) newest = entry.at;
6551
+ return newest;
6552
+ }
6511
6553
  /** Keep nothing less than one version, whatever the deployment asks for. */
6512
6554
  function clampKeep(keep) {
6513
6555
  return Number.isFinite(keep) ? Math.max(1, Math.floor(keep)) : 1;
@@ -6535,21 +6577,20 @@ function readVersionEntry(entry) {
6535
6577
  if (typeof candidate.action !== "string") return null;
6536
6578
  if (typeof candidate.chars !== "number") return null;
6537
6579
  const summary = typeof candidate.summary === "string" && candidate.summary !== "" ? candidate.summary : void 0;
6580
+ const path = typeof candidate.path === "string" && candidate.path !== "" ? candidate.path : void 0;
6538
6581
  const base = {
6539
6582
  v: candidate.v,
6540
6583
  at: candidate.at,
6541
6584
  action: candidate.action,
6542
6585
  hash: candidate.hash,
6543
- chars: candidate.chars
6586
+ chars: candidate.chars,
6587
+ ...summary === void 0 ? {} : { summary },
6588
+ ...path === void 0 ? {} : { path }
6544
6589
  };
6545
6590
  return typeof candidate.beforeHash === "string" && candidate.beforeHash !== "" ? {
6546
6591
  ...base,
6547
- beforeHash: candidate.beforeHash,
6548
- ...summary === void 0 ? {} : { summary }
6549
- } : {
6550
- ...base,
6551
- ...summary === void 0 ? {} : { summary }
6552
- };
6592
+ beforeHash: candidate.beforeHash
6593
+ } : base;
6553
6594
  }
6554
6595
  /**
6555
6596
  * Read one index body for a RECORDER: "understood", "no file", or "cannot be understood".
@@ -6609,12 +6650,14 @@ function nextHistoryIndex(versions, input, keep) {
6609
6650
  const beforeHash = input.before === null ? null : contentHash(input.before);
6610
6651
  const afterHash = input.after === null ? null : contentHash(input.after);
6611
6652
  const grown = [...versions];
6653
+ const pathField = input.path === void 0 ? {} : { path: input.path };
6612
6654
  if (beforeHash !== null && !grown.some((entry) => entry.hash === beforeHash)) grown.push({
6613
6655
  v: nextVersion(grown),
6614
6656
  at: input.at,
6615
6657
  action: BASELINE_ACTION,
6616
6658
  hash: beforeHash,
6617
- chars: input.before?.length ?? 0
6659
+ chars: input.before?.length ?? 0,
6660
+ ...pathField
6618
6661
  });
6619
6662
  if (afterHash !== null) {
6620
6663
  if (grown[grown.length - 1]?.hash !== afterHash) grown.push({
@@ -6623,6 +6666,7 @@ function nextHistoryIndex(versions, input, keep) {
6623
6666
  action: input.action,
6624
6667
  hash: afterHash,
6625
6668
  chars: input.after?.length ?? 0,
6669
+ ...pathField,
6626
6670
  ...input.summary === void 0 ? {} : { summary: input.summary },
6627
6671
  ...beforeHash === null ? {} : { beforeHash }
6628
6672
  });
@@ -7485,7 +7529,7 @@ var SkillLibrary = class {
7485
7529
  if (o.ghostDir === true) await this.cleanupGhostDir(path);
7486
7530
  let result = o.result;
7487
7531
  if (o.write !== null && o.audit) {
7488
- await this.audit(o.audit.skillName, o.audit.action, o.audit.before, o.audit.after, o.audit.summary);
7532
+ await this.audit(o.audit.skillName, o.audit.action, o.audit.before, o.audit.after, o.audit.summary, o.audit.path);
7489
7533
  const retention = contentRetentionFeedback({
7490
7534
  name: o.audit.skillName,
7491
7535
  action: o.audit.action,
@@ -7810,18 +7854,20 @@ var SkillLibrary = class {
7810
7854
  * mutation ledger that points at it. The history failure is not silent — a deployment whose
7811
7855
  * history stopped growing is a degradation worth seeing once (the ledger keeps hashes either
7812
7856
  * way). */
7813
- async audit(skillName, action, before, after, summary) {
7857
+ async audit(skillName, action, before, after, summary, path) {
7814
7858
  const at = (/* @__PURE__ */ new Date()).toISOString();
7815
7859
  let versions = null;
7816
7860
  try {
7817
7861
  const keep = this.limits.versionKeep ?? 20;
7818
- versions = await recordVersions(this.root, this.io, {
7862
+ const input = {
7819
7863
  skillName,
7820
7864
  action,
7821
7865
  before,
7822
7866
  after,
7823
- at
7824
- }, keep);
7867
+ at,
7868
+ ...path === void 0 ? {} : { path }
7869
+ };
7870
+ versions = await recordVersions(this.root, this.io, input, keep);
7825
7871
  } catch (error) {
7826
7872
  if (!this.historyWarned) {
7827
7873
  this.historyWarned = true;
@@ -9230,7 +9276,8 @@ var SkillLibrary = class {
9230
9276
  action: "write_file",
9231
9277
  before: current,
9232
9278
  after: content,
9233
- summary: `wrote ${filePath}`
9279
+ summary: `wrote ${filePath}`,
9280
+ path: filePath
9234
9281
  },
9235
9282
  event: {
9236
9283
  action: "write_file",
@@ -9293,7 +9340,7 @@ var SkillLibrary = class {
9293
9340
  };
9294
9341
  } else if (verdict === "match") await this.io.remove(target);
9295
9342
  if (verdict !== "match") return anchorRefusalFile(name, filePath, verdict);
9296
- await this.audit(name, "remove_file", before, null, `removed ${filePath}`);
9343
+ await this.audit(name, "remove_file", before, null, `removed ${filePath}`, filePath);
9297
9344
  this.notifyMutation({
9298
9345
  action: "remove_file",
9299
9346
  name,
@@ -11159,4 +11206,4 @@ function sessionAudited(ctx, sessionId, sessionScoped) {
11159
11206
  return false;
11160
11207
  }
11161
11208
  //#endregion
11162
- 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, 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, 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 };
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 };
@@ -54,6 +54,13 @@ export interface SkillVersion {
54
54
  * (registry `skillVersionSummary`). Absent is a first-class state: the faces say so instead of
55
55
  * inventing a sentence, and a version recorded before the feature existed simply has none. */
56
56
  summary?: string;
57
+ /**
58
+ * Which support file these bytes came from, RELATIVE to the skill directory (`references/foo.md`),
59
+ * when this entry records a support-file write or remove. Absent is a first-class state: content
60
+ * versions never carry it, and every entry recorded before this field existed has none — the bytes
61
+ * in the blob store do not carry the name, so a legacy entry stays nameless rather than guessed.
62
+ */
63
+ path?: string;
57
64
  }
58
65
  /** One history write, carrying the content the caller already holds. */
59
66
  export interface VersionRecordInput {
@@ -66,6 +73,8 @@ export interface VersionRecordInput {
66
73
  at: string;
67
74
  /** The one-line summary of THIS write, or undefined when the deployment does not summarize. */
68
75
  summary?: string;
76
+ /** The support file this write touched, relative to the skill directory; undefined for content. */
77
+ path?: string;
69
78
  }
70
79
  /** The version numbers one write produced; a side with no content contributes nothing. */
71
80
  export interface RecordedVersions {
@@ -108,9 +117,31 @@ export type VersionTarget = 'content' | 'support' | 'other';
108
117
  * @returns the artifact class; `other` when the label does not say.
109
118
  */
110
119
  export declare function versionTarget(action: string): VersionTarget;
120
+ /**
121
+ * Which artifact one INDEX ENTRY holds.
122
+ *
123
+ * {@link versionTarget} reads the ACTION, which is enough for the entries a write mints under its own
124
+ * label and is NOT enough for a {@link BASELINE_ACTION}: a baseline minted for a support write holds
125
+ * that FILE's previous bytes while its action says only "this is what was there". Two facts recover
126
+ * the artifact:
127
+ *
128
+ * - `path` is written exactly when the bytes come from a support file, on BOTH entries one support
129
+ * write can mint, so it decides on its own;
130
+ * - an entry recorded before `path` existed has none, and the link is the evidence left: a support
131
+ * write names the content it replaced through `beforeHash`, so a baseline that a support write
132
+ * names as its predecessor holds that file's bytes.
133
+ *
134
+ * The inference runs only for a baseline. Every other entry keeps the action's verdict, which is also
135
+ * the fail-closed one for an action this module does not know.
136
+ * @param entry - one entry of a skill's index.
137
+ * @param index - the index the entry came from: the legacy link is only readable across the whole
138
+ * index. Omitting it answers from `path` and the action alone.
139
+ * @returns the artifact class; `other` when nothing attributes the bytes.
140
+ */
141
+ export declare function entryTarget(entry: SkillVersion, index?: readonly SkillVersion[]): VersionTarget;
111
142
  /** The versions of one skill, split by the artifact they hold. */
112
143
  export interface VersionGroups {
113
- /** The body's versions, plus predecessors whose artifact the index cannot name. */
144
+ /** The body's versions, plus predecessors no evidence attributes to a support file. */
114
145
  readonly content: SkillVersion[];
115
146
  /** Support-file versions: real history, but not restorable over SKILL.md. */
116
147
  readonly support: SkillVersion[];
@@ -121,11 +152,23 @@ export interface VersionGroups {
121
152
  * Both share ONE index, so a skill that ever wrote a support file has two chains and
122
153
  * {@link orderVersions} cannot account for every entry (it falls back to the stored order). Splitting
123
154
  * first lets each group rebuild its own order, and keeps the body's chain intact by leaving every
124
- * entry the index cannot classify in it — a `baseline` predecessor is usually the body's first link.
155
+ * entry whose artifact nothing attributes in it — a `baseline` predecessor is usually the body's
156
+ * first link, and only the support-file baselines {@link entryTarget} recovers leave it.
125
157
  * @param versions - the stored index, oldest first as recorded.
126
158
  * @returns the two groups, each in content order when its chain is complete.
127
159
  */
128
160
  export declare function partitionVersions(versions: readonly SkillVersion[]): VersionGroups;
161
+ /**
162
+ * When this skill's content last changed: the newest `at` across BOTH chains, or null when the index
163
+ * holds nothing.
164
+ *
165
+ * The stored array is APPEND order and two writers of one skill can interleave, so the answer is the
166
+ * maximum timestamp rather than the tail. Every `at` this family writes is the same ISO-8601 UTC
167
+ * form, so comparing the strings is comparing the instants.
168
+ * @param versions - every entry the index holds, in any order.
169
+ * @returns the newest timestamp, or null when there is none to report.
170
+ */
171
+ export declare function latestVersionAt(versions: readonly SkillVersion[]): string | null;
129
172
  /** What one index file's bytes said. `absent` (no file yet) and `unreadable` (bytes that cannot be
130
173
  * understood: malformed JSON, a foreign shape, an entry this reader would have to drop, or a writer
131
174
  * NEWER than this reader) are DIFFERENT facts — the recorder must never replace the second with an
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.13.6",
4
+ "version": "0.14.1",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },