@lmzhen/dsh-evolution-core 0.30.23 → 0.30.25

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
@@ -1214,7 +1214,7 @@ var UnitTransactions = class {
1214
1214
  this.now = options.now ?? (() => Date.now());
1215
1215
  }
1216
1216
  unitId(plan) {
1217
- return plan.runId + ":" + createHash("sha256").update(plan.pairKey).digest("hex").slice(0, 16);
1217
+ return plan.unitId ?? plan.runId + ":" + createHash("sha256").update(plan.pairKey).digest("hex").slice(0, 16);
1218
1218
  }
1219
1219
  async snapshot(plan, unitId, planDigest) {
1220
1220
  const targetBefore = await this.options.backend.readSkill(plan.target);
@@ -2968,6 +2968,43 @@ function shrinksOverLimit(next, current, limit) {
2968
2968
  if (current === null || current === void 0 || !exceedsContentLimit(current, limit)) return false;
2969
2969
  return skillMdOnDisk(next).length < skillMdOnDisk(current).length;
2970
2970
  }
2971
+ /**
2972
+ * Synthesize a missing SKILL.md header at the write boundary.
2973
+ *
2974
+ * A model-authored create/update whose body starts with `# Title` is valid Markdown but the
2975
+ * skill writer rejects it before any content check. Repair only the truly headerless shape: an
2976
+ * existing fence is passed through byte-identical, even when it is malformed, so this helper
2977
+ * cannot mask a header error that the validator should report. The caller owns the audit notice.
2978
+ * @param content - the model-authored SKILL.md text.
2979
+ * @param name - the validated skill name used for the `name:` field.
2980
+ * @param description - optional description; otherwise derived from the first heading/prose.
2981
+ * @returns the write text and whether a header was synthesized.
2982
+ */
2983
+ function ensureSkillFrontmatter(content, name, description) {
2984
+ if (frontmatterBlock(content) !== null || content.trimStart().startsWith("---")) return {
2985
+ content,
2986
+ repaired: false
2987
+ };
2988
+ const body = content.replace(/^\uFEFF/, "").replace(/^(?:[ \t]*\r?\n)+/, "");
2989
+ const heading = /^#{1,6}\s+(.+?)\s*$/m.exec(body)?.[1];
2990
+ const firstLine = body.split(/\r?\n/).map((line) => line.trim()).find((line) => line !== "" && !line.startsWith("#")) ?? "";
2991
+ const source = (description?.trim() || heading || firstLine || name).replace(/\s+/g, " ").trim();
2992
+ const clipped = source.length > 58 ? source.slice(0, 57) + "…" : source;
2993
+ const summary = /[.。!?!?]$/.test(clipped) ? clipped : clipped + ".";
2994
+ const encoded = yamlPlainScalarNeedsQuotes(summary) ? JSON.stringify(summary) : summary;
2995
+ return {
2996
+ content: [
2997
+ "---",
2998
+ `name: ${name}`,
2999
+ `description: ${encoded}`,
3000
+ "version: 0.1.0",
3001
+ "author: Hermes",
3002
+ "---",
3003
+ ""
3004
+ ].join("\n") + "\n" + body,
3005
+ repaired: true
3006
+ };
3007
+ }
2971
3008
  function validateFrontmatter(content, expectedName, limits = DEFAULT_SKILL_LIMITS, current) {
2972
3009
  const parsed = parseFrontmatter(content);
2973
3010
  if (!parsed) return "SKILL.md 必须以 `---` 行开头,用另一个完全相同的 `---` 行结束 frontmatter(只容忍结尾的 `\\r`),并在其下包含正文。";
@@ -6493,7 +6530,8 @@ function runsFile(home) {
6493
6530
  const TERMINAL = new Set([
6494
6531
  "succeeded",
6495
6532
  "failed",
6496
- "cancelled"
6533
+ "cancelled",
6534
+ "interrupted"
6497
6535
  ]);
6498
6536
  /**
6499
6537
  * Parse an index body into records.
@@ -12250,6 +12288,7 @@ var SkillLibrary = class {
12250
12288
  return rollbackMessage(result.message, stuck);
12251
12289
  }
12252
12290
  }
12291
+ await this.foldArchivedUsage(sources, (/* @__PURE__ */ new Date()).toISOString());
12253
12292
  await plan.onPhase?.("sources-archived");
12254
12293
  await plan.onPhase?.("unit-written");
12255
12294
  return {
@@ -13953,6 +13992,22 @@ const PARAM_EXPOSURE = Object.freeze([
13953
13992
  values: "",
13954
13993
  card: "evolution-review"
13955
13994
  },
13995
+ {
13996
+ id: "reviewNotice",
13997
+ group: "review",
13998
+ tier: "E3",
13999
+ authority: "cordis",
14000
+ owner: "evolution-review",
14001
+ applies: "live",
14002
+ docAnchor: "PARAMETERS.md#review",
14003
+ summary: "Deliver result notices into the parent conversation.",
14004
+ label: "结果通知",
14005
+ hint: "关闭后检查结果不再写进对话;检查本身照常运行,结果留在审计记录里。",
14006
+ control: "switch",
14007
+ unit: "",
14008
+ values: "",
14009
+ card: "evolution-review"
14010
+ },
13956
14011
  {
13957
14012
  id: "reviewProvider",
13958
14013
  group: "review",
@@ -15827,4 +15882,4 @@ function isIgnorableEvent(event) {
15827
15882
  return classifySessionEvent(event) !== "model";
15828
15883
  }
15829
15884
  //#endregion
15830
- export { 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, DEDUP_MAX_PAIR_COMPARISONS, DEDUP_SIMILARITY_THRESHOLD, DEFAULT_ADMISSION, 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_PROBE_TIMEOUT_MS, 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_RUN_RECORDS, 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, DEFAULT_WRITE_CONFIRM_MODE, DEFAULT_WRITE_CONFIRM_TIMEOUT_SECONDS, DIAGNOSTICS_FACT_KEYS, DIAGNOSTICS_RUNTIME_KEYS, DIAGNOSTICS_VIEW_SCHEMA_VERSION, DISPATCH_EVENT_TYPES, DRIFT_MAX_LINE_CHARS, DRIFT_SIGNALS_VERSION, DRIFT_SIGNAL_NOUNS, DSH_AUTHORING_STANDARDS, ENTRY_DELIMITER, EVENT_ARCHIVE_PREFIX, EVENT_LOG_RETAIN_ARCHIVES, EVENT_LOG_ROTATE_AT, EVENT_LOG_VERSION, EVOLUTION_ERRORS, EVOLUTION_PRESET_IDS, EVOLUTION_WRITE_TOOLS, EvolutionGateSet, FAMILY_SESSION_TOOL_NAMES, FORBIDDEN_CONTROL_KEYS, FUZZY_MAX_PATTERN_CHARS, FUZZY_MAX_WORK, HEALTH_STAMP_RE, HISTORY_DIR, HISTORY_INDEX_VERSION, HOOK_LINE_RE, HOST_ROUTES, INSTANCE_KEYS, KEEP_LINE_RE, LONG_RUNS, LOW_QUALITY_THRESHOLD, MAINTAINER_PRESET_ID, MAINTAIN_OUTPUT_INSTRUCTION, MAINTAIN_PROMPT, MAX_DESCRIPTION_LENGTH, MAX_REQUEST_BODY_BYTES, 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, MODEL_SESSION_EVENT_TYPES as MODEL_SESSION_EVENTS, MODEL_SESSION_EVENT_TYPES, MUTATIONS_FILE_VERSION, MemoryStore, NAMESPACE_MIGRATIONS, 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, PLATFORM_LINE, PLATFORM_SERVICE_PROBES, 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, RESTRICTED_PRESET_DISPLAY, RESTRICTED_TOOLS_ROW_ID, RESTRICTOR_MODULE, RESTRUCTURE_TARGET_RE, RETENTION_FEEDBACK_KEEP_RATIO, RETENTION_FEEDBACK_MIN_CHARS, REVIEWER_PRESET_ID, RULES, RUNS_SCHEMA_VERSION, SKILLS_GUIDANCE, SKILLS_GUIDANCE_SECTION_ORDER, SKILL_ACTION_REQUIRED_FIELDS, SKILL_NAME_RE, SKILL_REVIEW_PLAN_PROMPT, SKILL_REVIEW_PROMPT, SNAPSHOT_EXTRA_NAME_RE, STORE_LEDGER, SUMMARY_DUPLICATE_HINT_THRESHOLD, SUPPORT_DIRS, SUPPORT_SPRAWL_FILES, SUPPRESSED_FILE_VERSION, SkillLibrary, TEXT_DIFF_MAX_CHARS, TEXT_DIFF_MAX_LINES, THREAT_EXEMPTION_HINT, TOKEN_ASCII_WEIGHT, TOKEN_CJK_WEIGHT, ToolDispatchNormalizer, ToolDispatchPayloadError, UNIT_JOURNAL_PHASES, UNIT_JOURNAL_SCHEMA_VERSION, UNIT_STORAGE_SCHEMA_VERSION, UNTRUSTED_LINE_BREAK, UNTRUSTED_LINE_MARK, UPSTREAM_LIMIT_CHARS_PER_TOKEN, UnitTransactions, VERSION_SUMMARY_MAX_CHARS, absentHostServices, acquireTreeWriteLock, admissionVerdict, advanceReview, affinity, ageCopyKey, allowRowCollisions, anchorVerdict, appendEvolutionEvent, applyCuratorLifecycleFields, applyCuratorMetaFields, applyNamespaceMigration, applyReferenceRewrite, asRecord, assertDispatchPayload, assertSkillsRootAliasRetired, assertUnitJournalTransition, assessStructureHealth, atomicWriteFiles, authoringFeedback, authorityFrom, backupsReachability, blobPath, bodyCost, buildCuratorRunReport, buildHealthBaseline, buildLearnPrompt, bumpPatch, bumpSupportRead, bumpUse, bumpView, callingScope, candidateSkills, canonicalWriteId, claimInstance, clampOnce, clampedNumber, classifyNamespaceMigration, classifySessionEvent, clearReviewChannel, collectReadSkillNames, computeDedupGroups, computeDriftSignals, computeLifecycleTransitions, computePrefixClusters, computeQualityScores, computeScopeView, contentHash, contentRetentionFeedback, countDispatches, countReferenceFiles, createGateSet, createSubagentChannel, daysSinceIso, declaredReportStamp, describeReferenceRewrite, diffFindings, dispatchKeyOf, dispatchStepOf, displayBodyOf, duplicateHeadings, elapsedSince, emptyRecord, entryTarget, errorText, evaluateThreat, eventsFile, evidenceKindIndex, evolutionActivityProjection, evolutionEventPayloadIssue, evolutionEvidenceProjection, evolutionHome, evolutionIoAdapter, evolutionReadsProjection, evolutionRoot, evolutionSignalsProjection, executeUnitUndo, filterUnreadSkillOps, findDriftSignal, foldCuratorFields, foldToolDispatches, foldTurnEvent, foldTurnEvents, foldUntrustedLines, frontmatterBlock, frontmatterCatalogInvalid, fuzzyPatch, getRecord, h2Sections, historyIndexFile, historyReachability, historyRoot, hostSurface, identity, idleDays, initialTurnFold, installEvolutionProjections, instanceClaimKey, instanceClaimedWriteSites, instanceHolder, isAbsent, isBookkeepingFrame, isCommittedWarning, isDeprecatedParamId, isFileShapedPath, isIgnorableEvent, isLandmark, isMissingPath, isPresent, isProcessAlive, isProgramToolName, isRecord, isReviewChannelSession, isSkillReadToolName, isSkillToolName, isUnknown, isUnreadWrite, json, landmarkVerdict, latestActivityAt, latestVersionAt, lifecycleCandidate, lintBody, lintSkill, listEventArchives, liveBool, liveEnum, liveNumber, liveString, loadMutations, loadSuppressedNames, loadUsage, loadVersionContent, loadVersions, makeSerialQueue, mapProbe, markAgentCreated, markReviewChannel, markerEntryName, memoryRoot, methodNotAllowed, missingSupportPointers, mutateUsage, mutationsFile, narrowNameMatches, nearDuplicateSummaries, newRunRegistry, newSkillLibrary, nextHistoryIndex, nodeEvolutionIo, normalizeFrontmatter, normalizeUsageRecord, normalizeVersionSummary, observeEvent, orderVersions, overlongLines, paramNamespace, paramRowId, paramSettingsId, parseCuratorNominations, parseEvolutionEvents, parseFrontmatter, parseHistoryIndex, partitionVersions, payloadText, persistedWriteSite, persistedWriteSites, pickWithPolicy, planNamespaceMigration, planReferenceRewrite, planRehoming, planUnitUndoAcross, policyStageLimits, probeAbsent, probeChannelState, probeList, probeMtime, probePresent, probeReason, probeText, probeUnknown, projectionText, protectedSkillNamesOf, readDispatchSignal, readEvolutionEvents, readEvolutionTimeline, readHistoryIndex, readJsonObject, readNumberParam, readParam, readTreeLock, readUnitEvidence, readUnitIndex, readUnitJournal, readUnitReceipt, readUnitSnapshot, readingStats, recordMutation, recordVersions, redactSecrets, referencedBlobs, registerHostRoutes, relatedSkillNames, releaseInstance, renameWithRetry, renderCuratorReportMarkdown, renderLongRunTable, reportTime, reportsReachability, reportsSweepLockTarget, resolveCitations, resolveExecOrigins, resolveOrigins, resolveParamId, resolveRootConfig, resolveSkillsRoot, resolveUnitMembers, resolveUnitMembersFromIndexes, restructureCandidates, retainEventArchives, retirementReport, reviewPrompt, revisionAnchor, revisionAnchorOf, revisionFingerprint, revisionSupportDigest, runWriteGates, runsFile, saveSuppressedNames, saveUsage, scanBodyHooks, scanContentThreats, scanMemoryThreats, scanThreats, scopeOfNearestManifest, scopedPackageName, scopedProbeReport, sessionAudited, sessionEvidenceIndex, sessionLastEventTime, sessionReadNames, sessionReadSkillNames, sessionSeesFamilyTools, sessionTurnSignals, skillLibraryUnitBackend, skillReadNameOf, skillRowCells, skillStateKey, skillWriteGateContext, skillsRoot, staleRouteStubs, subagentChannelState, supportFileReadOf, supportRefs, suppressedFile, sweepReports, sweepReviewChannelSessions, textDiffFacts, tokenLineFor, transactIo, transactTaskGuard, treeLockFile, trimPatternBoundaries, unhookedSupportPointers, unitEvidenceDigest, unitEvidencePath, unitIndexPath, unitJournalPath, unitJournalPhaseRank, unitMembersAreComplete, unitReceiptPath, unitSnapshotPath, unitSnapshotsDir, unitStorageKey, unwrapLive, updateSuppressedNames, upsertUnitIndex, usageFile, usageObserved, userSetKeys, validateFrontmatter, validateRestructureTarget, validateSupportPath, valueOr, verifyPromptBundle, versionActionKind, versionRowCells, versionSummaryPrompt, versionTarget, vocabulary, withTreeWrite, withTreeWriteLock, writeDurableTmp, writePathSymbols, writeUnitEvidence, writeUnitJournal, writeUnitReceipt, writeUnitSnapshot, yamlPlainScalarNeedsQuotes };
15885
+ export { 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, DEDUP_MAX_PAIR_COMPARISONS, DEDUP_SIMILARITY_THRESHOLD, DEFAULT_ADMISSION, 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_PROBE_TIMEOUT_MS, 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_RUN_RECORDS, 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, DEFAULT_WRITE_CONFIRM_MODE, DEFAULT_WRITE_CONFIRM_TIMEOUT_SECONDS, DIAGNOSTICS_FACT_KEYS, DIAGNOSTICS_RUNTIME_KEYS, DIAGNOSTICS_VIEW_SCHEMA_VERSION, DISPATCH_EVENT_TYPES, DRIFT_MAX_LINE_CHARS, DRIFT_SIGNALS_VERSION, DRIFT_SIGNAL_NOUNS, DSH_AUTHORING_STANDARDS, ENTRY_DELIMITER, EVENT_ARCHIVE_PREFIX, EVENT_LOG_RETAIN_ARCHIVES, EVENT_LOG_ROTATE_AT, EVENT_LOG_VERSION, EVOLUTION_ERRORS, EVOLUTION_PRESET_IDS, EVOLUTION_WRITE_TOOLS, EvolutionGateSet, FAMILY_SESSION_TOOL_NAMES, FORBIDDEN_CONTROL_KEYS, FUZZY_MAX_PATTERN_CHARS, FUZZY_MAX_WORK, HEALTH_STAMP_RE, HISTORY_DIR, HISTORY_INDEX_VERSION, HOOK_LINE_RE, HOST_ROUTES, INSTANCE_KEYS, KEEP_LINE_RE, LONG_RUNS, LOW_QUALITY_THRESHOLD, MAINTAINER_PRESET_ID, MAINTAIN_OUTPUT_INSTRUCTION, MAINTAIN_PROMPT, MAX_DESCRIPTION_LENGTH, MAX_REQUEST_BODY_BYTES, 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, MODEL_SESSION_EVENT_TYPES as MODEL_SESSION_EVENTS, MODEL_SESSION_EVENT_TYPES, MUTATIONS_FILE_VERSION, MemoryStore, NAMESPACE_MIGRATIONS, 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, PLATFORM_LINE, PLATFORM_SERVICE_PROBES, 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, RESTRICTED_PRESET_DISPLAY, RESTRICTED_TOOLS_ROW_ID, RESTRICTOR_MODULE, RESTRUCTURE_TARGET_RE, RETENTION_FEEDBACK_KEEP_RATIO, RETENTION_FEEDBACK_MIN_CHARS, REVIEWER_PRESET_ID, RULES, RUNS_SCHEMA_VERSION, SKILLS_GUIDANCE, SKILLS_GUIDANCE_SECTION_ORDER, SKILL_ACTION_REQUIRED_FIELDS, SKILL_NAME_RE, SKILL_REVIEW_PLAN_PROMPT, SKILL_REVIEW_PROMPT, SNAPSHOT_EXTRA_NAME_RE, STORE_LEDGER, SUMMARY_DUPLICATE_HINT_THRESHOLD, SUPPORT_DIRS, SUPPORT_SPRAWL_FILES, SUPPRESSED_FILE_VERSION, SkillLibrary, TEXT_DIFF_MAX_CHARS, TEXT_DIFF_MAX_LINES, THREAT_EXEMPTION_HINT, TOKEN_ASCII_WEIGHT, TOKEN_CJK_WEIGHT, ToolDispatchNormalizer, ToolDispatchPayloadError, UNIT_JOURNAL_PHASES, UNIT_JOURNAL_SCHEMA_VERSION, UNIT_STORAGE_SCHEMA_VERSION, UNTRUSTED_LINE_BREAK, UNTRUSTED_LINE_MARK, UPSTREAM_LIMIT_CHARS_PER_TOKEN, UnitTransactions, VERSION_SUMMARY_MAX_CHARS, absentHostServices, acquireTreeWriteLock, admissionVerdict, advanceReview, affinity, ageCopyKey, allowRowCollisions, anchorVerdict, appendEvolutionEvent, applyCuratorLifecycleFields, applyCuratorMetaFields, applyNamespaceMigration, applyReferenceRewrite, asRecord, assertDispatchPayload, assertSkillsRootAliasRetired, assertUnitJournalTransition, assessStructureHealth, atomicWriteFiles, authoringFeedback, authorityFrom, backupsReachability, blobPath, bodyCost, buildCuratorRunReport, buildHealthBaseline, buildLearnPrompt, bumpPatch, bumpSupportRead, bumpUse, bumpView, callingScope, candidateSkills, canonicalWriteId, claimInstance, clampOnce, clampedNumber, classifyNamespaceMigration, classifySessionEvent, clearReviewChannel, collectReadSkillNames, computeDedupGroups, computeDriftSignals, computeLifecycleTransitions, computePrefixClusters, computeQualityScores, computeScopeView, contentHash, contentRetentionFeedback, countDispatches, countReferenceFiles, createGateSet, createSubagentChannel, daysSinceIso, declaredReportStamp, describeReferenceRewrite, diffFindings, dispatchKeyOf, dispatchStepOf, displayBodyOf, duplicateHeadings, elapsedSince, emptyRecord, ensureSkillFrontmatter, entryTarget, errorText, evaluateThreat, eventsFile, evidenceKindIndex, evolutionActivityProjection, evolutionEventPayloadIssue, evolutionEvidenceProjection, evolutionHome, evolutionIoAdapter, evolutionReadsProjection, evolutionRoot, evolutionSignalsProjection, executeUnitUndo, filterUnreadSkillOps, findDriftSignal, foldCuratorFields, foldToolDispatches, foldTurnEvent, foldTurnEvents, foldUntrustedLines, frontmatterBlock, frontmatterCatalogInvalid, fuzzyPatch, getRecord, h2Sections, historyIndexFile, historyReachability, historyRoot, hostSurface, identity, idleDays, initialTurnFold, installEvolutionProjections, instanceClaimKey, instanceClaimedWriteSites, instanceHolder, isAbsent, isBookkeepingFrame, isCommittedWarning, isDeprecatedParamId, isFileShapedPath, isIgnorableEvent, isLandmark, isMissingPath, isPresent, isProcessAlive, isProgramToolName, isRecord, isReviewChannelSession, isSkillReadToolName, isSkillToolName, isUnknown, isUnreadWrite, json, landmarkVerdict, latestActivityAt, latestVersionAt, lifecycleCandidate, lintBody, lintSkill, listEventArchives, liveBool, liveEnum, liveNumber, liveString, loadMutations, loadSuppressedNames, loadUsage, loadVersionContent, loadVersions, makeSerialQueue, mapProbe, markAgentCreated, markReviewChannel, markerEntryName, memoryRoot, methodNotAllowed, missingSupportPointers, mutateUsage, mutationsFile, narrowNameMatches, nearDuplicateSummaries, newRunRegistry, newSkillLibrary, nextHistoryIndex, nodeEvolutionIo, normalizeFrontmatter, normalizeUsageRecord, normalizeVersionSummary, observeEvent, orderVersions, overlongLines, paramNamespace, paramRowId, paramSettingsId, parseCuratorNominations, parseEvolutionEvents, parseFrontmatter, parseHistoryIndex, partitionVersions, payloadText, persistedWriteSite, persistedWriteSites, pickWithPolicy, planNamespaceMigration, planReferenceRewrite, planRehoming, planUnitUndoAcross, policyStageLimits, probeAbsent, probeChannelState, probeList, probeMtime, probePresent, probeReason, probeText, probeUnknown, projectionText, protectedSkillNamesOf, readDispatchSignal, readEvolutionEvents, readEvolutionTimeline, readHistoryIndex, readJsonObject, readNumberParam, readParam, readTreeLock, readUnitEvidence, readUnitIndex, readUnitJournal, readUnitReceipt, readUnitSnapshot, readingStats, recordMutation, recordVersions, redactSecrets, referencedBlobs, registerHostRoutes, relatedSkillNames, releaseInstance, renameWithRetry, renderCuratorReportMarkdown, renderLongRunTable, reportTime, reportsReachability, reportsSweepLockTarget, resolveCitations, resolveExecOrigins, resolveOrigins, resolveParamId, resolveRootConfig, resolveSkillsRoot, resolveUnitMembers, resolveUnitMembersFromIndexes, restructureCandidates, retainEventArchives, retirementReport, reviewPrompt, revisionAnchor, revisionAnchorOf, revisionFingerprint, revisionSupportDigest, runWriteGates, runsFile, saveSuppressedNames, saveUsage, scanBodyHooks, scanContentThreats, scanMemoryThreats, scanThreats, scopeOfNearestManifest, scopedPackageName, scopedProbeReport, sessionAudited, sessionEvidenceIndex, sessionLastEventTime, sessionReadNames, sessionReadSkillNames, sessionSeesFamilyTools, sessionTurnSignals, skillLibraryUnitBackend, skillReadNameOf, skillRowCells, skillStateKey, skillWriteGateContext, skillsRoot, staleRouteStubs, subagentChannelState, supportFileReadOf, supportRefs, suppressedFile, sweepReports, sweepReviewChannelSessions, textDiffFacts, tokenLineFor, transactIo, transactTaskGuard, treeLockFile, trimPatternBoundaries, unhookedSupportPointers, unitEvidenceDigest, unitEvidencePath, unitIndexPath, unitJournalPath, unitJournalPhaseRank, unitMembersAreComplete, unitReceiptPath, unitSnapshotPath, unitSnapshotsDir, unitStorageKey, unwrapLive, updateSuppressedNames, upsertUnitIndex, usageFile, usageObserved, userSetKeys, validateFrontmatter, validateRestructureTarget, validateSupportPath, valueOr, verifyPromptBundle, versionActionKind, versionRowCells, versionSummaryPrompt, versionTarget, vocabulary, withTreeWrite, withTreeWriteLock, writeDurableTmp, writePathSymbols, writeUnitEvidence, writeUnitJournal, writeUnitReceipt, writeUnitSnapshot, yamlPlainScalarNeedsQuotes };
@@ -153,6 +153,25 @@ export declare function exceedsContentLimit(content: string, limit: number): boo
153
153
  /** S1.2: the repair path — a write that makes an already-over-limit file smaller.
154
154
  * Only a NET SHRINK is exempt; an equal or larger write stays refused. */
155
155
  export declare function shrinksOverLimit(next: string, current: string | null | undefined, limit: number): boolean;
156
+ export interface FrontmatterRepair {
157
+ /** The text to write: unchanged when a header was already present. */
158
+ readonly content: string;
159
+ /** True only when this call synthesized the missing header. */
160
+ readonly repaired: boolean;
161
+ }
162
+ /**
163
+ * Synthesize a missing SKILL.md header at the write boundary.
164
+ *
165
+ * A model-authored create/update whose body starts with `# Title` is valid Markdown but the
166
+ * skill writer rejects it before any content check. Repair only the truly headerless shape: an
167
+ * existing fence is passed through byte-identical, even when it is malformed, so this helper
168
+ * cannot mask a header error that the validator should report. The caller owns the audit notice.
169
+ * @param content - the model-authored SKILL.md text.
170
+ * @param name - the validated skill name used for the `name:` field.
171
+ * @param description - optional description; otherwise derived from the first heading/prose.
172
+ * @returns the write text and whether a header was synthesized.
173
+ */
174
+ export declare function ensureSkillFrontmatter(content: string, name: string, description?: string): FrontmatterRepair;
156
175
  export declare function validateFrontmatter(content: string, expectedName?: string, limits?: SkillLimits,
157
176
  /** On-disk bytes, so a NET SHRINK of an over-limit file is allowed (S1.2). */
158
177
  current?: string | null): string | null;
@@ -555,6 +555,33 @@ export function shrinksOverLimit(next, current, limit) {
555
555
  return false;
556
556
  return skillMdOnDisk(next).length < skillMdOnDisk(current).length;
557
557
  }
558
+ /**
559
+ * Synthesize a missing SKILL.md header at the write boundary.
560
+ *
561
+ * A model-authored create/update whose body starts with `# Title` is valid Markdown but the
562
+ * skill writer rejects it before any content check. Repair only the truly headerless shape: an
563
+ * existing fence is passed through byte-identical, even when it is malformed, so this helper
564
+ * cannot mask a header error that the validator should report. The caller owns the audit notice.
565
+ * @param content - the model-authored SKILL.md text.
566
+ * @param name - the validated skill name used for the `name:` field.
567
+ * @param description - optional description; otherwise derived from the first heading/prose.
568
+ * @returns the write text and whether a header was synthesized.
569
+ */
570
+ export function ensureSkillFrontmatter(content, name, description) {
571
+ // A valid header is byte-identical; a malformed fence is left for the validator to name,
572
+ // never silently replaced (that would hide the error and could duplicate the fence).
573
+ if (frontmatterBlock(content) !== null || content.trimStart().startsWith('---'))
574
+ return { content, repaired: false };
575
+ const body = content.replace(/^\uFEFF/, '').replace(/^(?:[ \t]*\r?\n)+/, '');
576
+ const heading = /^#{1,6}\s+(.+?)\s*$/m.exec(body)?.[1];
577
+ const firstLine = body.split(/\r?\n/).map(line => line.trim()).find(line => line !== '' && !line.startsWith('#')) ?? '';
578
+ const source = (description?.trim() || heading || firstLine || name).replace(/\s+/g, ' ').trim();
579
+ const clipped = source.length > AUTHORING_DESCRIPTION_BAR - 2 ? source.slice(0, AUTHORING_DESCRIPTION_BAR - 3) + '…' : source;
580
+ const summary = /[.。!?!?]$/.test(clipped) ? clipped : clipped + '.';
581
+ const encoded = yamlPlainScalarNeedsQuotes(summary) ? JSON.stringify(summary) : summary;
582
+ const header = ['---', `name: ${name}`, `description: ${encoded}`, 'version: 0.1.0', 'author: Hermes', '---', ''].join('\n');
583
+ return { content: header + '\n' + body, repaired: true };
584
+ }
558
585
  export function validateFrontmatter(content, expectedName, limits = DEFAULT_SKILL_LIMITS,
559
586
  /** On-disk bytes, so a NET SHRINK of an over-limit file is allowed (S1.2). */
560
587
  current) {
@@ -107,6 +107,7 @@ export const PARAM_EXPOSURE = Object.freeze([
107
107
  { id: 'reviewEnabled', group: 'review', tier: 'E3', authority: 'cordis', owner: 'evolution-review', applies: 'live', docAnchor: 'PARAMETERS.md#review', summary: 'Master switch for the review plugin.', label: '启用自动检查', hint: '关闭后不再自动回顾会话。', control: 'switch', unit: '', values: '', card: 'evolution-review' },
108
108
  { id: 'reviewMode', group: 'review', tier: 'E3', authority: 'cordis', owner: 'evolution-review', applies: 'live', docAnchor: 'PARAMETERS.md#review', summary: 'Run the review in the parent session (inject) or on a subagent.', label: '运行位置', hint: '在哪里运行检查:在当前会话里/交给子代理。', control: 'select', unit: '', values: 'subagent|inject', valueLabels: '交给子代理|在当前会话里', card: 'evolution-review' },
109
109
  { id: 'reviewWakeInject', group: 'review', tier: 'E3', authority: 'cordis', owner: 'evolution-review', applies: 'live', docAnchor: 'PARAMETERS.md#review', summary: 'Deliver the deferred review as a waking follow-up message.', label: '延后结果发提醒', hint: '会话空闲时,把延后的检查结果作为一条提醒发给你。', control: 'switch', unit: '', values: '', card: 'evolution-review' },
110
+ { id: 'reviewNotice', group: 'review', tier: 'E3', authority: 'cordis', owner: 'evolution-review', applies: 'live', docAnchor: 'PARAMETERS.md#review', summary: 'Deliver result notices into the parent conversation.', label: '结果通知', hint: '关闭后检查结果不再写进对话;检查本身照常运行,结果留在审计记录里。', control: 'switch', unit: '', values: '', card: 'evolution-review' },
110
111
  { id: 'reviewProvider', group: 'review', tier: 'E2', authority: 'cordis', owner: 'evolution-review', applies: 'none', docAnchor: 'PARAMETERS.md#review', summary: 'LLM provider for review subagents (deployment identity).', why: 'identity' },
111
112
  { id: 'reviewTimeoutMs', group: 'review', tier: 'E2', authority: 'cordis', owner: 'evolution-review', applies: 'none', docAnchor: 'PARAMETERS.md#review', summary: 'Bound on one review subagent run and its write leg.', why: 'internal' },
112
113
  { id: 'reviewContextMessages', group: 'review', tier: 'E2', authority: 'cordis', owner: 'evolution-review', applies: 'none', docAnchor: 'PARAMETERS.md#review', summary: 'Messages of context handed to a review subagent.', why: 'internal' },
@@ -50,7 +50,7 @@ export interface RunProgress {
50
50
  readonly total: number;
51
51
  }
52
52
  /** The four terminal-or-live states of a run. */
53
- export type RunState = 'running' | 'succeeded' | 'failed' | 'cancelled';
53
+ export type RunState = 'running' | 'succeeded' | 'failed' | 'cancelled' | 'interrupted';
54
54
  /** One tracked run. `resultRef` is a path to the run's report, never its content. */
55
55
  export interface RunRecord {
56
56
  id: string;
@@ -104,7 +104,7 @@ export interface RunHandle {
104
104
  }
105
105
  /** How a run ended, as reported by its owner. */
106
106
  export interface RunOutcome {
107
- state: 'succeeded' | 'failed' | 'cancelled';
107
+ state: 'succeeded' | 'failed' | 'cancelled' | 'interrupted';
108
108
  resultRef?: string | undefined;
109
109
  failure?: string | undefined;
110
110
  /** @deprecated Legacy merge projection; read-only compatibility, never written. */
@@ -49,7 +49,7 @@ export const DEFAULT_RUN_RECORDS = 50;
49
49
  export function runsFile(home) {
50
50
  return join(home, 'runs.json');
51
51
  }
52
- const TERMINAL = new Set(['succeeded', 'failed', 'cancelled']);
52
+ const TERMINAL = new Set(['succeeded', 'failed', 'cancelled', 'interrupted']);
53
53
  /**
54
54
  * Parse an index body into records.
55
55
  *
@@ -818,6 +818,7 @@ export interface NewSkillLibraryOptions {
818
818
  export declare function newSkillLibrary(options: NewSkillLibraryOptions): SkillLibrary;
819
819
  export { DEFAULT_SKILL_LIMITS, DEFAULT_CITATION_POLICY, DEFAULT_REFERENCE_REWRITE_POLICY, DEFAULT_ARCHIVE_RETENTION_POLICY, DEFAULT_SUPPORT_FILE_CHAR_POLICY, POLICY_STAGE_DEFAULTS, policyStageLimits, } from './limits.ts';
820
820
  export type { SkillLimits, CitationPolicy, ReferenceRewritePolicy, ArchiveRetentionPolicy, SupportFileCharPolicy, PolicyStageFields, } from './limits.ts';
821
- export { authoringFeedback, frontmatterBlock, frontmatterCatalogInvalid, normalizeFrontmatter, parseFrontmatter, relatedSkillNames, validateFrontmatter, yamlPlainScalarNeedsQuotes } from './frontmatter.ts';
821
+ export { authoringFeedback, ensureSkillFrontmatter, frontmatterBlock, frontmatterCatalogInvalid, normalizeFrontmatter, parseFrontmatter, relatedSkillNames, validateFrontmatter, yamlPlainScalarNeedsQuotes } from './frontmatter.ts';
822
+ export type { FrontmatterRepair } from './frontmatter.ts';
822
823
  export type { AuthoringFeedback, Frontmatter, FrontmatterNormalizeResult, FrontmatterRead, PlatformStringSplit } from './frontmatter.ts';
823
824
  //# sourceMappingURL=skill-store.d.ts.map
@@ -2392,6 +2392,7 @@ export class SkillLibrary {
2392
2392
  return rollbackMessage(result.message, stuck);
2393
2393
  }
2394
2394
  }
2395
+ await this.foldArchivedUsage(sources, new Date().toISOString());
2395
2396
  await plan.onPhase?.('sources-archived');
2396
2397
  await plan.onPhase?.('unit-written');
2397
2398
  return { ok: true, message: `已把 ${sources.join(', ')} 合并进「${target}」。`, unitId, targetPath: dir, archived, mutations: 1 + sources.length };
@@ -4007,5 +4008,5 @@ export function newSkillLibrary(options) {
4007
4008
  [...(threatExemptLabels ?? [])], authority);
4008
4009
  }
4009
4010
  export { DEFAULT_SKILL_LIMITS, DEFAULT_CITATION_POLICY, DEFAULT_REFERENCE_REWRITE_POLICY, DEFAULT_ARCHIVE_RETENTION_POLICY, DEFAULT_SUPPORT_FILE_CHAR_POLICY, POLICY_STAGE_DEFAULTS, policyStageLimits, } from "./limits.js";
4010
- export { authoringFeedback, frontmatterBlock, frontmatterCatalogInvalid, normalizeFrontmatter, parseFrontmatter, relatedSkillNames, validateFrontmatter, yamlPlainScalarNeedsQuotes } from "./frontmatter.js";
4011
+ export { authoringFeedback, ensureSkillFrontmatter, frontmatterBlock, frontmatterCatalogInvalid, normalizeFrontmatter, parseFrontmatter, relatedSkillNames, validateFrontmatter, yamlPlainScalarNeedsQuotes } from "./frontmatter.js";
4011
4012
  //# sourceMappingURL=skill-store.js.map
@@ -43,7 +43,9 @@ export class UnitTransactions {
43
43
  this.now = options.now ?? (() => Date.now());
44
44
  }
45
45
  unitId(plan) {
46
- return plan.runId + ":" + createHash("sha256").update(plan.pairKey).digest("hex").slice(0, 16);
46
+ // DEC-D5: the caller may provide the unitId and still get idempotent prepare/commit.
47
+ // Deriving one remains the fallback for callers that do not.
48
+ return plan.unitId ?? plan.runId + ":" + createHash("sha256").update(plan.pairKey).digest("hex").slice(0, 16);
47
49
  }
48
50
  async snapshot(plan, unitId, planDigest) {
49
51
  const targetBefore = await this.options.backend.readSkill(plan.target);
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.30.23",
4
+ "version": "0.30.25",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },
@@ -181,15 +181,6 @@
181
181
  "state": [],
182
182
  "note": "The merge rows and their persisted round-one decisions. One transaction per mutation; reads stay pure projections."
183
183
  },
184
- {
185
- "id": "merge-gate-cache",
186
- "path": "<evolutionHome>/merge/gate-cache.json",
187
- "writer": "evolution-merge/src/gate-cache.ts",
188
- "serializedBy": "transact",
189
- "marker": "transactIo(io, gateCachePath(home)",
190
- "state": [],
191
- "note": "The L0-L2 gate cache. A cache is still a durable write and goes through the same transaction seam."
192
- },
193
184
  {
194
185
  "id": "reports-retention-lock",
195
186
  "path": "<evolutionHome>/reports/.retention",