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.
Files changed (39) hide show
  1. package/README.md +17 -6
  2. package/docs/COST_MEASUREMENT.md +2 -2
  3. package/docs/DEVELOPMENT.md +1 -1
  4. package/docs/DSH_STORE.md +7 -1
  5. package/docs/GITEE_EMBEDDING_FIX.md +40 -0
  6. package/docs/INSTALL.md +21 -1
  7. package/docs/ISSUES_105_113.md +15 -0
  8. package/docs/ISSUES_88_95.md +4 -4
  9. package/docs/ISSUES_98_100.md +61 -0
  10. package/docs/ISSUE_109_REPAIRS.md +40 -0
  11. package/docs/OPENCODE_GO.md +31 -0
  12. package/docs/PLUGIN_MAINTENANCE.md +1 -1
  13. package/docs/RELEASE_ACCEPTANCE.md +18 -0
  14. package/package.json +11 -8
  15. package/packages/openwrite-bridge/lib/client.d.ts +2 -0
  16. package/packages/openwrite-bridge/lib/client.js +26 -2
  17. package/packages/openwrite-bridge/lib/domain.js +22 -3
  18. package/packages/openwrite-bridge/lib/index.d.ts +2 -0
  19. package/packages/openwrite-bridge/lib/index.js +3 -1
  20. package/packages/openwrite-bridge/lib/managed-runtime.d.ts +6 -0
  21. package/packages/openwrite-bridge/lib/managed-runtime.js +11 -1
  22. package/packages/openwrite-bridge/lib/tool-policy.js +2 -0
  23. package/packages/openwrite-bridge/lib/tools.js +103 -8
  24. package/packages/openwrite-bridge/package.json +6 -5
  25. package/packages/studio-panel/lib/client.js +1628 -580
  26. package/packages/studio-panel/lib/client.js.map +1 -1
  27. package/packages/studio-panel/lib/types/client/SerialWritingView.d.ts +6 -0
  28. package/packages/studio-panel/lib/types/client/benchmark-options.d.ts +1 -0
  29. package/packages/studio-panel/lib/types/client/dto.d.ts +3 -1
  30. package/packages/studio-panel/lib/types/client/locales.d.ts +1 -1
  31. package/packages/studio-panel/package.json +4 -3
  32. package/plugin.mjs +20 -10
  33. package/preset-definition.mjs +7 -1
  34. package/presets/openwrite/agent.cordis.yml +11 -0
  35. package/release/{openwrite-5.8.11-py3-none-any.whl → openwrite-5.8.14-py3-none-any.whl} +0 -0
  36. package/release/runtime-manifest.json +5 -5
  37. package/release/source.json +3 -3
  38. package/scripts/safe-upgrade.mjs +211 -0
  39. 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 Error(`Unsupported platform: ${process.platform}/${process.arch}`);
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"). Delivery applies publication gates; backup preserves the current work.' },
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-12000; use outline_chapter_count for outline range.' },
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": {