@maci0/dsh-caveman 0.16.2
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/LICENSE +22 -0
- package/README.md +192 -0
- package/cordis.patch.yml +13 -0
- package/icon.svg +6 -0
- package/lib/client.js +488 -0
- package/lib/compress-detect.js +98 -0
- package/lib/compress-files.js +155 -0
- package/lib/compress-pipeline.js +109 -0
- package/lib/compress-rules.js +308 -0
- package/lib/compress-validate.js +227 -0
- package/lib/frontmatter.js +347 -0
- package/lib/host.js +15 -0
- package/lib/index.js +616 -0
- package/lib/modes.js +126 -0
- package/lib/skills.js +177 -0
- package/lib/types/compress-detect.d.ts +18 -0
- package/lib/types/compress-files.d.ts +76 -0
- package/lib/types/compress-pipeline.d.ts +32 -0
- package/lib/types/compress-rules.d.ts +65 -0
- package/lib/types/compress-validate.d.ts +36 -0
- package/lib/types/frontmatter.d.ts +57 -0
- package/lib/types/host.d.ts +201 -0
- package/lib/types/index.d.ts +87 -0
- package/lib/types/modes.d.ts +102 -0
- package/lib/types/skills.d.ts +56 -0
- package/locale/en.json +6 -0
- package/locale/zh.json +6 -0
- package/package.json +112 -0
- package/scripts/sync-upstream.mjs +158 -0
- package/skills/cavecrew/SKILL.md +91 -0
- package/skills/cavecrew/cavecrew-builder.md +46 -0
- package/skills/cavecrew/cavecrew-investigator.md +56 -0
- package/skills/cavecrew/cavecrew-reviewer.md +47 -0
- package/skills/caveman/SKILL.md +103 -0
- package/skills/caveman-commit/SKILL.md +63 -0
- package/skills/caveman-compress/SKILL.md +105 -0
- package/skills/caveman-explore/SKILL.md +42 -0
- package/skills/caveman-help/SKILL.md +68 -0
- package/skills/caveman-review/SKILL.md +53 -0
- package/skills/caveman-stats/SKILL.md +30 -0
- package/skills/investigate-first/SKILL.md +16 -0
- package/skills/lean-build/SKILL.md +18 -0
- package/skills/migration/SKILL.md +17 -0
- package/skills/safe-refactor/SKILL.md +16 -0
- package/skills/surgical-patch/SKILL.md +16 -0
- package/skills/verify-and-stop/SKILL.md +16 -0
- package/sync.manifest.json +25 -0
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The slice of the DeepSeek Harness host surface this plugin uses, declared
|
|
3
|
+
* structurally.
|
|
4
|
+
*
|
|
5
|
+
* The plugin is installed from outside the harness checkout. It depends on the
|
|
6
|
+
* published `@deepseek-ai/dsh-tools` and `@deepseek-ai/dsh-skill` packages: the
|
|
7
|
+
* skill domain shapes (summaries, candidates, definitions, lookup options) are
|
|
8
|
+
* imported from the latter, while the services it reaches through
|
|
9
|
+
* `ctx.inject([...])` are declared structurally here: the host types remain
|
|
10
|
+
* authoritative, and a composition that does not mount a service simply omits
|
|
11
|
+
* that capability.
|
|
12
|
+
*
|
|
13
|
+
* @module dsh-caveman/host
|
|
14
|
+
*/
|
|
15
|
+
import type { SkillCandidate, SkillDefinition, SkillLookupOptions, SkillProviderObservation } from '@deepseek-ai/dsh-skill';
|
|
16
|
+
import type { ToolDefinition } from '@deepseek-ai/dsh-tools';
|
|
17
|
+
/** Disposer returned by every host registration. */
|
|
18
|
+
type Disposable = () => void;
|
|
19
|
+
/** One contributed system-prompt section. */
|
|
20
|
+
export interface PromptSectionContribution {
|
|
21
|
+
/** Unique section name across the composition. */
|
|
22
|
+
readonly name: string;
|
|
23
|
+
/** Ascending concatenation position. */
|
|
24
|
+
readonly order: number;
|
|
25
|
+
/** Static text, or a provider evaluated at each assembly (empty text is dropped). */
|
|
26
|
+
readonly text: string | ((context: unknown) => string);
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* The workspace-independent slice of the host's `SkillProvider` this plugin
|
|
30
|
+
* implements: native discovery observations, with lookup options optional for
|
|
31
|
+
* direct callers. The packaged provider ignores `cwd`.
|
|
32
|
+
*/
|
|
33
|
+
export interface SkillProviderLike {
|
|
34
|
+
/** Unique provider name in the registry. */
|
|
35
|
+
readonly name: string;
|
|
36
|
+
/** List candidates for the current lookup, settling promptly on abort. */
|
|
37
|
+
list(options?: SkillLookupOptions): Promise<readonly SkillCandidate[] | SkillProviderObservation>;
|
|
38
|
+
/** Load a winning candidate's body, or `undefined` when it is gone. */
|
|
39
|
+
get(candidate: SkillCandidate, options?: SkillLookupOptions): Promise<SkillDefinition | undefined>;
|
|
40
|
+
}
|
|
41
|
+
/** The slice of the calling agent this plugin reads. */
|
|
42
|
+
export interface AgentLike {
|
|
43
|
+
/** The agent's session; its header carries the workspace a relative path means. */
|
|
44
|
+
readonly session?: {
|
|
45
|
+
readonly header?: {
|
|
46
|
+
readonly cwd?: string | undefined;
|
|
47
|
+
} | undefined;
|
|
48
|
+
} | undefined;
|
|
49
|
+
}
|
|
50
|
+
/** The slice of a tool execution context this plugin reads. */
|
|
51
|
+
export interface ToolExecLike {
|
|
52
|
+
/** The agent on whose behalf the call runs. */
|
|
53
|
+
readonly agent?: AgentLike | undefined;
|
|
54
|
+
/** Caller-owned cancellation for this invocation. */
|
|
55
|
+
readonly signal?: AbortSignal | undefined;
|
|
56
|
+
}
|
|
57
|
+
/** One session-projection unit state. */
|
|
58
|
+
export interface ProjectionStateLike {
|
|
59
|
+
/** Cumulative provider-reported token buckets, named as the unit names them. */
|
|
60
|
+
readonly totals?: {
|
|
61
|
+
readonly uncachedInputTokens?: number;
|
|
62
|
+
readonly outputTokens?: number;
|
|
63
|
+
readonly cacheReadTokens?: number;
|
|
64
|
+
readonly cacheWriteTokens?: number;
|
|
65
|
+
} | undefined;
|
|
66
|
+
}
|
|
67
|
+
/** The slice of the session-projections service this plugin reads. */
|
|
68
|
+
export interface SessionProjectionsLike {
|
|
69
|
+
/** Read one unit's host state for a session, or `undefined` when absent. */
|
|
70
|
+
stateOf(session: unknown, key: string): ProjectionStateLike | undefined;
|
|
71
|
+
}
|
|
72
|
+
/** Invocation handed to a registered human command. */
|
|
73
|
+
export interface CommandInvocationLike {
|
|
74
|
+
/** Text following the command name, including separator whitespace. */
|
|
75
|
+
readonly rawInput: string;
|
|
76
|
+
/** The agent whose UI received the command. */
|
|
77
|
+
readonly agent?: AgentLike | undefined;
|
|
78
|
+
}
|
|
79
|
+
/** Direct-UI outcome of a human command. */
|
|
80
|
+
export type CommandResultLike = {
|
|
81
|
+
readonly kind: 'success';
|
|
82
|
+
readonly text?: string;
|
|
83
|
+
} | {
|
|
84
|
+
readonly kind: 'error';
|
|
85
|
+
readonly text: string;
|
|
86
|
+
};
|
|
87
|
+
/** A plugin-owned human command. */
|
|
88
|
+
export interface CommandDefinitionLike {
|
|
89
|
+
/** Lowercase command name without the leading slash. */
|
|
90
|
+
readonly name: string;
|
|
91
|
+
/** Summary used in discovery UI. */
|
|
92
|
+
readonly description: string;
|
|
93
|
+
/** Optional free-form input hint. */
|
|
94
|
+
readonly input?: {
|
|
95
|
+
readonly hint: string;
|
|
96
|
+
};
|
|
97
|
+
/** Execute against the receiving agent without a model message. */
|
|
98
|
+
handler(invocation: CommandInvocationLike): CommandResultLike | Promise<CommandResultLike>;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* The slice of a durable session message the deactivation watcher reads.
|
|
102
|
+
*
|
|
103
|
+
* `source.kind === 'user'` is what separates the human's own words from the
|
|
104
|
+
* context the harness injects into the same event stream (skill bodies,
|
|
105
|
+
* references, replayed history).
|
|
106
|
+
*/
|
|
107
|
+
export interface SessionMessageLike {
|
|
108
|
+
/** Content blocks; only `text` blocks carry words. */
|
|
109
|
+
readonly content?: readonly {
|
|
110
|
+
readonly type?: string;
|
|
111
|
+
readonly text?: string;
|
|
112
|
+
}[] | undefined;
|
|
113
|
+
/** Provenance of the message. */
|
|
114
|
+
readonly source?: {
|
|
115
|
+
readonly kind?: string;
|
|
116
|
+
} | undefined;
|
|
117
|
+
}
|
|
118
|
+
/** One durable session event, as `session/event` delivers it. */
|
|
119
|
+
export interface SessionEventLike {
|
|
120
|
+
/** Event discriminator, e.g. `user/message`. */
|
|
121
|
+
readonly type?: string;
|
|
122
|
+
/** Event payload; a {@link SessionMessageLike} for `user/message`. */
|
|
123
|
+
readonly data?: unknown;
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Structural view of the Cordis context the plugin uses.
|
|
127
|
+
*
|
|
128
|
+
* Members are only reached inside the matching `inject` callback, where the
|
|
129
|
+
* host guarantees the service is present.
|
|
130
|
+
*/
|
|
131
|
+
export interface HostContext {
|
|
132
|
+
/** Run `callback` once the named services are available. */
|
|
133
|
+
inject(dependencies: readonly string[], callback: (scope: HostContext) => void): unknown;
|
|
134
|
+
/** Bind a registration's disposer to the calling fiber. */
|
|
135
|
+
effect(callback: () => Disposable, label?: string): unknown;
|
|
136
|
+
/** Subscribe to a host event; the returned disposer removes the listener. */
|
|
137
|
+
on(event: 'session/event', listener: (session: unknown, event: SessionEventLike) => void): Disposable;
|
|
138
|
+
on(event: 'loader/volatile-update', listener: () => void): Disposable;
|
|
139
|
+
/** Read one mounted service. `undefined` when that service is absent. */
|
|
140
|
+
get(name: 'settings'): SettingsServiceLike | undefined;
|
|
141
|
+
get(name: 'sessionProjections'): SessionProjectionsLike | undefined;
|
|
142
|
+
/** Owning fiber, present once the loader mounted this plugin. */
|
|
143
|
+
readonly fiber?: {
|
|
144
|
+
readonly entry?: {
|
|
145
|
+
readonly options?: {
|
|
146
|
+
readonly id?: string;
|
|
147
|
+
};
|
|
148
|
+
};
|
|
149
|
+
};
|
|
150
|
+
readonly systemPrompt: {
|
|
151
|
+
section(section: PromptSectionContribution): Disposable;
|
|
152
|
+
};
|
|
153
|
+
readonly skills: {
|
|
154
|
+
registerProvider(create: () => SkillProviderLike): Disposable;
|
|
155
|
+
};
|
|
156
|
+
readonly tools: {
|
|
157
|
+
register(definition: ToolDefinition): Disposable;
|
|
158
|
+
};
|
|
159
|
+
readonly commands: {
|
|
160
|
+
register(definition: CommandDefinitionLike): Disposable;
|
|
161
|
+
};
|
|
162
|
+
readonly webServer: WebServerLike;
|
|
163
|
+
readonly connection: ConnectionLike;
|
|
164
|
+
}
|
|
165
|
+
/** The slice of an incoming HTTP request the level route reads. */
|
|
166
|
+
export interface RequestLike {
|
|
167
|
+
readonly method?: string | undefined;
|
|
168
|
+
readonly headers: object | undefined;
|
|
169
|
+
}
|
|
170
|
+
/** The slice of an HTTP response the level route writes. */
|
|
171
|
+
export interface ResponseLike {
|
|
172
|
+
statusCode: number;
|
|
173
|
+
setHeader(name: string, value: string): void;
|
|
174
|
+
end(body?: string): void;
|
|
175
|
+
}
|
|
176
|
+
/** The slice of the `webServer` service this plugin registers on. */
|
|
177
|
+
export interface WebServerLike {
|
|
178
|
+
/** Register one route; a duplicate path throws. */
|
|
179
|
+
register(route: {
|
|
180
|
+
readonly kind: 'exact';
|
|
181
|
+
readonly path: string;
|
|
182
|
+
handler(req: RequestLike, res: ResponseLike): void | Promise<void>;
|
|
183
|
+
}): Disposable;
|
|
184
|
+
}
|
|
185
|
+
/** The composition's trust fence for HTTP requests. */
|
|
186
|
+
export interface ConnectionLike {
|
|
187
|
+
/** The rejection status for an untrusted or unauthenticated request, else `undefined`. */
|
|
188
|
+
requestRejection(request: {
|
|
189
|
+
readonly headers: object | undefined;
|
|
190
|
+
}): 401 | 403 | undefined;
|
|
191
|
+
}
|
|
192
|
+
/** The slice of the settings service this plugin uses. */
|
|
193
|
+
export interface SettingsServiceLike {
|
|
194
|
+
/**
|
|
195
|
+
* Merge fields into one profile entry. `ns` is the entry id, not a namespace.
|
|
196
|
+
* @param ns - profile entry id.
|
|
197
|
+
* @param patch - fields to merge.
|
|
198
|
+
*/
|
|
199
|
+
update(ns: string, patch: Record<string, unknown>): Promise<void>;
|
|
200
|
+
}
|
|
201
|
+
export {};
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* dsh-caveman: Caveman terse-talk mode, as a DeepSeek Harness plugin.
|
|
3
|
+
*
|
|
4
|
+
* Four capabilities, all mounted through public Cordis extension points:
|
|
5
|
+
*
|
|
6
|
+
* - the bundled skills (`caveman`, `cavecrew`, `-commit`, `-review`,
|
|
7
|
+
* `-compress`, `-stats`, `-help`, plus six work patterns) become one
|
|
8
|
+
* `ctx.skills` provider;
|
|
9
|
+
* - while a level other than `off` is active, the mode-filtered ruleset is
|
|
10
|
+
* contributed to the system prompt on every assembly;
|
|
11
|
+
* - the level is switchable from the model (`caveman` tool) and the human
|
|
12
|
+
* (`/caveman` command);
|
|
13
|
+
* - the `caveman` settings namespace makes the level persistent and pairs with
|
|
14
|
+
* this package's browser half, which renders the card in the Web client's
|
|
15
|
+
* Plugins page, on the caveman row's Configure control.
|
|
16
|
+
*
|
|
17
|
+
* Skill content is adapted from the reference implementation
|
|
18
|
+
* (https://github.com/JuliusBrussee/caveman, MIT, © JuliusBrussee). Only the
|
|
19
|
+
* skill (talking-style) half is ported: the proxy, CLI verbs, and Cloud
|
|
20
|
+
* engine need an external runtime the harness has no extension point for.
|
|
21
|
+
*
|
|
22
|
+
* @module dsh-caveman
|
|
23
|
+
*/
|
|
24
|
+
import type { Volatile } from '@deepseek-ai/cordis';
|
|
25
|
+
import z from '@deepseek-ai/schemastery';
|
|
26
|
+
import { type CavemanMode } from './modes.ts';
|
|
27
|
+
import type { HostContext } from './host.ts';
|
|
28
|
+
/** Plugin name as it appears in the loader. */
|
|
29
|
+
export declare const name = "caveman";
|
|
30
|
+
/**
|
|
31
|
+
* Route the browser half reads for the level in use and its source. The card
|
|
32
|
+
* and the chip cannot see the env, the upstream config file, or a
|
|
33
|
+
* session-local level, so they ask the host instead of the settings document.
|
|
34
|
+
*/
|
|
35
|
+
export declare const LEVEL_ROUTE = "/caveman/level";
|
|
36
|
+
/**
|
|
37
|
+
* Configuration received by the plugin, as the loader resolved this row
|
|
38
|
+
* against the schema below: every ordinary field carries its default, and every
|
|
39
|
+
* volatile field arrives as the live reference the settings document writes
|
|
40
|
+
* through. Read `.get()` when starting an operation.
|
|
41
|
+
*/
|
|
42
|
+
export interface Config {
|
|
43
|
+
/** Startup level. Absent resolves through the chain, ending at `full`. */
|
|
44
|
+
readonly defaultMode: Volatile<CavemanMode | undefined>;
|
|
45
|
+
/**
|
|
46
|
+
* Size cap in bytes for `/caveman-compress`; defaults to 500000. Volatile,
|
|
47
|
+
* so the Plugins card can raise or lower it while the plugin runs.
|
|
48
|
+
*/
|
|
49
|
+
readonly maxFileSize: Volatile<number>;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Row schema: the accepted levels and the size cap live here.
|
|
53
|
+
*
|
|
54
|
+
* Both fields are volatile, the only kind the settings document accepts: a
|
|
55
|
+
* change commits into the running config without remounting the plugin. Each is
|
|
56
|
+
* read at the moment it is used (the level at every prompt assembly, the size
|
|
57
|
+
* cap at every compress call), so an edit from the Plugins card takes effect on
|
|
58
|
+
* the next use rather than on a restart.
|
|
59
|
+
*
|
|
60
|
+
* `defaultMode` carries no default, so absence keeps flowing to
|
|
61
|
+
* `resolveDefaultMode`. A schema default would fill the field before `apply`,
|
|
62
|
+
* which would silently outrank `CAVEMAN_DEFAULT_MODE` and
|
|
63
|
+
* `~/.config/caveman/config.json`.
|
|
64
|
+
*/
|
|
65
|
+
export declare const Config: z<Schemastery.ObjectS<NoInfer<{
|
|
66
|
+
defaultMode: z<"full" | "lite" | "off" | "ultra" | "wenyan-full" | "wenyan-lite" | "wenyan-ultra", "full" | "lite" | "off" | "ultra" | "wenyan-full" | "wenyan-lite" | "wenyan-ultra", "volatile">;
|
|
67
|
+
maxFileSize: z<number, number, "volatile-defined">;
|
|
68
|
+
}>>, Schemastery.ObjectT<NoInfer<{
|
|
69
|
+
defaultMode: z<"full" | "lite" | "off" | "ultra" | "wenyan-full" | "wenyan-lite" | "wenyan-ultra", "full" | "lite" | "off" | "ultra" | "wenyan-full" | "wenyan-lite" | "wenyan-ultra", "volatile">;
|
|
70
|
+
maxFileSize: z<number, number, "volatile-defined">;
|
|
71
|
+
}>>, "plain">;
|
|
72
|
+
/**
|
|
73
|
+
* Read the upstream config file's `defaultMode`, ignoring everything that
|
|
74
|
+
* would make startup fail: a missing file, an unreadable file, invalid JSON,
|
|
75
|
+
* or a non-object document all mean "no file default".
|
|
76
|
+
* @param path - config file path; the upstream location unless tests override it.
|
|
77
|
+
* @returns the parsed document, or `undefined` when there is nothing usable.
|
|
78
|
+
*/
|
|
79
|
+
export declare function readUpstreamConfigFile(path?: string): {
|
|
80
|
+
readonly defaultMode?: unknown;
|
|
81
|
+
} | undefined;
|
|
82
|
+
/**
|
|
83
|
+
* Mount the plugin.
|
|
84
|
+
* @param ctx - the host context.
|
|
85
|
+
* @param config - the schema-resolved row configuration.
|
|
86
|
+
*/
|
|
87
|
+
export declare function apply(ctx: HostContext, config: Config): void;
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Caveman's level model: the accepted levels, their normalization, the
|
|
3
|
+
* mode-specific filter over the `caveman` skill body, and the instruction
|
|
4
|
+
* block the plugin injects into the system prompt.
|
|
5
|
+
*
|
|
6
|
+
* Levels mirror upstream (`JuliusBrussee/caveman`, MIT): lite, full, ultra
|
|
7
|
+
* and the three wenyan variants. Unlike ponytail there is no session-only
|
|
8
|
+
* level: every level persists. The one addition over upstream is the
|
|
9
|
+
* `wenyan` shorthand for `wenyan-full`, accepted by the `/caveman` command.
|
|
10
|
+
*
|
|
11
|
+
* @module dsh-caveman/modes
|
|
12
|
+
*/
|
|
13
|
+
/** Every accepted level; all persist as a default. */
|
|
14
|
+
export declare const RUNTIME_MODES: readonly ['off', 'lite', 'full', 'ultra', 'wenyan-lite', 'wenyan-full', 'wenyan-ultra'];
|
|
15
|
+
/** Any level the plugin accepts. */
|
|
16
|
+
export type CavemanMode = (typeof RUNTIME_MODES)[number];
|
|
17
|
+
/** Level used when neither config nor environment sets one. */
|
|
18
|
+
export declare const DEFAULT_MODE: CavemanMode;
|
|
19
|
+
/**
|
|
20
|
+
* Normalize a value to a level that may be persisted as a default.
|
|
21
|
+
* @param value - candidate level from a config field, environment, or command.
|
|
22
|
+
* @returns the canonical runtime level, or `undefined` when unrecognized.
|
|
23
|
+
*/
|
|
24
|
+
export declare function normalizeMode(value: unknown): CavemanMode | undefined;
|
|
25
|
+
/**
|
|
26
|
+
* Whether a whole message is a deactivation command.
|
|
27
|
+
*
|
|
28
|
+
* "stop caveman" / "normal mode" turn caveman off, but only as a standalone
|
|
29
|
+
* command: matching the phrase anywhere in a message turned it off mid-task for
|
|
30
|
+
* ordinary requests like "add a normal mode toggle", so the whole trimmed
|
|
31
|
+
* message must be the command, ignoring case and trailing punctuation.
|
|
32
|
+
* @param text - user message text.
|
|
33
|
+
* @returns whether the message is the deactivation command.
|
|
34
|
+
*/
|
|
35
|
+
export declare function isDeactivationCommand(text: string): boolean;
|
|
36
|
+
/**
|
|
37
|
+
* Resolve a human `/caveman` argument to a level, including the `wenyan`
|
|
38
|
+
* shorthand for `wenyan-full` (upstream: `/caveman wenyan` means full 文言文).
|
|
39
|
+
* @param input - trimmed, lowercased command input.
|
|
40
|
+
* @returns the canonical level, or `undefined` when unrecognized.
|
|
41
|
+
*/
|
|
42
|
+
export declare function normalizeCommandMode(input: string): CavemanMode | undefined;
|
|
43
|
+
/**
|
|
44
|
+
* Where the level in use came from: the row's `defaultMode` (which the
|
|
45
|
+
* settings document edits), `CAVEMAN_DEFAULT_MODE`, the upstream config file,
|
|
46
|
+
* the built-in `full`, or a level held only by this process because the
|
|
47
|
+
* settings document could not take it.
|
|
48
|
+
*/
|
|
49
|
+
export type LevelSource = 'settings' | 'env' | 'config-file' | 'default' | 'session';
|
|
50
|
+
/** A level together with the source that decided it. */
|
|
51
|
+
export interface ResolvedLevel {
|
|
52
|
+
readonly mode: CavemanMode;
|
|
53
|
+
readonly source: LevelSource;
|
|
54
|
+
}
|
|
55
|
+
/** Inputs for {@link resolveDefaultMode}, all injectable for tests. */
|
|
56
|
+
interface DefaultModeSources {
|
|
57
|
+
/** Deployment default from this plugin's config field; wins over everything. */
|
|
58
|
+
readonly configured?: unknown;
|
|
59
|
+
/** Environment lookup; defaults to `process.env`. */
|
|
60
|
+
readonly env?: Record<string, string | undefined> | undefined;
|
|
61
|
+
/** Parsed upstream config file (`~/.config/caveman/config.json`); lowest config priority. */
|
|
62
|
+
readonly configFile?: {
|
|
63
|
+
readonly defaultMode?: unknown;
|
|
64
|
+
} | undefined;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Resolve the configured level and the source that decided it.
|
|
68
|
+
*
|
|
69
|
+
* Order: this plugin's config field, then `CAVEMAN_DEFAULT_MODE`, then the
|
|
70
|
+
* upstream config file (`~/.config/caveman/config.json`), then `full`.
|
|
71
|
+
* @param sources - injectable overrides for tests.
|
|
72
|
+
* @returns the level and its source.
|
|
73
|
+
*/
|
|
74
|
+
export declare function resolveDefaultMode(sources?: DefaultModeSources): ResolvedLevel;
|
|
75
|
+
/**
|
|
76
|
+
* Drop the intensity-table rows and worked examples that belong to other
|
|
77
|
+
* levels.
|
|
78
|
+
*
|
|
79
|
+
* Only the intensity table rows and worked examples are mode-specific, and both
|
|
80
|
+
* are keyed by a level name. A bullet whose label is not a level (e.g.
|
|
81
|
+
* "Never drop not/never/no/only/except ...") is a normal rule and stays
|
|
82
|
+
* verbatim; the quoted-value requirement on examples is what keeps a rule that
|
|
83
|
+
* merely starts with a level word from being dropped in every other mode.
|
|
84
|
+
* @param body - markdown of the `caveman` skill, frontmatter already removed.
|
|
85
|
+
* @param mode - the level to keep.
|
|
86
|
+
* @returns the body with other levels' rows and examples removed.
|
|
87
|
+
*/
|
|
88
|
+
export declare function filterSkillBodyForMode(body: string, mode: CavemanMode): string;
|
|
89
|
+
/** Inputs for {@link buildModeInstructions}. */
|
|
90
|
+
interface InstructionInput {
|
|
91
|
+
/** Active level. */
|
|
92
|
+
readonly mode: CavemanMode;
|
|
93
|
+
/** `skills/caveman/SKILL.md` body with its frontmatter already removed. */
|
|
94
|
+
readonly skillBody: string;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Build the exact text the system prompt carries for one level.
|
|
98
|
+
* @param input - the active level and the skill body.
|
|
99
|
+
* @returns the instruction block, or `''` when the level is `off`.
|
|
100
|
+
*/
|
|
101
|
+
export declare function buildModeInstructions(input: InstructionInput): string;
|
|
102
|
+
export {};
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The bundled caveman skills as a `ctx.skills` provider.
|
|
3
|
+
*
|
|
4
|
+
* Skills are read from this package's `skills/<name>/SKILL.md`, so the same
|
|
5
|
+
* files stay the single source of truth for both the always-on ruleset (which
|
|
6
|
+
* filters the `caveman` body per level) and the on-demand skills.
|
|
7
|
+
*
|
|
8
|
+
* @module dsh-caveman/skills
|
|
9
|
+
*/
|
|
10
|
+
import type { SkillInvocationPolicy } from '@deepseek-ai/dsh-skill';
|
|
11
|
+
import type { SkillProviderLike } from './host.ts';
|
|
12
|
+
/** One parsed bundled skill. */
|
|
13
|
+
interface CavemanSkill {
|
|
14
|
+
/** Kebab-case skill name from frontmatter, or the directory name. */
|
|
15
|
+
readonly name: string;
|
|
16
|
+
/** Routing description from frontmatter. */
|
|
17
|
+
readonly description: string;
|
|
18
|
+
/** Optional extra routing guidance from `whenToUse`. */
|
|
19
|
+
readonly whenToUse?: string;
|
|
20
|
+
/** Resolved invocation controls from the two canonical frontmatter keys. */
|
|
21
|
+
readonly invocation: SkillInvocationPolicy;
|
|
22
|
+
/** Instruction body with frontmatter removed. */
|
|
23
|
+
readonly content: string;
|
|
24
|
+
/** Frontmatter keys this provider does not project (`license`, `tools`, …). */
|
|
25
|
+
readonly metadata: Readonly<Record<string, unknown>>;
|
|
26
|
+
/** Absolute path of the instruction file. */
|
|
27
|
+
readonly path: string;
|
|
28
|
+
/** Absolute path of the skill directory, used as the resource base. */
|
|
29
|
+
readonly directory: string;
|
|
30
|
+
}
|
|
31
|
+
/** Options for {@link createSkillProvider}. */
|
|
32
|
+
interface SkillProviderOptions {
|
|
33
|
+
/** Directory holding one subdirectory per skill. */
|
|
34
|
+
readonly skillsDir: string;
|
|
35
|
+
/** Receives non-fatal discovery problems instead of throwing. */
|
|
36
|
+
readonly onWarn?: (message: string) => void;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Read every valid skill directory under `skillsDir`.
|
|
40
|
+
*
|
|
41
|
+
* A missing directory, a directory without `SKILL.md`, a file whose frontmatter
|
|
42
|
+
* the reader refuses, and a file with a missing description are reported
|
|
43
|
+
* through `onWarn` and skipped: one broken file must not cost the catalog its
|
|
44
|
+
* other skills.
|
|
45
|
+
* @param skillsDir - directory holding one subdirectory per skill.
|
|
46
|
+
* @param onWarn - optional non-fatal problem sink.
|
|
47
|
+
* @returns the parsed skills, sorted by name.
|
|
48
|
+
*/
|
|
49
|
+
export declare function discoverSkills(skillsDir: string, onWarn?: (message: string) => void): Promise<readonly CavemanSkill[]>;
|
|
50
|
+
/**
|
|
51
|
+
* Build the provider the skill registry mounts.
|
|
52
|
+
* @param options - skills directory and the non-fatal problem sink.
|
|
53
|
+
* @returns a provider whose candidates are summaries and whose bodies come from disk.
|
|
54
|
+
*/
|
|
55
|
+
export declare function createSkillProvider(options: SkillProviderOptions): SkillProviderLike;
|
|
56
|
+
export {};
|
package/locale/en.json
ADDED
package/locale/zh.json
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@maci0/dsh-caveman",
|
|
3
|
+
"version": "0.16.2",
|
|
4
|
+
"publishConfig": {
|
|
5
|
+
"access": "public",
|
|
6
|
+
"registry": "https://registry.npmjs.org/"
|
|
7
|
+
},
|
|
8
|
+
"type": "module",
|
|
9
|
+
"main": "lib/index.js",
|
|
10
|
+
"types": "lib/types/index.d.ts",
|
|
11
|
+
"description": "Caveman terse-talk mode, for DeepSeek Harness: bundled skills, an always-on compression ruleset, and a Plugin configuration card.",
|
|
12
|
+
"license": "MIT",
|
|
13
|
+
"exports": {
|
|
14
|
+
".": {
|
|
15
|
+
"types": "./lib/types/index.d.ts",
|
|
16
|
+
"default": "./lib/index.js"
|
|
17
|
+
},
|
|
18
|
+
"./client": {
|
|
19
|
+
"default": "./lib/client.js"
|
|
20
|
+
},
|
|
21
|
+
"./cordis.patch.yml": "./cordis.patch.yml",
|
|
22
|
+
"./locale/*.json": "./locale/*.json",
|
|
23
|
+
"./package.json": "./package.json"
|
|
24
|
+
},
|
|
25
|
+
"dsh": {
|
|
26
|
+
"bundle": {
|
|
27
|
+
"patch": "./cordis.patch.yml"
|
|
28
|
+
},
|
|
29
|
+
"client": {
|
|
30
|
+
"platform": "web",
|
|
31
|
+
"inject": [
|
|
32
|
+
"@deepseek-ai/dsh-client-connection",
|
|
33
|
+
"@deepseek-ai/dsh-client-locale",
|
|
34
|
+
"@deepseek-ai/dsh-client-ui-renderer",
|
|
35
|
+
"@deepseek-ai/dsh-client-ui-settings",
|
|
36
|
+
"@deepseek-ai/dsh-client-ui-plugin-manager"
|
|
37
|
+
]
|
|
38
|
+
},
|
|
39
|
+
"compatibility": {
|
|
40
|
+
"dsh": ">=0.2.0-rc.2 <0.3.0"
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
"files": [
|
|
44
|
+
"icon.svg",
|
|
45
|
+
"locale/*.json",
|
|
46
|
+
"lib/**/*.js",
|
|
47
|
+
"lib/types/**/*.d.ts",
|
|
48
|
+
"skills",
|
|
49
|
+
"scripts/sync-upstream.mjs",
|
|
50
|
+
"sync.manifest.json",
|
|
51
|
+
"cordis.patch.yml",
|
|
52
|
+
"README.md",
|
|
53
|
+
"LICENSE"
|
|
54
|
+
],
|
|
55
|
+
"scripts": {
|
|
56
|
+
"build": "bunx --bun tsc -p tsconfig.build.json",
|
|
57
|
+
"test": "bun test",
|
|
58
|
+
"typecheck": "bunx --bun tsc -p tsconfig.json",
|
|
59
|
+
"sync:check": "bun scripts/sync-upstream.mjs check",
|
|
60
|
+
"sync": "bun scripts/sync-upstream.mjs sync",
|
|
61
|
+
"test:node": "node --test tests/*.test.*"
|
|
62
|
+
},
|
|
63
|
+
"engines": {
|
|
64
|
+
"node": "^22.19.0 || >=24.0.0"
|
|
65
|
+
},
|
|
66
|
+
"dependencies": {
|
|
67
|
+
"@deepseek-ai/dsh-skill": "0.2.1-alpha.1",
|
|
68
|
+
"@deepseek-ai/dsh-tools": "0.2.1-alpha.1",
|
|
69
|
+
"@deepseek-ai/schemastery": "^3.18.4",
|
|
70
|
+
"yaml": "2.9.1"
|
|
71
|
+
},
|
|
72
|
+
"peerDependencies": {
|
|
73
|
+
"@deepseek-ai/cordis": "4.0.5-alpha.1",
|
|
74
|
+
"@deepseek-ai/dsh-client-connection": "*",
|
|
75
|
+
"@deepseek-ai/dsh-client-locale": "*",
|
|
76
|
+
"@deepseek-ai/dsh-client-ui-renderer": "*",
|
|
77
|
+
"@deepseek-ai/dsh-client-ui-settings": "*",
|
|
78
|
+
"@deepseek-ai/dsh-client-ui-plugin-manager": "*"
|
|
79
|
+
},
|
|
80
|
+
"peerDependenciesMeta": {
|
|
81
|
+
"@deepseek-ai/dsh-client-connection": {
|
|
82
|
+
"optional": true
|
|
83
|
+
},
|
|
84
|
+
"@deepseek-ai/dsh-client-locale": {
|
|
85
|
+
"optional": true
|
|
86
|
+
},
|
|
87
|
+
"@deepseek-ai/dsh-client-ui-renderer": {
|
|
88
|
+
"optional": true
|
|
89
|
+
},
|
|
90
|
+
"@deepseek-ai/dsh-client-ui-settings": {
|
|
91
|
+
"optional": true
|
|
92
|
+
},
|
|
93
|
+
"@deepseek-ai/dsh-client-ui-plugin-manager": {
|
|
94
|
+
"optional": true
|
|
95
|
+
}
|
|
96
|
+
},
|
|
97
|
+
"devDependencies": {
|
|
98
|
+
"@deepseek-ai/cordis": "4.0.5-alpha.1",
|
|
99
|
+
"@deepseek-ai/dsh-brand": "0.2.1-alpha.1",
|
|
100
|
+
"@deepseek-ai/dsh-llm": "0.2.1-alpha.1",
|
|
101
|
+
"@deepseek-ai/dsh-sandbox": "0.2.1-alpha.1",
|
|
102
|
+
"@deepseek-ai/dsh-scope": "0.2.1-alpha.1",
|
|
103
|
+
"@deepseek-ai/dsh-util-values": "0.2.1-alpha.1",
|
|
104
|
+
"@types/node": "^22.20.2",
|
|
105
|
+
"typescript": "^7.0.2"
|
|
106
|
+
},
|
|
107
|
+
"repository": {
|
|
108
|
+
"type": "git",
|
|
109
|
+
"url": "https://github.com/maci0/dsh-caveman.git"
|
|
110
|
+
},
|
|
111
|
+
"icon": "./icon.svg"
|
|
112
|
+
}
|