dsh-tiddlywiki 0.1.0
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 +21 -0
- package/README.md +172 -0
- package/cordis.patch.yml +13 -0
- package/lib/client.bundle.js +1417 -0
- package/lib/client.js +1427 -0
- package/lib/index.js +2153 -0
- package/lib/index.js.map +1 -0
- package/package.json +63 -0
- package/src/client/editor-popup.ts +121 -0
- package/src/client/index.ts +76 -0
- package/src/client/note-widget.ts +210 -0
- package/src/client/panel.ts +304 -0
- package/src/client/settings-page.ts +397 -0
- package/src/client/sidebar-entry.ts +148 -0
- package/src/client/state.ts +39 -0
- package/src/client/styles.ts +235 -0
- package/src/client/toast.ts +22 -0
- package/src/host/admin.ts +408 -0
- package/src/host/config.ts +86 -0
- package/src/host/git.ts +218 -0
- package/src/host/routes.ts +233 -0
- package/src/host/seed-notes.ts +62 -0
- package/src/host/tools.ts +254 -0
- package/src/host/tw-api.ts +157 -0
- package/src/host/wiki.ts +287 -0
- package/src/index.ts +331 -0
- package/src/sdk.ts +198 -0
package/src/sdk.ts
ADDED
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Self-contained replacements for the @deepseek-ai runtime imports the host
|
|
3
|
+
* half must NEVER take from npm-mirror SDK packages (dsh-home-paths,
|
|
4
|
+
* dsh-tools' defineTool).
|
|
5
|
+
*
|
|
6
|
+
* Why (design doc §4.4, taskboard lesson): a published copy must not resolve
|
|
7
|
+
* `@deepseek-ai/dsh-tools` from the profile's node_modules — an npm-mirror
|
|
8
|
+
* dsh-tools there shadows the CLI-internal build for the WHOLE base layer and
|
|
9
|
+
* breaks the agent loop. Everything here is a pure, structure-compatible
|
|
10
|
+
* reimplementation of the exact behavior the registry relies on:
|
|
11
|
+
*
|
|
12
|
+
* - `dshHomePath` mirrors `join(resolve(env.DSH_HOME ?? ~/.dsh), ...segments)`;
|
|
13
|
+
* - `defineTool` compiles author-facing parameter specs into the same raw
|
|
14
|
+
* JSON-Schema subset the registry expects and pre-validates model arguments.
|
|
15
|
+
*
|
|
16
|
+
* @module dsh-tiddlywiki/sdk
|
|
17
|
+
*/
|
|
18
|
+
import { homedir } from 'node:os'
|
|
19
|
+
import { join, resolve } from 'node:path'
|
|
20
|
+
|
|
21
|
+
/** The DSH user home (DSH_HOME overrides). */
|
|
22
|
+
export function dshHomePath(...segments: string[]): string {
|
|
23
|
+
const override = process.env.DSH_HOME
|
|
24
|
+
const home = resolve(override !== undefined && override.length > 0 ? override : join(homedir(), '.dsh'))
|
|
25
|
+
return join(home, ...segments)
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/** Author-facing scalar spec. */
|
|
29
|
+
interface ScalarSpec {
|
|
30
|
+
readonly type: 'string' | 'number' | 'integer' | 'boolean' | 'null'
|
|
31
|
+
readonly description?: string
|
|
32
|
+
readonly enum?: readonly unknown[]
|
|
33
|
+
readonly const?: unknown
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/** Author-facing object spec (additionalProperties is mandatory). */
|
|
37
|
+
interface ObjectSpec {
|
|
38
|
+
readonly type: 'object'
|
|
39
|
+
readonly additionalProperties: boolean
|
|
40
|
+
readonly description?: string
|
|
41
|
+
readonly properties?: Readonly<Record<string, ValueSpec>>
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/** Author-facing value spec. */
|
|
45
|
+
type ValueSpec = ScalarSpec | ObjectSpec | { readonly type: 'json'; readonly description?: string } | { readonly type: 'array'; readonly items?: ValueSpec; readonly description?: string }
|
|
46
|
+
|
|
47
|
+
/** Author-facing parameter entry (a value spec plus top-level required). */
|
|
48
|
+
type ParameterSpec = ValueSpec & { readonly required?: boolean }
|
|
49
|
+
|
|
50
|
+
/** Raw JSON-Schema subset node. */
|
|
51
|
+
type RawSchema = Record<string, unknown>
|
|
52
|
+
|
|
53
|
+
/** Compile one value spec to the raw subset (json → annotation-only). */
|
|
54
|
+
function compileValue(spec: ValueSpec): RawSchema {
|
|
55
|
+
const node: RawSchema = {}
|
|
56
|
+
const description = (spec as { description?: string }).description
|
|
57
|
+
if (typeof description === 'string' && description.length > 0) node.description = description
|
|
58
|
+
const type = (spec as { type?: string }).type
|
|
59
|
+
if (type === undefined || type === 'json') return node
|
|
60
|
+
if (type === 'object') {
|
|
61
|
+
const objectSpec = spec as ObjectSpec
|
|
62
|
+
node.type = 'object'
|
|
63
|
+
node.additionalProperties = objectSpec.additionalProperties
|
|
64
|
+
if (objectSpec.properties !== undefined) node.properties = compilePropertyMap(objectSpec.properties).properties
|
|
65
|
+
return node
|
|
66
|
+
}
|
|
67
|
+
if (type === 'array') {
|
|
68
|
+
node.type = 'array'
|
|
69
|
+
const items = (spec as { items?: ValueSpec }).items
|
|
70
|
+
if (items !== undefined) node.items = compileValue(items)
|
|
71
|
+
return node
|
|
72
|
+
}
|
|
73
|
+
node.type = type
|
|
74
|
+
const enumValues = (spec as ScalarSpec).enum
|
|
75
|
+
if (enumValues !== undefined) node.enum = [...enumValues]
|
|
76
|
+
const constValue = (spec as ScalarSpec).const
|
|
77
|
+
if (constValue !== undefined) node.const = constValue
|
|
78
|
+
return node
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/** Compile a property map: properties + collected required list. */
|
|
82
|
+
function compilePropertyMap(spec: Readonly<Record<string, ParameterSpec>>): { properties: Record<string, RawSchema>; required?: string[] } {
|
|
83
|
+
const properties: Record<string, RawSchema> = {}
|
|
84
|
+
const required: string[] = []
|
|
85
|
+
for (const [name, entry] of Object.entries(spec)) {
|
|
86
|
+
const { required: isRequired, ...valueSpec } = entry as ParameterSpec & Record<string, unknown>
|
|
87
|
+
properties[name] = compileValue(valueSpec as ValueSpec)
|
|
88
|
+
if (isRequired === true) required.push(name)
|
|
89
|
+
}
|
|
90
|
+
return required.length > 0 ? { properties, required } : { properties }
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/** Does a JS value match a raw-subset scalar type? */
|
|
94
|
+
function matchesScalarType(value: unknown, type: string): boolean {
|
|
95
|
+
switch (type) {
|
|
96
|
+
case 'string': return typeof value === 'string'
|
|
97
|
+
case 'number': return typeof value === 'number'
|
|
98
|
+
case 'integer': return typeof value === 'number' && Number.isInteger(value)
|
|
99
|
+
case 'boolean': return typeof value === 'boolean'
|
|
100
|
+
case 'null': return value === null
|
|
101
|
+
default: return true
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/** Validate a value against the compiled subset; returns path-qualified violations. */
|
|
106
|
+
function validateValue(schema: RawSchema, value: unknown, path: string): string[] {
|
|
107
|
+
if (typeof schema.type !== 'string' || schema.type.length === 0) return []
|
|
108
|
+
if (schema.type === 'object') {
|
|
109
|
+
if (typeof value !== 'object' || value === null || Array.isArray(value)) return [`${path} must be an object`]
|
|
110
|
+
const violations: string[] = []
|
|
111
|
+
const present = value as Record<string, unknown>
|
|
112
|
+
for (const key of (schema.required as string[] | undefined) ?? []) {
|
|
113
|
+
if (!(key in present)) violations.push(`${path}.${key} is required`)
|
|
114
|
+
}
|
|
115
|
+
if (schema.additionalProperties === false) {
|
|
116
|
+
const known = new Set(Object.keys((schema.properties as Record<string, RawSchema> | undefined) ?? {}))
|
|
117
|
+
for (const key of Object.keys(present)) {
|
|
118
|
+
if (!known.has(key)) violations.push(`${path}.${key} is not a declared property`)
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
for (const [key, child] of Object.entries((schema.properties as Record<string, RawSchema> | undefined) ?? {})) {
|
|
122
|
+
if (key in present) violations.push(...validateValue(child, present[key], `${path}.${key}`))
|
|
123
|
+
}
|
|
124
|
+
return violations
|
|
125
|
+
}
|
|
126
|
+
if (schema.type === 'array') {
|
|
127
|
+
if (!Array.isArray(value)) return [`${path} must be an array`]
|
|
128
|
+
const violations: string[] = []
|
|
129
|
+
const items = schema.items as RawSchema | undefined
|
|
130
|
+
if (items !== undefined) {
|
|
131
|
+
value.forEach((item, index) => { violations.push(...validateValue(items, item, `${path}[${index}]`)) })
|
|
132
|
+
}
|
|
133
|
+
return violations
|
|
134
|
+
}
|
|
135
|
+
if (!matchesScalarType(value, schema.type)) return [`${path} must be ${schema.type}`]
|
|
136
|
+
const enumValues = schema.enum as unknown[] | undefined
|
|
137
|
+
if (enumValues !== undefined && !enumValues.some(v => v === value)) {
|
|
138
|
+
return [`${path} must be one of ${enumValues.map(String).join(', ')}`]
|
|
139
|
+
}
|
|
140
|
+
const constValue = (schema as { const?: unknown }).const
|
|
141
|
+
if (constValue !== undefined && constValue !== value) {
|
|
142
|
+
return [`${path} must be ${String(constValue)}`]
|
|
143
|
+
}
|
|
144
|
+
return []
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/** Options shape we consume (a structural subset of the SDK's defineTool). */
|
|
148
|
+
export interface DefineToolOptions<A, V> {
|
|
149
|
+
readonly name: string
|
|
150
|
+
readonly description: string
|
|
151
|
+
readonly parameters: Readonly<Record<string, ParameterSpec>>
|
|
152
|
+
readonly output: {
|
|
153
|
+
readonly schema: { readonly type: 'json' }
|
|
154
|
+
render(args: A, value: V): Array<{ type: 'text'; text: string }>
|
|
155
|
+
}
|
|
156
|
+
execute(args: A, exec: unknown): Promise<V>
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/** A registry-ready tool definition (structure-compatible with the SDK's). */
|
|
160
|
+
export interface ToolDefinition<A = unknown, V = unknown> {
|
|
161
|
+
readonly name: string
|
|
162
|
+
readonly description: string
|
|
163
|
+
readonly parameters: RawSchema
|
|
164
|
+
readonly output: {
|
|
165
|
+
readonly schema: RawSchema
|
|
166
|
+
render(args: A, value: V): Array<{ type: 'text'; text: string }>
|
|
167
|
+
}
|
|
168
|
+
execute(args: A, exec: unknown): Promise<V>
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Define a first-party tool: compile the parameter spec, pre-validate
|
|
173
|
+
* arguments, and pass through the execution.
|
|
174
|
+
*/
|
|
175
|
+
export function defineTool<A extends Record<string, unknown>, V>(options: DefineToolOptions<A, V>): ToolDefinition<A, V> {
|
|
176
|
+
const compiled = compilePropertyMap(options.parameters as Readonly<Record<string, ParameterSpec>>)
|
|
177
|
+
const parameters: RawSchema = { type: 'object', properties: compiled.properties }
|
|
178
|
+
if (compiled.required !== undefined) parameters.required = compiled.required
|
|
179
|
+
const userExecute = options.execute
|
|
180
|
+
return {
|
|
181
|
+
name: options.name,
|
|
182
|
+
description: options.description,
|
|
183
|
+
parameters,
|
|
184
|
+
output: {
|
|
185
|
+
schema: {},
|
|
186
|
+
render(args, value) {
|
|
187
|
+
return options.output.render(args, value)
|
|
188
|
+
},
|
|
189
|
+
},
|
|
190
|
+
async execute(args, exec) {
|
|
191
|
+
const violations = validateValue(parameters, args, 'arguments')
|
|
192
|
+
if (violations.length > 0) {
|
|
193
|
+
throw new Error(`Error: invalid arguments: ${violations.join('; ')}`)
|
|
194
|
+
}
|
|
195
|
+
return userExecute(args, exec)
|
|
196
|
+
},
|
|
197
|
+
}
|
|
198
|
+
}
|