dsh-mnemon-source-skills 0.5.7 → 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 +67 -15
- package/lib/contracts.d.ts +17 -2
- package/lib/index.js +129 -26
- 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 +16 -2
package/lib/client.js
CHANGED
|
@@ -194,6 +194,7 @@ window.__ModuleLoader__.load({
|
|
|
194
194
|
"tab.market": "市场",
|
|
195
195
|
"tab.trash": "回收站",
|
|
196
196
|
"common.loading": "加载中",
|
|
197
|
+
"common.retry": "重试",
|
|
197
198
|
"common.cancel": "取消",
|
|
198
199
|
"common.close": "关闭",
|
|
199
200
|
"common.delete": "删除",
|
|
@@ -316,7 +317,9 @@ window.__ModuleLoader__.load({
|
|
|
316
317
|
"evolution.noAgent": "当前没有可用的任务 Agent",
|
|
317
318
|
"evolution.drafting": "正在生成草案",
|
|
318
319
|
"evolution.draftFailed": "草案生成失败:{error}",
|
|
319
|
-
"evolution.skillGone": "
|
|
320
|
+
"evolution.skillGone": "原技能文件已删除、移动或无法读取。请恢复文件,或在新位置打开技能并重新生成草案。",
|
|
321
|
+
"evolution.originUnavailable": "旧记录未可靠保存原工作区。请切换到原工作区,在技能页打开该技能并重新生成草案;现有草案和证据会保留。",
|
|
322
|
+
"evolution.currentSkill": "当前技能文件",
|
|
320
323
|
"evolution.skillChanged": "技能在建议之后被改过,生成草案前会以当前版本为准。",
|
|
321
324
|
"evolution.adopted": "已采纳",
|
|
322
325
|
"evolution.openSkill": "查看技能",
|
|
@@ -526,6 +529,10 @@ window.__ModuleLoader__.load({
|
|
|
526
529
|
"evolution.deleteTitle": "删除这条建议?",
|
|
527
530
|
"evolution.deleteBody": "它生成的草案和证据引用会一起删掉,无法恢复。",
|
|
528
531
|
"evolution.deleted": "已删除",
|
|
532
|
+
"evolution.missing": "该建议已删除",
|
|
533
|
+
"evolution.missingBody": "可以在左侧选择其他建议,或返回记录查看原始内容。",
|
|
534
|
+
"evolution.loadFailed": "无法加载这条建议",
|
|
535
|
+
"evolution.loadFailedBody": "请重试,或在左侧选择其他建议。",
|
|
529
536
|
"tests.model": "全局模型",
|
|
530
537
|
"tests.modelCard": "所选回测模型",
|
|
531
538
|
"tests.modelAuto": "跟随默认"
|
|
@@ -543,6 +550,7 @@ window.__ModuleLoader__.load({
|
|
|
543
550
|
"tab.market": "Market",
|
|
544
551
|
"tab.trash": "Trash",
|
|
545
552
|
"common.loading": "Loading",
|
|
553
|
+
"common.retry": "Retry",
|
|
546
554
|
"common.cancel": "Cancel",
|
|
547
555
|
"common.close": "Close",
|
|
548
556
|
"common.delete": "Delete",
|
|
@@ -665,7 +673,9 @@ window.__ModuleLoader__.load({
|
|
|
665
673
|
"evolution.noAgent": "No task Agent is available",
|
|
666
674
|
"evolution.drafting": "Drafting",
|
|
667
675
|
"evolution.draftFailed": "Drafting failed: {error}",
|
|
668
|
-
"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",
|
|
669
679
|
"evolution.skillChanged": "The skill changed after this suggestion; the draft starts from its current version.",
|
|
670
680
|
"evolution.adopted": "Adopted",
|
|
671
681
|
"evolution.openSkill": "Open skill",
|
|
@@ -875,6 +885,10 @@ window.__ModuleLoader__.load({
|
|
|
875
885
|
"evolution.deleteTitle": "Delete this suggestion?",
|
|
876
886
|
"evolution.deleteBody": "Its draft and the evidence references it cites go with it, and this cannot be undone.",
|
|
877
887
|
"evolution.deleted": "Deleted",
|
|
888
|
+
"evolution.missing": "This suggestion has been deleted",
|
|
889
|
+
"evolution.missingBody": "Select another suggestion on the left, or return to Evidence to read the original record.",
|
|
890
|
+
"evolution.loadFailed": "Could not load this suggestion",
|
|
891
|
+
"evolution.loadFailedBody": "Retry, or select another suggestion on the left.",
|
|
878
892
|
"tests.model": "Global model",
|
|
879
893
|
"tests.modelCard": "Selected model",
|
|
880
894
|
"tests.modelAuto": "Follow default"
|
|
@@ -3661,11 +3675,14 @@ window.__ModuleLoader__.load({
|
|
|
3661
3675
|
model: props.model.model
|
|
3662
3676
|
};
|
|
3663
3677
|
const [view, setView] = (0, react.useState)(null);
|
|
3678
|
+
const [loadError, setLoadError] = (0, react.useState)(null);
|
|
3679
|
+
const [reload, setReload] = (0, react.useState)(0);
|
|
3664
3680
|
const [trajectories, setTrajectories] = (0, react.useState)(/* @__PURE__ */ new Map());
|
|
3665
3681
|
const [busy, setBusy] = (0, react.useState)(false);
|
|
3666
3682
|
const [deleting, setDeleting] = (0, react.useState)(false);
|
|
3667
3683
|
(0, react.useEffect)(() => {
|
|
3668
3684
|
let active = true;
|
|
3685
|
+
setLoadError(null);
|
|
3669
3686
|
context.client.suggestion(props.id).then(async (value) => {
|
|
3670
3687
|
if (!active) return;
|
|
3671
3688
|
setView(value);
|
|
@@ -3675,15 +3692,34 @@ window.__ModuleLoader__.load({
|
|
|
3675
3692
|
loaded.set(reference.trajectoryId, await context.client.trajectory(reference.trajectoryId).catch(() => null));
|
|
3676
3693
|
}
|
|
3677
3694
|
if (active) setTrajectories(loaded);
|
|
3678
|
-
}).catch(
|
|
3695
|
+
}).catch((error) => {
|
|
3696
|
+
if (!active) return;
|
|
3697
|
+
setView(null);
|
|
3698
|
+
if ((error instanceof Error ? error.message : String(error)) === "suggestion not found: " + props.id) setLoadError("missing");
|
|
3699
|
+
else {
|
|
3700
|
+
setLoadError("failed");
|
|
3701
|
+
context.fail(error);
|
|
3702
|
+
}
|
|
3703
|
+
});
|
|
3679
3704
|
return () => {
|
|
3680
3705
|
active = false;
|
|
3681
3706
|
};
|
|
3682
3707
|
}, [
|
|
3683
3708
|
context.client,
|
|
3684
3709
|
props.id,
|
|
3685
|
-
context.revision
|
|
3710
|
+
context.revision,
|
|
3711
|
+
reload
|
|
3686
3712
|
]);
|
|
3713
|
+
if (loadError !== null) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Empty, {
|
|
3714
|
+
glyph: "?",
|
|
3715
|
+
title: t(loadError === "missing" ? "evolution.missing" : "evolution.loadFailed"),
|
|
3716
|
+
action: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
3717
|
+
variant: "ghost",
|
|
3718
|
+
onClick: () => setReload((value) => value + 1),
|
|
3719
|
+
children: t("common.retry")
|
|
3720
|
+
}),
|
|
3721
|
+
children: t(loadError === "missing" ? "evolution.missingBody" : "evolution.loadFailedBody")
|
|
3722
|
+
});
|
|
3687
3723
|
if (view === null) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Busy, { label: t("common.loading") });
|
|
3688
3724
|
const { suggestion } = view;
|
|
3689
3725
|
const canDraft = context.client.canAssist("skill-draft") && !(suggestion.action === "update" && view.skill === void 0);
|
|
@@ -3716,7 +3752,7 @@ window.__ModuleLoader__.load({
|
|
|
3716
3752
|
className: css.skKicker,
|
|
3717
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 })]
|
|
3718
3754
|
}),
|
|
3719
|
-
/* @__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", {
|
|
3720
3756
|
type: "button",
|
|
3721
3757
|
className: css.skTitleLink,
|
|
3722
3758
|
onClick: () => context.navigate({
|
|
@@ -3779,7 +3815,7 @@ window.__ModuleLoader__.load({
|
|
|
3779
3815
|
suggestion.rationale !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Clamp, { text: suggestion.rationale }),
|
|
3780
3816
|
suggestion.action === "update" && view.skill === void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
3781
3817
|
className: css.skWarn,
|
|
3782
|
-
children: t("evolution.skillGone")
|
|
3818
|
+
children: t(view.resolution === "origin-unavailable" ? "evolution.originUnavailable" : "evolution.skillGone")
|
|
3783
3819
|
}),
|
|
3784
3820
|
suggestion.action === "update" && view.skill !== void 0 && !view.hashCurrent && suggestion.status === "pending" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
3785
3821
|
className: css.skWarn,
|
|
@@ -3800,7 +3836,7 @@ window.__ModuleLoader__.load({
|
|
|
3800
3836
|
children: [
|
|
3801
3837
|
t("evolution.adopted"),
|
|
3802
3838
|
" ",
|
|
3803
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
3839
|
+
view.skillInCatalog !== false && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
3804
3840
|
type: "button",
|
|
3805
3841
|
className: css.skLink,
|
|
3806
3842
|
onClick: () => context.navigate({
|
|
@@ -3811,9 +3847,16 @@ window.__ModuleLoader__.load({
|
|
|
3811
3847
|
})
|
|
3812
3848
|
]
|
|
3813
3849
|
}),
|
|
3814
|
-
/* @__PURE__ */ (0, react_jsx_runtime.
|
|
3850
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3815
3851
|
className: css.skFolds,
|
|
3816
|
-
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, {
|
|
3817
3860
|
title: t("evolution.evidence"),
|
|
3818
3861
|
meta: t("evolution.evidenceMeta", {
|
|
3819
3862
|
conversations: references.length,
|
|
@@ -3852,7 +3895,7 @@ window.__ModuleLoader__.load({
|
|
|
3852
3895
|
})]
|
|
3853
3896
|
}, index);
|
|
3854
3897
|
})
|
|
3855
|
-
})
|
|
3898
|
+
})]
|
|
3856
3899
|
})
|
|
3857
3900
|
]
|
|
3858
3901
|
});
|
|
@@ -3954,16 +3997,21 @@ window.__ModuleLoader__.load({
|
|
|
3954
3997
|
});
|
|
3955
3998
|
const started = await context.client.backtest({
|
|
3956
3999
|
skillName: draft.skillName,
|
|
3957
|
-
target: {
|
|
4000
|
+
target: {
|
|
4001
|
+
kind: draft.action === "update" ? "current" : "none",
|
|
4002
|
+
...draft.action === "update" ? { draftId: draft.id } : {}
|
|
4003
|
+
}
|
|
3958
4004
|
});
|
|
3959
4005
|
await context.client.linkRun(draft.id, started.runId);
|
|
3960
4006
|
});
|
|
3961
4007
|
const redraft = (note) => act(() => context.client.generateDraft({
|
|
3962
|
-
|
|
4008
|
+
draftId: draft.id,
|
|
4009
|
+
...draft.suggestionId === void 0 ? {} : { suggestionId: draft.suggestionId },
|
|
3963
4010
|
guidance: note,
|
|
3964
4011
|
...route
|
|
3965
4012
|
}), () => setRedrafting(null));
|
|
3966
4013
|
const ready = draft.status === "ready";
|
|
4014
|
+
const originalAvailable = draft.action !== "update" || view.base !== void 0;
|
|
3967
4015
|
const progress = (run) => run === void 0 ? 0 : run.progress.done;
|
|
3968
4016
|
const total = (candidate?.progress.total ?? 0) + (baseline?.progress.total ?? 0);
|
|
3969
4017
|
const results = /* @__PURE__ */ new Map();
|
|
@@ -3997,7 +4045,7 @@ window.__ModuleLoader__.load({
|
|
|
3997
4045
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
3998
4046
|
variant: "primary",
|
|
3999
4047
|
size: "sm",
|
|
4000
|
-
disabled: !context.writable || busy || editing !== null || running,
|
|
4048
|
+
disabled: !context.writable || busy || editing !== null || running || !originalAvailable,
|
|
4001
4049
|
onClick: () => regressed ? setConfirmAdopt(true) : void adopt(),
|
|
4002
4050
|
children: t("draft.adopt")
|
|
4003
4051
|
}),
|
|
@@ -4015,13 +4063,17 @@ window.__ModuleLoader__.load({
|
|
|
4015
4063
|
items: [{
|
|
4016
4064
|
id: "edit",
|
|
4017
4065
|
label: t("draft.edit")
|
|
4018
|
-
}, ...context.client.canAssist("skill-draft") ? [{
|
|
4066
|
+
}, ...originalAvailable && context.client.canAssist("skill-draft") ? [{
|
|
4019
4067
|
id: "redraft",
|
|
4020
4068
|
label: t("draft.redraft")
|
|
4021
4069
|
}] : []]
|
|
4022
4070
|
})
|
|
4023
4071
|
] })]
|
|
4024
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
|
+
}),
|
|
4025
4077
|
draft.notes !== "" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Clamp, { text: draft.notes }),
|
|
4026
4078
|
draft.changes.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(MoreList, {
|
|
4027
4079
|
items: draft.changes,
|
|
@@ -4057,7 +4109,7 @@ window.__ModuleLoader__.load({
|
|
|
4057
4109
|
}), !running && (cases ?? 0) > 0 && context.client.canAssist("skill-backtest") && ready && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
4058
4110
|
variant: "ghost",
|
|
4059
4111
|
size: "sm",
|
|
4060
|
-
disabled: !context.writable || busy,
|
|
4112
|
+
disabled: !context.writable || busy || !originalAvailable,
|
|
4061
4113
|
onClick: () => void backtest(),
|
|
4062
4114
|
children: view.runs.length === 0 ? t("draft.runBacktest") : t("draft.rerun")
|
|
4063
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,
|
|
@@ -423,6 +450,19 @@ function trashStamp(id) {
|
|
|
423
450
|
const match = /^(\d{4}-\d{2}-\d{2})T(\d{2})-(\d{2})-(\d{2})-(\d{3})Z-/u.exec(id);
|
|
424
451
|
return match === null ? void 0 : `${match[1]}T${match[2]}:${match[3]}:${match[4]}.${match[5]}Z`;
|
|
425
452
|
}
|
|
453
|
+
/** References are navigation links, not evidence: keep the records when a suggestion is deleted. */
|
|
454
|
+
function pruneSuggestionLinks(ledger) {
|
|
455
|
+
const ids = new Set(ledger.suggestions.map((suggestion) => suggestion.id));
|
|
456
|
+
for (const review of ledger.reviews) {
|
|
457
|
+
if (review.suggestionIds === void 0) continue;
|
|
458
|
+
const kept = review.suggestionIds.filter((id) => ids.has(id));
|
|
459
|
+
if (kept.length !== review.suggestionIds.length) review.suggestions = Math.min(review.suggestions, kept.length);
|
|
460
|
+
if (kept.length === 0) delete review.suggestionIds;
|
|
461
|
+
else review.suggestionIds = kept;
|
|
462
|
+
}
|
|
463
|
+
for (const trajectory of ledger.trajectories) trajectory.suggestionIds = trajectory.suggestionIds.filter((id) => ids.has(id));
|
|
464
|
+
return ledger;
|
|
465
|
+
}
|
|
426
466
|
/**
|
|
427
467
|
* The Skills Source's own files under `<dataDir>/skills`. Every file is
|
|
428
468
|
* replaced atomically; callers serialize writes with the storage lock.
|
|
@@ -478,7 +518,7 @@ var SkillsStore = class {
|
|
|
478
518
|
ledger() {
|
|
479
519
|
const value = object$1(this.readJson("ledger.json"));
|
|
480
520
|
if (value === void 0) return emptyLedger();
|
|
481
|
-
return {
|
|
521
|
+
return pruneSuggestionLinks({
|
|
482
522
|
version: 1,
|
|
483
523
|
generation: typeof value.generation === "number" ? value.generation : 0,
|
|
484
524
|
suggestions: array(value.suggestions),
|
|
@@ -487,7 +527,7 @@ var SkillsStore = class {
|
|
|
487
527
|
versions: array(value.versions),
|
|
488
528
|
trajectories: array(value.trajectories),
|
|
489
529
|
installs: array(value.installs)
|
|
490
|
-
};
|
|
530
|
+
});
|
|
491
531
|
}
|
|
492
532
|
/**
|
|
493
533
|
* What the user picked for draft and backtest runs, kept out of `fingerprint()`
|
|
@@ -527,6 +567,7 @@ var SkillsStore = class {
|
|
|
527
567
|
this.writeJson("preferences.json", preferences);
|
|
528
568
|
}
|
|
529
569
|
saveLedger(ledger) {
|
|
570
|
+
pruneSuggestionLinks(ledger);
|
|
530
571
|
ledger.generation += 1;
|
|
531
572
|
ledger.reviews = ledger.reviews.slice(0, 200);
|
|
532
573
|
const kept = /* @__PURE__ */ new Set();
|
|
@@ -558,7 +599,16 @@ var SkillsStore = class {
|
|
|
558
599
|
if (!/^[a-z0-9-]{1,80}$/u.test(id)) throw new Error("invalid trajectory id");
|
|
559
600
|
const value = object$1(this.readJson(join("trajectories", `${id}.json`)));
|
|
560
601
|
if (value === void 0) throw new Error("trajectory not found: " + id);
|
|
561
|
-
|
|
602
|
+
const trajectory = value;
|
|
603
|
+
const ids = new Set(this.ledger().suggestions.map((suggestion) => suggestion.id));
|
|
604
|
+
trajectory.suggestionIds = trajectory.suggestionIds.filter((id) => ids.has(id));
|
|
605
|
+
for (const annotation of trajectory.annotations) {
|
|
606
|
+
if (annotation.suggestionIds === void 0) continue;
|
|
607
|
+
const kept = annotation.suggestionIds.filter((id) => ids.has(id));
|
|
608
|
+
if (kept.length === 0) delete annotation.suggestionIds;
|
|
609
|
+
else annotation.suggestionIds = kept;
|
|
610
|
+
}
|
|
611
|
+
return trajectory;
|
|
562
612
|
}
|
|
563
613
|
saveTrajectory(trajectory) {
|
|
564
614
|
this.writeJson(join("trajectories", `${trajectory.id}.json`), trajectory);
|
|
@@ -930,7 +980,9 @@ function admitReview(context, input) {
|
|
|
930
980
|
});
|
|
931
981
|
continue;
|
|
932
982
|
}
|
|
933
|
-
|
|
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) {
|
|
934
986
|
skipped.push({
|
|
935
987
|
skillName: proposal.skillName,
|
|
936
988
|
action: proposal.action,
|
|
@@ -938,8 +990,7 @@ function admitReview(context, input) {
|
|
|
938
990
|
});
|
|
939
991
|
continue;
|
|
940
992
|
}
|
|
941
|
-
const
|
|
942
|
-
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));
|
|
943
994
|
if (open !== void 0) {
|
|
944
995
|
open.evidence = [...open.evidence, evidence].slice(-12);
|
|
945
996
|
open.signals = signals([...open.signals, ...proposal.signals]);
|
|
@@ -951,6 +1002,7 @@ function admitReview(context, input) {
|
|
|
951
1002
|
if (skill !== void 0) {
|
|
952
1003
|
open.skillKey = skill.key;
|
|
953
1004
|
open.skillFileHash = skill.hash;
|
|
1005
|
+
open.origin = skillOrigin(catalog, skill);
|
|
954
1006
|
}
|
|
955
1007
|
updated++;
|
|
956
1008
|
} else skipped.push({
|
|
@@ -974,7 +1026,8 @@ function admitReview(context, input) {
|
|
|
974
1026
|
evidence: [evidence],
|
|
975
1027
|
...skill === void 0 ? {} : {
|
|
976
1028
|
skillKey: skill.key,
|
|
977
|
-
skillFileHash: skill.hash
|
|
1029
|
+
skillFileHash: skill.hash,
|
|
1030
|
+
origin: skillOrigin(catalog, skill)
|
|
978
1031
|
},
|
|
979
1032
|
sourceSessionId: input.review.sessionId,
|
|
980
1033
|
...input.review.sessionTitle === void 0 ? {} : { sourceSessionTitle: input.review.sessionTitle },
|
|
@@ -3050,6 +3103,28 @@ var SkillsService = class {
|
|
|
3050
3103
|
catalog(workspace) {
|
|
3051
3104
|
return readCatalog(this.options(workspace));
|
|
3052
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
|
+
}
|
|
3053
3128
|
catalogView(workspace) {
|
|
3054
3129
|
const catalog = this.catalog(workspace);
|
|
3055
3130
|
const ledger = this.store.ledger();
|
|
@@ -3147,13 +3222,19 @@ var SkillsService = class {
|
|
|
3147
3222
|
expireSuggestions(ledger, this.clock());
|
|
3148
3223
|
const suggestion = ledger.suggestions.find((candidate) => candidate.id === id);
|
|
3149
3224
|
if (suggestion === void 0) throw new Error("suggestion not found: " + id);
|
|
3150
|
-
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;
|
|
3151
3228
|
const draft = suggestion.draftId === void 0 ? void 0 : ledger.drafts.find((candidate) => candidate.id === suggestion.draftId);
|
|
3152
3229
|
const cited = new Set(suggestion.evidence.map((reference) => reference.trajectoryId));
|
|
3153
3230
|
return {
|
|
3154
3231
|
suggestion,
|
|
3155
3232
|
hashCurrent: suggestion.action === "create" ? skill === void 0 : skill !== void 0 && skill.hash === suggestion.skillFileHash,
|
|
3156
|
-
...
|
|
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
|
+
},
|
|
3157
3238
|
...draft === void 0 ? {} : { draft },
|
|
3158
3239
|
trajectories: ledger.trajectories.filter((entry) => cited.has(entry.id))
|
|
3159
3240
|
};
|
|
@@ -3182,16 +3263,19 @@ var SkillsService = class {
|
|
|
3182
3263
|
return staleRun(run, this.clock().getTime());
|
|
3183
3264
|
}
|
|
3184
3265
|
drafts(filter = {}) {
|
|
3185
|
-
|
|
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));
|
|
3186
3268
|
}
|
|
3187
|
-
draft(
|
|
3188
|
-
const
|
|
3269
|
+
draft(_workspace, id) {
|
|
3270
|
+
const ledger = this.store.ledger();
|
|
3271
|
+
const draft = ledger.drafts.find((candidate) => candidate.id === id);
|
|
3189
3272
|
if (draft === void 0) throw new Error("draft not found: " + id);
|
|
3190
|
-
const
|
|
3191
|
-
const base =
|
|
3273
|
+
const original = draft.action === "update" ? this.draftOriginal(ledger, draft) : void 0;
|
|
3274
|
+
const base = original?.skill;
|
|
3192
3275
|
const now = this.clock().getTime();
|
|
3193
3276
|
return {
|
|
3194
3277
|
draft,
|
|
3278
|
+
...original === void 0 ? {} : { resolution: original.resolution },
|
|
3195
3279
|
...base === void 0 ? {} : { base: readSkillDocument(base) },
|
|
3196
3280
|
runs: draft.runIds.flatMap((id) => {
|
|
3197
3281
|
const run = this.store.evals().runs.find((candidate) => candidate.id === id);
|
|
@@ -3208,11 +3292,14 @@ var SkillsService = class {
|
|
|
3208
3292
|
const ledger = this.store.ledger();
|
|
3209
3293
|
const evals = this.store.evals();
|
|
3210
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");
|
|
3211
3298
|
const suggestion = input.suggestionId === void 0 ? void 0 : ledger.suggestions.find((candidate) => candidate.id === input.suggestionId);
|
|
3212
3299
|
if (input.suggestionId !== void 0 && suggestion === void 0) throw new Error("suggestion not found: " + input.suggestionId);
|
|
3213
|
-
const skillName = suggestion?.skillName ?? input.skill;
|
|
3300
|
+
const skillName = prior?.skillName ?? suggestion?.skillName ?? input.skill;
|
|
3214
3301
|
if (skillName === void 0 || !isSkillName(skillName)) throw new Error("a skill name or a suggestion is required");
|
|
3215
|
-
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);
|
|
3216
3303
|
const action = loaded === void 0 ? "create" : "update";
|
|
3217
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) => ({
|
|
3218
3305
|
trajectoryId: entry.id,
|
|
@@ -3250,7 +3337,7 @@ var SkillsService = class {
|
|
|
3250
3337
|
description: clip(skill.description, 200),
|
|
3251
3338
|
root: skill.root
|
|
3252
3339
|
})),
|
|
3253
|
-
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)
|
|
3254
3341
|
};
|
|
3255
3342
|
}
|
|
3256
3343
|
/** Bump the ledger generation, so the revision moves with every write. */
|
|
@@ -3698,11 +3785,18 @@ var SkillsService = class {
|
|
|
3698
3785
|
return this.write(() => {
|
|
3699
3786
|
validateSkillContent(input.content, input.skillName);
|
|
3700
3787
|
const ledger = this.store.ledger();
|
|
3701
|
-
const
|
|
3788
|
+
const catalog = this.catalog(workspace);
|
|
3702
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");
|
|
3703
3793
|
const suggestion = input.suggestionId === void 0 ? void 0 : ledger.suggestions.find((candidate) => candidate.id === input.suggestionId);
|
|
3704
3794
|
if (input.suggestionId !== void 0 && suggestion === void 0) throw new Error("suggestion not found: " + input.suggestionId);
|
|
3705
|
-
|
|
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)) {
|
|
3706
3800
|
draft.status = "discarded";
|
|
3707
3801
|
draft.updatedAt = now;
|
|
3708
3802
|
}
|
|
@@ -3713,7 +3807,8 @@ var SkillsService = class {
|
|
|
3713
3807
|
action: loaded === void 0 ? "create" : "update",
|
|
3714
3808
|
...loaded === void 0 ? { targetRoot: input.targetRoot ?? suggestion?.targetRoot ?? DEFAULT_ROOT } : {
|
|
3715
3809
|
baseKey: loaded.key,
|
|
3716
|
-
baseHash: loaded.hash
|
|
3810
|
+
baseHash: loaded.hash,
|
|
3811
|
+
origin
|
|
3717
3812
|
},
|
|
3718
3813
|
content: input.content,
|
|
3719
3814
|
notes: clip(input.notes, 2e3),
|
|
@@ -3757,12 +3852,14 @@ var SkillsService = class {
|
|
|
3757
3852
|
const catalog = this.catalog(workspace);
|
|
3758
3853
|
let key;
|
|
3759
3854
|
let previous;
|
|
3855
|
+
let updated;
|
|
3760
3856
|
if (draft.action === "update") {
|
|
3761
|
-
const
|
|
3762
|
-
|
|
3857
|
+
const original = this.draftOriginal(ledger, draft);
|
|
3858
|
+
const base = this.requireOriginal(original);
|
|
3763
3859
|
previous = this.requireHash(base, draft.baseHash);
|
|
3764
3860
|
writeFileAtomic(base.path, draft.content);
|
|
3765
3861
|
key = base.key;
|
|
3862
|
+
updated = findSkill(this.catalog(original.origin?.workspace), key);
|
|
3766
3863
|
} else {
|
|
3767
3864
|
const root = input.root ?? draft.targetRoot ?? DEFAULT_ROOT;
|
|
3768
3865
|
if (activeSkill(catalog, draft.skillName) !== void 0) throw new Error(`${draft.skillName} exists now; draft it again as an update`);
|
|
@@ -3791,7 +3888,7 @@ var SkillsService = class {
|
|
|
3791
3888
|
}
|
|
3792
3889
|
this.store.saveLedger(ledger);
|
|
3793
3890
|
return {
|
|
3794
|
-
skill: findSkill(this.catalog(workspace), key),
|
|
3891
|
+
skill: updated ?? findSkill(this.catalog(workspace), key),
|
|
3795
3892
|
version
|
|
3796
3893
|
};
|
|
3797
3894
|
});
|
|
@@ -3876,7 +3973,9 @@ var SkillsService = class {
|
|
|
3876
3973
|
}
|
|
3877
3974
|
};
|
|
3878
3975
|
}
|
|
3879
|
-
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));
|
|
3880
3979
|
if (loaded === void 0) throw new Error(`${skillName} has no file to test; test a draft or no skill`);
|
|
3881
3980
|
const document = readSkillDocument(loaded);
|
|
3882
3981
|
return {
|
|
@@ -3884,7 +3983,8 @@ var SkillsService = class {
|
|
|
3884
3983
|
target: {
|
|
3885
3984
|
kind: "current",
|
|
3886
3985
|
skillKey: loaded.key,
|
|
3887
|
-
hash: document.hash
|
|
3986
|
+
hash: document.hash,
|
|
3987
|
+
...draft === void 0 ? {} : { draftId: draft.id }
|
|
3888
3988
|
}
|
|
3889
3989
|
};
|
|
3890
3990
|
}
|
|
@@ -4731,7 +4831,8 @@ function createSkillsMemorySource(config = {}) {
|
|
|
4731
4831
|
case "run": return service.run(memoryInputText(fields.id, "id", 100));
|
|
4732
4832
|
case "drafts": return service.drafts({
|
|
4733
4833
|
...optionalText(fields.suggestionId, "suggestionId", 100) === void 0 ? {} : { suggestionId: optionalText(fields.suggestionId, "suggestionId", 100) },
|
|
4734
|
-
...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) }
|
|
4735
4836
|
});
|
|
4736
4837
|
case "draft": return service.draft(root, memoryInputText(fields.id, "id", 100));
|
|
4737
4838
|
case "draft-preferences": return service.draftPreferences();
|
|
@@ -4741,6 +4842,7 @@ function createSkillsMemorySource(config = {}) {
|
|
|
4741
4842
|
});
|
|
4742
4843
|
case "evidence-pack": return service.evidencePack(root, {
|
|
4743
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) },
|
|
4744
4846
|
...optionalText(fields.skill, "skill", 64) === void 0 ? {} : { skill: optionalText(fields.skill, "skill", 64) }
|
|
4745
4847
|
});
|
|
4746
4848
|
case "target-content": return service.targetContent(root, memoryInputText(fields.skillName, "skillName", 64), runTarget(fields.target));
|
|
@@ -4861,6 +4963,7 @@ function createSkillsMemorySource(config = {}) {
|
|
|
4861
4963
|
case "draft-record":
|
|
4862
4964
|
value = await service.recordDraft(root, {
|
|
4863
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) },
|
|
4864
4967
|
skillName: memoryInputText(fields.skillName, "skillName", 64),
|
|
4865
4968
|
content: typeof fields.content === "string" ? fields.content : "",
|
|
4866
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",
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
"tab.market": "市场",
|
|
13
13
|
"tab.trash": "回收站",
|
|
14
14
|
"common.loading": "加载中",
|
|
15
|
+
"common.retry": "重试",
|
|
15
16
|
"common.cancel": "取消",
|
|
16
17
|
"common.close": "关闭",
|
|
17
18
|
"common.delete": "删除",
|
|
@@ -134,7 +135,9 @@
|
|
|
134
135
|
"evolution.noAgent": "当前没有可用的任务 Agent",
|
|
135
136
|
"evolution.drafting": "正在生成草案",
|
|
136
137
|
"evolution.draftFailed": "草案生成失败:{error}",
|
|
137
|
-
"evolution.skillGone": "
|
|
138
|
+
"evolution.skillGone": "原技能文件已删除、移动或无法读取。请恢复文件,或在新位置打开技能并重新生成草案。",
|
|
139
|
+
"evolution.originUnavailable": "旧记录未可靠保存原工作区。请切换到原工作区,在技能页打开该技能并重新生成草案;现有草案和证据会保留。",
|
|
140
|
+
"evolution.currentSkill": "当前技能文件",
|
|
138
141
|
"evolution.skillChanged": "技能在建议之后被改过,生成草案前会以当前版本为准。",
|
|
139
142
|
"evolution.adopted": "已采纳",
|
|
140
143
|
"evolution.openSkill": "查看技能",
|
|
@@ -344,6 +347,10 @@
|
|
|
344
347
|
"evolution.deleteTitle": "删除这条建议?",
|
|
345
348
|
"evolution.deleteBody": "它生成的草案和证据引用会一起删掉,无法恢复。",
|
|
346
349
|
"evolution.deleted": "已删除",
|
|
350
|
+
"evolution.missing": "该建议已删除",
|
|
351
|
+
"evolution.missingBody": "可以在左侧选择其他建议,或返回记录查看原始内容。",
|
|
352
|
+
"evolution.loadFailed": "无法加载这条建议",
|
|
353
|
+
"evolution.loadFailedBody": "请重试,或在左侧选择其他建议。",
|
|
347
354
|
"tests.model": "全局模型",
|
|
348
355
|
"tests.modelCard": "所选回测模型",
|
|
349
356
|
"tests.modelAuto": "跟随默认"
|
|
@@ -361,6 +368,7 @@
|
|
|
361
368
|
"tab.market": "Market",
|
|
362
369
|
"tab.trash": "Trash",
|
|
363
370
|
"common.loading": "Loading",
|
|
371
|
+
"common.retry": "Retry",
|
|
364
372
|
"common.cancel": "Cancel",
|
|
365
373
|
"common.close": "Close",
|
|
366
374
|
"common.delete": "Delete",
|
|
@@ -483,7 +491,9 @@
|
|
|
483
491
|
"evolution.noAgent": "No task Agent is available",
|
|
484
492
|
"evolution.drafting": "Drafting",
|
|
485
493
|
"evolution.draftFailed": "Drafting failed: {error}",
|
|
486
|
-
"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",
|
|
487
497
|
"evolution.skillChanged": "The skill changed after this suggestion; the draft starts from its current version.",
|
|
488
498
|
"evolution.adopted": "Adopted",
|
|
489
499
|
"evolution.openSkill": "Open skill",
|
|
@@ -693,6 +703,10 @@
|
|
|
693
703
|
"evolution.deleteTitle": "Delete this suggestion?",
|
|
694
704
|
"evolution.deleteBody": "Its draft and the evidence references it cites go with it, and this cannot be undone.",
|
|
695
705
|
"evolution.deleted": "Deleted",
|
|
706
|
+
"evolution.missing": "This suggestion has been deleted",
|
|
707
|
+
"evolution.missingBody": "Select another suggestion on the left, or return to Evidence to read the original record.",
|
|
708
|
+
"evolution.loadFailed": "Could not load this suggestion",
|
|
709
|
+
"evolution.loadFailedBody": "Retry, or select another suggestion on the left.",
|
|
696
710
|
"tests.model": "Global model",
|
|
697
711
|
"tests.modelCard": "Selected model",
|
|
698
712
|
"tests.modelAuto": "Follow default"
|