@aiwg/cli 2026.9.4 → 2026.9.6

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 (93) hide show
  1. package/THIRD_PARTY_NOTICES.md +16 -0
  2. package/agentic/code/providers/capability-matrix.yaml +45 -3
  3. package/agentic/code/providers/deepseek-harness/README.md +8 -0
  4. package/agentic/code/providers/deepseek-harness/aiwg.cordis.patch.yml +10 -0
  5. package/agentic/code/providers/model-capabilities.v1.json +11 -0
  6. package/agentic/code/providers/model-catalog.v1.json +8 -0
  7. package/bin/aiwg.mjs +1 -0
  8. package/dist/src/api/index.d.ts +14 -0
  9. package/dist/src/api/index.js +14 -0
  10. package/dist/src/artifacts/corpus-tools/source-types.js +1 -0
  11. package/dist/src/artifacts/index-files.js +17 -2
  12. package/dist/src/artifacts/repair.js +55 -6
  13. package/dist/src/catalog/cli.js +21 -7
  14. package/dist/src/catalog/cli.mjs +22 -7
  15. package/dist/src/cli/agent-spawn.js +10 -1
  16. package/dist/src/cli/handlers/artifacts.js +22 -3
  17. package/dist/src/cli/handlers/help.js +3 -0
  18. package/dist/src/cli/handlers/index.js +5 -1
  19. package/dist/src/cli/handlers/models.js +2 -2
  20. package/dist/src/cli/handlers/output-mode.js +1 -1
  21. package/dist/src/cli/handlers/runtime-info.js +1 -1
  22. package/dist/src/cli/handlers/sessions.js +55 -15
  23. package/dist/src/cli/handlers/steward.js +1 -1
  24. package/dist/src/cli/handlers/subcommands.js +5 -0
  25. package/dist/src/cli/handlers/writer-profile.js +110 -0
  26. package/dist/src/cli/handlers/writing.js +122 -0
  27. package/dist/src/cli/router.js +5 -1
  28. package/dist/src/config/project-artifacts-runtime.mjs +33 -1
  29. package/dist/src/config/project-artifacts.js +1 -1
  30. package/dist/src/dataset/fortemi-dataset-execution.d.ts +23 -0
  31. package/dist/src/dataset/fortemi-dataset-execution.js +158 -0
  32. package/dist/src/dataset/fortemi-live-qualification.d.ts +4 -2
  33. package/dist/src/dataset/fortemi-live-qualification.js +20 -21
  34. package/dist/src/dataset/fortemi-run-receipt.d.ts +44 -0
  35. package/dist/src/dataset/fortemi-run-receipt.js +74 -0
  36. package/dist/src/dataset/index.d.ts +2 -0
  37. package/dist/src/dataset/index.js +2 -0
  38. package/dist/src/extensions/commands/definitions.js +24 -0
  39. package/dist/src/extensions/manifest.js +3 -0
  40. package/dist/src/mcp/server.mjs +2 -0
  41. package/dist/src/mcp/tools/writer-profiles.mjs +40 -0
  42. package/dist/src/models/model-capabilities.v1.json +11 -0
  43. package/dist/src/models/model-catalog.v1.json +8 -0
  44. package/dist/src/models/provider-policy.js +1 -1
  45. package/dist/src/network-analysis/analyzer.js +667 -0
  46. package/dist/src/network-analysis/citations.js +107 -0
  47. package/dist/src/network-analysis/forensics.js +132 -0
  48. package/dist/src/network-analysis/governance.js +216 -0
  49. package/dist/src/network-analysis/index.js +10 -0
  50. package/dist/src/network-analysis/probe.js +405 -0
  51. package/dist/src/network-analysis/recipes.js +88 -0
  52. package/dist/src/network-analysis/research.js +181 -0
  53. package/dist/src/network-analysis/termshark.js +252 -0
  54. package/dist/src/network-analysis/verification.js +171 -0
  55. package/dist/src/output-modes/registry.js +37 -6
  56. package/dist/src/output-modes/runtime.js +164 -28
  57. package/dist/src/providers/capability-matrix.yaml +45 -3
  58. package/dist/src/providers/provider-definitions.js +49 -0
  59. package/dist/src/providers/provider-inventory.js +1 -0
  60. package/dist/src/providers/transformation-receipt.js +3 -2
  61. package/dist/src/sessions/adapters/deepseek-harness.js +178 -0
  62. package/dist/src/sessions/batch-import.js +7 -0
  63. package/dist/src/sessions/contracts.js +2 -1
  64. package/dist/src/sessions/index.js +1 -0
  65. package/dist/src/sessions/workspace-discovery.js +5 -1
  66. package/dist/src/skills/deployer.js +6 -6
  67. package/dist/src/smiths/context-pipeline/workspace-context.js +7 -0
  68. package/dist/src/writing/channel-packs.js +13 -0
  69. package/dist/src/writing/contextual-diagnostics.js +142 -0
  70. package/dist/src/writing/example-generator.js +7 -6
  71. package/dist/src/writing/exemplar-selection.js +186 -0
  72. package/dist/src/writing/fidelity.js +61 -0
  73. package/dist/src/writing/validation-engine.js +32 -15
  74. package/dist/src/writing/voice-evaluation.js +301 -0
  75. package/dist/src/writing/voice-revision.js +201 -0
  76. package/dist/src/writing/writer-migration.js +216 -0
  77. package/dist/src/writing/writer-profile-legacy.js +145 -0
  78. package/dist/src/writing/writer-profile-store.js +117 -0
  79. package/dist/src/writing/writer-profile.js +222 -0
  80. package/dist/src/writing/writing-brief.js +166 -0
  81. package/dist/src/writing/writing-channels.js +63 -0
  82. package/dist/src/writing/writing-consumer.js +39 -0
  83. package/dist/src/writing/writing-receipt.js +266 -0
  84. package/package.json +2 -1
  85. package/schemas/dataset/fortemi-live-qualification-receipt.v2.schema.json +196 -0
  86. package/schemas/dataset/fortemi-run-receipt/validation-1.0.1/authority.json +12 -0
  87. package/schemas/dataset/fortemi-run-receipt/validation-1.0.1/run-receipt.schema.json +819 -0
  88. package/tools/agents/deploy-agents.mjs +7 -3
  89. package/tools/agents/providers/antigravity.mjs +1 -1
  90. package/tools/agents/providers/base.mjs +3 -2
  91. package/tools/agents/providers/deepseek-harness.mjs +66 -0
  92. package/tools/agents/providers/hermes.mjs +1 -1
  93. package/tools/agents/providers/openhuman.mjs +2 -2
@@ -1,30 +1,101 @@
1
+ import { assessWritingFidelity } from '../writing/fidelity.js';
2
+ import { parseWritingBrief } from '../writing/writing-brief.js';
1
3
  function protectedPattern(classes) {
2
4
  const set = new Set(classes);
3
5
  const alternatives = [];
4
- if (set.has('machine-readable-blocks') || set.has('code'))
5
- alternatives.push('```[\\s\\S]*?```');
6
+ if (set.has('machine-readable-blocks') || set.has('code')) {
7
+ alternatives.push('^ {0,3}(?<backtickFence>`{3,})[^\\n]*\\n[\\s\\S]*?(?:^ {0,3}\\k<backtickFence>`*[ \\t]*$|(?![\\s\\S]))');
8
+ alternatives.push('^ {0,3}(?<tildeFence>~{3,})[^\\n]*\\n[\\s\\S]*?(?:^ {0,3}\\k<tildeFence>~*[ \\t]*$|(?![\\s\\S]))');
9
+ }
6
10
  if (set.has('code') || set.has('commands'))
7
- alternatives.push('`[^`\\n]+`');
11
+ alternatives.push('(?<!`)(?<ticks>`+)(?!`)[\\s\\S]*?(?<!`)\\k<ticks>(?!`)');
8
12
  if (set.has('quoted-text'))
9
- alternatives.push('^>.*(?:\\n>.*)*', '“[^”]*”', '"[^"\\n]+"');
13
+ alternatives.push('^ {0,3}>.*(?:\\n {0,3}>.*)*', '“[^”]*”', '"[^"\\n]+"');
10
14
  if (set.has('citations'))
11
15
  alternatives.push('\\[[^\\]\\n]+\\]\\([^\\s)]+\\)', '\\[[0-9]+\\]');
12
16
  if (set.has('identifiers'))
13
17
  alternatives.push('\\b(?:[A-Za-z_$][\\w$]*\\.)+[A-Za-z_$][\\w$]*\\b', '\\b[A-Z][A-Z0-9_]{2,}\\b');
14
18
  return alternatives.length ? new RegExp(alternatives.join('|'), 'gm') : null;
15
19
  }
16
- function protect(content, classes) {
20
+ function markdownLinkRanges(content) {
21
+ const ranges = [];
22
+ for (let start = 0; start < content.length; start++) {
23
+ if (content[start] !== '[' || content[start - 1] === '\\')
24
+ continue;
25
+ let at = start + 1, brackets = 1;
26
+ for (; at < content.length && brackets; at++) {
27
+ if (content[at] === '\\') {
28
+ at++;
29
+ continue;
30
+ }
31
+ if (content[at] === '[')
32
+ brackets++;
33
+ if (content[at] === ']')
34
+ brackets--;
35
+ }
36
+ if (brackets || content[at] !== '(')
37
+ continue;
38
+ let depth = 1;
39
+ let quote = '';
40
+ for (at++; at < content.length && depth; at++) {
41
+ const char = content[at];
42
+ if (char === '\\') {
43
+ at++;
44
+ continue;
45
+ }
46
+ if (quote) {
47
+ if (char === quote)
48
+ quote = '';
49
+ continue;
50
+ }
51
+ if ((char === '"' || char === "'") && /\s/.test(content[at - 1])) {
52
+ quote = char;
53
+ continue;
54
+ }
55
+ if (char === '(')
56
+ depth++;
57
+ if (char === ')')
58
+ depth--;
59
+ }
60
+ if (!depth) {
61
+ ranges.push({ start, end: at });
62
+ start = at - 1;
63
+ }
64
+ }
65
+ return ranges;
66
+ }
67
+ function protect(content, classes, explicitLiterals) {
17
68
  const literals = [];
18
69
  const pattern = protectedPattern(classes);
70
+ const ranges = pattern ? [...content.matchAll(pattern)].map(m => ({ start: m.index, end: m.index + m[0].length })) : [];
71
+ if (classes.includes('citations'))
72
+ ranges.push(...markdownLinkRanges(content));
73
+ for (const literal of explicitLiterals) {
74
+ for (let start = content.indexOf(literal); start !== -1; start = content.indexOf(literal, start + 1)) {
75
+ ranges.push({ start, end: start + literal.length });
76
+ }
77
+ }
78
+ ranges.sort((a, b) => a.start - b.start || b.end - a.end);
79
+ const merged = [];
80
+ for (const range of ranges) {
81
+ const last = merged.at(-1);
82
+ if (last && range.start < last.end)
83
+ last.end = Math.max(last.end, range.end);
84
+ else
85
+ merged.push({ ...range });
86
+ }
19
87
  let tokenPrefix = '\uE000AIWG_OUTPUT_MODE_';
20
88
  while (content.includes(tokenPrefix))
21
89
  tokenPrefix += '_';
22
- const protectedContent = pattern ? content.replace(pattern, value => {
90
+ let protectedContent = '';
91
+ let cursor = 0;
92
+ for (const range of merged) {
23
93
  const token = `${tokenPrefix}${literals.length}\uE001`;
24
- literals.push({ token, value });
25
- return token;
26
- }) : content;
27
- return { content: protectedContent, literals };
94
+ literals.push({ token, value: content.slice(range.start, range.end) });
95
+ protectedContent += content.slice(cursor, range.start) + token;
96
+ cursor = range.end;
97
+ }
98
+ return { content: protectedContent + content.slice(cursor), literals };
28
99
  }
29
100
  function restore(content, literals, mode) {
30
101
  let restored = content;
@@ -32,35 +103,100 @@ function restore(content, literals, mode) {
32
103
  const occurrences = restored.split(literal.token).length - 1;
33
104
  if (occurrences !== 1)
34
105
  throw new Error(`Output mode '${mode}' modified, removed, or duplicated a protected literal.`);
35
- restored = restored.replace(literal.token, literal.value);
106
+ restored = restored.replace(literal.token, () => literal.value);
36
107
  }
108
+ if (literals.length && restored.includes(literals[0].token.slice(0, -2)))
109
+ throw new Error(`Output mode '${mode}' introduced an invalid protected literal token.`);
37
110
  return restored;
38
111
  }
112
+ async function bounded(action, milliseconds) {
113
+ let timer;
114
+ try {
115
+ return await Promise.race([Promise.resolve().then(action), new Promise((_, reject) => {
116
+ timer = setTimeout(() => reject(new Error('Output validation timed out.')), milliseconds);
117
+ })]);
118
+ }
119
+ finally {
120
+ if (timer)
121
+ clearTimeout(timer);
122
+ }
123
+ }
39
124
  export async function applyOutputModes(input, modes, options) {
40
- if (modes.length === 0)
125
+ if (options.protectedLiterals !== undefined && (!Array.isArray(options.protectedLiterals) || options.protectedLiterals.some(value => typeof value !== 'string' || !value.trim() || /[\uD800-\uDFFF]/u.test(value))))
126
+ throw new Error('Protected literals must be nonempty well-formed strings.');
127
+ const protectedLiterals = [...new Set(options.protectedLiterals ?? [])];
128
+ options = { ...options, ...(options.fidelity ? { fidelity: { brief: parseWritingBrief(options.fidelity.brief) } } : {}) };
129
+ if (modes.length === 0 && !options.requireFinalValidator && !options.fidelity && !options.validateFinal)
41
130
  return { content: input, diagnostics: [], applied: [], fallback: 'none' };
131
+ const activeModes = structuredClone(modes).filter(mode => mode.id !== 'unaltered');
132
+ const brief = options.fidelity ? parseWritingBrief(options.fidelity.brief) : undefined;
42
133
  let content = input;
43
134
  const diagnostics = [];
135
+ const attempted = [];
44
136
  const applied = [];
45
- for (const mode of modes) {
46
- const masked = protect(content, mode.protectedContent ?? []);
47
- const transformed = await options.transform(masked.content, mode);
48
- if (typeof transformed !== 'string')
49
- throw new Error(`Output mode '${mode.id}' transform returned a non-string result.`);
50
- content = restore(transformed, masked.literals, mode.id);
51
- if (mode.validation.level !== 'advisory') {
137
+ const timeout = options.validationTimeoutMs ?? 30_000;
138
+ if (!Number.isFinite(timeout) || timeout <= 0 || timeout > 300_000)
139
+ throw new Error('Invalid output validation timeout.');
140
+ // Earlier stage protection remains mandatory through later presentation passes.
141
+ const protectedClasses = [...new Set(activeModes.flatMap(mode => mode.protectedContent ?? []))];
142
+ let fidelity;
143
+ let currentMode = 'final';
144
+ let level = 'validated';
145
+ try {
146
+ for (const mode of activeModes) {
147
+ currentMode = mode.id;
148
+ level = mode.validation.level;
149
+ attempted.push(mode.id);
150
+ const masked = protect(content, protectedClasses, protectedLiterals);
151
+ const transformed = await options.transform(masked.content, structuredClone(mode));
152
+ if (typeof transformed !== 'string')
153
+ throw new Error('Output transform returned a non-string result.');
154
+ content = restore(transformed, masked.literals, mode.id);
155
+ if (mode.validation.level !== 'advisory') {
156
+ if (!options.validate)
157
+ throw new Error('Mandatory output validator is missing.');
158
+ const result = await bounded(() => options.validate(content, structuredClone(mode)), timeout);
159
+ if (result?.valid !== true) {
160
+ diagnostics.push({ mode: mode.id, level: mode.validation.level, message: result?.message ?? 'Mandatory output validation did not pass.' });
161
+ throw new Error('Mandatory output validation did not pass.');
162
+ }
163
+ }
164
+ applied.push(mode.id);
165
+ }
166
+ currentMode = 'final';
167
+ level = 'validated';
168
+ // Recheck every mandatory stage against final prose, including structure/presentation changes.
169
+ for (const mode of activeModes.filter(mode => mode.validation.level !== 'advisory')) {
52
170
  if (!options.validate)
53
- throw new Error(`Output mode '${mode.id}' declares ${mode.validation.level} validation but no validator is configured.`);
54
- const result = await options.validate(content, mode);
55
- if (!result.valid) {
56
- diagnostics.push({ mode: mode.id, level: mode.validation.level, message: result.message ?? 'validation failed' });
57
- if ((options.onMandatoryValidationFailure ?? 'unaltered') === 'fail')
58
- throw new Error(`Output mode '${mode.id}' validation failed: ${result.message ?? 'no diagnostic'}`);
59
- return { content: input, diagnostics, applied, fallback: 'unaltered' };
171
+ throw new Error('Mandatory output validator is missing.');
172
+ const result = await bounded(() => options.validate(content, structuredClone(mode)), timeout);
173
+ if (result?.valid !== true) {
174
+ diagnostics.push({ mode: mode.id, level: mode.validation.level, message: result?.message ?? 'Mandatory validation of final output did not pass.' });
175
+ throw new Error('Mandatory validation of final output did not pass.');
60
176
  }
61
177
  }
62
- applied.push(mode.id);
178
+ if (brief) {
179
+ fidelity = assessWritingFidelity(input, content, brief);
180
+ if (fidelity.outcome === 'fail')
181
+ throw new Error('Final fidelity guards detected a material change.');
182
+ }
183
+ if (options.requireFinalValidator && !options.validateFinal)
184
+ throw new Error('Required final validator is missing.');
185
+ if (options.validateFinal) {
186
+ const final = await bounded(() => options.validateFinal(input, content, fidelity ? structuredClone(fidelity) : undefined), timeout);
187
+ if (final?.outcome !== 'pass')
188
+ throw new Error('Final semantic validation failed or requires review.');
189
+ }
190
+ else if (fidelity?.outcome === 'uncertain')
191
+ throw new Error('Changed prose requires semantic review.');
192
+ return { content, diagnostics, applied, attempted, retained: [...applied], fallback: 'none', ...(fidelity ? { fidelity } : {}) };
193
+ }
194
+ catch (error) {
195
+ if (!diagnostics.length)
196
+ diagnostics.push({ mode: currentMode, level, message: error instanceof Error && /^(Output mode|Output validation|Mandatory|Required final|Final |Changed prose)/.test(error.message) ? error.message : 'Output transformation or validation failed.' });
197
+ if (options.onMandatoryValidationFailure === 'fail' || (options.onMandatoryValidationFailure === undefined && error instanceof Error && error.message.includes('protected literal')))
198
+ throw error;
199
+ return { content: input, diagnostics, applied: [], attempted, retained: [], fallback: 'unaltered', ...(fidelity ? { fidelity } : {}) };
63
200
  }
64
- return { content, diagnostics, applied, fallback: 'none' };
65
201
  }
66
202
  //# sourceMappingURL=runtime.js.map
@@ -370,7 +370,7 @@ providers:
370
370
  # bridge. The "MCP:" entries below are the optional enrichment path, not a
371
371
  # requirement. Broader MCP modernization: #1533.
372
372
  agents: AGENTS.md
373
- commands: "AGENTS.md bridge + aiwg discover/show (MCP command-run optional)"
373
+ commands: "Indexed: aiwg discover / aiwg show command (MCP command-run optional)"
374
374
  skills: "~/.hermes/skills/"
375
375
  skills_cross_agent: "~/.hermes/skills/.aiwg/"
376
376
  rules: "AGENTS.md ### Rule sections + aiwg show rule (MCP rule-list/rule-show optional)"
@@ -442,8 +442,8 @@ providers:
442
442
  daemon_tier: unsupported
443
443
  daemon_pty_adapter: false
444
444
  artifact_paths:
445
- agents: ".agents/agents/" # markdown personas (workspace-scoped the coding hosts OpenHuman drives); harness TOML is Tier-2 (#1559)
446
- commands: "AGENTS.md bridge (no native command surface)"
445
+ agents: "Indexed: aiwg discover / aiwg show agent" # native TOML harness agents are opt-in (#1559)
446
+ commands: "Indexed: aiwg discover / aiwg show command"
447
447
  skills: "~/.openhuman/skills/" # global/home-dir like OpenClaw — ungated user-scope native scan (ops_discover.rs); same root OpenHuman's own installer writes to (#1553)
448
448
  skills_cross_agent: "~/.openhuman/.aiwg/skills/"
449
449
  rules: "AGENTS.md ### Rule sections + aiwg show rule"
@@ -515,6 +515,48 @@ providers:
515
515
  deploy_target: project
516
516
  aggregated_output: false
517
517
 
518
+ deepseek-harness:
519
+ display_name: DeepSeek Harness
520
+ aliases:
521
+ - dsh
522
+ status: experimental
523
+ daemon_tier: unsupported
524
+ daemon_pty_adapter: false
525
+ artifact_paths:
526
+ agents: .agents/skills/
527
+ commands: null
528
+ skills: .agents/skills/
529
+ rules: AGENTS.md
530
+ behaviors: null
531
+ cordis_patch: .dsh/aiwg.cordis.patch.yml
532
+ native_features:
533
+ cron: false
534
+ agent_teams: true
535
+ tasks: true
536
+ mcp: true
537
+ behaviors: true
538
+ mission_control: false
539
+ daemon: false
540
+ emulation:
541
+ cron: external-trigger
542
+ agent_teams: native
543
+ tasks: native
544
+ mcp: native
545
+ behaviors: null
546
+ mission_control: aiwg-mc
547
+ daemon: null
548
+ hook_wiring:
549
+ at_link_support: false
550
+ fallback: full-inject
551
+ context_file: AGENTS.md
552
+ max_bytes: 65536
553
+ interaction:
554
+ structured_questions: none
555
+ fallback: markdown
556
+ notes: Headless and SDK profiles do not expose an interactive question UI.
557
+ deploy_target: project
558
+ aggregated_output: false
559
+
518
560
  pi:
519
561
  display_name: Pi Coding Agent
520
562
  aliases:
@@ -17,6 +17,7 @@ const ProviderDefinitionSchema = z.object({
17
17
  'codex',
18
18
  'copilot',
19
19
  'cursor',
20
+ 'deepseek-harness',
20
21
  'factory',
21
22
  'hermes',
22
23
  'opencode',
@@ -32,6 +33,13 @@ const ProviderDefinitionSchema = z.object({
32
33
  aliases: z.array(z.string().min(1)),
33
34
  status: z.enum(['stable', 'experimental', 'deprecated']),
34
35
  builtIn: z.boolean(),
36
+ upstream: z.object({
37
+ source: z.string().url(),
38
+ version: z.string().min(1),
39
+ revision: z.string().regex(/^[0-9a-f]{40}$/),
40
+ runtime: z.string().min(1),
41
+ lastVerified: z.string().regex(/^\d{4}-\d{2}-\d{2}$/),
42
+ }).optional(),
35
43
  surfaces: z.object({
36
44
  primary: z.string().min(1),
37
45
  compatibility: z.array(z.string().min(1)),
@@ -130,6 +138,7 @@ export const PROVIDER_IDS = [
130
138
  'codex',
131
139
  'copilot',
132
140
  'cursor',
141
+ 'deepseek-harness',
133
142
  'factory',
134
143
  'hermes',
135
144
  'opencode',
@@ -178,6 +187,17 @@ const CONTEXT_CONTRACTS = {
178
187
  bootstrapTargets: ['AGENTS.md'], maxContextBytes: null, recommendedMaxLines: 500, nestedContext: false, support: 'supported',
179
188
  verification: { method: 'official Cursor rules and CLI documentation', source: 'https://docs.cursor.com/context/rules-for-ai', lastVerified: VERIFIED_ON },
180
189
  },
190
+ 'deepseek-harness': {
191
+ startupFiles: ['AGENTS.md', 'CLAUDE.md'],
192
+ precedence: ['provider/system', 'project AGENTS.md or CLAUDE.md', 'nested project context'],
193
+ loadMode: 'prose-directive', includeSyntax: null, configRegistration: null,
194
+ bootstrapTargets: ['AGENTS.md'], maxContextBytes: 65536, recommendedMaxLines: null, nestedContext: true, support: 'supported',
195
+ verification: {
196
+ method: 'DeepSeek Harness instruction and filesystem-skill source review',
197
+ source: 'https://github.com/deepseek-ai/deepseek-harness',
198
+ lastVerified: '2026-09-05',
199
+ },
200
+ },
181
201
  factory: {
182
202
  startupFiles: ['AGENTS.md', '~/.factory/AGENTS.md'], precedence: ['provider/system', 'nearest AGENTS.md', 'root AGENTS.md', 'personal override'],
183
203
  loadMode: 'prose-directive', includeSyntax: null, configRegistration: null,
@@ -731,6 +751,35 @@ const BUILT_IN_SEEDS = [
731
751
  },
732
752
  matrixRef: 'openhuman',
733
753
  },
754
+ {
755
+ id: 'deepseek-harness',
756
+ displayName: 'DeepSeek Harness',
757
+ aliases: ['dsh'],
758
+ builtIn: true,
759
+ upstream: {
760
+ source: 'https://github.com/deepseek-ai/deepseek-harness',
761
+ version: 'dsh-v0.1.3-alpha.1',
762
+ revision: 'd347e703908d0406b7a7ef80e3a0e594d86b2215',
763
+ runtime: 'Node.js ^22.19.0 || >=24.0.0',
764
+ lastVerified: '2026-09-05',
765
+ },
766
+ surfaces: {
767
+ primary: 'dsh', compatibility: ['deepseek-harness'],
768
+ precedence: ['AGENTS.md', 'CLAUDE.md', '.agents/skills/', '.dsh/skills/', '.dsh/aiwg.cordis.patch.yml'], related: [],
769
+ },
770
+ detection: { env: ['DSH_HOME'], process: ['dsh'], capabilityId: 'deepseek-harness' },
771
+ paths: {
772
+ artifacts: { agents: '.agents/skills', commands: null, skills: '.agents/skills', rules: null, behaviors: null },
773
+ kernelSkills: '.agents/skills',
774
+ contextDiscovery: { agents: '.agents/skills', skills: '.agents/skills', rules: null, behaviors: null },
775
+ configFile: '.dsh/aiwg.cordis.patch.yml',
776
+ contextFiles: { aiwgMd: true, agentsMd: true, claudeMdHook: false, hookFile: null, contextFile: 'AGENTS.md' },
777
+ },
778
+ smithPaths: { agents: '.agents/skills', commands: null, skills: '.agents/skills', rules: null, fileExtension: '.md', configFile: '.dsh/aiwg.cordis.patch.yml', aggregated: false },
779
+ skillNamespace: { deploymentGroup: 'deep-recursion', pathType: 'project', skillsBaseDir: '.agents/skills', subdirLayout: true },
780
+ adapters: { agentFormat: 'agents-md', hookBridge: null, mcpInjection: null, contextAggregation: 'agents-md', ruleFormat: 'agents-md-section' },
781
+ matrixRef: 'deepseek-harness',
782
+ },
734
783
  {
735
784
  id: 'omp',
736
785
  aliases: ['oh-my-pi'],
@@ -10,6 +10,7 @@ const PROVIDER_EXECUTABLES = {
10
10
  codex: ['codex'],
11
11
  copilot: ['github-copilot-cli', 'copilot'],
12
12
  cursor: ['cursor'],
13
+ 'deepseek-harness': ['dsh'],
13
14
  factory: ['droid'],
14
15
  hermes: ['hermes'],
15
16
  opencode: ['opencode'],
@@ -1,6 +1,7 @@
1
1
  import { createHash, randomUUID } from 'node:crypto';
2
2
  import { lstat, mkdir, readFile, realpath, rename, rm, writeFile } from 'node:fs/promises';
3
3
  import path from 'node:path';
4
+ import { projectAiwgPath, projectAiwgWritePath } from '../config/project-artifacts.js';
4
5
  export const PROVIDER_TRANSFORMATION_RECEIPT_SCHEMA = 'aiwg.provider-transformation-receipt.v1';
5
6
  const SHA256 = /^[a-f0-9]{64}$/;
6
7
  const IDENTIFIER = /^[a-zA-Z0-9][a-zA-Z0-9._:/@+-]*$/;
@@ -52,7 +53,7 @@ export function providerTransformationReceiptPath(projectRoot, provider, scope)
52
53
  filenameSegment(provider, 'provider');
53
54
  if (scope !== 'project' && scope !== 'user')
54
55
  throw new Error('scope must be project or user');
55
- return path.join(projectRoot, '.aiwg', 'receipts', 'providers', `${provider}.${scope}.json`);
56
+ return projectAiwgPath(projectRoot, 'receipts', 'providers', `${provider}.${scope}.json`);
56
57
  }
57
58
  export function validateProviderTransformationReceipt(value) {
58
59
  if (!value || typeof value !== 'object' || Array.isArray(value))
@@ -108,7 +109,7 @@ export async function createProviderTransformationReceipt(options) {
108
109
  }
109
110
  export async function writeProviderTransformationReceipt(projectRoot, receipt) {
110
111
  validateProviderTransformationReceipt(receipt);
111
- const destination = providerTransformationReceiptPath(projectRoot, receipt.provider, receipt.scope);
112
+ const destination = projectAiwgWritePath(projectRoot, 'receipts', 'providers', `${receipt.provider}.${receipt.scope}.json`);
112
113
  await mkdir(path.dirname(destination), { recursive: true });
113
114
  try {
114
115
  const existing = validateProviderTransformationReceipt(JSON.parse(await readFile(destination, 'utf8')));
@@ -0,0 +1,178 @@
1
+ import { opendir } from 'node:fs/promises';
2
+ import { resolve } from 'node:path';
3
+ import { z } from 'zod';
4
+ import { SessionContractError, } from '../contracts.js';
5
+ import { readBoundedJsonLines, streamBoundedJsonLines } from '../readers.js';
6
+ export const DEEPSEEK_HARNESS_ADAPTER_VERSION = '1.0.0';
7
+ export const DEEPSEEK_HARNESS_SOURCE_SCHEMA_VERSION = '2.0.0';
8
+ const Header = z.object({
9
+ type: z.literal('session'), version: z.number().int(), id: z.string().min(1),
10
+ createdAt: z.number().finite(), cwd: z.string().optional(), parentSession: z.string().optional(),
11
+ isSeeded: z.boolean(), origin: z.literal('subagent').optional(),
12
+ delegationDepth: z.number().int().nonnegative(), agentPreset: z.string().optional(),
13
+ }).passthrough();
14
+ const Event = z.object({
15
+ type: z.string().min(1), seq: z.number().int().nonnegative(), time: z.number().finite(),
16
+ data: z.unknown(),
17
+ }).passthrough();
18
+ const KNOWN = new Set([
19
+ 'turn/start', 'user/message', 'step/start', 'assistant/message', 'tool/call',
20
+ 'tool/result', 'request/header', 'request/context', 'session/end-seed',
21
+ 'step/end', 'turn/end',
22
+ ]);
23
+ export class DeepSeekHarnessSessionAdapter {
24
+ limits;
25
+ maxFiles;
26
+ provider = 'deepseek-harness';
27
+ adapterVersion = DEEPSEEK_HARNESS_ADAPTER_VERSION;
28
+ disposition = 'implemented';
29
+ supportedOperations = ['discover', 'inspect', 'stream'];
30
+ acquisitionModes = ['jsonl'];
31
+ constructor(limits, maxFiles = 10_000) {
32
+ this.limits = limits;
33
+ this.maxFiles = maxFiles;
34
+ }
35
+ async *discover(scope) {
36
+ if (!scope.allowedRoots.length)
37
+ throw new SessionContractError('SOURCE_NOT_AUTHORIZED', 'DeepSeek Harness discovery requires an explicitly authorized sessions root');
38
+ let count = 0;
39
+ for (const root of [...scope.allowedRoots].sort()) {
40
+ for await (const locator of jsonlFiles(resolve(root))) {
41
+ if (++count > this.maxFiles)
42
+ throw new SessionContractError('RESOURCE_LIMIT_EXCEEDED', 'DeepSeek Harness discovery file limit exceeded');
43
+ yield { provider: this.provider, locator, locatorClass: 'deepseek-harness-session-v2-jsonl' };
44
+ }
45
+ }
46
+ }
47
+ async inspect(source) {
48
+ let input;
49
+ try {
50
+ input = await readBoundedJsonLines({ selectedPath: source.locator, allowedRoots: source.authorizedScope.allowedRoots }, { consistency: 'provisional', limits: this.limits });
51
+ }
52
+ catch (error) {
53
+ throw normalizeAuthorizationError(error);
54
+ }
55
+ const header = parseHeader(input.records[0]?.value);
56
+ if (input.incompleteTail)
57
+ throw new SessionContractError('TRUNCATED_SOURCE', 'DeepSeek Harness session has a truncated JSONL tail');
58
+ return { sourceSchemaVersion: `${header.version}.0.0`, consistency: 'complete', operationalState: 'available' };
59
+ }
60
+ async *stream(source, cursor) {
61
+ let input;
62
+ try {
63
+ input = await streamBoundedJsonLines({ selectedPath: source.locator, allowedRoots: source.authorizedScope.allowedRoots }, { consistency: 'provisional', limits: this.limits });
64
+ }
65
+ catch (error) {
66
+ throw normalizeAuthorizationError(error);
67
+ }
68
+ const start = cursor?.value.replace(/^byte:/, '') ?? '0';
69
+ if (!/^\d+$/.test(start))
70
+ throw new SessionContractError('SCHEMA_DRIFT', 'invalid DeepSeek Harness cursor');
71
+ let header;
72
+ let expectedSeq = 0;
73
+ let end = 0;
74
+ for await (const line of input) {
75
+ end = line.byteOffset + line.byteLength;
76
+ if (Number(start) > line.byteOffset && Number(start) < end)
77
+ throw new SessionContractError('SCHEMA_DRIFT', 'DeepSeek Harness cursor is not a record boundary');
78
+ if (!header) {
79
+ header = parseHeader(line.value);
80
+ continue;
81
+ }
82
+ const parsed = Event.safeParse(line.value);
83
+ if (!parsed.success)
84
+ throw new SessionContractError('MALFORMED_SOURCE', 'DeepSeek Harness session event is malformed');
85
+ const event = parsed.data;
86
+ if (event.seq !== expectedSeq)
87
+ throw new SessionContractError(event.seq < expectedSeq ? 'DUPLICATE_NATIVE_ID' : 'SCHEMA_DRIFT', `DeepSeek Harness sequence expected ${expectedSeq}, received ${event.seq}`);
88
+ expectedSeq++;
89
+ if (end <= Number(start))
90
+ continue;
91
+ const data = object(event.data);
92
+ const message = object(data.message ?? event.data);
93
+ const sensitive = isSensitive(event.type);
94
+ const source = object(message.source);
95
+ const role = event.type === 'user/message' ? 'user' : event.type === 'assistant/message' ? 'assistant' : undefined;
96
+ const text = sensitive ? '[redacted provider content]' : textContent(message.content ?? data.content);
97
+ const terminal = event.type === 'turn/end';
98
+ yield {
99
+ nativeSessionId: header.id,
100
+ nativeEventId: `${header.id}:${event.seq}`,
101
+ sequence: event.seq,
102
+ kind: kindFor(event.type, role),
103
+ role,
104
+ toolName: event.type.startsWith('tool/') ? string(data.name) ?? string(data.toolName) : undefined,
105
+ toolCallId: event.type.startsWith('tool/') ? string(data.id) ?? string(data.toolCallId) : undefined,
106
+ model: string(source.model) ?? string(data.model),
107
+ occurredAt: new Date(event.time).toISOString(),
108
+ text,
109
+ sourceCursor: `byte:${end}`,
110
+ sourceBytes: line.byteLength,
111
+ rawReference: { locatorClass: 'deepseek-harness-session-v2-jsonl', offset: line.byteOffset },
112
+ activityBoundary: terminal ? 'end' : undefined,
113
+ activityBoundaryBasis: terminal ? 'deepseek-harness:turn/end' : undefined,
114
+ activityBoundaryConfidence: terminal ? 'high' : undefined,
115
+ extensions: {
116
+ provenance: { acquisition: 'deepseek-harness-session-v2', cwd: header.cwd, parentSession: header.parentSession, origin: header.origin },
117
+ opaque: !KNOWN.has(event.type), redacted: sensitive, nativeType: event.type,
118
+ turn: integer(data.turn), step: integer(data.step), delegationDepth: header.delegationDepth,
119
+ agentPreset: header.agentPreset, provider: string(source.provider), model: string(source.model),
120
+ },
121
+ };
122
+ }
123
+ if (!header)
124
+ throw new SessionContractError('MALFORMED_SOURCE', 'DeepSeek Harness session header is missing');
125
+ if (Number(start) > end)
126
+ throw new SessionContractError('SCHEMA_DRIFT', 'DeepSeek Harness cursor exceeds source size');
127
+ if (input.incompleteTail)
128
+ throw new SessionContractError('TRUNCATED_SOURCE', 'DeepSeek Harness session has a truncated JSONL tail');
129
+ }
130
+ }
131
+ function parseHeader(value) {
132
+ const parsed = Header.safeParse(value);
133
+ if (!parsed.success)
134
+ throw new SessionContractError('MALFORMED_SOURCE', 'DeepSeek Harness session header is malformed');
135
+ if (parsed.data.version !== 2)
136
+ throw new SessionContractError('UNKNOWN_SCHEMA_MAJOR', `unsupported DeepSeek Harness session version: ${parsed.data.version}`);
137
+ return parsed.data;
138
+ }
139
+ function isSensitive(type) { return !KNOWN.has(type) || type === 'tool/call' || type === 'tool/result' || type === 'request/header' || type === 'request/context'; }
140
+ function kindFor(type, role) { return role ? `message.${role}` : `deepseek-harness.${type}`; }
141
+ function object(value) { return value && typeof value === 'object' ? value : {}; }
142
+ function string(value) { return typeof value === 'string' && value ? value : undefined; }
143
+ function integer(value) { return Number.isInteger(value) ? value : undefined; }
144
+ function textContent(value) {
145
+ if (typeof value === 'string')
146
+ return value;
147
+ if (!Array.isArray(value))
148
+ return '';
149
+ return value.flatMap(part => {
150
+ if (typeof part === 'string')
151
+ return part;
152
+ const item = object(part);
153
+ return item.type === 'text' && typeof item.text === 'string' ? item.text : [];
154
+ }).join('\n');
155
+ }
156
+ async function* jsonlFiles(root) {
157
+ let directory;
158
+ try {
159
+ directory = await opendir(root);
160
+ }
161
+ catch {
162
+ return;
163
+ }
164
+ for await (const entry of directory) {
165
+ const path = resolve(root, entry.name);
166
+ if (entry.isDirectory())
167
+ yield* jsonlFiles(path);
168
+ else if (entry.isFile() && entry.name.endsWith('.jsonl') && !entry.name.endsWith('.jsonl.zstd'))
169
+ yield path;
170
+ }
171
+ }
172
+ function normalizeAuthorizationError(error) {
173
+ if (error instanceof SessionContractError && ['SOURCE_OUTSIDE_ALLOWED_ROOT', 'SOURCE_SYMLINK', 'SOURCE_NOT_REGULAR_FILE'].includes(error.code)) {
174
+ return new SessionContractError('SOURCE_NOT_AUTHORIZED', 'DeepSeek Harness source is not an authorized regular file');
175
+ }
176
+ return error;
177
+ }
178
+ //# sourceMappingURL=deepseek-harness.js.map
@@ -1,4 +1,5 @@
1
1
  import { OmpSessionAdapter, OMP_ADAPTER_VERSION } from './adapters/omp.js';
2
+ import { DeepSeekHarnessSessionAdapter, DEEPSEEK_HARNESS_ADAPTER_VERSION } from './adapters/deepseek-harness.js';
2
3
  import { stat } from 'node:fs/promises';
3
4
  import { CLAUDE_ADAPTER_VERSION, ClaudeSessionAdapter, } from './adapters/claude.js';
4
5
  import { CODEX_ADAPTER_VERSION, CodexSessionAdapter, } from './adapters/codex.js';
@@ -198,6 +199,8 @@ async function assertManifestSourceUnchanged(source) {
198
199
  }
199
200
  }
200
201
  function adapterFor(provider) {
202
+ if (provider === 'deepseek-harness')
203
+ return new DeepSeekHarnessSessionAdapter();
201
204
  if (provider === 'omp')
202
205
  return new OmpSessionAdapter();
203
206
  if (provider === 'claude')
@@ -229,6 +232,8 @@ async function sessionSource(selected, adapter) {
229
232
  });
230
233
  }
231
234
  function adapterVersion(provider) {
235
+ if (provider === 'deepseek-harness')
236
+ return DEEPSEEK_HARNESS_ADAPTER_VERSION;
232
237
  if (provider === 'omp')
233
238
  return OMP_ADAPTER_VERSION;
234
239
  if (provider === 'claude')
@@ -242,6 +247,8 @@ function adapterVersion(provider) {
242
247
  return '1.0.0';
243
248
  }
244
249
  function providerProfile(provider, locatorClass) {
250
+ if (provider === 'deepseek-harness')
251
+ return 'native-session-v2-jsonl';
245
252
  if (provider === 'omp')
246
253
  return 'native-title-slot-v3';
247
254
  if (provider === 'claude')
@@ -3,11 +3,12 @@ import { z } from 'zod';
3
3
  export const SESSION_CONTRACT_VERSION = '1.0.0';
4
4
  export const SESSION_PROVIDER_IDS = [
5
5
  'claude', 'codex', 'copilot', 'cursor', 'factory', 'hermes',
6
- 'opencode', 'openclaw', 'openhuman', 'pi', 'omp', 'warp', 'devin-desktop', 'generic',
6
+ 'opencode', 'openclaw', 'openhuman', 'pi', 'omp', 'deepseek-harness', 'warp', 'devin-desktop', 'generic',
7
7
  ];
8
8
  export const SessionProviderIdSchema = z.enum(SESSION_PROVIDER_IDS);
9
9
  export const SESSION_PROVIDER_ALIASES = Object.freeze({
10
10
  windsurf: 'devin-desktop',
11
+ dsh: 'deepseek-harness',
11
12
  });
12
13
  const CompatibleSessionProviderIdSchema = z.preprocess((value) => typeof value === 'string'
13
14
  ? (SESSION_PROVIDER_ALIASES[value] ?? value)
@@ -29,6 +29,7 @@ export * from './adapters/opencode.js';
29
29
  export * from './adapters/openclaw.js';
30
30
  export * from './adapters/openhuman.js';
31
31
  export * from './adapters/pi.js';
32
+ export * from './adapters/deepseek-harness.js';
32
33
  export * from './adapters/warp.js';
33
34
  export * from './adapters/windsurf.js';
34
35
  export * from './adapters/omp.js';