dsh-mnemon-source-skills 0.5.8 → 0.5.9
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/client.js +33 -13
- package/lib/contracts.d.ts +17 -2
- package/lib/index.js +103 -23
- package/lib/types/client/api.d.ts +2 -0
- package/lib/types/contracts.d.ts +16 -1
- package/package.json +2 -2
- package/presentation/locales.json +6 -2
package/lib/client.js
CHANGED
|
@@ -317,7 +317,9 @@ window.__ModuleLoader__.load({
|
|
|
317
317
|
"evolution.noAgent": "当前没有可用的任务 Agent",
|
|
318
318
|
"evolution.drafting": "正在生成草案",
|
|
319
319
|
"evolution.draftFailed": "草案生成失败:{error}",
|
|
320
|
-
"evolution.skillGone": "
|
|
320
|
+
"evolution.skillGone": "原技能文件已删除、移动或无法读取。请恢复文件,或在新位置打开技能并重新生成草案。",
|
|
321
|
+
"evolution.originUnavailable": "旧记录未可靠保存原工作区。请切换到原工作区,在技能页打开该技能并重新生成草案;现有草案和证据会保留。",
|
|
322
|
+
"evolution.currentSkill": "当前技能文件",
|
|
321
323
|
"evolution.skillChanged": "技能在建议之后被改过,生成草案前会以当前版本为准。",
|
|
322
324
|
"evolution.adopted": "已采纳",
|
|
323
325
|
"evolution.openSkill": "查看技能",
|
|
@@ -671,7 +673,9 @@ window.__ModuleLoader__.load({
|
|
|
671
673
|
"evolution.noAgent": "No task Agent is available",
|
|
672
674
|
"evolution.drafting": "Drafting",
|
|
673
675
|
"evolution.draftFailed": "Drafting failed: {error}",
|
|
674
|
-
"evolution.skillGone": "
|
|
676
|
+
"evolution.skillGone": "The original skill file was deleted, moved, or cannot be read. Restore it or open the skill at its new location and generate a new draft.",
|
|
677
|
+
"evolution.originUnavailable": "The original workspace was not recorded reliably. Select its original workspace, open the skill on the Skills page and generate a new draft; the existing draft and evidence are kept.",
|
|
678
|
+
"evolution.currentSkill": "Current skill file",
|
|
675
679
|
"evolution.skillChanged": "The skill changed after this suggestion; the draft starts from its current version.",
|
|
676
680
|
"evolution.adopted": "Adopted",
|
|
677
681
|
"evolution.openSkill": "Open skill",
|
|
@@ -3748,7 +3752,7 @@ window.__ModuleLoader__.load({
|
|
|
3748
3752
|
className: css.skKicker,
|
|
3749
3753
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ActionTag, { action: suggestion.action }), suggestion.status !== "pending" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(StatusTag, { status: suggestion.status })]
|
|
3750
3754
|
}),
|
|
3751
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", { children: view.skill === void 0 ? suggestion.skillName : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
3755
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", { children: view.skill === void 0 || view.skillInCatalog === false ? suggestion.skillName : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
3752
3756
|
type: "button",
|
|
3753
3757
|
className: css.skTitleLink,
|
|
3754
3758
|
onClick: () => context.navigate({
|
|
@@ -3811,7 +3815,7 @@ window.__ModuleLoader__.load({
|
|
|
3811
3815
|
suggestion.rationale !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Clamp, { text: suggestion.rationale }),
|
|
3812
3816
|
suggestion.action === "update" && view.skill === void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
3813
3817
|
className: css.skWarn,
|
|
3814
|
-
children: t("evolution.skillGone")
|
|
3818
|
+
children: t(view.resolution === "origin-unavailable" ? "evolution.originUnavailable" : "evolution.skillGone")
|
|
3815
3819
|
}),
|
|
3816
3820
|
suggestion.action === "update" && view.skill !== void 0 && !view.hashCurrent && suggestion.status === "pending" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
3817
3821
|
className: css.skWarn,
|
|
@@ -3832,7 +3836,7 @@ window.__ModuleLoader__.load({
|
|
|
3832
3836
|
children: [
|
|
3833
3837
|
t("evolution.adopted"),
|
|
3834
3838
|
" ",
|
|
3835
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
3839
|
+
view.skillInCatalog !== false && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
3836
3840
|
type: "button",
|
|
3837
3841
|
className: css.skLink,
|
|
3838
3842
|
onClick: () => context.navigate({
|
|
@@ -3843,9 +3847,16 @@ window.__ModuleLoader__.load({
|
|
|
3843
3847
|
})
|
|
3844
3848
|
]
|
|
3845
3849
|
}),
|
|
3846
|
-
/* @__PURE__ */ (0, react_jsx_runtime.
|
|
3850
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3847
3851
|
className: css.skFolds,
|
|
3848
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.
|
|
3852
|
+
children: [view.skill !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Fold, {
|
|
3853
|
+
title: t("evolution.currentSkill"),
|
|
3854
|
+
meta: t(`root.${view.skill.root}`),
|
|
3855
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
3856
|
+
className: css.skMuted,
|
|
3857
|
+
children: view.skill.path
|
|
3858
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SkillMarkdown, { body: view.skill.body })]
|
|
3859
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Fold, {
|
|
3849
3860
|
title: t("evolution.evidence"),
|
|
3850
3861
|
meta: t("evolution.evidenceMeta", {
|
|
3851
3862
|
conversations: references.length,
|
|
@@ -3884,7 +3895,7 @@ window.__ModuleLoader__.load({
|
|
|
3884
3895
|
})]
|
|
3885
3896
|
}, index);
|
|
3886
3897
|
})
|
|
3887
|
-
})
|
|
3898
|
+
})]
|
|
3888
3899
|
})
|
|
3889
3900
|
]
|
|
3890
3901
|
});
|
|
@@ -3986,16 +3997,21 @@ window.__ModuleLoader__.load({
|
|
|
3986
3997
|
});
|
|
3987
3998
|
const started = await context.client.backtest({
|
|
3988
3999
|
skillName: draft.skillName,
|
|
3989
|
-
target: {
|
|
4000
|
+
target: {
|
|
4001
|
+
kind: draft.action === "update" ? "current" : "none",
|
|
4002
|
+
...draft.action === "update" ? { draftId: draft.id } : {}
|
|
4003
|
+
}
|
|
3990
4004
|
});
|
|
3991
4005
|
await context.client.linkRun(draft.id, started.runId);
|
|
3992
4006
|
});
|
|
3993
4007
|
const redraft = (note) => act(() => context.client.generateDraft({
|
|
3994
|
-
|
|
4008
|
+
draftId: draft.id,
|
|
4009
|
+
...draft.suggestionId === void 0 ? {} : { suggestionId: draft.suggestionId },
|
|
3995
4010
|
guidance: note,
|
|
3996
4011
|
...route
|
|
3997
4012
|
}), () => setRedrafting(null));
|
|
3998
4013
|
const ready = draft.status === "ready";
|
|
4014
|
+
const originalAvailable = draft.action !== "update" || view.base !== void 0;
|
|
3999
4015
|
const progress = (run) => run === void 0 ? 0 : run.progress.done;
|
|
4000
4016
|
const total = (candidate?.progress.total ?? 0) + (baseline?.progress.total ?? 0);
|
|
4001
4017
|
const results = /* @__PURE__ */ new Map();
|
|
@@ -4029,7 +4045,7 @@ window.__ModuleLoader__.load({
|
|
|
4029
4045
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
4030
4046
|
variant: "primary",
|
|
4031
4047
|
size: "sm",
|
|
4032
|
-
disabled: !context.writable || busy || editing !== null || running,
|
|
4048
|
+
disabled: !context.writable || busy || editing !== null || running || !originalAvailable,
|
|
4033
4049
|
onClick: () => regressed ? setConfirmAdopt(true) : void adopt(),
|
|
4034
4050
|
children: t("draft.adopt")
|
|
4035
4051
|
}),
|
|
@@ -4047,13 +4063,17 @@ window.__ModuleLoader__.load({
|
|
|
4047
4063
|
items: [{
|
|
4048
4064
|
id: "edit",
|
|
4049
4065
|
label: t("draft.edit")
|
|
4050
|
-
}, ...context.client.canAssist("skill-draft") ? [{
|
|
4066
|
+
}, ...originalAvailable && context.client.canAssist("skill-draft") ? [{
|
|
4051
4067
|
id: "redraft",
|
|
4052
4068
|
label: t("draft.redraft")
|
|
4053
4069
|
}] : []]
|
|
4054
4070
|
})
|
|
4055
4071
|
] })]
|
|
4056
4072
|
}),
|
|
4073
|
+
!originalAvailable && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
4074
|
+
className: css.skWarn,
|
|
4075
|
+
children: t(view.resolution === "origin-unavailable" ? "evolution.originUnavailable" : "evolution.skillGone")
|
|
4076
|
+
}),
|
|
4057
4077
|
draft.notes !== "" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Clamp, { text: draft.notes }),
|
|
4058
4078
|
draft.changes.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(MoreList, {
|
|
4059
4079
|
items: draft.changes,
|
|
@@ -4089,7 +4109,7 @@ window.__ModuleLoader__.load({
|
|
|
4089
4109
|
}), !running && (cases ?? 0) > 0 && context.client.canAssist("skill-backtest") && ready && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
4090
4110
|
variant: "ghost",
|
|
4091
4111
|
size: "sm",
|
|
4092
|
-
disabled: !context.writable || busy,
|
|
4112
|
+
disabled: !context.writable || busy || !originalAvailable,
|
|
4093
4113
|
onClick: () => void backtest(),
|
|
4094
4114
|
children: view.runs.length === 0 ? t("draft.runBacktest") : t("draft.rerun")
|
|
4095
4115
|
})]
|
package/lib/contracts.d.ts
CHANGED
|
@@ -163,6 +163,13 @@ interface EvidenceReference {
|
|
|
163
163
|
}
|
|
164
164
|
type SuggestionStatus = 'pending' | 'drafting' | 'review' | 'adopted' | 'dismissed' | 'expired' | 'invalidated';
|
|
165
165
|
declare const SUGGESTION_STATUSES: readonly SuggestionStatus[];
|
|
166
|
+
/** A file selected by the Source catalog, independent of the page's storage scope. */
|
|
167
|
+
interface SkillOrigin {
|
|
168
|
+
path: string;
|
|
169
|
+
/** The owning project root; absent for user skills. */
|
|
170
|
+
workspace?: string;
|
|
171
|
+
}
|
|
172
|
+
type SkillResolution = 'available' | 'missing' | 'origin-unavailable';
|
|
166
173
|
interface SkillSuggestion {
|
|
167
174
|
id: string;
|
|
168
175
|
skillName: string;
|
|
@@ -177,6 +184,8 @@ interface SkillSuggestion {
|
|
|
177
184
|
/** For `update`: the SKILL.md the reviewer read, so a later edit invalidates it. */
|
|
178
185
|
skillKey?: string;
|
|
179
186
|
skillFileHash?: string;
|
|
187
|
+
/** Absent on legacy records; never supplied by the model. */
|
|
188
|
+
origin?: SkillOrigin;
|
|
180
189
|
sourceSessionId?: string;
|
|
181
190
|
sourceSessionTitle?: string;
|
|
182
191
|
reviewId?: string;
|
|
@@ -196,6 +205,8 @@ interface SkillDraft {
|
|
|
196
205
|
/** For `update`, the SKILL.md hash the draft was written against. */
|
|
197
206
|
baseKey?: string;
|
|
198
207
|
baseHash?: string;
|
|
208
|
+
/** The file this update replaces; absent on legacy records. */
|
|
209
|
+
origin?: SkillOrigin;
|
|
199
210
|
/** For `create`, where adopting writes the new bundle. */
|
|
200
211
|
targetRoot?: SkillRootKind;
|
|
201
212
|
content: string;
|
|
@@ -467,7 +478,10 @@ interface SuggestionView {
|
|
|
467
478
|
suggestion: SkillSuggestion;
|
|
468
479
|
/** The loaded file is still the one the reviewer read. */
|
|
469
480
|
hashCurrent: boolean;
|
|
470
|
-
skill?:
|
|
481
|
+
skill?: SkillDocument;
|
|
482
|
+
resolution?: SkillResolution;
|
|
483
|
+
/** Whether the selected scope's catalog offers this same file for navigation. */
|
|
484
|
+
skillInCatalog?: boolean;
|
|
471
485
|
draft?: SkillDraft;
|
|
472
486
|
trajectories: TrajectorySummary[];
|
|
473
487
|
}
|
|
@@ -475,6 +489,7 @@ interface DraftView {
|
|
|
475
489
|
draft: SkillDraft;
|
|
476
490
|
/** The file the draft replaces, as it is now. */
|
|
477
491
|
base?: SkillDocument;
|
|
492
|
+
resolution?: SkillResolution;
|
|
478
493
|
runs: BacktestRun[];
|
|
479
494
|
}
|
|
480
495
|
/** A string, or the same text per language. */
|
|
@@ -623,4 +638,4 @@ interface MarketInstall {
|
|
|
623
638
|
installedAt: string;
|
|
624
639
|
}
|
|
625
640
|
//#endregion
|
|
626
|
-
export { BacktestRun, CaseResult, CatalogView, DEFAULT_SKILLS_POLICY, type DetectedSource, DraftPreferences, DraftPreferencesView, DraftStatus, DraftView, EVOLUTION_SIGNALS, EvalCase, EvalCheck, EvidencePack, EvidenceReference, EvolutionSignal, LocalizedText, MarketAudit, MarketEntry, MarketInstall, MarketInstallState, MarketItem, MarketPreview, MarketRegistry, MarketRegistryFile, MarketSearchResult, MarketSource, type MarketSourceKind, MarketView, ModelRoute, ReviewLogEntry, ReviewRecordInput, ReviewRecordResult, ReviewScore, RunStatus, RunTarget, RunTargetKind, SKILL_ROOT_KINDS, SKILL_ROOT_RANK, SUGGESTION_STATUSES, SkillCatalog, SkillDocument, SkillDraft, SkillInvocation, SkillProblem, SkillRoot, SkillRootKind, SkillSuggestion, SkillSummary, SkillVersion, SkillVersionReason, SkillsOverview, SkillsPolicy, SuggestionStatus, SuggestionView, Trajectory, TrajectoryAnnotation, TrajectoryStats, TrajectoryStep, TrajectoryStepKind, TrajectorySummary, TrashEntry, TrashRestoreInput, TrashRestorePreview };
|
|
641
|
+
export { BacktestRun, CaseResult, CatalogView, DEFAULT_SKILLS_POLICY, type DetectedSource, DraftPreferences, DraftPreferencesView, DraftStatus, DraftView, EVOLUTION_SIGNALS, EvalCase, EvalCheck, EvidencePack, EvidenceReference, EvolutionSignal, LocalizedText, MarketAudit, MarketEntry, MarketInstall, MarketInstallState, MarketItem, MarketPreview, MarketRegistry, MarketRegistryFile, MarketSearchResult, MarketSource, type MarketSourceKind, MarketView, ModelRoute, ReviewLogEntry, ReviewRecordInput, ReviewRecordResult, ReviewScore, RunStatus, RunTarget, RunTargetKind, SKILL_ROOT_KINDS, SKILL_ROOT_RANK, SUGGESTION_STATUSES, SkillCatalog, SkillDocument, SkillDraft, SkillInvocation, SkillOrigin, SkillProblem, SkillResolution, SkillRoot, SkillRootKind, SkillSuggestion, SkillSummary, SkillVersion, SkillVersionReason, SkillsOverview, SkillsPolicy, SuggestionStatus, SuggestionView, Trajectory, TrajectoryAnnotation, TrajectoryStats, TrajectoryStep, TrajectoryStepKind, TrajectorySummary, TrashEntry, TrashRestoreInput, TrashRestorePreview };
|
package/lib/index.js
CHANGED
|
@@ -368,6 +368,33 @@ function rootPath(catalog, kind) {
|
|
|
368
368
|
if (root === void 0) throw new Error(kind.startsWith("project") ? "project skill roots need a selected workspace" : "unknown skill root: " + kind);
|
|
369
369
|
return root.path;
|
|
370
370
|
}
|
|
371
|
+
//#endregion
|
|
372
|
+
//#region src/identity.ts
|
|
373
|
+
function skillOrigin(catalog, skill) {
|
|
374
|
+
return {
|
|
375
|
+
path: skill.path,
|
|
376
|
+
...skill.root.startsWith("project-") ? { workspace: catalog.projectRoot } : {}
|
|
377
|
+
};
|
|
378
|
+
}
|
|
379
|
+
function validOrigin(key, origin) {
|
|
380
|
+
return origin !== null && typeof origin === "object" && typeof origin.path === "string" && isAbsolute(origin.path) && (key.startsWith("project-") ? typeof origin.workspace === "string" && isAbsolute(origin.workspace) : origin.workspace === void 0);
|
|
381
|
+
}
|
|
382
|
+
/** Old reviews kept their cwd in the cited trajectory, even before origins existed. */
|
|
383
|
+
function legacySuggestionWorkspace(ledger, suggestion) {
|
|
384
|
+
if (!suggestion.skillKey?.startsWith("project-")) return void 0;
|
|
385
|
+
const cited = new Set(suggestion.evidence.map((reference) => reference.trajectoryId));
|
|
386
|
+
const trajectories = ledger.trajectories.filter((trajectory) => cited.has(trajectory.id) && (suggestion.reviewId === void 0 || trajectory.reviewId === suggestion.reviewId));
|
|
387
|
+
if (suggestion.reviewId === void 0 && trajectories.length !== cited.size) return void 0;
|
|
388
|
+
if (trajectories.length === 0 || trajectories.some((trajectory) => typeof trajectory.workspace !== "string" || !isAbsolute(trajectory.workspace))) return void 0;
|
|
389
|
+
const roots = new Set(trajectories.map((trajectory) => projectRoot(trajectory.workspace)));
|
|
390
|
+
return roots.size === 1 ? [...roots][0] : void 0;
|
|
391
|
+
}
|
|
392
|
+
/** A name alone, or identical contents in another project, is not an identity. */
|
|
393
|
+
function sameSuggestionSkill(ledger, suggestion, catalog, skill) {
|
|
394
|
+
if (suggestion.skillKey !== skill.key) return false;
|
|
395
|
+
if (suggestion.origin !== void 0) return validOrigin(skill.key, suggestion.origin) && resolve(suggestion.origin.path) === resolve(skill.path) && (!skill.root.startsWith("project-") || resolve(suggestion.origin.workspace) === catalog.projectRoot);
|
|
396
|
+
return !skill.root.startsWith("project-") || legacySuggestionWorkspace(ledger, suggestion) === catalog.projectRoot;
|
|
397
|
+
}
|
|
371
398
|
function emptyLedger() {
|
|
372
399
|
return {
|
|
373
400
|
version: 1,
|
|
@@ -953,7 +980,9 @@ function admitReview(context, input) {
|
|
|
953
980
|
});
|
|
954
981
|
continue;
|
|
955
982
|
}
|
|
956
|
-
|
|
983
|
+
const skill = activeSkill(catalog, proposal.skillName);
|
|
984
|
+
const sameSkill = (suggestion) => suggestion.skillName === proposal.skillName && suggestion.action === proposal.action && (skill === void 0 || sameSuggestionSkill(ledger, suggestion, catalog, skill));
|
|
985
|
+
if (ledger.suggestions.find((suggestion) => sameSkill(suggestion) && suggestion.status === "dismissed" && suggestion.sourceSessionId === input.review.sessionId && now.getTime() - Date.parse(suggestion.updatedAt) < DISMISSED_COOLDOWN_MS) !== void 0) {
|
|
957
986
|
skipped.push({
|
|
958
987
|
skillName: proposal.skillName,
|
|
959
988
|
action: proposal.action,
|
|
@@ -961,8 +990,7 @@ function admitReview(context, input) {
|
|
|
961
990
|
});
|
|
962
991
|
continue;
|
|
963
992
|
}
|
|
964
|
-
const
|
|
965
|
-
const open = ledger.suggestions.find((suggestion) => suggestion.skillName === proposal.skillName && suggestion.action === proposal.action && OPEN_STATUSES.has(suggestion.status));
|
|
993
|
+
const open = ledger.suggestions.find((suggestion) => sameSkill(suggestion) && OPEN_STATUSES.has(suggestion.status));
|
|
966
994
|
if (open !== void 0) {
|
|
967
995
|
open.evidence = [...open.evidence, evidence].slice(-12);
|
|
968
996
|
open.signals = signals([...open.signals, ...proposal.signals]);
|
|
@@ -974,6 +1002,7 @@ function admitReview(context, input) {
|
|
|
974
1002
|
if (skill !== void 0) {
|
|
975
1003
|
open.skillKey = skill.key;
|
|
976
1004
|
open.skillFileHash = skill.hash;
|
|
1005
|
+
open.origin = skillOrigin(catalog, skill);
|
|
977
1006
|
}
|
|
978
1007
|
updated++;
|
|
979
1008
|
} else skipped.push({
|
|
@@ -997,7 +1026,8 @@ function admitReview(context, input) {
|
|
|
997
1026
|
evidence: [evidence],
|
|
998
1027
|
...skill === void 0 ? {} : {
|
|
999
1028
|
skillKey: skill.key,
|
|
1000
|
-
skillFileHash: skill.hash
|
|
1029
|
+
skillFileHash: skill.hash,
|
|
1030
|
+
origin: skillOrigin(catalog, skill)
|
|
1001
1031
|
},
|
|
1002
1032
|
sourceSessionId: input.review.sessionId,
|
|
1003
1033
|
...input.review.sessionTitle === void 0 ? {} : { sourceSessionTitle: input.review.sessionTitle },
|
|
@@ -3073,6 +3103,28 @@ var SkillsService = class {
|
|
|
3073
3103
|
catalog(workspace) {
|
|
3074
3104
|
return readCatalog(this.options(workspace));
|
|
3075
3105
|
}
|
|
3106
|
+
original(key, origin, legacyWorkspace) {
|
|
3107
|
+
if (key === void 0 || origin !== void 0 && !validOrigin(key, origin) || key.startsWith("project-") && origin === void 0 && legacyWorkspace === void 0) return { resolution: "origin-unavailable" };
|
|
3108
|
+
const catalog = this.catalog(origin?.workspace ?? legacyWorkspace);
|
|
3109
|
+
const skill = catalog.skills.find((candidate) => candidate.key === key && (origin === void 0 || resolve(candidate.path) === resolve(origin.path)));
|
|
3110
|
+
return skill === void 0 ? { resolution: "missing" } : {
|
|
3111
|
+
resolution: "available",
|
|
3112
|
+
skill,
|
|
3113
|
+
origin: skillOrigin(catalog, skill)
|
|
3114
|
+
};
|
|
3115
|
+
}
|
|
3116
|
+
suggestionOriginal(ledger, suggestion) {
|
|
3117
|
+
return this.original(suggestion.skillKey, suggestion.origin, suggestion.origin === void 0 ? legacySuggestionWorkspace(ledger, suggestion) : void 0);
|
|
3118
|
+
}
|
|
3119
|
+
draftOriginal(ledger, draft) {
|
|
3120
|
+
if (draft.origin !== void 0) return this.original(draft.baseKey, draft.origin);
|
|
3121
|
+
const suggestion = ledger.suggestions.find((candidate) => candidate.id === draft.suggestionId && candidate.skillKey === draft.baseKey);
|
|
3122
|
+
return suggestion === void 0 ? this.original(draft.baseKey, void 0) : this.suggestionOriginal(ledger, suggestion);
|
|
3123
|
+
}
|
|
3124
|
+
requireOriginal(original) {
|
|
3125
|
+
if (original.skill !== void 0) return original.skill;
|
|
3126
|
+
throw new Error(original.resolution === "origin-unavailable" ? "The original workspace was not recorded reliably. Open the skill in its original workspace and generate a new draft; the existing draft and evidence are kept." : "The original skill file was deleted, moved, or cannot be read. Restore it or open the skill at its new location and generate a new draft.");
|
|
3127
|
+
}
|
|
3076
3128
|
catalogView(workspace) {
|
|
3077
3129
|
const catalog = this.catalog(workspace);
|
|
3078
3130
|
const ledger = this.store.ledger();
|
|
@@ -3170,13 +3222,19 @@ var SkillsService = class {
|
|
|
3170
3222
|
expireSuggestions(ledger, this.clock());
|
|
3171
3223
|
const suggestion = ledger.suggestions.find((candidate) => candidate.id === id);
|
|
3172
3224
|
if (suggestion === void 0) throw new Error("suggestion not found: " + id);
|
|
3173
|
-
const
|
|
3225
|
+
const original = suggestion.action === "update" ? this.suggestionOriginal(ledger, suggestion) : void 0;
|
|
3226
|
+
const catalog = this.catalog(workspace);
|
|
3227
|
+
const skill = original === void 0 ? activeSkill(catalog, suggestion.skillName) : original.skill;
|
|
3174
3228
|
const draft = suggestion.draftId === void 0 ? void 0 : ledger.drafts.find((candidate) => candidate.id === suggestion.draftId);
|
|
3175
3229
|
const cited = new Set(suggestion.evidence.map((reference) => reference.trajectoryId));
|
|
3176
3230
|
return {
|
|
3177
3231
|
suggestion,
|
|
3178
3232
|
hashCurrent: suggestion.action === "create" ? skill === void 0 : skill !== void 0 && skill.hash === suggestion.skillFileHash,
|
|
3179
|
-
...
|
|
3233
|
+
...original === void 0 ? {} : { resolution: original.resolution },
|
|
3234
|
+
...skill === void 0 ? {} : {
|
|
3235
|
+
skill: readSkillDocument(skill),
|
|
3236
|
+
skillInCatalog: catalog.skills.some((candidate) => candidate.key === skill.key && candidate.path === skill.path)
|
|
3237
|
+
},
|
|
3180
3238
|
...draft === void 0 ? {} : { draft },
|
|
3181
3239
|
trajectories: ledger.trajectories.filter((entry) => cited.has(entry.id))
|
|
3182
3240
|
};
|
|
@@ -3205,16 +3263,19 @@ var SkillsService = class {
|
|
|
3205
3263
|
return staleRun(run, this.clock().getTime());
|
|
3206
3264
|
}
|
|
3207
3265
|
drafts(filter = {}) {
|
|
3208
|
-
|
|
3266
|
+
const ledger = this.store.ledger();
|
|
3267
|
+
return ledger.drafts.filter((draft) => (filter.suggestionId === void 0 || draft.suggestionId === filter.suggestionId) && (filter.skill === void 0 || draft.skillName === filter.skill) && (filter.path === void 0 || this.draftOriginal(ledger, draft).skill?.path === filter.path));
|
|
3209
3268
|
}
|
|
3210
|
-
draft(
|
|
3211
|
-
const
|
|
3269
|
+
draft(_workspace, id) {
|
|
3270
|
+
const ledger = this.store.ledger();
|
|
3271
|
+
const draft = ledger.drafts.find((candidate) => candidate.id === id);
|
|
3212
3272
|
if (draft === void 0) throw new Error("draft not found: " + id);
|
|
3213
|
-
const
|
|
3214
|
-
const base =
|
|
3273
|
+
const original = draft.action === "update" ? this.draftOriginal(ledger, draft) : void 0;
|
|
3274
|
+
const base = original?.skill;
|
|
3215
3275
|
const now = this.clock().getTime();
|
|
3216
3276
|
return {
|
|
3217
3277
|
draft,
|
|
3278
|
+
...original === void 0 ? {} : { resolution: original.resolution },
|
|
3218
3279
|
...base === void 0 ? {} : { base: readSkillDocument(base) },
|
|
3219
3280
|
runs: draft.runIds.flatMap((id) => {
|
|
3220
3281
|
const run = this.store.evals().runs.find((candidate) => candidate.id === id);
|
|
@@ -3231,11 +3292,14 @@ var SkillsService = class {
|
|
|
3231
3292
|
const ledger = this.store.ledger();
|
|
3232
3293
|
const evals = this.store.evals();
|
|
3233
3294
|
const catalog = this.catalog(workspace);
|
|
3295
|
+
const prior = input.draftId === void 0 ? void 0 : ledger.drafts.find((candidate) => candidate.id === input.draftId);
|
|
3296
|
+
if (input.draftId !== void 0 && prior === void 0) throw new Error("draft not found: " + input.draftId);
|
|
3297
|
+
if (prior !== void 0 && input.suggestionId !== void 0 && prior.suggestionId !== input.suggestionId) throw new Error("draft is for another suggestion");
|
|
3234
3298
|
const suggestion = input.suggestionId === void 0 ? void 0 : ledger.suggestions.find((candidate) => candidate.id === input.suggestionId);
|
|
3235
3299
|
if (input.suggestionId !== void 0 && suggestion === void 0) throw new Error("suggestion not found: " + input.suggestionId);
|
|
3236
|
-
const skillName = suggestion?.skillName ?? input.skill;
|
|
3300
|
+
const skillName = prior?.skillName ?? suggestion?.skillName ?? input.skill;
|
|
3237
3301
|
if (skillName === void 0 || !isSkillName(skillName)) throw new Error("a skill name or a suggestion is required");
|
|
3238
|
-
const loaded = activeSkill(catalog, skillName);
|
|
3302
|
+
const loaded = prior?.action === "update" ? this.requireOriginal(this.draftOriginal(ledger, prior)) : suggestion?.action === "update" ? this.requireOriginal(this.suggestionOriginal(ledger, suggestion)) : activeSkill(catalog, skillName);
|
|
3239
3303
|
const action = loaded === void 0 ? "create" : "update";
|
|
3240
3304
|
const references = suggestion?.evidence ?? ledger.trajectories.filter((entry) => entry.stats.skills.includes(skillName) || entry.suggestionIds.some((id) => ledger.suggestions.find((candidate) => candidate.id === id)?.skillName === skillName)).slice(0, 3).map((entry) => ({
|
|
3241
3305
|
trajectoryId: entry.id,
|
|
@@ -3273,7 +3337,7 @@ var SkillsService = class {
|
|
|
3273
3337
|
description: clip(skill.description, 200),
|
|
3274
3338
|
root: skill.root
|
|
3275
3339
|
})),
|
|
3276
|
-
drafts: ledger.drafts.filter((draft) => draft.skillName === skillName).slice(0, 3)
|
|
3340
|
+
drafts: ledger.drafts.filter((draft) => draft.skillName === skillName && (loaded === void 0 ? draft.action === "create" : this.draftOriginal(ledger, draft).skill?.path === loaded.path)).slice(0, 3)
|
|
3277
3341
|
};
|
|
3278
3342
|
}
|
|
3279
3343
|
/** Bump the ledger generation, so the revision moves with every write. */
|
|
@@ -3721,11 +3785,18 @@ var SkillsService = class {
|
|
|
3721
3785
|
return this.write(() => {
|
|
3722
3786
|
validateSkillContent(input.content, input.skillName);
|
|
3723
3787
|
const ledger = this.store.ledger();
|
|
3724
|
-
const
|
|
3788
|
+
const catalog = this.catalog(workspace);
|
|
3725
3789
|
const now = this.clock().toISOString();
|
|
3790
|
+
const prior = input.draftId === void 0 ? void 0 : ledger.drafts.find((candidate) => candidate.id === input.draftId);
|
|
3791
|
+
if (input.draftId !== void 0 && prior === void 0) throw new Error("draft not found: " + input.draftId);
|
|
3792
|
+
if (prior !== void 0 && (prior.skillName !== input.skillName || prior.suggestionId !== input.suggestionId)) throw new Error("draft is for another skill or suggestion");
|
|
3726
3793
|
const suggestion = input.suggestionId === void 0 ? void 0 : ledger.suggestions.find((candidate) => candidate.id === input.suggestionId);
|
|
3727
3794
|
if (input.suggestionId !== void 0 && suggestion === void 0) throw new Error("suggestion not found: " + input.suggestionId);
|
|
3728
|
-
|
|
3795
|
+
if (suggestion !== void 0 && suggestion.skillName !== input.skillName) throw new Error("suggestion is for another skill");
|
|
3796
|
+
const original = prior?.action === "update" ? this.draftOriginal(ledger, prior) : suggestion?.action === "update" ? this.suggestionOriginal(ledger, suggestion) : void 0;
|
|
3797
|
+
const loaded = original === void 0 ? activeSkill(catalog, input.skillName) : this.requireOriginal(original);
|
|
3798
|
+
const origin = loaded === void 0 ? void 0 : original?.origin ?? skillOrigin(catalog, loaded);
|
|
3799
|
+
for (const draft of ledger.drafts) if (draft.status === "ready" && draft.skillName === input.skillName && draft.suggestionId === input.suggestionId && (loaded === void 0 ? draft.action === "create" : this.draftOriginal(ledger, draft).skill?.path === loaded.path)) {
|
|
3729
3800
|
draft.status = "discarded";
|
|
3730
3801
|
draft.updatedAt = now;
|
|
3731
3802
|
}
|
|
@@ -3736,7 +3807,8 @@ var SkillsService = class {
|
|
|
3736
3807
|
action: loaded === void 0 ? "create" : "update",
|
|
3737
3808
|
...loaded === void 0 ? { targetRoot: input.targetRoot ?? suggestion?.targetRoot ?? DEFAULT_ROOT } : {
|
|
3738
3809
|
baseKey: loaded.key,
|
|
3739
|
-
baseHash: loaded.hash
|
|
3810
|
+
baseHash: loaded.hash,
|
|
3811
|
+
origin
|
|
3740
3812
|
},
|
|
3741
3813
|
content: input.content,
|
|
3742
3814
|
notes: clip(input.notes, 2e3),
|
|
@@ -3780,12 +3852,14 @@ var SkillsService = class {
|
|
|
3780
3852
|
const catalog = this.catalog(workspace);
|
|
3781
3853
|
let key;
|
|
3782
3854
|
let previous;
|
|
3855
|
+
let updated;
|
|
3783
3856
|
if (draft.action === "update") {
|
|
3784
|
-
const
|
|
3785
|
-
|
|
3857
|
+
const original = this.draftOriginal(ledger, draft);
|
|
3858
|
+
const base = this.requireOriginal(original);
|
|
3786
3859
|
previous = this.requireHash(base, draft.baseHash);
|
|
3787
3860
|
writeFileAtomic(base.path, draft.content);
|
|
3788
3861
|
key = base.key;
|
|
3862
|
+
updated = findSkill(this.catalog(original.origin?.workspace), key);
|
|
3789
3863
|
} else {
|
|
3790
3864
|
const root = input.root ?? draft.targetRoot ?? DEFAULT_ROOT;
|
|
3791
3865
|
if (activeSkill(catalog, draft.skillName) !== void 0) throw new Error(`${draft.skillName} exists now; draft it again as an update`);
|
|
@@ -3814,7 +3888,7 @@ var SkillsService = class {
|
|
|
3814
3888
|
}
|
|
3815
3889
|
this.store.saveLedger(ledger);
|
|
3816
3890
|
return {
|
|
3817
|
-
skill: findSkill(this.catalog(workspace), key),
|
|
3891
|
+
skill: updated ?? findSkill(this.catalog(workspace), key),
|
|
3818
3892
|
version
|
|
3819
3893
|
};
|
|
3820
3894
|
});
|
|
@@ -3899,7 +3973,9 @@ var SkillsService = class {
|
|
|
3899
3973
|
}
|
|
3900
3974
|
};
|
|
3901
3975
|
}
|
|
3902
|
-
const
|
|
3976
|
+
const draft = target.draftId === void 0 ? void 0 : this.store.ledger().drafts.find((candidate) => candidate.id === target.draftId && candidate.skillName === skillName);
|
|
3977
|
+
if (target.draftId !== void 0 && draft === void 0) throw new Error("draft not found for this skill");
|
|
3978
|
+
const loaded = draft === void 0 ? activeSkill(this.catalog(workspace), skillName) : this.requireOriginal(this.draftOriginal(this.store.ledger(), draft));
|
|
3903
3979
|
if (loaded === void 0) throw new Error(`${skillName} has no file to test; test a draft or no skill`);
|
|
3904
3980
|
const document = readSkillDocument(loaded);
|
|
3905
3981
|
return {
|
|
@@ -3907,7 +3983,8 @@ var SkillsService = class {
|
|
|
3907
3983
|
target: {
|
|
3908
3984
|
kind: "current",
|
|
3909
3985
|
skillKey: loaded.key,
|
|
3910
|
-
hash: document.hash
|
|
3986
|
+
hash: document.hash,
|
|
3987
|
+
...draft === void 0 ? {} : { draftId: draft.id }
|
|
3911
3988
|
}
|
|
3912
3989
|
};
|
|
3913
3990
|
}
|
|
@@ -4754,7 +4831,8 @@ function createSkillsMemorySource(config = {}) {
|
|
|
4754
4831
|
case "run": return service.run(memoryInputText(fields.id, "id", 100));
|
|
4755
4832
|
case "drafts": return service.drafts({
|
|
4756
4833
|
...optionalText(fields.suggestionId, "suggestionId", 100) === void 0 ? {} : { suggestionId: optionalText(fields.suggestionId, "suggestionId", 100) },
|
|
4757
|
-
...optionalText(fields.skill, "skill", 64) === void 0 ? {} : { skill: optionalText(fields.skill, "skill", 64) }
|
|
4834
|
+
...optionalText(fields.skill, "skill", 64) === void 0 ? {} : { skill: optionalText(fields.skill, "skill", 64) },
|
|
4835
|
+
...optionalText(fields.path, "path", 4096) === void 0 ? {} : { path: optionalText(fields.path, "path", 4096) }
|
|
4758
4836
|
});
|
|
4759
4837
|
case "draft": return service.draft(root, memoryInputText(fields.id, "id", 100));
|
|
4760
4838
|
case "draft-preferences": return service.draftPreferences();
|
|
@@ -4764,6 +4842,7 @@ function createSkillsMemorySource(config = {}) {
|
|
|
4764
4842
|
});
|
|
4765
4843
|
case "evidence-pack": return service.evidencePack(root, {
|
|
4766
4844
|
...optionalText(fields.suggestionId, "suggestionId", 100) === void 0 ? {} : { suggestionId: optionalText(fields.suggestionId, "suggestionId", 100) },
|
|
4845
|
+
...optionalText(fields.draftId, "draftId", 100) === void 0 ? {} : { draftId: optionalText(fields.draftId, "draftId", 100) },
|
|
4767
4846
|
...optionalText(fields.skill, "skill", 64) === void 0 ? {} : { skill: optionalText(fields.skill, "skill", 64) }
|
|
4768
4847
|
});
|
|
4769
4848
|
case "target-content": return service.targetContent(root, memoryInputText(fields.skillName, "skillName", 64), runTarget(fields.target));
|
|
@@ -4884,6 +4963,7 @@ function createSkillsMemorySource(config = {}) {
|
|
|
4884
4963
|
case "draft-record":
|
|
4885
4964
|
value = await service.recordDraft(root, {
|
|
4886
4965
|
...optionalText(fields.suggestionId, "suggestionId", 100) === void 0 ? {} : { suggestionId: optionalText(fields.suggestionId, "suggestionId", 100) },
|
|
4966
|
+
...optionalText(fields.draftId, "draftId", 100) === void 0 ? {} : { draftId: optionalText(fields.draftId, "draftId", 100) },
|
|
4887
4967
|
skillName: memoryInputText(fields.skillName, "skillName", 64),
|
|
4888
4968
|
content: typeof fields.content === "string" ? fields.content : "",
|
|
4889
4969
|
notes: typeof fields.notes === "string" ? fields.notes : "",
|
|
@@ -42,6 +42,7 @@ export interface SkillsPageClient {
|
|
|
42
42
|
}): Promise<ReviewLogEntry[]>;
|
|
43
43
|
evidencePack(input: {
|
|
44
44
|
suggestionId?: string;
|
|
45
|
+
draftId?: string;
|
|
45
46
|
skill?: string;
|
|
46
47
|
}): Promise<EvidencePack>;
|
|
47
48
|
createSkill(input: {
|
|
@@ -135,6 +136,7 @@ export interface SkillsPageClient {
|
|
|
135
136
|
canAssist(operation: 'skill-draft' | 'skill-backtest' | 'skill-derive-cases' | 'skill-review-now'): boolean;
|
|
136
137
|
generateDraft(input: {
|
|
137
138
|
suggestionId?: string;
|
|
139
|
+
draftId?: string;
|
|
138
140
|
skill?: string;
|
|
139
141
|
guidance?: string;
|
|
140
142
|
targetRoot?: SkillRootKind;
|
package/lib/types/contracts.d.ts
CHANGED
|
@@ -145,6 +145,13 @@ export interface EvidenceReference {
|
|
|
145
145
|
}
|
|
146
146
|
export type SuggestionStatus = 'pending' | 'drafting' | 'review' | 'adopted' | 'dismissed' | 'expired' | 'invalidated';
|
|
147
147
|
export declare const SUGGESTION_STATUSES: readonly SuggestionStatus[];
|
|
148
|
+
/** A file selected by the Source catalog, independent of the page's storage scope. */
|
|
149
|
+
export interface SkillOrigin {
|
|
150
|
+
path: string;
|
|
151
|
+
/** The owning project root; absent for user skills. */
|
|
152
|
+
workspace?: string;
|
|
153
|
+
}
|
|
154
|
+
export type SkillResolution = 'available' | 'missing' | 'origin-unavailable';
|
|
148
155
|
export interface SkillSuggestion {
|
|
149
156
|
id: string;
|
|
150
157
|
skillName: string;
|
|
@@ -159,6 +166,8 @@ export interface SkillSuggestion {
|
|
|
159
166
|
/** For `update`: the SKILL.md the reviewer read, so a later edit invalidates it. */
|
|
160
167
|
skillKey?: string;
|
|
161
168
|
skillFileHash?: string;
|
|
169
|
+
/** Absent on legacy records; never supplied by the model. */
|
|
170
|
+
origin?: SkillOrigin;
|
|
162
171
|
sourceSessionId?: string;
|
|
163
172
|
sourceSessionTitle?: string;
|
|
164
173
|
reviewId?: string;
|
|
@@ -178,6 +187,8 @@ export interface SkillDraft {
|
|
|
178
187
|
/** For `update`, the SKILL.md hash the draft was written against. */
|
|
179
188
|
baseKey?: string;
|
|
180
189
|
baseHash?: string;
|
|
190
|
+
/** The file this update replaces; absent on legacy records. */
|
|
191
|
+
origin?: SkillOrigin;
|
|
181
192
|
/** For `create`, where adopting writes the new bundle. */
|
|
182
193
|
targetRoot?: SkillRootKind;
|
|
183
194
|
content: string;
|
|
@@ -449,7 +460,10 @@ export interface SuggestionView {
|
|
|
449
460
|
suggestion: SkillSuggestion;
|
|
450
461
|
/** The loaded file is still the one the reviewer read. */
|
|
451
462
|
hashCurrent: boolean;
|
|
452
|
-
skill?:
|
|
463
|
+
skill?: SkillDocument;
|
|
464
|
+
resolution?: SkillResolution;
|
|
465
|
+
/** Whether the selected scope's catalog offers this same file for navigation. */
|
|
466
|
+
skillInCatalog?: boolean;
|
|
453
467
|
draft?: SkillDraft;
|
|
454
468
|
trajectories: TrajectorySummary[];
|
|
455
469
|
}
|
|
@@ -457,6 +471,7 @@ export interface DraftView {
|
|
|
457
471
|
draft: SkillDraft;
|
|
458
472
|
/** The file the draft replaces, as it is now. */
|
|
459
473
|
base?: SkillDocument;
|
|
474
|
+
resolution?: SkillResolution;
|
|
460
475
|
runs: BacktestRun[];
|
|
461
476
|
}
|
|
462
477
|
export type { DetectedSource, MarketSourceKind } from './source-kind.ts';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-mnemon-source-skills",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.9",
|
|
4
4
|
"description": "Skills Source for Composable View Memory: DSH skill management, evolution suggestions, evidence trajectories and eval sets.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -62,7 +62,7 @@
|
|
|
62
62
|
"@types/node": "^22.0.0",
|
|
63
63
|
"@types/react": "^18.3.0",
|
|
64
64
|
"@types/react-dom": "^18.3.0",
|
|
65
|
-
"dsh-mnemon": "^0.5.
|
|
65
|
+
"dsh-mnemon": "^0.5.42",
|
|
66
66
|
"jsdom": "^26.0.0",
|
|
67
67
|
"react": "^18.2.0",
|
|
68
68
|
"react-dom": "^18.2.0",
|
|
@@ -135,7 +135,9 @@
|
|
|
135
135
|
"evolution.noAgent": "当前没有可用的任务 Agent",
|
|
136
136
|
"evolution.drafting": "正在生成草案",
|
|
137
137
|
"evolution.draftFailed": "草案生成失败:{error}",
|
|
138
|
-
"evolution.skillGone": "
|
|
138
|
+
"evolution.skillGone": "原技能文件已删除、移动或无法读取。请恢复文件,或在新位置打开技能并重新生成草案。",
|
|
139
|
+
"evolution.originUnavailable": "旧记录未可靠保存原工作区。请切换到原工作区,在技能页打开该技能并重新生成草案;现有草案和证据会保留。",
|
|
140
|
+
"evolution.currentSkill": "当前技能文件",
|
|
139
141
|
"evolution.skillChanged": "技能在建议之后被改过,生成草案前会以当前版本为准。",
|
|
140
142
|
"evolution.adopted": "已采纳",
|
|
141
143
|
"evolution.openSkill": "查看技能",
|
|
@@ -489,7 +491,9 @@
|
|
|
489
491
|
"evolution.noAgent": "No task Agent is available",
|
|
490
492
|
"evolution.drafting": "Drafting",
|
|
491
493
|
"evolution.draftFailed": "Drafting failed: {error}",
|
|
492
|
-
"evolution.skillGone": "
|
|
494
|
+
"evolution.skillGone": "The original skill file was deleted, moved, or cannot be read. Restore it or open the skill at its new location and generate a new draft.",
|
|
495
|
+
"evolution.originUnavailable": "The original workspace was not recorded reliably. Select its original workspace, open the skill on the Skills page and generate a new draft; the existing draft and evidence are kept.",
|
|
496
|
+
"evolution.currentSkill": "Current skill file",
|
|
493
497
|
"evolution.skillChanged": "The skill changed after this suggestion; the draft starts from its current version.",
|
|
494
498
|
"evolution.adopted": "Adopted",
|
|
495
499
|
"evolution.openSkill": "Open skill",
|