@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.
- package/THIRD_PARTY_NOTICES.md +16 -0
- package/agentic/code/providers/capability-matrix.yaml +45 -3
- package/agentic/code/providers/deepseek-harness/README.md +8 -0
- package/agentic/code/providers/deepseek-harness/aiwg.cordis.patch.yml +10 -0
- package/agentic/code/providers/model-capabilities.v1.json +11 -0
- package/agentic/code/providers/model-catalog.v1.json +8 -0
- package/bin/aiwg.mjs +1 -0
- package/dist/src/api/index.d.ts +14 -0
- package/dist/src/api/index.js +14 -0
- package/dist/src/artifacts/corpus-tools/source-types.js +1 -0
- package/dist/src/artifacts/index-files.js +17 -2
- package/dist/src/artifacts/repair.js +55 -6
- package/dist/src/catalog/cli.js +21 -7
- package/dist/src/catalog/cli.mjs +22 -7
- package/dist/src/cli/agent-spawn.js +10 -1
- package/dist/src/cli/handlers/artifacts.js +22 -3
- package/dist/src/cli/handlers/help.js +3 -0
- package/dist/src/cli/handlers/index.js +5 -1
- package/dist/src/cli/handlers/models.js +2 -2
- package/dist/src/cli/handlers/output-mode.js +1 -1
- package/dist/src/cli/handlers/runtime-info.js +1 -1
- package/dist/src/cli/handlers/sessions.js +55 -15
- package/dist/src/cli/handlers/steward.js +1 -1
- package/dist/src/cli/handlers/subcommands.js +5 -0
- package/dist/src/cli/handlers/writer-profile.js +110 -0
- package/dist/src/cli/handlers/writing.js +122 -0
- package/dist/src/cli/router.js +5 -1
- package/dist/src/config/project-artifacts-runtime.mjs +33 -1
- package/dist/src/config/project-artifacts.js +1 -1
- package/dist/src/dataset/fortemi-dataset-execution.d.ts +23 -0
- package/dist/src/dataset/fortemi-dataset-execution.js +158 -0
- package/dist/src/dataset/fortemi-live-qualification.d.ts +4 -2
- package/dist/src/dataset/fortemi-live-qualification.js +20 -21
- package/dist/src/dataset/fortemi-run-receipt.d.ts +44 -0
- package/dist/src/dataset/fortemi-run-receipt.js +74 -0
- package/dist/src/dataset/index.d.ts +2 -0
- package/dist/src/dataset/index.js +2 -0
- package/dist/src/extensions/commands/definitions.js +24 -0
- package/dist/src/extensions/manifest.js +3 -0
- package/dist/src/mcp/server.mjs +2 -0
- package/dist/src/mcp/tools/writer-profiles.mjs +40 -0
- package/dist/src/models/model-capabilities.v1.json +11 -0
- package/dist/src/models/model-catalog.v1.json +8 -0
- package/dist/src/models/provider-policy.js +1 -1
- package/dist/src/network-analysis/analyzer.js +667 -0
- package/dist/src/network-analysis/citations.js +107 -0
- package/dist/src/network-analysis/forensics.js +132 -0
- package/dist/src/network-analysis/governance.js +216 -0
- package/dist/src/network-analysis/index.js +10 -0
- package/dist/src/network-analysis/probe.js +405 -0
- package/dist/src/network-analysis/recipes.js +88 -0
- package/dist/src/network-analysis/research.js +181 -0
- package/dist/src/network-analysis/termshark.js +252 -0
- package/dist/src/network-analysis/verification.js +171 -0
- package/dist/src/output-modes/registry.js +37 -6
- package/dist/src/output-modes/runtime.js +164 -28
- package/dist/src/providers/capability-matrix.yaml +45 -3
- package/dist/src/providers/provider-definitions.js +49 -0
- package/dist/src/providers/provider-inventory.js +1 -0
- package/dist/src/providers/transformation-receipt.js +3 -2
- package/dist/src/sessions/adapters/deepseek-harness.js +178 -0
- package/dist/src/sessions/batch-import.js +7 -0
- package/dist/src/sessions/contracts.js +2 -1
- package/dist/src/sessions/index.js +1 -0
- package/dist/src/sessions/workspace-discovery.js +5 -1
- package/dist/src/skills/deployer.js +6 -6
- package/dist/src/smiths/context-pipeline/workspace-context.js +7 -0
- package/dist/src/writing/channel-packs.js +13 -0
- package/dist/src/writing/contextual-diagnostics.js +142 -0
- package/dist/src/writing/example-generator.js +7 -6
- package/dist/src/writing/exemplar-selection.js +186 -0
- package/dist/src/writing/fidelity.js +61 -0
- package/dist/src/writing/validation-engine.js +32 -15
- package/dist/src/writing/voice-evaluation.js +301 -0
- package/dist/src/writing/voice-revision.js +201 -0
- package/dist/src/writing/writer-migration.js +216 -0
- package/dist/src/writing/writer-profile-legacy.js +145 -0
- package/dist/src/writing/writer-profile-store.js +117 -0
- package/dist/src/writing/writer-profile.js +222 -0
- package/dist/src/writing/writing-brief.js +166 -0
- package/dist/src/writing/writing-channels.js +63 -0
- package/dist/src/writing/writing-consumer.js +39 -0
- package/dist/src/writing/writing-receipt.js +266 -0
- package/package.json +2 -1
- package/schemas/dataset/fortemi-live-qualification-receipt.v2.schema.json +196 -0
- package/schemas/dataset/fortemi-run-receipt/validation-1.0.1/authority.json +12 -0
- package/schemas/dataset/fortemi-run-receipt/validation-1.0.1/run-receipt.schema.json +819 -0
- package/tools/agents/deploy-agents.mjs +7 -3
- package/tools/agents/providers/antigravity.mjs +1 -1
- package/tools/agents/providers/base.mjs +3 -2
- package/tools/agents/providers/deepseek-harness.mjs +66 -0
- package/tools/agents/providers/hermes.mjs +1 -1
- 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('
|
|
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('
|
|
11
|
+
alternatives.push('(?<!`)(?<ticks>`+)(?!`)[\\s\\S]*?(?<!`)\\k<ticks>(?!`)');
|
|
8
12
|
if (set.has('quoted-text'))
|
|
9
|
-
alternatives.push('
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
26
|
-
|
|
27
|
-
|
|
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 (
|
|
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
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
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(
|
|
54
|
-
const result = await options.validate(content, mode);
|
|
55
|
-
if (
|
|
56
|
-
diagnostics.push({ mode: mode.id, level: mode.validation.level, message: result
|
|
57
|
-
|
|
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
|
-
|
|
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: "
|
|
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: "
|
|
446
|
-
commands: "
|
|
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'],
|
|
@@ -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
|
|
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 =
|
|
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';
|