@lmzhen/dsh-evolution-skill-discovery 0.0.0-stage → 0.30.40
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/README.md +16 -2
- package/lib/index.js +2457 -0
- package/lib/types/adapter.d.ts +48 -0
- package/lib/types/assignment-queue.d.ts +24 -0
- package/lib/types/assignment-sidecar.d.ts +30 -0
- package/lib/types/assignment.d.ts +131 -0
- package/lib/types/awareness.d.ts +6 -0
- package/lib/types/domain-bootstrap.d.ts +14 -0
- package/lib/types/domain-description.d.ts +19 -0
- package/lib/types/domain-generation-prompt.d.ts +14 -0
- package/lib/types/domain-generation-service.d.ts +23 -0
- package/lib/types/domain-generation.d.ts +48 -0
- package/lib/types/domain-map-store.d.ts +39 -0
- package/lib/types/domain-map.d.ts +52 -0
- package/lib/types/domain-metrics.d.ts +41 -0
- package/lib/types/domain-policy.d.ts +34 -0
- package/lib/types/domain-projection.d.ts +43 -0
- package/lib/types/domain-quality.d.ts +17 -0
- package/lib/types/domain-view.d.ts +15 -0
- package/lib/types/features.d.ts +11 -0
- package/lib/types/identity.d.ts +67 -0
- package/lib/types/index.d.ts +74 -0
- package/lib/types/maintenance.d.ts +62 -0
- package/lib/types/plugin.d.ts +37 -0
- package/lib/types/projection.d.ts +58 -0
- package/lib/types/runtime.d.ts +42 -0
- package/lib/types/search-judge.d.ts +26 -0
- package/lib/types/search.d.ts +84 -0
- package/lib/types/security.d.ts +14 -0
- package/lib/types/session-projection.d.ts +19 -0
- package/lib/types/session-store.d.ts +22 -0
- package/lib/types/shadow-evidence.d.ts +22 -0
- package/lib/types/stages.d.ts +6 -0
- package/lib/types/tool.d.ts +26 -0
- package/lib/types/ui.d.ts +69 -0
- package/lib/types/worker.d.ts +14 -0
- package/package.json +58 -4
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
2
|
+
import type { Agent, PreStepDecision } from '@deepseek-ai/dsh-agent';
|
|
3
|
+
import type { ContextFormed } from '@deepseek-ai/dsh-llm';
|
|
4
|
+
import type { CatalogEntry, ProjectionResult } from './projection.ts';
|
|
5
|
+
declare module '@deepseek-ai/dsh-llm' {
|
|
6
|
+
interface MessageSourceMap {
|
|
7
|
+
'skill-catalog': {
|
|
8
|
+
readonly kind: 'skill-catalog';
|
|
9
|
+
readonly form: 'catalog';
|
|
10
|
+
readonly entries: readonly CatalogEntry[];
|
|
11
|
+
} & ContextFormed;
|
|
12
|
+
'evolution-skill-projection': {
|
|
13
|
+
readonly kind: 'evolution-skill-projection';
|
|
14
|
+
readonly entries: readonly CatalogEntry[];
|
|
15
|
+
readonly hiddenNames: readonly string[];
|
|
16
|
+
readonly digest: string;
|
|
17
|
+
} & ContextFormed;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
/** Provider the plugin supplies from SkillIndex + DomainMap + policy. */
|
|
21
|
+
export interface ProjectionDigestStore {
|
|
22
|
+
get(agentKey: string): Promise<string | undefined>;
|
|
23
|
+
set(agentKey: string, digest: string): Promise<void>;
|
|
24
|
+
}
|
|
25
|
+
export interface CatalogProjectionProvider {
|
|
26
|
+
/** Optional persisted-session gate; false keeps the full catalog. */
|
|
27
|
+
shouldProject?(agent: Agent): boolean | Promise<boolean>;
|
|
28
|
+
project(input: {
|
|
29
|
+
readonly agent: Agent;
|
|
30
|
+
readonly catalogEntries: readonly CatalogEntry[];
|
|
31
|
+
}): ProjectionResult | Promise<ProjectionResult>;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Atomically replace one platform catalog message with the plugin projection.
|
|
35
|
+
* @param decision - the waterfall decision; only enter decisions are changed.
|
|
36
|
+
* @param result - a complete projection; incomplete results are ignored.
|
|
37
|
+
* @returns a new decision, or the original when no safe replacement exists.
|
|
38
|
+
*/
|
|
39
|
+
export declare function applyCatalogProjection(decision: PreStepDecision, result: ProjectionResult): PreStepDecision;
|
|
40
|
+
/**
|
|
41
|
+
* Install the thin pre-step adapter. The listener is outer; it always calls
|
|
42
|
+
* next, only touches the platform catalog message, and fails open.
|
|
43
|
+
* @param ctx - plugin context.
|
|
44
|
+
* @param provider - projection provider backed by SkillIndex/DomainMap.
|
|
45
|
+
* @returns disposer from ctx.on.
|
|
46
|
+
*/
|
|
47
|
+
export declare function installCatalogProjection(ctx: Context, provider: CatalogProjectionProvider, digestStore?: ProjectionDigestStore): () => void;
|
|
48
|
+
//# sourceMappingURL=adapter.d.ts.map
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { EvolutionIoLike } from '@lmzhen/dsh-evolution-core';
|
|
2
|
+
import type { AssignmentQueue, AssignmentQueueEntry, AssignmentSubmission } from './assignment.ts';
|
|
3
|
+
/** Durable assignment queue; process-local cache over one JSON file. */
|
|
4
|
+
export declare class JsonAssignmentQueue implements AssignmentQueue {
|
|
5
|
+
private readonly entries;
|
|
6
|
+
private loaded;
|
|
7
|
+
private readonly io;
|
|
8
|
+
private readonly path;
|
|
9
|
+
constructor(io: EvolutionIoLike, path: string);
|
|
10
|
+
load(): Promise<void>;
|
|
11
|
+
private persist;
|
|
12
|
+
enqueue(input: {
|
|
13
|
+
key: string;
|
|
14
|
+
submission: AssignmentSubmission;
|
|
15
|
+
proposalDigest: string;
|
|
16
|
+
createdAt: number;
|
|
17
|
+
}): Promise<{
|
|
18
|
+
entry: AssignmentQueueEntry;
|
|
19
|
+
duplicate: boolean;
|
|
20
|
+
}>;
|
|
21
|
+
update(key: string, status: AssignmentQueueEntry['status'], pendingReason?: AssignmentQueueEntry['pendingReason']): Promise<void>;
|
|
22
|
+
list(): readonly AssignmentQueueEntry[];
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=assignment-queue.d.ts.map
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
2
|
+
import type { DomainAssignmentService } from './assignment.ts';
|
|
3
|
+
declare module '@deepseek-ai/cordis' {
|
|
4
|
+
interface Events {
|
|
5
|
+
'evolution/approval-decided'(payload: {
|
|
6
|
+
readonly record: {
|
|
7
|
+
readonly kind: string;
|
|
8
|
+
readonly args: unknown;
|
|
9
|
+
};
|
|
10
|
+
readonly action: 'approve' | 'reject';
|
|
11
|
+
readonly ok: boolean;
|
|
12
|
+
}): void;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
/** Options for the create sidecar; it never writes skill content. */
|
|
16
|
+
export interface AssignmentSidecarOptions {
|
|
17
|
+
readonly provider?: string | undefined;
|
|
18
|
+
readonly source?: string | undefined;
|
|
19
|
+
readonly onSubmitted?: (() => void) | undefined;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Observe successful create calls and submit their optional domain proposal.
|
|
23
|
+
* Direct creates submit immediately; staged creates submit only after approval.
|
|
24
|
+
* @param ctx - plugin context with tools and approval events.
|
|
25
|
+
* @param service - the one assignment service.
|
|
26
|
+
* @param options - provider/source identity for skillKey.
|
|
27
|
+
* @returns disposer for both listeners.
|
|
28
|
+
*/
|
|
29
|
+
export declare function installAssignmentSidecar(ctx: Context, service: DomainAssignmentService, options?: AssignmentSidecarOptions): () => void;
|
|
30
|
+
//# sourceMappingURL=assignment-sidecar.d.ts.map
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import type { DomainMapStore, DomainNode } from './domain-map.ts';
|
|
2
|
+
import type { SkillKey } from './identity.ts';
|
|
3
|
+
/** Closed technical pending set; semantic uncertainty is not pending. */
|
|
4
|
+
export type AssignmentPendingReason = 'invalid-id' | 'unknown-domain' | 'map-version-stale' | 'new-domain-conflict' | 'schema-invalid' | 'queue-unavailable';
|
|
5
|
+
/** LLM proposal accepted by skill_manage create; code validates/mints. */
|
|
6
|
+
export interface AssignmentProposal {
|
|
7
|
+
readonly mode: 'existing' | 'new';
|
|
8
|
+
readonly id?: string | undefined;
|
|
9
|
+
readonly proposed?: {
|
|
10
|
+
readonly title: string;
|
|
11
|
+
readonly purpose: string;
|
|
12
|
+
readonly inScope: readonly string[];
|
|
13
|
+
readonly outOfScope: readonly string[];
|
|
14
|
+
readonly triggers: readonly string[];
|
|
15
|
+
readonly evidenceSkillKeys: readonly string[];
|
|
16
|
+
} | undefined;
|
|
17
|
+
readonly secondaryDomainIds?: readonly string[] | undefined;
|
|
18
|
+
readonly confidence: number;
|
|
19
|
+
readonly reason: string;
|
|
20
|
+
readonly needsReview?: boolean | undefined;
|
|
21
|
+
readonly mapVersion: string;
|
|
22
|
+
}
|
|
23
|
+
/** One create-side queue submission. */
|
|
24
|
+
export interface AssignmentSubmission {
|
|
25
|
+
readonly skillKey: SkillKey;
|
|
26
|
+
readonly threeFieldHash: string;
|
|
27
|
+
readonly modelInvocable: boolean;
|
|
28
|
+
readonly whenToUse?: string | undefined;
|
|
29
|
+
readonly proposal?: AssignmentProposal | undefined;
|
|
30
|
+
readonly now?: number | undefined;
|
|
31
|
+
}
|
|
32
|
+
/** Queue entry; key is the idempotency key. */
|
|
33
|
+
export interface AssignmentQueueEntry {
|
|
34
|
+
readonly key: string;
|
|
35
|
+
readonly submission: AssignmentSubmission;
|
|
36
|
+
readonly proposalDigest: string;
|
|
37
|
+
readonly createdAt: number;
|
|
38
|
+
status: 'queued' | 'pending' | 'applied' | 'provisional';
|
|
39
|
+
pendingReason?: AssignmentPendingReason | undefined;
|
|
40
|
+
}
|
|
41
|
+
/** Queue abstraction used by the one assignment service. */
|
|
42
|
+
export interface AssignmentQueue {
|
|
43
|
+
enqueue(entry: {
|
|
44
|
+
readonly key: string;
|
|
45
|
+
readonly submission: AssignmentSubmission;
|
|
46
|
+
readonly proposalDigest: string;
|
|
47
|
+
readonly createdAt: number;
|
|
48
|
+
}): Promise<{
|
|
49
|
+
entry: AssignmentQueueEntry;
|
|
50
|
+
duplicate: boolean;
|
|
51
|
+
}>;
|
|
52
|
+
update(key: string, status: AssignmentQueueEntry['status'], pendingReason?: AssignmentPendingReason): Promise<void>;
|
|
53
|
+
}
|
|
54
|
+
/** In-memory idempotent queue; production adapter can persist by key. */
|
|
55
|
+
export declare class MemoryAssignmentQueue implements AssignmentQueue {
|
|
56
|
+
private readonly entries;
|
|
57
|
+
enqueue(input: {
|
|
58
|
+
key: string;
|
|
59
|
+
submission: AssignmentSubmission;
|
|
60
|
+
proposalDigest: string;
|
|
61
|
+
createdAt: number;
|
|
62
|
+
}): Promise<{
|
|
63
|
+
entry: AssignmentQueueEntry;
|
|
64
|
+
duplicate: boolean;
|
|
65
|
+
}>;
|
|
66
|
+
update(key: string, status: AssignmentQueueEntry['status'], pendingReason?: AssignmentPendingReason): Promise<void>;
|
|
67
|
+
list(): readonly AssignmentQueueEntry[];
|
|
68
|
+
}
|
|
69
|
+
/** Staged create: no queue entry until approval. */
|
|
70
|
+
export interface StagedAssignment {
|
|
71
|
+
readonly id: string;
|
|
72
|
+
readonly submission: AssignmentSubmission;
|
|
73
|
+
}
|
|
74
|
+
/** Result of submit/process; create failure never appears here. */
|
|
75
|
+
export type AssignmentResult = {
|
|
76
|
+
readonly kind: 'unclassified';
|
|
77
|
+
readonly reason: 'feature-off' | 'no-proposal' | 'not-model-invocable';
|
|
78
|
+
} | {
|
|
79
|
+
readonly kind: 'queued';
|
|
80
|
+
readonly entry: AssignmentQueueEntry;
|
|
81
|
+
readonly duplicate: boolean;
|
|
82
|
+
} | {
|
|
83
|
+
readonly kind: 'applied' | 'provisional';
|
|
84
|
+
readonly entry: AssignmentQueueEntry;
|
|
85
|
+
readonly mapVersion: string;
|
|
86
|
+
} | {
|
|
87
|
+
readonly kind: 'pending';
|
|
88
|
+
readonly entry: AssignmentQueueEntry;
|
|
89
|
+
readonly reason: AssignmentPendingReason;
|
|
90
|
+
};
|
|
91
|
+
/** @returns idempotency key for one proposal observation. */
|
|
92
|
+
export declare function assignmentKey(input: {
|
|
93
|
+
skillKey: SkillKey;
|
|
94
|
+
threeFieldHash: string;
|
|
95
|
+
proposalDigest: string;
|
|
96
|
+
mapVersion: string;
|
|
97
|
+
}): string;
|
|
98
|
+
/** @returns stable proposal digest; undefined proposal is digest of null. */
|
|
99
|
+
export declare function proposalDigest(proposal: AssignmentProposal | undefined): string;
|
|
100
|
+
/** @returns a closed-set pending reason or undefined when the proposal can enqueue. */
|
|
101
|
+
export declare function validateProposal(proposal: AssignmentProposal): AssignmentPendingReason | undefined;
|
|
102
|
+
/** @returns true only when whenToUse is covered by in/out/triggers; names alone do not count. */
|
|
103
|
+
export declare function coveredByDomain(whenToUse: string, domain: Pick<DomainNode, 'inScope' | 'outOfScope' | 'triggers'>): boolean;
|
|
104
|
+
/** One assignment sidecar service; the only map write path for create. */
|
|
105
|
+
export declare class DomainAssignmentService {
|
|
106
|
+
private readonly queue;
|
|
107
|
+
private readonly store;
|
|
108
|
+
private readonly options;
|
|
109
|
+
constructor(queue: AssignmentQueue, store: DomainMapStore, options: {
|
|
110
|
+
readonly createClassificationEnabled: boolean;
|
|
111
|
+
readonly createCardsAvailable?: boolean;
|
|
112
|
+
readonly provisionalThreshold?: number;
|
|
113
|
+
readonly now?: () => number;
|
|
114
|
+
});
|
|
115
|
+
/** Stage a create proposal without queueing it. */
|
|
116
|
+
stage(submission: AssignmentSubmission): StagedAssignment;
|
|
117
|
+
/** Approve a staged create; only this call enqueues. */
|
|
118
|
+
approve(staged: StagedAssignment): Promise<AssignmentResult>;
|
|
119
|
+
/**
|
|
120
|
+
* Submit a create proposal after SkillLibrary.create succeeded.
|
|
121
|
+
* @param submission - skill identity, three-field hash, permission, proposal.
|
|
122
|
+
* @returns queue/pending/unclassified; never rolls back create.
|
|
123
|
+
*/
|
|
124
|
+
submit(submission: AssignmentSubmission): Promise<AssignmentResult>;
|
|
125
|
+
/** Process one queued entry with the current map; CAS failure becomes pending. */
|
|
126
|
+
process(entry: AssignmentQueueEntry): Promise<AssignmentResult>;
|
|
127
|
+
/** Manually confirm one provisional domain; no semantic reclassification. */
|
|
128
|
+
confirm(domainId: string): Promise<boolean>;
|
|
129
|
+
private now;
|
|
130
|
+
}
|
|
131
|
+
//# sourceMappingURL=assignment.d.ts.map
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
2
|
+
/** Static 1–2 sentence awareness; no domain list/tree. */
|
|
3
|
+
export declare const DISCOVERY_AWARENESS = "When skill coverage for a task is uncertain, the domain cards and skill_search can reduce it; search is optional, not a required step.";
|
|
4
|
+
/** Register the static awareness section; absent systemPrompt is a no-op. */
|
|
5
|
+
export declare function installDiscoveryAwareness(ctx: Context): () => void;
|
|
6
|
+
//# sourceMappingURL=awareness.d.ts.map
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { DomainMapSnapshot, DomainMapStore } from './domain-map.ts';
|
|
2
|
+
import { type DomainGenerationProposal } from './domain-generation.ts';
|
|
3
|
+
import type { SkillKey } from './identity.ts';
|
|
4
|
+
/**
|
|
5
|
+
* Write an initial LLM domain proposal into the map. Code owns IDs and
|
|
6
|
+
* validation; no embedding taxonomy and no skill body is read.
|
|
7
|
+
* @param store - domain map owner.
|
|
8
|
+
* @param proposal - validated 8–12 domain proposal.
|
|
9
|
+
* @param skillKeys - evidence skill name -> stable skillKey.
|
|
10
|
+
* @param expectedMapVersion - CAS precondition.
|
|
11
|
+
* @returns committed snapshot.
|
|
12
|
+
*/
|
|
13
|
+
export declare function bootstrapDomainMap(store: DomainMapStore, proposal: DomainGenerationProposal, skillKeys: Readonly<Record<string, SkillKey>>, expectedMapVersion: string): Promise<DomainMapSnapshot>;
|
|
14
|
+
//# sourceMappingURL=domain-bootstrap.d.ts.map
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { DomainNode } from './domain-map.ts';
|
|
2
|
+
/** Description lifecycle; stale is still servable, failed is not a new description. */
|
|
3
|
+
export type DescriptionStatus = 'fresh' | 'stale' | 'failed';
|
|
4
|
+
/** Events allowed to regenerate a domain description. */
|
|
5
|
+
export type DescriptionRegenerationEvent = 'new' | 'split' | 'merge' | 'definition' | 'children' | 'skill-add';
|
|
6
|
+
/** @returns true only for structural/definition events; normal skill add does not rewrite. */
|
|
7
|
+
export declare function shouldRegenerateDescription(event: DescriptionRegenerationEvent): boolean;
|
|
8
|
+
/** @returns true when the existing description may still serve. */
|
|
9
|
+
export declare function descriptionIsServable(status: DescriptionStatus): boolean;
|
|
10
|
+
/** @returns hash of child ids/description versions, never member skill names. */
|
|
11
|
+
export declare function descriptionHashOf(domain: Pick<DomainNode, 'id' | 'descriptionVersion'>, children: readonly Pick<DomainNode, 'id' | 'descriptionVersion'>[]): string;
|
|
12
|
+
/**
|
|
13
|
+
* Render a domain description from definition fields only. It never appends
|
|
14
|
+
* evidence/member skill names and is capped to 600 characters.
|
|
15
|
+
* @param domain - domain definition.
|
|
16
|
+
* @returns description text.
|
|
17
|
+
*/
|
|
18
|
+
export declare function renderDomainDescription(domain: Pick<DomainNode, 'name' | 'purpose' | 'inScope' | 'outOfScope' | 'triggers'>): string;
|
|
19
|
+
//# sourceMappingURL=domain-description.d.ts.map
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/** Frozen initial domain-generation prompt; caller owns schema/IDs. */
|
|
2
|
+
export declare const DOMAIN_GENERATION_PROMPT_VERSION = "v2";
|
|
3
|
+
export declare const DOMAIN_GENERATION_PROMPT_V1 = "Group the provided skills into first-level domains.\nUse only name, description, and whenToUse; do not infer from skill bodies.\nProduce 8\u201312 domains that are coherent, distinct, task-recognizable, and useful as an awareness layer. A single skill is not a domain. Each domain has a name, one-sentence purpose, in-scope, out-of-scope, triggers, and evidence skill names that actually support it.\nPrefer clear boundaries over exhaustive coverage. If the evidence is weak, leave the skill unassigned rather than forcing it into a domain. Together the domains should cover the library where evidence supports it. Domain IDs are assigned by the caller.\nReturn only the structured result.";
|
|
4
|
+
export interface DomainGenerationPromptOptions {
|
|
5
|
+
readonly minDomains?: number;
|
|
6
|
+
readonly maxDomains?: number;
|
|
7
|
+
}
|
|
8
|
+
/** @returns a parameterized initial-domain prompt; default 8–12. */
|
|
9
|
+
export declare function buildDomainGenerationPrompt(options?: DomainGenerationPromptOptions): string;
|
|
10
|
+
export declare const DOMAIN_GENERATION_PROMPT_V2: string;
|
|
11
|
+
export declare const DOMAIN_GENERATION_PROMPT_HASH: string;
|
|
12
|
+
/** Active prompt; v1 remains frozen for traceability. */
|
|
13
|
+
export declare const DOMAIN_GENERATION_PROMPT: string;
|
|
14
|
+
//# sourceMappingURL=domain-generation-prompt.d.ts.map
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { DomainMapSnapshot, DomainMapStore } from './domain-map.ts';
|
|
2
|
+
import type { DomainGenerationProposal } from './domain-generation.ts';
|
|
3
|
+
import type { GenerationSkillFact } from './domain-generation.ts';
|
|
4
|
+
import type { SkillKey } from './identity.ts';
|
|
5
|
+
/** External LLM adapter port; discovery owns validation/persistence only. */
|
|
6
|
+
export interface DomainGenerationPort {
|
|
7
|
+
generate(input: {
|
|
8
|
+
readonly skills: readonly GenerationSkillFact[];
|
|
9
|
+
readonly prompt: string;
|
|
10
|
+
readonly signal?: AbortSignal | undefined;
|
|
11
|
+
}): Promise<DomainGenerationProposal>;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Generate and persist the initial map only when the map has no domains.
|
|
15
|
+
* @param store - map owner.
|
|
16
|
+
* @param port - external LLM adapter.
|
|
17
|
+
* @param skills - name/description/whenToUse facts.
|
|
18
|
+
* @param skillKeys - evidence name -> stable key.
|
|
19
|
+
* @param expectedMapVersion - CAS precondition.
|
|
20
|
+
* @returns committed snapshot, or existing snapshot when already bootstrapped.
|
|
21
|
+
*/
|
|
22
|
+
export declare function initialDomainMap(store: DomainMapStore, port: DomainGenerationPort, skills: readonly GenerationSkillFact[], skillKeys: Readonly<Record<string, SkillKey>>, expectedMapVersion: string, signal?: AbortSignal, prompt?: string): Promise<DomainMapSnapshot>;
|
|
23
|
+
//# sourceMappingURL=domain-generation-service.d.ts.map
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/** One three-field fact supplied to the domain generator. */
|
|
2
|
+
export interface GenerationSkillFact {
|
|
3
|
+
readonly name: string;
|
|
4
|
+
readonly description: string;
|
|
5
|
+
readonly whenToUse?: string | undefined;
|
|
6
|
+
}
|
|
7
|
+
/** Input of the initial LLM domain-generation step. */
|
|
8
|
+
export interface DomainGenerationInput {
|
|
9
|
+
readonly skills: readonly GenerationSkillFact[];
|
|
10
|
+
}
|
|
11
|
+
/** One LLM-proposed domain; no id, no parent pointer. */
|
|
12
|
+
export interface GeneratedDomain {
|
|
13
|
+
readonly title: string;
|
|
14
|
+
readonly purpose: string;
|
|
15
|
+
readonly inScope: readonly string[];
|
|
16
|
+
readonly outOfScope: readonly string[];
|
|
17
|
+
readonly triggers: readonly string[];
|
|
18
|
+
readonly evidenceSkillKeys: readonly string[];
|
|
19
|
+
}
|
|
20
|
+
/** Raw LLM proposal. */
|
|
21
|
+
export interface DomainGenerationProposal {
|
|
22
|
+
readonly domains: readonly GeneratedDomain[];
|
|
23
|
+
}
|
|
24
|
+
/** Normalized domain after code mints stable IDs. */
|
|
25
|
+
export interface MintedDomain extends GeneratedDomain {
|
|
26
|
+
readonly id: string;
|
|
27
|
+
}
|
|
28
|
+
/** Validation result; errors are stable strings for retry/observability. */
|
|
29
|
+
export type DomainGenerationValidation = {
|
|
30
|
+
readonly ok: true;
|
|
31
|
+
readonly domains: readonly MintedDomain[];
|
|
32
|
+
} | {
|
|
33
|
+
readonly ok: false;
|
|
34
|
+
readonly errors: readonly string[];
|
|
35
|
+
};
|
|
36
|
+
/** @returns stable id derived from title, not the title itself. */
|
|
37
|
+
export declare function mintDomainId(title: string): string;
|
|
38
|
+
/** @returns direct for <=100 skills; prechunk-eligible above 100. */
|
|
39
|
+
export declare function domainGenerationMode(skillCount: number): 'direct' | 'prechunk-eligible';
|
|
40
|
+
/**
|
|
41
|
+
* Validate an initial generation proposal and mint ids. Does not call an LLM
|
|
42
|
+
* and does not read skill bodies; embedding taxonomy is rejected.
|
|
43
|
+
* @param input - skills the proposal was generated from.
|
|
44
|
+
* @param proposal - LLM output.
|
|
45
|
+
* @returns normalized domains or stable errors.
|
|
46
|
+
*/
|
|
47
|
+
export declare function validateDomainGeneration(input: DomainGenerationInput, proposal: DomainGenerationProposal): DomainGenerationValidation;
|
|
48
|
+
//# sourceMappingURL=domain-generation.d.ts.map
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { EvolutionIoLike } from '@lmzhen/dsh-evolution-core';
|
|
2
|
+
import type { DomainMapSnapshot, DomainMapStore, DomainMapWrite } from './domain-map.ts';
|
|
3
|
+
/** File schema version supported by this store. */
|
|
4
|
+
export declare const DOMAIN_MAP_SCHEMA_VERSION = 1;
|
|
5
|
+
/** Typed failure for an invalid persisted file. */
|
|
6
|
+
export declare class DomainMapCorruptError extends Error {
|
|
7
|
+
readonly code = "domain-map-corrupt";
|
|
8
|
+
constructor(message: string);
|
|
9
|
+
}
|
|
10
|
+
/** Typed failure for a CAS mismatch. */
|
|
11
|
+
export declare class DomainMapVersionConflict extends Error {
|
|
12
|
+
readonly code = "domain-map-version-conflict";
|
|
13
|
+
readonly expected: string;
|
|
14
|
+
readonly actual: string;
|
|
15
|
+
constructor(expected: string, actual: string);
|
|
16
|
+
}
|
|
17
|
+
/** Typed failure for an invalid write. */
|
|
18
|
+
export declare class DomainMapValidationError extends Error {
|
|
19
|
+
readonly code = "domain-map-invalid";
|
|
20
|
+
constructor(message: string);
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* JSON-backed DomainMap owner. One file, schemaVersion, CAS mapVersion, and a
|
|
24
|
+
* best-effort .bak for rollback; no evolution-state tables or graph DB.
|
|
25
|
+
*/
|
|
26
|
+
export declare class DomainMapFileStore implements DomainMapStore {
|
|
27
|
+
private queue;
|
|
28
|
+
private readonly io;
|
|
29
|
+
private readonly path;
|
|
30
|
+
private readonly now;
|
|
31
|
+
constructor(io: EvolutionIoLike, path: string, now?: () => number);
|
|
32
|
+
private get backupPath();
|
|
33
|
+
private parse;
|
|
34
|
+
read(): Promise<DomainMapSnapshot>;
|
|
35
|
+
private commitNow;
|
|
36
|
+
commit(expectedMapVersion: string, next: DomainMapWrite): Promise<DomainMapSnapshot>;
|
|
37
|
+
rollback(): Promise<DomainMapSnapshot>;
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=domain-map-store.d.ts.map
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import type { SkillKey } from './identity.ts';
|
|
2
|
+
/** One domain fact node; id is stable and never renamed by policy. */
|
|
3
|
+
export interface DomainNode {
|
|
4
|
+
readonly id: string;
|
|
5
|
+
readonly name: string;
|
|
6
|
+
readonly purpose: string;
|
|
7
|
+
readonly description: string;
|
|
8
|
+
readonly inScope: readonly string[];
|
|
9
|
+
readonly outOfScope: readonly string[];
|
|
10
|
+
readonly triggers: readonly string[];
|
|
11
|
+
readonly parentIds: readonly string[];
|
|
12
|
+
readonly status: 'active' | 'provisional' | 'deprecated';
|
|
13
|
+
readonly version: number;
|
|
14
|
+
readonly createdAt: number;
|
|
15
|
+
readonly updatedAt: number;
|
|
16
|
+
readonly descriptionHash: string;
|
|
17
|
+
readonly descriptionVersion: number;
|
|
18
|
+
readonly descriptionStatus: 'fresh' | 'stale' | 'failed';
|
|
19
|
+
readonly provenance: Readonly<Record<string, string>>;
|
|
20
|
+
readonly quality: Readonly<Record<string, number>>;
|
|
21
|
+
}
|
|
22
|
+
/** One skill-domain edge; skillKey is the global identity, not a display name. */
|
|
23
|
+
export interface SkillDomainEdge {
|
|
24
|
+
readonly skillKey: SkillKey;
|
|
25
|
+
readonly domainId: string;
|
|
26
|
+
readonly role: 'primary' | 'secondary';
|
|
27
|
+
readonly confidence: number;
|
|
28
|
+
readonly source: 'create' | 'manual' | 'maintenance';
|
|
29
|
+
readonly skillHash: string;
|
|
30
|
+
readonly mapVersion: string;
|
|
31
|
+
readonly status: 'active' | 'stale' | 'pending';
|
|
32
|
+
readonly assignedAt: number;
|
|
33
|
+
}
|
|
34
|
+
/** Immutable view of the domain fact store. */
|
|
35
|
+
export interface DomainMapSnapshot {
|
|
36
|
+
readonly mapVersion: string;
|
|
37
|
+
readonly domains: readonly DomainNode[];
|
|
38
|
+
readonly edges: readonly SkillDomainEdge[];
|
|
39
|
+
}
|
|
40
|
+
/** A committed domain-map write. */
|
|
41
|
+
export interface DomainMapWrite {
|
|
42
|
+
readonly mapVersion: string;
|
|
43
|
+
readonly domains: readonly DomainNode[];
|
|
44
|
+
readonly edges: readonly SkillDomainEdge[];
|
|
45
|
+
}
|
|
46
|
+
/** Owner contract; G1 supplies the JSON-backed implementation. */
|
|
47
|
+
export interface DomainMapStore {
|
|
48
|
+
read(): Promise<DomainMapSnapshot>;
|
|
49
|
+
commit(expectedMapVersion: string, next: DomainMapWrite): Promise<DomainMapSnapshot>;
|
|
50
|
+
rollback(): Promise<DomainMapSnapshot>;
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=domain-map.d.ts.map
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { DomainMapSnapshot } from './domain-map.ts';
|
|
2
|
+
import type { SkillKey } from './identity.ts';
|
|
3
|
+
/** Optional labels for assignment accuracy; absent means unmeasured. */
|
|
4
|
+
export interface DomainMetricLabels {
|
|
5
|
+
readonly expectedBySkill: Readonly<Record<SkillKey, string>>;
|
|
6
|
+
readonly predictedBySkill: Readonly<Record<SkillKey, string>>;
|
|
7
|
+
readonly newDomainIds?: readonly string[] | undefined;
|
|
8
|
+
readonly predictedNewDomainIds?: readonly string[] | undefined;
|
|
9
|
+
}
|
|
10
|
+
/** Recomputable domain/assignment metrics; no sentence locking. */
|
|
11
|
+
export interface DomainMetricCounters {
|
|
12
|
+
readonly descriptionRewritten?: number | undefined;
|
|
13
|
+
readonly descriptionEligible?: number | undefined;
|
|
14
|
+
readonly refusedAssignments?: number | undefined;
|
|
15
|
+
readonly assignmentAttempts?: number | undefined;
|
|
16
|
+
readonly maxDomainsPerSkill?: number | undefined;
|
|
17
|
+
}
|
|
18
|
+
/** Recomputable domain/assignment metrics; no sentence locking. */
|
|
19
|
+
export interface DomainMetrics {
|
|
20
|
+
readonly measured: boolean;
|
|
21
|
+
readonly visibleSkills: number;
|
|
22
|
+
readonly coverage: number | null;
|
|
23
|
+
readonly unclassifiedRatio: number | null;
|
|
24
|
+
readonly emptyDomainCount: number;
|
|
25
|
+
readonly crossDomainRatio: number | null;
|
|
26
|
+
readonly pendingRate: number | null;
|
|
27
|
+
readonly assignmentAccuracy: number | null;
|
|
28
|
+
readonly newDomainPrecision: number | null;
|
|
29
|
+
readonly descriptionRewriteRate: number | null;
|
|
30
|
+
readonly staleDescriptionRatio: number | null;
|
|
31
|
+
readonly overAssignmentRate: number | null;
|
|
32
|
+
readonly refusalRate: number | null;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* @param snapshot - domain facts.
|
|
36
|
+
* @param visibleSkillKeys - skills visible in this view.
|
|
37
|
+
* @param labels - optional assignment labels.
|
|
38
|
+
* @returns metrics; null means the denominator is zero/unmeasured.
|
|
39
|
+
*/
|
|
40
|
+
export declare function computeDomainMetrics(snapshot: DomainMapSnapshot, visibleSkillKeys: ReadonlySet<SkillKey>, labels?: DomainMetricLabels, counters?: DomainMetricCounters): DomainMetrics;
|
|
41
|
+
//# sourceMappingURL=domain-metrics.d.ts.map
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/** One policy layer; only these fields are user-editable. */
|
|
2
|
+
export type DomainPolicyMode = 'off' | 'auto' | 'on';
|
|
3
|
+
export interface DomainPolicyLayer {
|
|
4
|
+
readonly mode?: DomainPolicyMode | undefined;
|
|
5
|
+
readonly pinDomains?: readonly string[] | undefined;
|
|
6
|
+
readonly disableDomains?: readonly string[] | undefined;
|
|
7
|
+
readonly revision?: string | undefined;
|
|
8
|
+
}
|
|
9
|
+
/** Effective policy consumed by projection; never written back to DomainMap. */
|
|
10
|
+
export interface EffectiveDomainPolicy {
|
|
11
|
+
readonly mode: DomainPolicyMode;
|
|
12
|
+
readonly pinned: ReadonlySet<string>;
|
|
13
|
+
readonly disabled: ReadonlySet<string>;
|
|
14
|
+
readonly degraded: readonly string[];
|
|
15
|
+
readonly globalRevision?: string | undefined;
|
|
16
|
+
readonly workspaceRevision?: string | undefined;
|
|
17
|
+
readonly scopeRevision?: string | undefined;
|
|
18
|
+
}
|
|
19
|
+
/** Invalid policy layer (e.g. attempts to edit taxonomy). */
|
|
20
|
+
export declare class DomainPolicyValidationError extends Error {
|
|
21
|
+
readonly code = "domain-policy-invalid";
|
|
22
|
+
constructor(message: string);
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Merge global -> workspace -> scope policy. Disable wins over pin; unknown
|
|
26
|
+
* domains are ignored and reported as degraded.
|
|
27
|
+
* @param global - mandatory global layer.
|
|
28
|
+
* @param workspace - optional workspace overlay.
|
|
29
|
+
* @param scope - optional scope overlay.
|
|
30
|
+
* @param knownDomainIds - optional known ids for validation.
|
|
31
|
+
* @returns immutable effective policy.
|
|
32
|
+
*/
|
|
33
|
+
export declare function mergeDomainPolicy(global: DomainPolicyLayer, workspace?: DomainPolicyLayer, scope?: DomainPolicyLayer, knownDomainIds?: ReadonlySet<string>): EffectiveDomainPolicy;
|
|
34
|
+
//# sourceMappingURL=domain-policy.d.ts.map
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { DomainMapSnapshot } from './domain-map.ts';
|
|
2
|
+
import type { EffectiveDomainPolicy } from './domain-policy.ts';
|
|
3
|
+
import type { SkillIndexRow } from './identity.ts';
|
|
4
|
+
import { type CatalogEntry, type ProjectionResult } from './projection.ts';
|
|
5
|
+
/** Input for one view's domain/catalog projection. */
|
|
6
|
+
export interface DomainProjectionInput {
|
|
7
|
+
readonly entries: readonly CatalogEntry[];
|
|
8
|
+
readonly rows: readonly SkillIndexRow[];
|
|
9
|
+
readonly complete: boolean;
|
|
10
|
+
readonly mapStale?: boolean | undefined;
|
|
11
|
+
readonly searchAvailable?: boolean | undefined;
|
|
12
|
+
readonly mode?: 'off' | 'shadow' | 'on' | undefined;
|
|
13
|
+
readonly snapshot: DomainMapSnapshot;
|
|
14
|
+
readonly policy: EffectiveDomainPolicy;
|
|
15
|
+
readonly viewKey: string;
|
|
16
|
+
readonly scope: string;
|
|
17
|
+
readonly mapVersion: string;
|
|
18
|
+
readonly policyDigest: string;
|
|
19
|
+
readonly viewCatalogDigest: string;
|
|
20
|
+
readonly adapterVersion: string;
|
|
21
|
+
readonly projectionSchemaVersion: string;
|
|
22
|
+
readonly discoveryMode: string;
|
|
23
|
+
readonly maxCards?: number | undefined;
|
|
24
|
+
readonly tokenBudget?: number | undefined;
|
|
25
|
+
readonly now?: number | undefined;
|
|
26
|
+
readonly staleAfterHours?: number | undefined;
|
|
27
|
+
readonly maxVisibleDepth?: number | undefined;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Build L1 cards and the hidden set for one view, then delegate the pure
|
|
31
|
+
* catalog rewrite. Structural staleness fails open; description staleness does not.
|
|
32
|
+
* @param input - rows, domain facts, policy, and identity inputs.
|
|
33
|
+
* @returns projection result with cards and hidden names.
|
|
34
|
+
*/
|
|
35
|
+
export declare function hiddenRecoverable(hiddenNames: readonly string[], searchResultNames: ReadonlySet<string>): boolean;
|
|
36
|
+
export declare function buildDomainProjection(input: DomainProjectionInput): ProjectionResult;
|
|
37
|
+
/** @returns true when shadow evidence is sufficient to promote to on. */
|
|
38
|
+
export declare function canPromoteShadow(input: {
|
|
39
|
+
readonly samples: number;
|
|
40
|
+
readonly hiddenRecoverableRate: number;
|
|
41
|
+
readonly silentMisses: number;
|
|
42
|
+
}): boolean;
|
|
43
|
+
//# sourceMappingURL=domain-projection.d.ts.map
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { DomainNode } from './domain-map.ts';
|
|
2
|
+
/** Stable quality issue codes. */
|
|
3
|
+
export type DomainQualityIssue = 'empty-purpose' | 'vague-purpose' | 'empty-in-scope' | 'empty-out-of-scope' | 'empty-triggers' | 'overlaps-peer' | 'indistinguishable';
|
|
4
|
+
/** Quality result is evidence, not an automatic mutation. */
|
|
5
|
+
export interface DomainQualityResult {
|
|
6
|
+
readonly passed: boolean;
|
|
7
|
+
readonly issues: readonly DomainQualityIssue[];
|
|
8
|
+
readonly score: number;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Evaluate whether a domain definition is specific, triggered, and distinct.
|
|
12
|
+
* @param domain - candidate domain.
|
|
13
|
+
* @param peers - other visible domains.
|
|
14
|
+
* @returns auditable issues; does not mutate the candidate.
|
|
15
|
+
*/
|
|
16
|
+
export declare function evaluateDomainQuality(domain: Pick<DomainNode, 'name' | 'purpose' | 'inScope' | 'outOfScope' | 'triggers'>, peers: readonly Pick<DomainNode, 'name' | 'purpose' | 'inScope' | 'outOfScope' | 'triggers'>[]): DomainQualityResult;
|
|
17
|
+
//# sourceMappingURL=domain-quality.d.ts.map
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { DomainMapSnapshot } from './domain-map.ts';
|
|
2
|
+
import type { SkillKey } from './identity.ts';
|
|
3
|
+
/** Per-view membership counts; unclassified is virtual, never a domain id. */
|
|
4
|
+
export interface DomainViewCounts {
|
|
5
|
+
readonly byDomain: ReadonlyMap<string, number>;
|
|
6
|
+
readonly unclassified: number;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Count visible skills by active domain membership.
|
|
10
|
+
* @param snapshot - global domain facts.
|
|
11
|
+
* @param visibleSkillKeys - skill keys visible in this view.
|
|
12
|
+
* @returns per-domain member counts plus the unclassified virtual count.
|
|
13
|
+
*/
|
|
14
|
+
export declare function domainViewCounts(snapshot: DomainMapSnapshot, visibleSkillKeys: ReadonlySet<SkillKey>): DomainViewCounts;
|
|
15
|
+
//# sourceMappingURL=domain-view.d.ts.map
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/** Discovery feature gates; v0 defaults everything off. */
|
|
2
|
+
export type DiscoveryMode = 'off' | 'shadow' | 'on';
|
|
3
|
+
export interface DiscoveryFeatureConfig {
|
|
4
|
+
readonly projectionEnabled: boolean;
|
|
5
|
+
readonly searchEnabled: boolean;
|
|
6
|
+
readonly createClassificationEnabled: boolean;
|
|
7
|
+
readonly discoveryMode: DiscoveryMode;
|
|
8
|
+
}
|
|
9
|
+
export declare const V0_DISCOVERY_FEATURES: DiscoveryFeatureConfig;
|
|
10
|
+
export declare function canClassifyAtCreate(config: DiscoveryFeatureConfig, hasCreateDomainCards: boolean): boolean;
|
|
11
|
+
//# sourceMappingURL=features.d.ts.map
|