dsh-openwrite 0.2.24 → 0.2.26
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 +17 -6
- package/docs/COST_MEASUREMENT.md +2 -2
- package/docs/DEVELOPMENT.md +1 -1
- package/docs/DSH_STORE.md +7 -1
- package/docs/GITEE_EMBEDDING_FIX.md +40 -0
- package/docs/INSTALL.md +21 -1
- package/docs/ISSUES_105_113.md +15 -0
- package/docs/ISSUES_88_95.md +4 -4
- package/docs/ISSUES_98_100.md +61 -0
- package/docs/ISSUE_109_REPAIRS.md +40 -0
- package/docs/OPENCODE_GO.md +31 -0
- package/docs/PLUGIN_MAINTENANCE.md +1 -1
- package/docs/RELEASE_ACCEPTANCE.md +18 -0
- package/package.json +11 -8
- package/packages/openwrite-bridge/lib/client.d.ts +2 -0
- package/packages/openwrite-bridge/lib/client.js +26 -2
- package/packages/openwrite-bridge/lib/domain.js +22 -3
- package/packages/openwrite-bridge/lib/index.d.ts +2 -0
- package/packages/openwrite-bridge/lib/index.js +3 -1
- package/packages/openwrite-bridge/lib/managed-runtime.d.ts +6 -0
- package/packages/openwrite-bridge/lib/managed-runtime.js +11 -1
- package/packages/openwrite-bridge/lib/tool-policy.js +2 -0
- package/packages/openwrite-bridge/lib/tools.js +103 -8
- package/packages/openwrite-bridge/package.json +6 -5
- package/packages/studio-panel/lib/client.js +1628 -580
- package/packages/studio-panel/lib/client.js.map +1 -1
- package/packages/studio-panel/lib/types/client/SerialWritingView.d.ts +6 -0
- package/packages/studio-panel/lib/types/client/benchmark-options.d.ts +1 -0
- package/packages/studio-panel/lib/types/client/dto.d.ts +3 -1
- package/packages/studio-panel/lib/types/client/locales.d.ts +1 -1
- package/packages/studio-panel/package.json +4 -3
- package/plugin.mjs +20 -10
- package/preset-definition.mjs +7 -1
- package/presets/openwrite/agent.cordis.yml +11 -0
- package/release/{openwrite-5.8.11-py3-none-any.whl → openwrite-5.8.14-py3-none-any.whl} +0 -0
- package/release/runtime-manifest.json +5 -5
- package/release/source.json +3 -3
- package/scripts/safe-upgrade.mjs +211 -0
- package/vendor/dsh-dog/package.json +10 -9
|
@@ -17,6 +17,7 @@ export const Config = Schema.object({
|
|
|
17
17
|
runtimeRoot: Schema.string(),
|
|
18
18
|
artifacts: Schema.string(),
|
|
19
19
|
baseUrl: Schema.string().default('http://127.0.0.1:4567'),
|
|
20
|
+
authToken: Schema.string().role('secret'),
|
|
20
21
|
timeoutMs: Schema.number().default(600000),
|
|
21
22
|
outputDir: Schema.string().default(join(tmpdir(), 'openwrite-exports')),
|
|
22
23
|
});
|
|
@@ -38,7 +39,8 @@ export function apply(ctx, config) {
|
|
|
38
39
|
return connection ? connection.requestRejection({ headers }) : 503;
|
|
39
40
|
};
|
|
40
41
|
const domain = new NovelDomainService(ctx, { authorizeRequest, baseUrl: config.baseUrl, timeoutMs: config.timeoutMs, outputDir: config.outputDir, resolveWorkspace,
|
|
41
|
-
...(runtime ? { connect: () => runtime.ensure() }
|
|
42
|
+
...(runtime ? { connect: () => runtime.ensure() }
|
|
43
|
+
: config.authToken ? { connect: async () => ({ baseUrl: config.baseUrl, token: config.authToken }) } : {}),
|
|
42
44
|
});
|
|
43
45
|
ctx.effect(() => () => runtime?.dispose(), 'openwrite: owned runtime cleanup');
|
|
44
46
|
ctx.inject(['webServer'], webCtx => webCtx.effect(() => webCtx.webServer.register({
|
|
@@ -40,6 +40,12 @@ export interface BackendConnection {
|
|
|
40
40
|
baseUrl: string;
|
|
41
41
|
token?: string;
|
|
42
42
|
}
|
|
43
|
+
export declare class UnsupportedRuntimePlatformError extends Error {
|
|
44
|
+
readonly platform: string;
|
|
45
|
+
readonly code = "RUNTIME_PLATFORM_UNSUPPORTED";
|
|
46
|
+
readonly status = 503;
|
|
47
|
+
constructor(platform: string);
|
|
48
|
+
}
|
|
43
49
|
export type SpawnFn = (command: string, args: readonly string[], options: SpawnOptions) => ChildProcess;
|
|
44
50
|
export interface RuntimeOptions {
|
|
45
51
|
spawn?: SpawnFn;
|
|
@@ -8,6 +8,16 @@ import { createInterface } from 'node:readline';
|
|
|
8
8
|
import { x as untar } from 'tar';
|
|
9
9
|
import { unzipSync } from 'fflate';
|
|
10
10
|
import { lock as acquireLock } from 'proper-lockfile';
|
|
11
|
+
export class UnsupportedRuntimePlatformError extends Error {
|
|
12
|
+
platform;
|
|
13
|
+
code = 'RUNTIME_PLATFORM_UNSUPPORTED';
|
|
14
|
+
status = 503;
|
|
15
|
+
constructor(platform) {
|
|
16
|
+
super(`OpenWrite Studio managed runtime is unavailable on ${platform}. Configure the bridge with mode: external and baseUrl pointing to a supported Studio server; see docs/INSTALL.md#external-studio. File tools that do not require Studio remain available.`);
|
|
17
|
+
this.platform = platform;
|
|
18
|
+
this.name = 'UnsupportedRuntimePlatformError';
|
|
19
|
+
}
|
|
20
|
+
}
|
|
11
21
|
export const DEFAULT_RESTART_LIMIT = 5;
|
|
12
22
|
export const DEFAULT_BACKOFF_MS = [1_000, 2_000, 4_000, 8_000, 16_000];
|
|
13
23
|
/** Budget for the per-request liveness probe of a previously-ready backend. */
|
|
@@ -538,7 +548,7 @@ export class ManagedRuntime {
|
|
|
538
548
|
const manifest = JSON.parse(await readFile(join(this.artifacts, 'runtime-manifest.json'), 'utf8'));
|
|
539
549
|
const platform = manifest.platforms[`${process.platform}-${process.arch}`];
|
|
540
550
|
if (!platform)
|
|
541
|
-
throw new
|
|
551
|
+
throw new UnsupportedRuntimePlatformError(`${process.platform}/${process.arch}`);
|
|
542
552
|
if (!manifest.wheel || !manifest.requirements)
|
|
543
553
|
throw new Error('The package is missing Core or dependency checksums');
|
|
544
554
|
const wheel = join(this.artifacts, manifest.wheel.file);
|
|
@@ -6,6 +6,7 @@ const reads = new Set([
|
|
|
6
6
|
'novel_revision_get', 'novel_tasks_list', 'novel_continuity', 'novel_diagnostics',
|
|
7
7
|
'novel_research_status', 'novel_research_report', 'novel_model_profiles',
|
|
8
8
|
'novel_manuscript_acceptance', 'novel_export_preflight',
|
|
9
|
+
'novel_manuscript_metrics', 'novel_outline_audit',
|
|
9
10
|
]);
|
|
10
11
|
const generates = new Set([
|
|
11
12
|
'novel_write_chapter', 'novel_review_chapter', 'novel_multi_write', 'novel_task_create',
|
|
@@ -14,6 +15,7 @@ const generates = new Set([
|
|
|
14
15
|
'novel_model_test', 'novel_model_embedding_test',
|
|
15
16
|
]);
|
|
16
17
|
const readActions = {
|
|
18
|
+
novel_writing_assets: ['get'],
|
|
17
19
|
novel_model_benchmark: ['list', 'get', 'options'],
|
|
18
20
|
novel_chapter_run_action: ['list', 'get'],
|
|
19
21
|
novel_rolling_plan_action: ['list', 'get'],
|
|
@@ -178,6 +178,11 @@ function resolveReviewPath(args) {
|
|
|
178
178
|
function objectValue(value) {
|
|
179
179
|
return value !== null && typeof value === 'object' && !Array.isArray(value) ? value : {};
|
|
180
180
|
}
|
|
181
|
+
function requireRecord(value, name) {
|
|
182
|
+
if (value === null || typeof value !== 'object' || Array.isArray(value))
|
|
183
|
+
throw new Error(`${name} must be a JSON object`);
|
|
184
|
+
return value;
|
|
185
|
+
}
|
|
181
186
|
async function deliveryForResponse(client, response, chapterId, signal, threshold) {
|
|
182
187
|
const embedded = objectValue(response)['workspace'];
|
|
183
188
|
const workspace = embedded !== null && typeof embedded === 'object' && !Array.isArray(embedded)
|
|
@@ -345,16 +350,17 @@ export function registerNovelTools(ctx, clientFactory, options) {
|
|
|
345
350
|
}));
|
|
346
351
|
ctx.tools.register(defineTool({
|
|
347
352
|
name: 'novel_context_preview',
|
|
348
|
-
description: 'Preview the context packet OpenWrite would assemble for writing a chapter (relevant outline, assets, foreshadowing, and prior-chapter memory).',
|
|
353
|
+
description: 'Preview the context packet OpenWrite would assemble for writing a chapter (relevant outline, assets, foreshadowing, and prior-chapter memory). Set include_agent_payload to inspect canonical writer inputs and document inclusion without calling a model.',
|
|
349
354
|
parameters: {
|
|
350
355
|
chapter: { type: 'string', description: 'Chapter id (e.g. "ch_0007"); omit or pass "next" for the next chapter to write.' },
|
|
356
|
+
include_agent_payload: { type: 'boolean', description: 'Include the full writer payload, rendered initial messages and document inventory. Later segment/retry messages depend on the write request.' },
|
|
351
357
|
},
|
|
352
358
|
output: { schema: JSON_OUTPUT_SCHEMA, render: (_args, value) => renderJson(value) },
|
|
353
359
|
timeoutMs,
|
|
354
360
|
isConcurrencySafe: () => true,
|
|
355
361
|
async execute(args, exec) {
|
|
356
362
|
const client = clientFor(exec);
|
|
357
|
-
return await client.getJson('/api/context', { chapter: args.chapter?.trim() || 'next' }, exec.signal);
|
|
363
|
+
return await client.getJson('/api/context', { chapter: args.chapter?.trim() || 'next', ...(args.include_agent_payload ? { include_agent_payload: 'true' } : {}) }, exec.signal);
|
|
358
364
|
},
|
|
359
365
|
}));
|
|
360
366
|
ctx.tools.register(defineTool({
|
|
@@ -798,6 +804,7 @@ export function registerNovelTools(ctx, clientFactory, options) {
|
|
|
798
804
|
data: { type: 'json', description: 'Object of asset fields to merge (e.g. name, summary, aliases).' },
|
|
799
805
|
body_markdown: { type: 'string', description: 'Replacement markdown body (character/world assets).' },
|
|
800
806
|
raw_text: { type: 'string', description: 'Full replacement document text, validated by the server.' },
|
|
807
|
+
related_mode: { type: 'string', enum: ['merge', 'replace'], description: 'Preserve and merge existing related entries by default; replace explicitly clears or replaces relations.' },
|
|
801
808
|
},
|
|
802
809
|
output: { schema: JSON_OUTPUT_SCHEMA, render: (_args, value) => renderJson(value) },
|
|
803
810
|
timeoutMs,
|
|
@@ -810,6 +817,8 @@ export function registerNovelTools(ctx, clientFactory, options) {
|
|
|
810
817
|
body['body_markdown'] = args.body_markdown;
|
|
811
818
|
if (args.raw_text !== undefined)
|
|
812
819
|
body['raw_text'] = args.raw_text;
|
|
820
|
+
if (args.related_mode !== undefined)
|
|
821
|
+
body['related_mode'] = args.related_mode;
|
|
813
822
|
return await client.postJson('/api/assets/update', body, exec.signal);
|
|
814
823
|
},
|
|
815
824
|
}));
|
|
@@ -883,7 +892,7 @@ export function registerNovelTools(ctx, clientFactory, options) {
|
|
|
883
892
|
action: { type: 'string', required: true, enum: ['preview', 'apply', 'reject', 'retry', 'undo'], description: 'Plan lifecycle action.' },
|
|
884
893
|
confirm: { type: 'boolean', description: 'Required true for apply and undo after author acceptance.' },
|
|
885
894
|
path: { type: 'string', description: 'Existing document path for preview, relative to the novel root.' },
|
|
886
|
-
edits: { type: 'json', description: 'Preview edits: [{old_text,new_text}] or [{start_text,end_text,new_text}].' },
|
|
895
|
+
edits: { type: 'json', description: 'Preview edits: [{old_text,new_text}] or [{start_text,end_text,new_text,end_inclusive}]. Range end defaults to inclusive for compatibility; end_inclusive:false preserves the end anchor (e.g. the next heading).' },
|
|
887
896
|
preview_token: { type: 'string', description: 'Immutable preview or undo token for apply/reject/retry/undo.' },
|
|
888
897
|
},
|
|
889
898
|
output: { schema: JSON_OUTPUT_SCHEMA, render: (_args, value) => renderJson(value) },
|
|
@@ -979,7 +988,7 @@ export function registerNovelTools(ctx, clientFactory, options) {
|
|
|
979
988
|
'so the downloaded file is bound to the manuscript state that was inspected.',
|
|
980
989
|
parameters: {
|
|
981
990
|
format: { type: 'string', enum: ['md', 'txt', 'epub'], description: 'Export format (default "md").' },
|
|
982
|
-
purpose: { type: 'string', enum: ['backup', 'delivery'], description: 'Export purpose (default "delivery").
|
|
991
|
+
purpose: { type: 'string', enum: ['backup', 'delivery', 'personal_archive'], description: 'Export purpose (default "delivery"). personal_archive preserves author copies with gate findings recorded as warnings.' },
|
|
983
992
|
},
|
|
984
993
|
output: { schema: JSON_OUTPUT_SCHEMA, render: (_args, value) => renderJson(value) },
|
|
985
994
|
timeoutMs,
|
|
@@ -998,7 +1007,7 @@ export function registerNovelTools(ctx, clientFactory, options) {
|
|
|
998
1007
|
'preflight_revision unchanged to bind the download to that inspected manuscript state. Returns the saved file path.',
|
|
999
1008
|
parameters: {
|
|
1000
1009
|
format: { type: 'string', enum: ['md', 'txt', 'epub'], description: 'Export format (default "md").' },
|
|
1001
|
-
purpose: { type: 'string', enum: ['backup', 'delivery'], description: 'Export purpose (default "delivery").' },
|
|
1010
|
+
purpose: { type: 'string', enum: ['backup', 'delivery', 'personal_archive'], description: 'Export purpose (default "delivery").' },
|
|
1002
1011
|
preflight_revision: { type: 'string', description: 'Revision returned by novel_export_preflight for the same format and purpose.' },
|
|
1003
1012
|
},
|
|
1004
1013
|
output: {
|
|
@@ -2174,6 +2183,8 @@ export function registerNovelTools(ctx, clientFactory, options) {
|
|
|
2174
2183
|
'acknowledge are confirmation-gated by the server.',
|
|
2175
2184
|
parameters: {
|
|
2176
2185
|
action: { type: 'string', required: true, enum: ['baseline', 'external', 'resume', 'acknowledge', 'abandon'], description: 'The reconciliation action.' },
|
|
2186
|
+
mode: { type: 'string', enum: ['full', 'fast'], description: 'resume: fast accepts frozen manuscript without calling a model; derived facts remain stale and can be reconciled later.' },
|
|
2187
|
+
no_model: { type: 'boolean', description: 'external: accept manuscript bytes without extracting facts; does not clear the facts guard.' },
|
|
2177
2188
|
chapter_id: { type: 'string', description: 'Optional chapter id (ch_<digits>); omit for the project-level operation.' },
|
|
2178
2189
|
operation_id: { type: 'string', description: 'Durable operation id to resume or acknowledge.' },
|
|
2179
2190
|
domains: { type: 'array', items: { type: 'string' }, description: 'Affected domains to acknowledge or retry; acknowledge defaults to outline and foreshadowing.' },
|
|
@@ -2186,7 +2197,7 @@ export function registerNovelTools(ctx, clientFactory, options) {
|
|
|
2186
2197
|
throw new Error(`chapter_id must match ch_<digits>, got "${args.chapter_id}"`);
|
|
2187
2198
|
}
|
|
2188
2199
|
const body = {};
|
|
2189
|
-
for (const key of ['chapter_id', 'operation_id', 'domains', 'confirm']) {
|
|
2200
|
+
for (const key of ['chapter_id', 'operation_id', 'domains', 'confirm', 'mode', 'no_model']) {
|
|
2190
2201
|
const value = args[key];
|
|
2191
2202
|
if (value !== undefined)
|
|
2192
2203
|
body[key] = value;
|
|
@@ -2197,6 +2208,89 @@ export function registerNovelTools(ctx, clientFactory, options) {
|
|
|
2197
2208
|
return await clientFor(exec).postJson(`/api/manuscript/acceptance/${route}`, body, exec.signal);
|
|
2198
2209
|
},
|
|
2199
2210
|
}));
|
|
2211
|
+
ctx.tools.register(defineTool({
|
|
2212
|
+
name: 'novel_writing_assets',
|
|
2213
|
+
description: 'Read or save shared project terminology, review_terms toggle, concrete noun lexicon, overlap_threshold and character_groups. Anchors are Markdown files in the novel anchor/ directory. Save requires the revision returned by get. Character groups are optional descriptive material; retain identity and canonical state in character cards.',
|
|
2214
|
+
parameters: {
|
|
2215
|
+
action: { type: 'string', required: true, enum: ['get', 'save', 'save_anchor', 'mark_usage'], description: 'Asset operation.' },
|
|
2216
|
+
assets: { type: 'json', description: 'Object: terms [{term, forbidden?, replacement?, min_occurrences?, example?}], character_groups {name: [{id,text}]}, review_terms?, concrete_nouns?, overlap_threshold?.' },
|
|
2217
|
+
expected_revision: { type: 'string', description: 'Revision from get; empty for a new asset table.' },
|
|
2218
|
+
name: { type: 'string', description: 'save_anchor: simple .md filename.' },
|
|
2219
|
+
content: { type: 'string', description: 'save_anchor: Markdown reference prose.' },
|
|
2220
|
+
chapter_id: { type: 'string', description: 'mark_usage: chapter whose optional character details were used.' },
|
|
2221
|
+
groups: { type: 'json', description: 'mark_usage: character name to group IDs used in this chapter.' },
|
|
2222
|
+
},
|
|
2223
|
+
output: { schema: JSON_OUTPUT_SCHEMA, render: (_args, value) => renderJson(value) },
|
|
2224
|
+
timeoutMs,
|
|
2225
|
+
isConcurrencySafe: args => args.action === 'get',
|
|
2226
|
+
async execute(args, exec) {
|
|
2227
|
+
const client = clientFor(exec);
|
|
2228
|
+
if (args.action === 'get')
|
|
2229
|
+
return await client.getJson('/api/writing-assets', {}, exec.signal);
|
|
2230
|
+
if (args.action === 'save_anchor')
|
|
2231
|
+
return await client.postJson('/api/writing-assets', { action: args.action, name: args.name ?? '', content: args.content ?? '', expected_revision: args.expected_revision ?? '' }, exec.signal);
|
|
2232
|
+
if (args.action === 'mark_usage')
|
|
2233
|
+
return await client.postJson('/api/writing-assets', { action: args.action, chapter_id: args.chapter_id ?? '', groups: requireRecord(args.groups, 'groups') }, exec.signal);
|
|
2234
|
+
const assets = requireRecord(args.assets, 'assets');
|
|
2235
|
+
return await client.postJson('/api/writing-assets', { assets: assets, expected_revision: args.expected_revision ?? '' }, exec.signal);
|
|
2236
|
+
},
|
|
2237
|
+
}));
|
|
2238
|
+
ctx.tools.register(defineTool({
|
|
2239
|
+
name: 'novel_manuscript_metrics',
|
|
2240
|
+
description: 'Read deterministic chapter metrics, terminology findings, overlap against anchors and the previous three chapters, duplicate paragraphs and selected character groups. Overlap spans use Unicode codepoint offsets. No model call.',
|
|
2241
|
+
parameters: { chapter_id: { type: 'string', required: true, description: 'Canonical chapter ID.' } },
|
|
2242
|
+
output: { schema: JSON_OUTPUT_SCHEMA, render: (_args, value) => renderJson(value) },
|
|
2243
|
+
timeoutMs, isConcurrencySafe: () => true,
|
|
2244
|
+
async execute(args, exec) {
|
|
2245
|
+
if (!CHAPTER_ID_PATTERN.test(args.chapter_id))
|
|
2246
|
+
throw new Error('Invalid chapter_id');
|
|
2247
|
+
return await clientFor(exec).getJson(`/api/manuscript/${encodeURIComponent(args.chapter_id)}/metrics`, {}, exec.signal);
|
|
2248
|
+
},
|
|
2249
|
+
}));
|
|
2250
|
+
ctx.tools.register(defineTool({
|
|
2251
|
+
name: 'novel_outline_audit',
|
|
2252
|
+
description: 'Read countable chapter-group facts: budgets/actual words, declared promises and function streaks, declared/confirmed payoffs, overdue hooks and drift ledger. Never generates a score or claims prose fulfilled a promise. No model call.',
|
|
2253
|
+
parameters: {
|
|
2254
|
+
group_id: { type: 'string', description: 'Optional sec_* or arc_* group.' },
|
|
2255
|
+
start: { type: 'string', description: 'Optional first chapter ID.' },
|
|
2256
|
+
end: { type: 'string', description: 'Optional last chapter ID.' },
|
|
2257
|
+
},
|
|
2258
|
+
output: { schema: JSON_OUTPUT_SCHEMA, render: (_args, value) => renderJson(value) },
|
|
2259
|
+
timeoutMs, isConcurrencySafe: () => true,
|
|
2260
|
+
async execute(args, exec) {
|
|
2261
|
+
return await clientFor(exec).getJson('/api/outline/audit', { group_id: args.group_id ?? '', start: args.start ?? '', end: args.end ?? '' }, exec.signal);
|
|
2262
|
+
},
|
|
2263
|
+
}));
|
|
2264
|
+
ctx.tools.register(defineTool({
|
|
2265
|
+
name: 'novel_drift_entry',
|
|
2266
|
+
description: 'Record author-observed chapter drift. Saves an immutable outline/manuscript baseline first. More than two unresolved rewrite drifts in a section freezes generation until explicit reconciliation and replanning.',
|
|
2267
|
+
parameters: {
|
|
2268
|
+
group_id: { type: 'string', required: true, description: 'Section ID sec_*.' },
|
|
2269
|
+
chapter_id: { type: 'string', required: true, description: 'Chapter in this section.' },
|
|
2270
|
+
kind: { type: 'string', required: true, enum: ['growth', 'escape', 'dilution', 'snowball'], description: 'Drift kind.' },
|
|
2271
|
+
impact: { type: 'string', required: true, enum: ['local', 'section', 'arc'], description: 'Impact scope.' },
|
|
2272
|
+
rewrite: { type: 'boolean', description: 'Counts toward rewrite budget; default true.' },
|
|
2273
|
+
note: { type: 'string', required: true, description: 'Observed drift and supporting evidence.' },
|
|
2274
|
+
expected_revision: { type: 'integer', required: true, description: 'ledger.revision from outline audit.' },
|
|
2275
|
+
},
|
|
2276
|
+
output: { schema: JSON_OUTPUT_SCHEMA, render: (_args, value) => renderJson(value) },
|
|
2277
|
+
timeoutMs,
|
|
2278
|
+
async execute(args, exec) {
|
|
2279
|
+
return await clientFor(exec).postJson('/api/arc-reconcile', { ...args, action: 'drift_entry' }, exec.signal);
|
|
2280
|
+
},
|
|
2281
|
+
}));
|
|
2282
|
+
ctx.tools.register(defineTool({
|
|
2283
|
+
name: 'novel_arc_reconcile',
|
|
2284
|
+
description: 'Resolve selected drift entries by absorbing authored outline metadata, scheduling recovery in a later chapter, or freezing. Absorption requires concrete outline_updates and outline_revision; baseline is saved before edits. resume=true explicitly resumes a replanned group within budget. Does not rewrite manuscript.',
|
|
2285
|
+
parameters: {
|
|
2286
|
+
data: { type: 'json', required: true, description: 'Object: group_id, expected_revision, entry_ids[], decision absorb/recover/freeze, confirm:true. absorb: outline_revision, outline_updates[{node_id,metadata}], resume?. recover: plan, target_chapter_id.' },
|
|
2287
|
+
},
|
|
2288
|
+
output: { schema: JSON_OUTPUT_SCHEMA, render: (_args, value) => renderJson(value) },
|
|
2289
|
+
timeoutMs,
|
|
2290
|
+
async execute(args, exec) {
|
|
2291
|
+
return await clientFor(exec).postJson('/api/arc-reconcile', { ...requireRecord(args.data, 'data'), action: 'arc_reconcile' }, exec.signal);
|
|
2292
|
+
},
|
|
2293
|
+
}));
|
|
2200
2294
|
// ── style sources, reference library, runtime skills, rules ──────────────
|
|
2201
2295
|
ctx.tools.register(defineTool({
|
|
2202
2296
|
name: 'novel_source_action',
|
|
@@ -2393,13 +2487,14 @@ export function registerNovelTools(ctx, clientFactory, options) {
|
|
|
2393
2487
|
run_id: { type: 'string', description: 'Benchmark run id for get.' },
|
|
2394
2488
|
task_type: { type: 'string', enum: ['chapter', 'outline'], description: 'Run target: chapter (default) or outline. Outline supports framework mode only.' },
|
|
2395
2489
|
chapter_id: { type: 'string', description: 'Chapter task target: next (default) or an available canonical chapter_id from options, e.g. ch_003. Unavailable targets are rejected without fallback; inspect availability/reason first.' },
|
|
2490
|
+
allow_historical: { type: 'boolean', description: 'Explicit isolated rewrite of an already written chapter using current canon. This is not a reconstructed pre-chapter baseline. Source manuscript and ledgers remain unchanged.' },
|
|
2396
2491
|
outline_start_chapter: { type: 'integer', description: 'Outline task first chapter number, inclusive, 1-100000. Omit to continue after the last outline chapter.' },
|
|
2397
2492
|
outline_chapter_count: { type: 'integer', description: 'Outline task range length including its starting chapter, 1-20 (default 3).' },
|
|
2398
2493
|
writer_profile_ids: { type: 'array', items: { type: 'string' }, description: 'Writing profiles to compare (run).' },
|
|
2399
2494
|
reviewer_profile_ids: { type: 'array', items: { type: 'string' }, description: 'Independent blind-review profiles (run).' },
|
|
2400
2495
|
execution_mode: { type: 'string', enum: ['framework', 'creative'], description: 'Execution path: full framework (default); creative diagnostic is available only for chapter tasks. Read task pipelines with options.' },
|
|
2401
2496
|
repeats: { type: 'integer', description: 'Repeats per writing profile, 1-5.' },
|
|
2402
|
-
target_words: { type: 'integer', description: 'Chapter candidate target length, 200-
|
|
2497
|
+
target_words: { type: 'integer', description: 'Chapter candidate target length, 200-50000; use outline_chapter_count for outline range.' },
|
|
2403
2498
|
concurrency: { type: 'integer', description: 'Concurrent model jobs, 1-4.' },
|
|
2404
2499
|
limit: { type: 'integer', description: 'List limit, default 20.' },
|
|
2405
2500
|
},
|
|
@@ -2429,7 +2524,7 @@ export function registerNovelTools(ctx, clientFactory, options) {
|
|
|
2429
2524
|
writer_profile_ids: args.writer_profile_ids,
|
|
2430
2525
|
reviewer_profile_ids: args.reviewer_profile_ids,
|
|
2431
2526
|
};
|
|
2432
|
-
for (const key of ['task_type', 'chapter_id', 'outline_start_chapter', 'outline_chapter_count', 'execution_mode', 'repeats', 'target_words', 'concurrency']) {
|
|
2527
|
+
for (const key of ['task_type', 'chapter_id', 'allow_historical', 'outline_start_chapter', 'outline_chapter_count', 'execution_mode', 'repeats', 'target_words', 'concurrency']) {
|
|
2433
2528
|
const value = args[key];
|
|
2434
2529
|
if (value !== undefined)
|
|
2435
2530
|
body[key] = value;
|
|
@@ -28,12 +28,13 @@
|
|
|
28
28
|
"patch": "./cordis.patch.yml"
|
|
29
29
|
},
|
|
30
30
|
"compatibility": {
|
|
31
|
-
"dsh": "0.1.2-rc.1 || 0.1.5-alpha.1 || 0.2.0-rc.2 || 0.2.1-rc.2",
|
|
31
|
+
"dsh": "0.1.2-rc.1 || 0.1.5-alpha.1 || 0.2.0-rc.2 || 0.2.1-rc.2 || 0.2.1-rc.3",
|
|
32
32
|
"dshReleases": {
|
|
33
33
|
"0.1.2-rc.1": "compatible",
|
|
34
34
|
"0.1.5-alpha.1": "compatible",
|
|
35
35
|
"0.2.0-rc.2": "compatible",
|
|
36
|
-
"0.2.1-rc.2": "compatible"
|
|
36
|
+
"0.2.1-rc.2": "compatible",
|
|
37
|
+
"0.2.1-rc.3": "compatible"
|
|
37
38
|
}
|
|
38
39
|
}
|
|
39
40
|
},
|
|
@@ -45,9 +46,9 @@
|
|
|
45
46
|
},
|
|
46
47
|
"peerDependencies": {
|
|
47
48
|
"@deepseek-ai/cordis": "4.0.2 || ~4.0.4",
|
|
48
|
-
"@deepseek-ai/dsh-host-webserver": "0.1.2-rc.1 || 0.1.5-alpha.1 || 0.2.0-rc.2 || 0.2.1-rc.2",
|
|
49
|
-
"@deepseek-ai/dsh-tools": "0.1.2-rc.1 || 0.1.5-alpha.1 || 0.2.0-rc.2 || 0.2.1-rc.2",
|
|
50
|
-
"@deepseek-ai/dsh-workspace": "0.1.2-rc.1 || 0.1.5-alpha.1 || 0.2.0-rc.2 || 0.2.1-rc.2"
|
|
49
|
+
"@deepseek-ai/dsh-host-webserver": "0.1.2-rc.1 || 0.1.5-alpha.1 || 0.2.0-rc.2 || 0.2.1-rc.2 || 0.2.1-rc.3",
|
|
50
|
+
"@deepseek-ai/dsh-tools": "0.1.2-rc.1 || 0.1.5-alpha.1 || 0.2.0-rc.2 || 0.2.1-rc.2 || 0.2.1-rc.3",
|
|
51
|
+
"@deepseek-ai/dsh-workspace": "0.1.2-rc.1 || 0.1.5-alpha.1 || 0.2.0-rc.2 || 0.2.1-rc.2 || 0.2.1-rc.3"
|
|
51
52
|
},
|
|
52
53
|
"peerDependenciesMeta": {
|
|
53
54
|
"@deepseek-ai/dsh-host-webserver": {
|