@milpa/comal 0.1.7 → 0.2.1

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 (134) hide show
  1. package/README.md +19 -1
  2. package/backend/contracts/remote-commands-v1.json +12 -0
  3. package/governance/chrome-task-v10.json +323 -0
  4. package/governance/chrome-task-v11.json +355 -0
  5. package/governance/chrome-task-v12.json +387 -0
  6. package/governance/chrome-task-v13.json +419 -0
  7. package/governance/chrome-task-v3.json +99 -0
  8. package/governance/chrome-task-v4.json +131 -0
  9. package/governance/chrome-task-v5.json +163 -0
  10. package/governance/chrome-task-v6.json +195 -0
  11. package/governance/chrome-task-v7.json +227 -0
  12. package/governance/chrome-task-v8.json +259 -0
  13. package/governance/chrome-task-v9.json +291 -0
  14. package/governance/source-task-v1.json +1 -0
  15. package/governance/source-task-v2.json +1 -0
  16. package/package.json +14 -1
  17. package/src/agent-recovery-proof.mjs +12 -1
  18. package/src/agent.mjs +94 -30
  19. package/src/audit.mjs +21 -6
  20. package/src/auto-guard.mjs +48 -1
  21. package/src/chrome-candidate-recovery-proof.mjs +47 -0
  22. package/src/chrome-recovery-proof.mjs +6 -2
  23. package/src/chrome-source-syntax.mjs +93 -0
  24. package/src/cli.mjs +158 -54
  25. package/src/codex-provider.mjs +3 -2
  26. package/src/connection-settings.mjs +204 -0
  27. package/src/context-pressure.mjs +2 -1
  28. package/src/durable-agent-runs.mjs +5 -11
  29. package/src/event-channels.mjs +8 -0
  30. package/src/file-recovery-proof.mjs +11 -3
  31. package/src/file-recovery.mjs +24 -0
  32. package/src/gemini-provider.mjs +6 -1
  33. package/src/git-agent-revision.mjs +12 -0
  34. package/src/git-agent-workspaces.mjs +143 -0
  35. package/src/git-integration-lineage.mjs +20 -0
  36. package/src/git-integration-operations.mjs +200 -0
  37. package/src/git-integration-recovery-proof.mjs +70 -0
  38. package/src/git-page-cli-bridge.mjs +61 -0
  39. package/src/git-page-evidence.mjs +30 -0
  40. package/src/git-page-identity.mjs +10 -0
  41. package/src/git-page-proof.mjs +96 -0
  42. package/src/git-page-settlement.mjs +21 -0
  43. package/src/git-page-verification.mjs +134 -0
  44. package/src/git-plumbing.mjs +212 -0
  45. package/src/git-process-worker.mjs +50 -0
  46. package/src/git-source.mjs +110 -0
  47. package/src/git-workspaces.mjs +519 -0
  48. package/src/goals.mjs +13 -7
  49. package/src/house.mjs +246 -20
  50. package/src/i18n/cli-es.mjs +4 -0
  51. package/src/i18n/es.mjs +35 -0
  52. package/src/judges.mjs +27 -11
  53. package/src/mcp-runtime.mjs +15 -3
  54. package/src/model-controls.mjs +11 -1
  55. package/src/model-deadline.mjs +4 -3
  56. package/src/native-refusal.mjs +38 -0
  57. package/src/onboarding.mjs +88 -24
  58. package/src/openai-provider.mjs +14 -7
  59. package/src/operations.mjs +9 -2
  60. package/src/output-recovery.mjs +48 -0
  61. package/src/peer-tools.mjs +18 -8
  62. package/src/permission-controls.mjs +232 -0
  63. package/src/permission-rules.mjs +312 -0
  64. package/src/permissions.mjs +113 -30
  65. package/src/plugin-catalog.mjs +84 -0
  66. package/src/plugin-config.mjs +48 -6
  67. package/src/plugin-controls.mjs +332 -0
  68. package/src/plugin-notices.mjs +88 -0
  69. package/src/plugin-trust.mjs +104 -0
  70. package/src/plugins/chrome-lab/bridge.mjs +38 -12
  71. package/src/plugins/chrome-lab/client.mjs +103 -25
  72. package/src/plugins/chrome-lab/diagnostics.mjs +19 -0
  73. package/src/plugins/chrome-lab/index.mjs +116 -26
  74. package/src/plugins/chrome-lab/project.mjs +30 -2
  75. package/src/plugins/chrome-lab/scoped-input.mjs +135 -0
  76. package/src/plugins/chrome-lab/worker-diagnostics.mjs +51 -0
  77. package/src/plugins/open-relay/actions.mjs +205 -0
  78. package/src/plugins/open-relay/bound.mjs +47 -0
  79. package/src/plugins/open-relay/client.mjs +158 -0
  80. package/src/plugins/open-relay/dossier.mjs +119 -0
  81. package/src/plugins/open-relay/index.mjs +153 -0
  82. package/src/plugins/open-relay/lookup.mjs +45 -0
  83. package/src/plugins/open-relay/notices.mjs +79 -0
  84. package/src/plugins/open-relay/watch.mjs +127 -0
  85. package/src/plugins.mjs +72 -29
  86. package/src/private-fs.mjs +46 -0
  87. package/src/process-lock.mjs +24 -13
  88. package/src/provider-auth.mjs +14 -3
  89. package/src/provider.mjs +11 -2
  90. package/src/read-only-check.mjs +7 -3
  91. package/src/scope-ceiling.mjs +56 -0
  92. package/src/scoped-policy.mjs +39 -0
  93. package/src/secret-login.mjs +68 -0
  94. package/src/session-bus.mjs +41 -7
  95. package/src/session-projections-candidate.mjs +119 -0
  96. package/src/session-projections.mjs +119 -0
  97. package/src/session-read-cache.mjs +23 -3
  98. package/src/sessions.mjs +35 -11
  99. package/src/source-editor-role.mjs +13 -0
  100. package/src/source-ownership.mjs +76 -0
  101. package/src/source-proposal-proof.mjs +55 -0
  102. package/src/source-proposals.mjs +118 -0
  103. package/src/source-requests.mjs +148 -0
  104. package/src/source-task-proof.mjs +24 -0
  105. package/src/source-task-revision-proof.mjs +44 -0
  106. package/src/subagents.mjs +187 -87
  107. package/src/tool-packs.mjs +5 -5
  108. package/src/tools.mjs +82 -15
  109. package/src/trusted-context.mjs +5 -1
  110. package/src/tui/connection-transition.mjs +1 -1
  111. package/src/tui/controller.mjs +8 -4
  112. package/src/tui/discovery.mjs +24 -12
  113. package/src/tui/inbound-blocks.mjs +55 -0
  114. package/src/tui/present.mjs +504 -0
  115. package/src/tui/screen.mjs +49 -13
  116. package/src/windows-private.ps1 +63 -0
  117. package/src/work-assertions.mjs +6 -2
  118. package/src/work-plan.mjs +34 -8
  119. package/src/work-state.mjs +15 -9
  120. package/src/workflows/chrome-page-cases.mjs +156 -0
  121. package/src/workflows/chrome-page-checkpoint-reader.mjs +10 -0
  122. package/src/workflows/chrome-page-diagnostics.mjs +113 -0
  123. package/src/workflows/chrome-page-law.mjs +48 -0
  124. package/src/workflows/chrome-page-recovery-host-v13.mjs +14 -0
  125. package/src/workflows/chrome-page-recovery-v13.mjs +104 -0
  126. package/src/workflows/chrome-page-task.mjs +429 -0
  127. package/src/workflows/chrome-page-verifier.mjs +123 -0
  128. package/src/workflows/chrome-source.mjs +73 -0
  129. package/src/workflows/chrome-supplied-inputs.mjs +43 -0
  130. package/src/workflows/chrome-task-adoption.mjs +122 -0
  131. package/src/workflows/chrome-task.mjs +379 -74
  132. package/src/workflows/source-task-v1.mjs +124 -0
  133. package/src/workflows/source-task-v2.mjs +227 -0
  134. package/src/workflows/source-task.mjs +13 -0
@@ -0,0 +1,93 @@
1
+ import { Script } from 'node:vm';
2
+ import { createHash } from 'node:crypto';
3
+ import { open, realpath, lstat } from 'node:fs/promises';
4
+ import { constants } from 'node:fs';
5
+ import path from 'node:path';
6
+ import { safeRelative } from './plugins/chrome-lab/project.mjs';
7
+
8
+ const scopes = new WeakMap();
9
+ const sha = bytes => createHash('sha256').update(bytes).digest('hex');
10
+ const protectedPart = part => ['.git', '.comal', '.harness', '.ssh', 'node_modules'].includes(part) || /^\.env(?:\.|$)/i.test(part);
11
+
12
+ // Native host metadata only. This supplies a dialect hint, never source access,
13
+ // permission, code execution or a callback supplied by a resident/plugin.
14
+ export function bindChromeSourceSyntax(workspace, sessionId, facts) {
15
+ if (typeof sessionId !== 'string' || !sessionId || !facts ||
16
+ Object.keys(facts).sort().join() !== 'directory,task_digest' ||
17
+ !/^[a-f0-9]{64}$/.test(facts.task_digest ?? '')) throw new Error('Invalid Chrome source syntax scope.');
18
+ const directory = safeRelative(facts.directory);
19
+ if (directory.split('/').some(protectedPart)) throw new Error('Protected Chrome source syntax scope.');
20
+ let sessions = scopes.get(workspace);
21
+ if (!sessions) scopes.set(workspace, sessions = new Map());
22
+ const token = Object.freeze({ directory, task_digest: facts.task_digest });
23
+ sessions.set(sessionId, token);
24
+ return {
25
+ dispose() { if (sessions.get(sessionId) === token) sessions.delete(sessionId); },
26
+ };
27
+ }
28
+
29
+ export function classicScriptSyntaxAdvice(source) {
30
+ if (typeof source !== 'string' || Buffer.byteLength(source) > 1048576) throw new Error('Expected bounded UTF-8 source.');
31
+ const advice = {
32
+ advisory: true, dialect: 'classic_script', parser: `node:${process.versions.node}/vm.Script`,
33
+ source_sha256: sha(source), execution: 'not_run', semantic_verification: 'unjudged',
34
+ scope: 'Node syntax only; Chrome compatibility and application behavior still require verification.',
35
+ };
36
+ try {
37
+ // Parsing never evaluates the candidate, including top-level expressions.
38
+ new Script(source, { filename: 'comal-content-script', displayErrors: true });
39
+ return { ...advice, status: 'parsed' };
40
+ } catch (error) {
41
+ if (!(error instanceof SyntaxError)) return { ...advice, status: 'unavailable', reason: 'parser_unavailable' };
42
+ const location = /^comal-content-script:(\d+)(?::(\d+))?$/.exec(String(error.stack).split('\n')[0]);
43
+ return {
44
+ ...advice, status: 'syntax_error', line: location ? Number(location[1]) : null,
45
+ message: String(error.message).replace(/[\x00-\x1f\x7f]/g, ' ').slice(0, 240),
46
+ next_action: 'Correct this candidate source before publishing; the file write itself is still recorded separately.',
47
+ };
48
+ }
49
+ }
50
+
51
+ // Only a currently declared classic content script receives parser feedback.
52
+ // Missing/invalid/changed manifests, ESM workers and unrelated files are unknown,
53
+ // not fabricated classic-script syntax errors. No raw manifest/code is returned.
54
+ export async function chromeSourceSyntaxAdvice(workspace, { sessionId, file, source }) {
55
+ const sessions = scopes.get(workspace), scope = sessions?.get(sessionId);
56
+ if (!scope) return undefined;
57
+ let handle;
58
+ try {
59
+ const directory = path.resolve(workspace.cwd, scope.directory);
60
+ const relative = path.relative(directory, file);
61
+ if (!relative || relative === '..' || relative === 'manifest.json' || relative.startsWith('..' + path.sep) || path.isAbsolute(relative)) return undefined;
62
+ if (!workspace.inside(directory) || await realpath(directory) !== directory) return undefined;
63
+ const manifestFile = path.join(directory, 'manifest.json');
64
+ if (await workspace.resolve(manifestFile) !== manifestFile || await realpath(manifestFile) !== manifestFile) return undefined;
65
+ handle = await open(manifestFile, constants.O_RDONLY | (constants.O_NOFOLLOW ?? 0));
66
+ const before = await handle.stat({ bigint: true });
67
+ if (!before.isFile() || before.size > 65536n) return undefined;
68
+ // A pre-stat cannot bound readFile when an ordinary file grows afterwards.
69
+ // Read at most64KiB plus one overflow byte, even across short reads/growth.
70
+ const buffer = Buffer.alloc(65537); let length = 0;
71
+ while (length < buffer.length) {
72
+ const { bytesRead } = await handle.read(buffer, length, buffer.length - length, length);
73
+ if (!bytesRead) break;
74
+ length += bytesRead;
75
+ }
76
+ const bytes = buffer.subarray(0, length), after = await handle.stat({ bigint: true }), named = await lstat(manifestFile, { bigint: true });
77
+ if (length > 65536 || before.dev !== after.dev || before.ino !== after.ino || before.size !== after.size || before.mtimeNs !== after.mtimeNs ||
78
+ named.isSymbolicLink() || named.dev !== after.dev || named.ino !== after.ino || named.size !== after.size || named.mtimeNs !== after.mtimeNs ||
79
+ BigInt(bytes.length) !== before.size || await realpath(manifestFile) !== manifestFile || sessions.get(sessionId) !== scope) return undefined;
80
+ const manifest = JSON.parse(bytes.toString('utf8'));
81
+ if (manifest?.manifest_version !== 3 || !Array.isArray(manifest.content_scripts)) return undefined;
82
+ const packaged = relative.split(path.sep).join('/');
83
+ const declared = manifest.content_scripts.some(group => group && Array.isArray(group.js) && group.js.some(value => {
84
+ try { return safeRelative(value) === packaged; } catch { return false; }
85
+ }));
86
+ if (!declared) return undefined;
87
+ return { ...classicScriptSyntaxAdvice(source), task_digest: scope.task_digest, manifest_sha256: sha(bytes) };
88
+ } catch {
89
+ // An advisory availability failure must not convert an authorized Write/Edit
90
+ // into a failure or change its source/permission/recovery semantics.
91
+ return undefined;
92
+ } finally { await handle?.close().catch(() => {}); }
93
+ }