@ckanner/flywheel 0.33.0 → 0.34.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (151) hide show
  1. package/CHANGELOG.md +32 -0
  2. package/README.md +1 -0
  3. package/README.zh-CN.md +2 -0
  4. package/THIRD_PARTY_NOTICES.md +5 -1
  5. package/bin/flywheel-kimi-native-worker.js +5 -0
  6. package/bin/flywheel.js +8 -1
  7. package/bin/runtime.js +5 -1
  8. package/dist/bridge.mjs +89 -7
  9. package/dist/claude-code-pro-bridge.mjs +55 -6
  10. package/dist/client.js +107 -10
  11. package/dist/codex-pro-bridge.mjs +12 -5
  12. package/dist/control.mjs +1 -1
  13. package/dist/kimi-native-bridge.mjs +429 -0
  14. package/dist/kimi-native-runtime.mjs +233 -0
  15. package/dist/kimi-native-worker.mjs +77 -0
  16. package/dist/kimi-tower-candidate.mjs +227 -0
  17. package/dist/machine-worker.mjs +39 -5
  18. package/dist/managed-lcu.mjs +223 -0
  19. package/dist/native-doctor.mjs +36 -0
  20. package/dist/native-jobs.mjs +72 -0
  21. package/dist/native-policy.mjs +371 -0
  22. package/dist/native-resources.mjs +144 -0
  23. package/dist/native.mjs +251 -0
  24. package/dist/policy.mjs +13 -3
  25. package/dist/prewarm.mjs +4 -1
  26. package/dist/protocol.mjs +8 -1
  27. package/dist/worker.mjs +16 -9
  28. package/docs/README.md +9 -0
  29. package/docs/README.zh-CN.md +3 -0
  30. package/docs/design.md +34 -12
  31. package/docs/en/claude-code-pro.md +2 -2
  32. package/docs/en/configuration.md +17 -5
  33. package/docs/en/contributing.md +5 -3
  34. package/docs/en/flow-console.md +1 -1
  35. package/docs/en/getting-started.md +2 -2
  36. package/docs/en/model-policy.md +2 -2
  37. package/docs/en/native-capabilities.md +185 -0
  38. package/docs/en/releasing.md +2 -2
  39. package/docs/en/session-recovery.md +2 -2
  40. package/docs/plans/2026-11-13-native-harness-capabilities.en.md +258 -0
  41. package/docs/plans/2026-11-13-native-harness-capabilities.md +276 -0
  42. package/docs/plans/README.md +1 -0
  43. package/docs/validation/2026-11-14-desktop-native-configuration.md +128 -0
  44. package/docs/validation/2026-11-14-native-harness-implementation.md +215 -0
  45. package/docs/validation/2026-11-14-published-companions.md +15 -0
  46. package/docs/validation/2026-11-14-release-0.33.0.md +49 -0
  47. package/docs/validation/2026-11-14-release-0.33.1.md +78 -0
  48. package/docs/validation/README.md +4 -0
  49. package/docs/validation/evidence/2026-11-14-native-harness-candidate.json +255 -0
  50. package/docs/validation/evidence/2026-11-14-native-harness-sessions.json +6009 -0
  51. package/docs/validation/evidence/2026-11-14-native-harness-tower-candidate.json +192 -0
  52. package/docs/zh-CN/claude-code-pro.md +2 -2
  53. package/docs/zh-CN/configuration.md +21 -8
  54. package/docs/zh-CN/contributing.md +5 -3
  55. package/docs/zh-CN/flow-console.md +1 -1
  56. package/docs/zh-CN/getting-started.md +2 -2
  57. package/docs/zh-CN/model-policy.md +2 -2
  58. package/docs/zh-CN/native-capabilities.md +184 -0
  59. package/docs/zh-CN/releasing.md +2 -2
  60. package/docs/zh-CN/session-recovery.md +1 -1
  61. package/native/darwin-amd64/flywheel +0 -0
  62. package/native/darwin-arm64/flywheel +0 -0
  63. package/native/linux-amd64/flywheel +0 -0
  64. package/native/linux-arm64/flywheel +0 -0
  65. package/native/manifest.json +9 -9
  66. package/node_modules/dsh-preset-generator/CHANGELOG.md +77 -0
  67. package/node_modules/dsh-preset-generator/LICENSE +21 -0
  68. package/node_modules/dsh-preset-generator/README.md +149 -0
  69. package/node_modules/dsh-preset-generator/docs/README.zh.md +95 -0
  70. package/node_modules/dsh-preset-generator/package.json +43 -0
  71. package/node_modules/dsh-preset-generator/src/composition.mjs +150 -0
  72. package/node_modules/dsh-preset-generator/src/gen-presets.mjs +367 -0
  73. package/node_modules/dsh-preset-generator/src/policy.mjs +17 -0
  74. package/node_modules/dsh-subagent-codex-pro/CHANGELOG.md +16 -1
  75. package/node_modules/dsh-subagent-codex-pro/README.md +57 -4
  76. package/node_modules/dsh-subagent-codex-pro/assets/native-client.js +118 -0
  77. package/node_modules/dsh-subagent-codex-pro/cordis.patch.yml +6 -0
  78. package/node_modules/dsh-subagent-codex-pro/docs/README.zh.md +49 -2
  79. package/node_modules/dsh-subagent-codex-pro/docs/machine-lifecycle-validation.md +1 -1
  80. package/node_modules/dsh-subagent-codex-pro/docs/machine-lifecycle.md +1 -1
  81. package/node_modules/dsh-subagent-codex-pro/docs/machine-lifecycle.zh.md +1 -1
  82. package/node_modules/dsh-subagent-codex-pro/docs/machine.md +2 -2
  83. package/node_modules/dsh-subagent-codex-pro/docs/native-capabilities.md +254 -0
  84. package/node_modules/dsh-subagent-codex-pro/docs/native-capabilities.zh.md +180 -0
  85. package/node_modules/dsh-subagent-codex-pro/lib/config.js +56 -0
  86. package/node_modules/dsh-subagent-codex-pro/lib/config.js.map +1 -0
  87. package/node_modules/dsh-subagent-codex-pro/lib/desktop-native.js +109 -0
  88. package/node_modules/dsh-subagent-codex-pro/lib/desktop-native.js.map +1 -0
  89. package/node_modules/dsh-subagent-codex-pro/lib/dsh-types.js +3 -4
  90. package/node_modules/dsh-subagent-codex-pro/lib/dsh-types.js.map +1 -1
  91. package/node_modules/dsh-subagent-codex-pro/lib/index.js +64 -15
  92. package/node_modules/dsh-subagent-codex-pro/lib/index.js.map +1 -1
  93. package/node_modules/dsh-subagent-codex-pro/lib/jobs.js +6 -2
  94. package/node_modules/dsh-subagent-codex-pro/lib/jobs.js.map +1 -1
  95. package/node_modules/dsh-subagent-codex-pro/lib/machine-cli.js +2 -2
  96. package/node_modules/dsh-subagent-codex-pro/lib/machine-cli.js.map +1 -1
  97. package/node_modules/dsh-subagent-codex-pro/lib/machine-local.js +5 -2
  98. package/node_modules/dsh-subagent-codex-pro/lib/machine-local.js.map +1 -1
  99. package/node_modules/dsh-subagent-codex-pro/lib/machine-supervision.js +11 -0
  100. package/node_modules/dsh-subagent-codex-pro/lib/machine-supervision.js.map +1 -1
  101. package/node_modules/dsh-subagent-codex-pro/lib/machine-supervisor.js +1 -0
  102. package/node_modules/dsh-subagent-codex-pro/lib/machine-supervisor.js.map +1 -1
  103. package/node_modules/dsh-subagent-codex-pro/lib/machine.js +20 -3
  104. package/node_modules/dsh-subagent-codex-pro/lib/machine.js.map +1 -1
  105. package/node_modules/dsh-subagent-codex-pro/lib/native.js +297 -0
  106. package/node_modules/dsh-subagent-codex-pro/lib/native.js.map +1 -0
  107. package/node_modules/dsh-subagent-codex-pro/lib/process-guardian.js +11 -1
  108. package/node_modules/dsh-subagent-codex-pro/lib/process-guardian.js.map +1 -1
  109. package/node_modules/dsh-subagent-codex-pro/lib/run.js +19 -1
  110. package/node_modules/dsh-subagent-codex-pro/lib/run.js.map +1 -1
  111. package/node_modules/dsh-subagent-codex-pro/lib/tool.js +123 -57
  112. package/node_modules/dsh-subagent-codex-pro/lib/tool.js.map +1 -1
  113. package/node_modules/dsh-subagent-codex-pro/lib/types/config.d.ts +31 -0
  114. package/node_modules/dsh-subagent-codex-pro/lib/types/config.d.ts.map +1 -0
  115. package/node_modules/dsh-subagent-codex-pro/lib/types/desktop-native.d.ts +30 -0
  116. package/node_modules/dsh-subagent-codex-pro/lib/types/desktop-native.d.ts.map +1 -0
  117. package/node_modules/dsh-subagent-codex-pro/lib/types/dsh-types.d.ts +7 -5
  118. package/node_modules/dsh-subagent-codex-pro/lib/types/dsh-types.d.ts.map +1 -1
  119. package/node_modules/dsh-subagent-codex-pro/lib/types/index.d.ts +31 -0
  120. package/node_modules/dsh-subagent-codex-pro/lib/types/index.d.ts.map +1 -1
  121. package/node_modules/dsh-subagent-codex-pro/lib/types/jobs.d.ts +2 -0
  122. package/node_modules/dsh-subagent-codex-pro/lib/types/jobs.d.ts.map +1 -1
  123. package/node_modules/dsh-subagent-codex-pro/lib/types/machine-local.d.ts.map +1 -1
  124. package/node_modules/dsh-subagent-codex-pro/lib/types/machine-supervision.d.ts.map +1 -1
  125. package/node_modules/dsh-subagent-codex-pro/lib/types/machine.d.ts +7 -0
  126. package/node_modules/dsh-subagent-codex-pro/lib/types/machine.d.ts.map +1 -1
  127. package/node_modules/dsh-subagent-codex-pro/lib/types/native.d.ts +120 -0
  128. package/node_modules/dsh-subagent-codex-pro/lib/types/native.d.ts.map +1 -0
  129. package/node_modules/dsh-subagent-codex-pro/lib/types/run.d.ts +11 -0
  130. package/node_modules/dsh-subagent-codex-pro/lib/types/run.d.ts.map +1 -1
  131. package/node_modules/dsh-subagent-codex-pro/lib/types/tool.d.ts +11 -0
  132. package/node_modules/dsh-subagent-codex-pro/lib/types/tool.d.ts.map +1 -1
  133. package/node_modules/dsh-subagent-codex-pro/lib/types/wire.d.ts +7 -1
  134. package/node_modules/dsh-subagent-codex-pro/lib/types/wire.d.ts.map +1 -1
  135. package/node_modules/dsh-subagent-codex-pro/lib/wire.js +34 -6
  136. package/node_modules/dsh-subagent-codex-pro/lib/wire.js.map +1 -1
  137. package/node_modules/dsh-subagent-codex-pro/package.json +28 -4
  138. package/npm/install.js +2 -2
  139. package/package.json +25 -10
  140. package/plugins/dsh/KIMI_NATIVE_PROTOCOL.en.md +76 -0
  141. package/plugins/dsh/KIMI_NATIVE_PROTOCOL.md +76 -0
  142. package/plugins/dsh/PROTOCOL.md +151 -17
  143. package/plugins/dsh/README.md +15 -12
  144. package/plugins/dsh/README.zh-CN.md +8 -8
  145. package/plugins/dsh/THIRD_PARTY_NOTICES.md +5 -1
  146. package/plugins/dsh/vendor/README.md +40 -11
  147. package/plugins/dsh/vendor/chatgpt.json +21 -0
  148. package/plugins/dsh/vendor/claude-code-pro.json +21 -0
  149. package/plugins/dsh/vendor/codex-pro.json +13 -8
  150. package/plugins/dsh/vendor/lcu.json +21 -0
  151. package/plugins/dsh/vendor/preset-generator.json +16 -0
package/dist/client.js CHANGED
@@ -815,6 +815,53 @@ function Feedback({ control, selection, reconcile, t }) {
815
815
  !selection.taskDir.trim() && h('p', null, t('taskRequired'))));
816
816
  }
817
817
 
818
+ // Plain-JS external clients supply real schema factories through the public
819
+ // Typert codec contract; src-json is not a valid generated Client input codec.
820
+ function consoleReadCodec(type, parse) {
821
+ return { mode: 'strict', typeSymbol: '@ckanner/flywheel#' + type, create: () => ({ parse }) };
822
+ }
823
+ function consoleReadObject(value, keys, label) {
824
+ if (!record(value) || Object.keys(value).some(key => !keys.includes(key))) throw new Error('Invalid ' + label);
825
+ return value;
826
+ }
827
+ function consoleReadString(value, label) {
828
+ if (typeof value !== 'string' || !value.trim()) throw new Error('Invalid ' + label);
829
+ return value;
830
+ }
831
+ function consoleReadInput(value) {
832
+ consoleReadObject(value, ['action', 'taskDir', 'cwd', 'probe', 'editor', 'packet', 'runId', 'sessionKey', 'delivery'], 'console read request');
833
+ if (!['runs', 'status', 'config', 'config-edit', 'metrics', 'history', 'node', 'delivery', 'doctor'].includes(value.action)) throw new Error('Console Remote accepts reads only');
834
+ const output = { action: value.action };
835
+ for (const key of ['taskDir', 'cwd', 'packet', 'runId', 'sessionKey']) {
836
+ if (value[key] !== undefined) output[key] = consoleReadString(value[key], key);
837
+ }
838
+ if (value.probe !== undefined) {
839
+ if (value.action !== 'doctor' || typeof value.probe !== 'boolean') throw new Error('Invalid doctor probe');
840
+ output.probe = value.probe;
841
+ }
842
+ if (value.action === 'config-edit') {
843
+ consoleReadObject(value.editor, ['scope'], 'configuration scope');
844
+ if (!['global', 'project'].includes(value.editor.scope)) throw new Error('Invalid configuration scope');
845
+ output.editor = { scope: value.editor.scope };
846
+ } else if (value.editor !== undefined) throw new Error('Editor requires config-edit');
847
+ if (value.action === 'delivery') {
848
+ consoleReadObject(value.delivery, ['action', 'headBranch'], 'delivery inspection');
849
+ if (value.delivery.action !== 'inspect') throw new Error('Delivery Remote accepts inspection only');
850
+ output.delivery = { action: 'inspect' };
851
+ if (value.delivery.headBranch !== undefined) output.delivery.headBranch = consoleReadString(value.delivery.headBranch, 'headBranch');
852
+ } else if (value.delivery !== undefined) throw new Error('Delivery requires inspection');
853
+ if (value.action === 'node' ? !/^M\d+-T\d+$/.test(output.packet ?? '') : value.packet !== undefined) throw new Error('Invalid node packet');
854
+ if (value.action === 'history' ? !output.sessionKey : value.sessionKey !== undefined) throw new Error('Invalid history session key');
855
+ if (value.runId !== undefined && (value.action !== 'metrics' || value.runId.length > 128 || /[\0\r\n]/.test(value.runId))) throw new Error('Invalid metrics run ID');
856
+ return output;
857
+ }
858
+ function consoleReadResult(value) {
859
+ consoleReadObject(value, ['result'], 'console read result');
860
+ const result = consoleReadObject(value.result, ['kind', 'text'], 'console result envelope');
861
+ if (!['success', 'error'].includes(result.kind) || typeof result.text !== 'string') throw new Error('Invalid console result envelope');
862
+ return { result: { kind: result.kind, text: result.text } };
863
+ }
864
+
818
865
  exports.inject = ['slots', 'remote', 'remote.commands', 'locale'];
819
866
  exports.apply = function apply(ctx) {
820
867
  ctx.effect(() => ctx.locale.register(NS, { zh, en }), 'flywheel: locales');
@@ -833,10 +880,25 @@ exports.apply = function apply(ctx) {
833
880
  const readsReady = ctx.remote.$mount({ package: '@ckanner/flywheel', descriptors: [{
834
881
  id: '@ckanner/flywheel#flywheelConsole/read', service: 'flywheelConsole', namespace: 'flywheelConsole', method: 'read',
835
882
  invocation: { kind: 'direct' }, parameters: [
836
- { name: 'agent', wire: 'sessionId', source: 'lookup', lookup: 'agent', codec: { mode: 'src-json' } },
837
- { name: 'input', wire: 'input', source: 'json', codec: { mode: 'src-json' } },
838
- ], cancellation: { parameter: 'signal' }, result: { mode: 'src-json' },
839
- }] });
883
+ { name: 'agent', wire: 'agentId', source: 'lookup', lookup: 'agent', codec: consoleReadCodec('SessionId', value => consoleReadString(value, 'sessionId')) },
884
+ { name: 'input', wire: 'input', source: 'json', codec: consoleReadCodec('ConsoleReadRequest', consoleReadInput) },
885
+ ], cancellation: { parameter: 'signal' }, result: { ...consoleReadCodec('ConsoleReadResult', consoleReadResult), decode: consoleReadResult },
886
+ }] }).then(async () => {
887
+ let readConsole;
888
+ // The namespace is installed asynchronously by $mount. Own its consumer in
889
+ // an injected child scope; the outer plugin cannot access undeclared services.
890
+ const consumer = ctx.inject(['remote.flywheelConsole'], scope => {
891
+ readConsole = (sessionId, request) => scope.remote.flywheelConsole.read(sessionId, request);
892
+ });
893
+ try {
894
+ await consumer;
895
+ if (disposed || !readConsole) throw new Error('Flywheel read scope is unavailable');
896
+ return readConsole;
897
+ } catch (error) {
898
+ await consumer.dispose();
899
+ throw error;
900
+ }
901
+ });
840
902
  // A missing read capability is a visible error, never a noisy command fallback.
841
903
  readsReady.catch(() => {});
842
904
  ctx.slots.inject('conversation.view', () => ctx.slots.register({
@@ -851,7 +913,7 @@ exports.apply = function apply(ctx) {
851
913
  control = createControl(async request => {
852
914
  const value = readReply(await (mutates(request.action) || request.action === 'status' && control?.source.getSnapshot().uncertainty
853
915
  ? ctx.remote.commands.execute(sessionId, '/flywheel ' + JSON.stringify(request), [])
854
- : readsReady.then(() => ctx.remote.flywheelConsole.read(sessionId, request))), request);
916
+ : readsReady.then(readConsole => readConsole(sessionId, request))), request);
855
917
  if (Array.isArray(value.runs)) value.runs = value.runs.filter(item => item.hostSessionId === sessionId);
856
918
  return value;
857
919
  }, pendingOperations, () => disposed);
@@ -1312,7 +1374,7 @@ function RuntimeDecisionPanel({ ledger, packetID, t }) {
1312
1374
 
1313
1375
  function validExecutionPolicyHistory(packet) {
1314
1376
  const policy = packet?.['execution-policy'];
1315
- const binding = value => record(value) && ['harness', 'provider', 'channel', 'model', 'thinking', 'permission', 'sessionMode']
1377
+ const binding = value => record(value) && ['harness', 'provider', 'channel', 'model', 'thinking', 'nativeProfile', 'permission', 'sessionMode']
1316
1378
  .every(key => value[key] == null || typeof value[key] === 'string');
1317
1379
  return record(packet) && (policy == null || record(policy) &&
1318
1380
  (policy.history == null || Array.isArray(policy.history) && policy.history.every(change =>
@@ -1324,7 +1386,7 @@ function ExecutionPolicyChanges({ packets, packetID, t }) {
1324
1386
  const changes = Object.entries(packets ?? {}).flatMap(([id, packet]) => !packetID || id === packetID
1325
1387
  ? (packet['execution-policy']?.history ?? []).map(change => ({ id, change })) : []);
1326
1388
  if (!changes.length) return null;
1327
- const fields = ['harness', 'provider', 'channel', 'model', 'thinking', 'permission', 'sessionMode'];
1389
+ const fields = ['harness', 'provider', 'channel', 'model', 'thinking', 'nativeProfile', 'permission', 'sessionMode'];
1328
1390
  const bindingDetails = (binding, label) => h('div', null,
1329
1391
  h('p', null, t(label)),
1330
1392
  h('dl', { className: css.consoleProperties }, ...fields.filter(field => binding[field]).map(field =>
@@ -2394,7 +2456,7 @@ function WorkbenchNodeInspector({
2394
2456
  ((chosen.packet && !chosen.stage) || chosen.group) && h(Button, { onClick: () => expand(chosen) }, t(chosen.packet ? 'wbExpand' : 'wbExpandGroup')),
2395
2457
  ['delivery', 'merge'].includes(chosen.id) && h(DeliveryPanel, { control, selection, run, t }),
2396
2458
  binding && h('section', { className: css.inspectorSection }, h('h4', null, t('wbConfiguration')),
2397
- h('dl', { className: css.consoleProperties }, property(t('consoleProvider'), bindingCaption({ ...binding, model: '' })), property(t('consoleModel'), binding.model), property(t('consoleThinking'), ({off:'cfgEffortOff',minimal:'cfgEffortMinimal',low:'cfgEffortLow',medium:'cfgEffortMedium',high:'cfgEffortHigh',xhigh:'cfgEffortXhigh',max:'cfgEffortMax'})[binding.thinking] ? t(({off:'cfgEffortOff',minimal:'cfgEffortMinimal',low:'cfgEffortLow',medium:'cfgEffortMedium',high:'cfgEffortHigh',xhigh:'cfgEffortXhigh',max:'cfgEffortMax'})[binding.thinking]) : binding.thinking), property(t('permission'), permissionLabels[binding.permission] ? t(permissionLabels[binding.permission]) : binding.permission))),
2459
+ h('dl', { className: css.consoleProperties }, property(t('consoleProvider'), bindingCaption({ ...binding, model: '' })), property(t('consoleModel'), binding.model), property(t('cfgNative'), binding['native-profile'] || binding.nativeProfile), property(t('consoleThinking'), ({off:'cfgEffortOff',minimal:'cfgEffortMinimal',low:'cfgEffortLow',medium:'cfgEffortMedium',high:'cfgEffortHigh',xhigh:'cfgEffortXhigh',max:'cfgEffortMax'})[binding.thinking] ? t(({off:'cfgEffortOff',minimal:'cfgEffortMinimal',low:'cfgEffortLow',medium:'cfgEffortMedium',high:'cfgEffortHigh',xhigh:'cfgEffortXhigh',max:'cfgEffortMax'})[binding.thinking]) : binding.thinking), property(t('permission'), permissionLabels[binding.permission] ? t(permissionLabels[binding.permission]) : binding.permission))),
2398
2460
  h('section', { className: css.inspectorSection }, h('h4', null, t('wbSession')),
2399
2461
  sessions.length ? sessions.map(([key, value]) => h('article', { key, className: css.sessionSummary },
2400
2462
  h('h4', null, (roleLabels[value.role] ? t(roleLabels[value.role]) : value.role) + ' · ' + value.scope),
@@ -3227,6 +3289,27 @@ function ConfigEditor({ control, selection, run, t, active = false, cache, conte
3227
3289
  else next[group][key][field] = value;
3228
3290
  replace(next);
3229
3291
  };
3292
+ const nativeChoices = value => {
3293
+ const inherited = draft.profiles?.[value.profile]?.['native-profile'];
3294
+ const harness = value.harness || draft.profiles?.[value.profile]?.harness;
3295
+ const choices = [['__inherit__', t('consoleInherit') + (inherited ? ' · ' + inherited : '')], ['', t('cfgNativeNone')],
3296
+ ...Object.entries(draft['native-profiles'] ?? {}).filter(([, definition]) => definition.harness === harness).map(([name]) => [name, name])];
3297
+ const selected = value['native-profile'];
3298
+ if (selected && !choices.some(([name]) => name === selected)) choices.push([selected, selected]);
3299
+ return choices;
3300
+ };
3301
+ const setNativeProfile = (value, name) => {
3302
+ const next = { ...value };
3303
+ if (name === '__inherit__') delete next['native-profile'];
3304
+ else next['native-profile'] = name;
3305
+ return next;
3306
+ };
3307
+ const inlineNativeProfile = (group, key, name) => {
3308
+ const next = cloneConfig(draft);
3309
+ if (group === 'panel') next['judge-panel'] = setNativeProfile(next['judge-panel'], name);
3310
+ else next[group][key] = setNativeProfile(next[group][key], name);
3311
+ replace(next);
3312
+ };
3230
3313
  const saveBinding = () => {
3231
3314
  const { group, key, role, value, permission, session } = bindingEdit,
3232
3315
  next = cloneConfig(draft);
@@ -3363,7 +3446,7 @@ function ConfigEditor({ control, selection, run, t, active = false, cache, conte
3363
3446
  fields = h(React.Fragment, null,
3364
3447
  h('p', { className: css.meta }, t('cfgSessionDefault', { mode: t(draft.sessions?.mode === 'scoped' ? 'cfgReuse' : 'cfgFresh') })),
3365
3448
  h('div', { className: css.stageTableScroll }, h('table', { className: css.stageTable, 'aria-label': t('cfgModels') },
3366
- h('thead', null, h('tr', null, ...['cfgModelRole', 'consoleResource', 'consoleModel', 'consoleThinking', 'consoleSession'].map(key => h('th', { key, scope: 'col' }, t(key))))),
3449
+ h('thead', null, h('tr', null, ...['cfgModelRole', 'consoleResource', 'consoleModel', 'consoleThinking', 'cfgNative', 'consoleSession'].map(key => h('th', { key, scope: 'col' }, t(key))))),
3367
3450
  h('tbody', null, ...rows.map(([group, key, value]) => {
3368
3451
  const role = group === 'routes' ? 'execute' : key;
3369
3452
  const sessionChoices = [['inherit', roleSession(role)], ['scoped', t('cfgReuse')], ['fresh', t('cfgFresh')]];
@@ -3374,9 +3457,11 @@ function ConfigEditor({ control, selection, run, t, active = false, cache, conte
3374
3457
  h('td', null, h(Button, { disabled: busy, onClick: () => openBinding(group, key, value), 'aria-label': t('cfgEdit') + ' ' + roleName(group, key) }, resourceNames[resourceOf(value)])),
3375
3458
  h('td', null, h('input', { className: css.editorInput, value: value.model ?? '', placeholder: value.profile || t('cfgEffortDefault'), disabled: busy, 'aria-label': roleName(group, key) + ' · ' + t('consoleModel'), onChange: e => inlineBinding(group, key, 'model', e.target.value) })),
3376
3459
  h('td', null, h('select', { className: css.modeSelect, value: value.thinking ?? '', disabled: busy, 'aria-label': roleName(group, key) + ' · ' + t('consoleThinking'), onChange: e => inlineBinding(group, key, 'thinking', e.target.value) }, ...[...new Set([...Object.keys(efforts), value.thinking ?? ''])].map(effort => h('option', { key: effort, value: effort }, efforts[effort] ?? effort)))),
3460
+ h('td', null, h('select', { className: css.modeSelect, disabled: busy, value: value['native-profile'] ?? '__inherit__', 'aria-label': roleName(group, key) + ' · ' + t('cfgNative'), onChange: e => inlineNativeProfile(group, key, e.target.value) }, ...nativeChoices(value).map(([name, label]) => h('option', { key: name, value: name }, label)))),
3377
3461
  h('td', null, ['intake', 'garden'].includes(role) ? t('cfgIndependent') : h('select', { className: css.modeSelect, disabled: busy, value: draft.sessions?.roles?.[role] ?? 'inherit', 'aria-label': roleName(group, key) + ' · ' + t('consoleSession'), onChange: e => inlineBinding(group, key, 'session', e.target.value) }, ...sessionChoices.map(([v, label]) => h('option', { key: v, value: v }, label))), planConflict && h('div', { className: css.settingsHelp }, t('cfgPlanConflict'), h(Button, { disabled: busy, onClick: () => inlineBinding(group, key, 'session', policy) }, t('cfgApplyPolicy')))));
3378
3462
  })))),
3379
- h('p', { className: css.settingsHelp }, t('consoleRouteSession')));
3463
+ h('p', { className: css.settingsHelp }, t('consoleRouteSession')),
3464
+ h('p', { className: css.settingsHelp }, t('cfgNativeHelp')));
3380
3465
  if (draft && section === 'jev')
3381
3466
  fields = h(
3382
3467
  React.Fragment,
@@ -3689,6 +3774,9 @@ function ConfigEditor({ control, selection, run, t, active = false, cache, conte
3689
3774
  },
3690
3775
  ),
3691
3776
  ),
3777
+ field('binding.native-profile', t('cfgNative'), t('cfgNativeHelp'),
3778
+ select('binding.native-profile', bindingEdit.value['native-profile'] ?? '__inherit__', nativeChoices(bindingEdit.value),
3779
+ name => setBindingEdit(old => ({ ...old, value: setNativeProfile(old.value, name) })))),
3692
3780
  field(
3693
3781
  'binding.permission',
3694
3782
  t('permission'),
@@ -3769,6 +3857,15 @@ Object.assign(en, {
3769
3857
  Object.assign(zh, { cfgPlanConflict: 'Plan 旧历史开关与此策略不同', cfgApplyPolicy: '同步此策略' });
3770
3858
  Object.assign(en, { cfgPlanConflict: 'The legacy Plan history switch differs', cfgApplyPolicy: 'Align policy' });
3771
3859
 
3860
+ Object.assign(zh, {
3861
+ cfgNative: '原生能力', cfgNativeNone: '不启用原生能力配置',
3862
+ cfgNativeHelp: '选择与当前后端匹配的能力配置;在高级 JSON 中编辑 native-profiles。JEV 关闭时仍生效,实际可用性以运行回执为准。',
3863
+ });
3864
+ Object.assign(en, {
3865
+ cfgNative: 'Native capabilities', cfgNativeNone: 'No native capability profile',
3866
+ cfgNativeHelp: 'Select a profile for this backend; edit native-profiles in advanced JSON. Profiles work with JEV off. Runtime receipts establish actual availability.',
3867
+ });
3868
+
3772
3869
  Object.assign(zh, {
3773
3870
  runsDetails: '运行详情',
3774
3871
  runsNoReference: '不设置对照',
@@ -1,8 +1,9 @@
1
1
  // Public machine API consumer. Go remains the owner of scheduling and acceptance.
2
2
  import { createRequire } from 'node:module';
3
3
  import { isAbsolute } from 'node:path';
4
+ import { validateNativeAdmission } from './machine-worker.mjs';
4
5
 
5
- export const ADAPTER = Object.freeze({ package: 'dsh-subagent-codex-pro', version: '0.9.0', protocol: 1 });
6
+ export const ADAPTER = Object.freeze({ package: 'dsh-subagent-codex-pro', version: '0.10.0', protocol: 1 });
6
7
  export const LIMITS = Object.freeze({ requestBytes: 1024 * 1024, machineOutputBytes: 1024 * 1024,
7
8
  progressBytes: 1024 * 1024, receiptFrameBytes: 8 * 1024 * 1024, admissionMs: 10000 });
8
9
  const require = createRequire(import.meta.url);
@@ -20,7 +21,7 @@ export async function loadAdapter() {
20
21
  try {
21
22
  manifest = require('dsh-subagent-codex-pro/package.json');
22
23
  } catch {
23
- throw new WorkerError('ADAPTER_UNAVAILABLE', 'Install the exact dsh-subagent-codex-pro@0.9.0 dependency with Flywheel');
24
+ throw new WorkerError('ADAPTER_UNAVAILABLE', 'Install the exact dsh-subagent-codex-pro@0.10.0 dependency with Flywheel');
24
25
  }
25
26
  if (manifest.name !== ADAPTER.package || manifest.version !== ADAPTER.version) {
26
27
  throw new WorkerError('ADAPTER_MISMATCH', 'Codex Pro package identity or version does not match the pinned contract');
@@ -31,7 +32,9 @@ export async function loadAdapter() {
31
32
  typeof api.parseMachineRequest !== 'function' || typeof api.runMachine !== 'function' || typeof api.MachineInputError !== 'function' ||
32
33
  api.MACHINE_LIFECYCLE_VERSION !== 1 || typeof api.recoverMachine !== 'function' ||
33
34
  api.MACHINE_LIFECYCLE_CAPABILITIES?.durableJournal !== true || api.MACHINE_LIFECYCLE_CAPABILITIES?.readOnlyRecovery !== true ||
34
- api.MACHINE_LIFECYCLE_CAPABILITIES?.threadReadyBeforeDispatch !== true) {
35
+ api.MACHINE_LIFECYCLE_CAPABILITIES?.threadReadyBeforeDispatch !== true ||
36
+ api.MACHINE_NATIVE_VERSION !== 1 || api.MACHINE_NATIVE_CAPABILITIES?.version !== 1 ||
37
+ api.MACHINE_NATIVE_CAPABILITIES?.agents !== true || api.MACHINE_NATIVE_CAPABILITIES?.review !== true) {
35
38
  throw new WorkerError('ADAPTER_MISMATCH', 'Codex Pro package identity, version or public machine API does not match the pinned contract');
36
39
  }
37
40
  return api;
@@ -41,7 +44,7 @@ export async function loadAdapter() {
41
44
  export function machineRequest(value, api, env) {
42
45
  const lifecycle = value?.protocol === 3;
43
46
  const persistent = value?.protocol === 2 || (lifecycle && value.threadMode === 'persistent');
44
- const keys = new Set(['type', 'protocol', 'requestId', 'cwd', 'model', 'reasoningEffort', 'permissionMode', 'prompt', 'timeoutMs',
47
+ const keys = new Set(['type', 'protocol', 'requestId', 'cwd', 'model', 'reasoningEffort', 'permissionMode', 'prompt', 'timeoutMs', 'native', 'managed', 'images', 'outputSchema',
45
48
  ...(persistent || lifecycle ? ['threadMode', 'threadId'] : []), ...(lifecycle ? ['recoveryDirectory'] : [])]);
46
49
  if (value === null || typeof value !== 'object' || Array.isArray(value) || value.type !== 'start' || ![1, 2, 3].includes(value.protocol) ||
47
50
  Object.keys(value).some(key => !keys.has(key)) || typeof value.requestId !== 'string' || value.requestId.length > 256 ||
@@ -56,11 +59,15 @@ export function machineRequest(value, api, env) {
56
59
  if (value.timeoutMs !== undefined && (!Number.isSafeInteger(value.timeoutMs) || value.timeoutMs < 1 || value.timeoutMs > 2147483647)) {
57
60
  throw new WorkerError('INVALID_REQUEST', 'timeoutMs must be a positive safe integer no greater than 2147483647');
58
61
  }
62
+ validateNativeAdmission(value.managed, value.requestId, WorkerError);
59
63
  try {
60
64
  return api.parseMachineRequest({ protocol: 1, requestId: value.requestId, cwd: value.cwd, model: value.model,
61
65
  effort: value.reasoningEffort,
62
66
  permissionMode: value.permissionMode === 'danger-full-access' ? 'dangerously-bypass-approvals-and-sandbox' : value.permissionMode,
63
67
  prompt: value.prompt,
68
+ ...(value.native === undefined ? {} : { native: value.native }),
69
+ ...(value.images === undefined ? {} : { images: value.images }),
70
+ ...(value.outputSchema === undefined ? {} : { outputSchema: value.outputSchema }),
64
71
  ...(value.timeoutMs === undefined ? {} : { timeoutMs: value.timeoutMs }),
65
72
  command: env.FLYWHEEL_CODEX_BIN || 'codex', threadMode: persistent ? 'persistent' : 'ephemeral',
66
73
  ...(persistent && value.threadId !== undefined ? { threadId: value.threadId } : {}), maxOutputBytes: LIMITS.machineOutputBytes });
@@ -71,5 +78,5 @@ export function machineRequest(value, api, env) {
71
78
 
72
79
  export function doctorResult() {
73
80
  return { protocol: 1, type: 'doctor', package: ADAPTER.package, version: ADAPTER.version,
74
- machineProtocol: ADAPTER.protocol, available: true, inferenceTested: false };
81
+ machineProtocol: ADAPTER.protocol, nativeVersion: 1, available: true, inferenceTested: false };
75
82
  }
package/dist/control.mjs CHANGED
@@ -73,7 +73,7 @@ function validConfiguration(value) {
73
73
  Array.isArray(value.bindings) && value.bindings.every(binding => record(binding) &&
74
74
  ['id', 'role', 'harness'].every(key =>
75
75
  typeof binding[key] === 'string' && binding[key].trim() !== '') &&
76
- ['route', 'profile', 'provider', 'channel', 'model', 'thinking', 'permissionMode'].every(key =>
76
+ ['route', 'profile', 'nativeProfile', 'provider', 'channel', 'model', 'thinking', 'permissionMode'].every(key =>
77
77
  binding[key] === undefined || typeof binding[key] === 'string') &&
78
78
  ['residentSession', 'inScope'].every(key => binding[key] === undefined || typeof binding[key] === 'boolean'));
79
79
  }