@superjackfruitlabs/salaam 0.0.1 → 0.0.2

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 (110) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/README.md +25 -17
  3. package/dist/src/a2a-backend.js +225 -0
  4. package/dist/src/a2a-inbound.js +487 -0
  5. package/dist/src/a2a-peer.js +370 -0
  6. package/dist/src/a2a-protocol.js +250 -0
  7. package/dist/src/agent-profiles.js +289 -0
  8. package/dist/src/children.js +132 -26
  9. package/dist/src/claude-provider.js +2 -179
  10. package/dist/src/cli-help.js +107 -6
  11. package/dist/src/cli.js +477 -13
  12. package/dist/src/config.js +26 -3
  13. package/dist/src/credentials.js +7 -2
  14. package/dist/src/external-runtime.js +1 -0
  15. package/dist/src/external-work.js +583 -0
  16. package/dist/src/harness-backend.js +466 -0
  17. package/dist/src/harness-container.js +450 -0
  18. package/dist/src/harness-model-gateway.js +104 -0
  19. package/dist/src/harness-prepare.js +88 -0
  20. package/dist/src/harness-probe.js +111 -0
  21. package/dist/src/harness-protocol.js +325 -0
  22. package/dist/src/harness-readiness.js +50 -0
  23. package/dist/src/harness-rpc.js +206 -0
  24. package/dist/src/harness-tool-identity.js +87 -0
  25. package/dist/src/harness-wire-bridge.js +387 -0
  26. package/dist/src/host.js +6 -1
  27. package/dist/src/house-extension.js +147 -64
  28. package/dist/src/live-provider.js +301 -0
  29. package/dist/src/managed.js +33 -3
  30. package/dist/src/protocol.js +9 -5
  31. package/dist/src/provider-auth.js +300 -0
  32. package/dist/src/provider-config.js +65 -17
  33. package/dist/src/provider-model.js +78 -0
  34. package/dist/src/provider-payload.js +264 -0
  35. package/dist/src/provider-transport.js +36 -0
  36. package/dist/src/provider-usage.js +59 -0
  37. package/dist/src/repository-snapshots.js +219 -0
  38. package/dist/src/service.js +274 -9
  39. package/dist/src/store.js +44 -2
  40. package/dist/src/supervisor.js +246 -35
  41. package/dist/src/task-budget.js +17 -8
  42. package/dist/src/task-context.js +15 -0
  43. package/dist/src/task-driver.js +38 -14
  44. package/dist/src/task-policy.js +20 -1
  45. package/dist/src/task-verification.js +3 -0
  46. package/dist/src/task-work.js +31 -0
  47. package/dist/src/team-work.js +378 -0
  48. package/dist/src/tui-view.js +65 -10
  49. package/dist/src/tui.js +4 -2
  50. package/dist/src/usage.js +18 -0
  51. package/dist/src/worker-boundary.js +298 -0
  52. package/dist/src/worker-workspaces.js +274 -0
  53. package/dist/src/workspaces.js +6 -2
  54. package/harness-runtime/codex-pins.json +10 -0
  55. package/harness-runtime/package-lock.json +560 -0
  56. package/harness-runtime/package.json +9 -0
  57. package/npm-shrinkwrap.json +57 -2
  58. package/package.json +2 -1
  59. package/src/a2a-backend.ts +254 -0
  60. package/src/a2a-inbound.ts +585 -0
  61. package/src/a2a-peer.ts +441 -0
  62. package/src/a2a-protocol.ts +286 -0
  63. package/src/agent-profiles.ts +379 -0
  64. package/src/children.ts +168 -27
  65. package/src/claude-provider.ts +2 -189
  66. package/src/cli-help.ts +107 -6
  67. package/src/cli.ts +602 -12
  68. package/src/config.ts +34 -3
  69. package/src/credentials.ts +9 -2
  70. package/src/external-runtime.ts +54 -0
  71. package/src/external-work.ts +663 -0
  72. package/src/harness-backend.ts +557 -0
  73. package/src/harness-container.ts +543 -0
  74. package/src/harness-model-gateway.ts +138 -0
  75. package/src/harness-prepare.ts +113 -0
  76. package/src/harness-probe.ts +150 -0
  77. package/src/harness-protocol.ts +388 -0
  78. package/src/harness-readiness.ts +71 -0
  79. package/src/harness-rpc.ts +244 -0
  80. package/src/harness-tool-identity.ts +91 -0
  81. package/src/harness-wire-bridge.ts +418 -0
  82. package/src/host.ts +11 -6
  83. package/src/house-extension.ts +165 -66
  84. package/src/live-provider.ts +347 -0
  85. package/src/managed.ts +43 -4
  86. package/src/protocol.ts +36 -8
  87. package/src/provider-auth.ts +336 -0
  88. package/src/provider-config.ts +89 -18
  89. package/src/provider-model.ts +86 -0
  90. package/src/provider-payload.ts +263 -0
  91. package/src/provider-transport.ts +51 -0
  92. package/src/provider-usage.ts +64 -0
  93. package/src/repository-snapshots.ts +259 -0
  94. package/src/service.ts +446 -11
  95. package/src/store.ts +60 -4
  96. package/src/supervisor.ts +294 -41
  97. package/src/task-budget.ts +24 -11
  98. package/src/task-context.ts +17 -0
  99. package/src/task-driver.ts +51 -15
  100. package/src/task-policy.ts +23 -3
  101. package/src/task-verification.ts +2 -0
  102. package/src/task-work.ts +46 -1
  103. package/src/team-work.ts +554 -0
  104. package/src/tui-client.ts +5 -0
  105. package/src/tui-view.ts +164 -12
  106. package/src/tui.ts +5 -2
  107. package/src/usage.ts +17 -0
  108. package/src/worker-boundary.ts +395 -0
  109. package/src/worker-workspaces.ts +390 -0
  110. package/src/workspaces.ts +4 -2
@@ -0,0 +1,274 @@
1
+ import { randomUUID } from 'node:crypto';
2
+ import { readTree } from './workspaces.js';
3
+ import { repositoryPath } from './repository-snapshots.js';
4
+ import { canonical, digest, ServiceError } from './protocol.js';
5
+ import { workspaceDiff } from './workspace-diff.js';
6
+ /** Drafts are private owned copies. Integration reuses the hash-bound workspace journal. */
7
+ export class WorkerWorkspaces {
8
+ store;
9
+ workspaces;
10
+ repositories;
11
+ artifacts;
12
+ coding;
13
+ children;
14
+ constructor(store, workspaces, repositories, artifacts, coding, children) {
15
+ this.store = store;
16
+ this.workspaces = workspaces;
17
+ this.repositories = repositories;
18
+ this.artifacts = artifacts;
19
+ this.coding = coding;
20
+ this.children = children;
21
+ }
22
+ execution() {
23
+ const executor = this.coding.executor;
24
+ if (!executor?.profileDigest ||
25
+ !executor.engineId ||
26
+ (executor.evidence.probe !== 'passed' && executor.evidence.fixture !== true))
27
+ throw new ServiceError('executor_unavailable', 'Writing specialists require a configured execution boundary');
28
+ return {
29
+ profile_digest: executor.profileDigest,
30
+ engine_id: executor.engineId,
31
+ evidence: executor.evidence.fixture === true ? 'fixture' : 'proven',
32
+ };
33
+ }
34
+ prepare(session, repository) {
35
+ const execution = this.execution();
36
+ const tree = JSON.parse(this.artifacts.read(repository.artifact_id));
37
+ if (digest(tree) !== repository.digest)
38
+ throw new ServiceError('artifact_corrupt', 'Worker baseline digest changed');
39
+ const workspace = this.workspaces.cloneSnapshot(session, tree);
40
+ return {
41
+ workspace_id: workspace.id,
42
+ baseline_artifact: repository.artifact_id,
43
+ digest: repository.digest,
44
+ execution,
45
+ };
46
+ }
47
+ assert(binding) {
48
+ const scope = binding.isolation;
49
+ if (!scope || canonical(scope.execution) !== canonical(this.execution()))
50
+ throw new ServiceError('worker_binding_changed', 'Worker execution environment changed');
51
+ const workspace = this.workspaces.get(binding.session_id);
52
+ if (workspace.id !== scope.workspace_id ||
53
+ scope.digest !== binding.repository?.digest ||
54
+ scope.baseline_artifact !== binding.repository?.artifact_id)
55
+ throw new ServiceError('worker_binding_changed', 'Worker workspace ownership changed');
56
+ this.coding.assertSafe(binding.session_id);
57
+ }
58
+ settled(parent, id, complete = true) {
59
+ const child = this.children.inspect(parent, id), binding = child.worker.binding;
60
+ if (!binding.isolation ||
61
+ (binding.external && !this.children.external?.stopped(child.id)) ||
62
+ (complete ? child.state !== 'completed' : child.state === 'accepted') ||
63
+ this.store.db
64
+ .prepare("SELECT 1 FROM workers WHERE session_id=? AND state!='exited'")
65
+ .get(child.child_session) ||
66
+ this.store.db
67
+ .prepare("SELECT 1 FROM command_runs WHERE session_id=? AND state NOT IN ('succeeded','failed','cancelled','timed_out','output_limited','interrupted')")
68
+ .get(child.child_session))
69
+ throw new ServiceError('worker_not_settled', 'Wait for the owned worker and commands to stop before inspecting its proposal');
70
+ this.assert(binding);
71
+ return { child, binding };
72
+ }
73
+ proposal(parent, id, offset) {
74
+ const { child, binding } = this.settled(parent, id, false);
75
+ const workspace = this.workspaces.verify(child.child_session), baseline = this.repositories.tree(binding), current = readTree(workspace.root);
76
+ if (digest(current) !== workspace.digest)
77
+ throw new ServiceError('workspace_changed', 'Worker draft changed during inspection');
78
+ const changes = [...new Set([...Object.keys(baseline), ...Object.keys(current)])]
79
+ .sort()
80
+ .filter((path) => digest(baseline[path] ?? null) !== digest(current[path] ?? null))
81
+ .map((path) => {
82
+ repositoryPath(path);
83
+ return { path, before: baseline[path] ?? null, after: current[path] ?? null };
84
+ });
85
+ const patch = {
86
+ schema_version: 1,
87
+ worker_id: binding.worker_id,
88
+ child_id: id,
89
+ worker_state: child.state,
90
+ baseline_digest: binding.repository.digest,
91
+ draft_digest: workspace.digest,
92
+ changes,
93
+ };
94
+ return {
95
+ ...patch,
96
+ changes: offset === undefined ? changes : changes.slice(offset, offset + 1),
97
+ diff: (offset === undefined ? changes : changes.slice(offset, offset + 1)).map(workspaceDiff),
98
+ next_offset: offset !== undefined && offset + 1 < changes.length ? offset + 1 : null,
99
+ patch_digest: digest(patch),
100
+ verified_success: false,
101
+ };
102
+ }
103
+ integrate(parent, childId, request, revision, rootDigest, patchDigest, authorize) {
104
+ let fresh = false;
105
+ const receipt = this.store.request('local-operator', request, { kind: 'worker-integrate', parent, childId, revision, rootDigest, patchDigest }, () => {
106
+ authorize();
107
+ const task = this.store.db
108
+ .prepare('SELECT state FROM durable_tasks WHERE session_id=?')
109
+ .get(parent);
110
+ if (task?.state === 'cancelled')
111
+ throw new ServiceError('task_settled', 'Task cancellation revoked integration authority');
112
+ const { child, binding } = this.settled(parent, childId);
113
+ this.assertRootIdle(parent);
114
+ if (this.store.db.prepare('SELECT 1 FROM worker_integrations WHERE child_id=?').get(childId))
115
+ throw new ServiceError('integration_exists', 'This draft already has an integration intent; inspect its receipt');
116
+ const proposal = this.proposal(parent, childId);
117
+ if (proposal.patch_digest !== patchDigest)
118
+ throw new ServiceError('proposal_changed', 'Review the exact current worker proposal');
119
+ if (this.store.db
120
+ .prepare("SELECT 1 FROM attempts WHERE session_id=? AND state IN ('accepted','dispatching','running')")
121
+ .get(parent))
122
+ throw new ServiceError('task_busy', 'Pause root work before integration');
123
+ const workspace = this.workspaces.verify(parent);
124
+ if (workspace.revision !== revision || workspace.digest !== rootDigest)
125
+ throw new ServiceError('workspace_changed', 'Root workspace changed since review');
126
+ const before = readTree(workspace.root), after = { ...before };
127
+ for (const change of proposal.changes) {
128
+ if (digest(before[change.path] ?? null) !== digest(change.before))
129
+ throw new ServiceError('integration_conflict', 'Root and worker both changed ' + change.path);
130
+ if (change.after)
131
+ after[change.path] = change.after;
132
+ else
133
+ delete after[change.path];
134
+ }
135
+ const artifact = this.artifacts.prepare(parent, JSON.stringify(after));
136
+ artifact.commit();
137
+ const id = randomUUID();
138
+ this.store.db
139
+ .prepare("INSERT INTO worker_integrations VALUES (?,?,?,?,?,?,?,?,'prepared',NULL,?,1)")
140
+ .run(id, parent, child.id, binding.worker_id, patchDigest, workspace.revision, workspace.digest, artifact.id, 'worker-integration:' + id);
141
+ this.store.event(parent, 'worker.integration_prepared', {
142
+ integration_id: id,
143
+ child_id: childId,
144
+ patch_digest: patchDigest,
145
+ before_digest: workspace.digest,
146
+ after_digest: digest(after),
147
+ });
148
+ fresh = true;
149
+ return { id };
150
+ });
151
+ if (fresh)
152
+ this.apply(receipt.id, authorize);
153
+ return this.inspect(receipt.id);
154
+ }
155
+ apply(id, authorize) {
156
+ const row = this.row(id), parent = String(row.parent_session), workspace = this.workspaces.verify(parent), before = readTree(workspace.root), after = JSON.parse(this.artifacts.read(String(row.after_artifact)));
157
+ authorize();
158
+ this.assertRootIdle(parent);
159
+ if (workspace.revision !== row.before_revision || digest(before) !== row.before_digest)
160
+ throw new ServiceError('workspace_changed', 'Root changed after integration intent; no overwrite was performed');
161
+ this.workspaces.replace(parent, String(row.mutation_key), String(row.patch_digest), Number(row.before_revision), before, after);
162
+ this.reconcile(id);
163
+ }
164
+ resolve(id, request, revision, rootDigest, authorize) {
165
+ let fresh = false;
166
+ this.store.request('local-operator', request, { kind: 'integration-resolve', id, revision, rootDigest }, () => {
167
+ authorize();
168
+ const row = this.row(id), parent = String(row.parent_session), workspace = this.workspaces.verify(parent);
169
+ this.assertRootIdle(parent);
170
+ const task = this.store.db
171
+ .prepare('SELECT state FROM durable_tasks WHERE session_id=?')
172
+ .get(parent);
173
+ if (task?.state === 'cancelled')
174
+ throw new ServiceError('task_settled', 'Task cancellation revoked integration authority');
175
+ if (!['prepared', 'needs_resolution'].includes(String(row.state)) ||
176
+ Number(row.generation) >= 8)
177
+ throw new ServiceError('integration_settled', 'Integration is applied or its resolution limit was reached');
178
+ if (workspace.revision !== revision ||
179
+ workspace.digest !== rootDigest ||
180
+ revision !== row.before_revision ||
181
+ rootDigest !== row.before_digest)
182
+ throw new ServiceError('workspace_changed', 'Resolution requires the exact unchanged pre-integration root');
183
+ const mutation = this.store.db
184
+ .prepare('SELECT state FROM workspace_mutations WHERE workspace_id=? AND request_key=?')
185
+ .get(workspace.id, String(row.mutation_key));
186
+ if (mutation && mutation.state !== 'failed_definite')
187
+ throw new ServiceError('integration_uncertain', 'Reconcile the existing workspace mutation before a new apply');
188
+ const generation = Number(row.generation) + 1, key = 'worker-integration:' + id + ':' + generation;
189
+ this.store.db
190
+ .prepare("UPDATE worker_integrations SET state='prepared',mutation_id=NULL,mutation_key=?,generation=? WHERE id=?")
191
+ .run(key, generation, id);
192
+ this.store.event(parent, 'worker.integration_resolution_admitted', {
193
+ integration_id: id,
194
+ generation,
195
+ mutation_key: key,
196
+ request_id: request,
197
+ });
198
+ fresh = true;
199
+ return { id };
200
+ });
201
+ if (fresh)
202
+ this.apply(id, authorize);
203
+ return this.inspect(id);
204
+ }
205
+ owner(id) {
206
+ return String(this.row(id).parent_session);
207
+ }
208
+ assertRootIdle(parent) {
209
+ if (this.store.db
210
+ .prepare("SELECT 1 FROM attempts WHERE session_id=? AND state IN ('accepted','dispatching','running')")
211
+ .get(parent) ||
212
+ this.store.db
213
+ .prepare("SELECT 1 FROM compactions WHERE session_id=? AND state='running'")
214
+ .get(parent))
215
+ throw new ServiceError('task_busy', 'Pause root work before integration');
216
+ }
217
+ row(id) {
218
+ const row = this.store.db.prepare('SELECT * FROM worker_integrations WHERE id=?').get(id);
219
+ if (!row)
220
+ throw new ServiceError('not_found', 'Integration receipt not found', 404);
221
+ return row;
222
+ }
223
+ inspect(id) {
224
+ const row = this.row(id), workspace = this.workspaces.get(String(row.parent_session)), after = JSON.parse(this.artifacts.read(String(row.after_artifact)));
225
+ let current = false;
226
+ try {
227
+ current =
228
+ row.state === 'applied' &&
229
+ this.workspaces.verify(String(row.parent_session)).digest === digest(after);
230
+ }
231
+ catch { }
232
+ return { ...row, after_digest: digest(after), current, verified_success: false };
233
+ }
234
+ reconcile(id) {
235
+ const row = this.row(id);
236
+ if (row.state === 'applied')
237
+ return;
238
+ const workspace = this.workspaces.get(String(row.parent_session)), after = JSON.parse(this.artifacts.read(String(row.after_artifact)));
239
+ const mutation = this.store.db
240
+ .prepare('SELECT * FROM workspace_mutations WHERE workspace_id=? AND request_key=?')
241
+ .get(workspace.id, String(row.mutation_key));
242
+ const applied = mutation?.state === 'applied' && mutation.after_digest === digest(after);
243
+ this.store.transaction(() => {
244
+ this.store.db
245
+ .prepare('UPDATE worker_integrations SET state=?,mutation_id=? WHERE id=?')
246
+ .run(applied ? 'applied' : 'needs_resolution', mutation ? String(mutation.id) : null, id);
247
+ this.store.event(String(row.parent_session), 'worker.integration_reconciled', {
248
+ integration_id: id,
249
+ state: applied ? 'applied' : 'needs_resolution',
250
+ mutation_id: mutation?.id ?? null,
251
+ });
252
+ });
253
+ }
254
+ recover() {
255
+ for (const row of this.store.db
256
+ .prepare("SELECT id FROM worker_integrations WHERE state='prepared'")
257
+ .all())
258
+ this.reconcile(String(row.id));
259
+ }
260
+ assertStepReview(task, step) {
261
+ const row = this.store.db
262
+ .prepare('SELECT c.id,b.binding FROM task_steps s JOIN child_tasks c ON c.child_attempt=s.attempt_id JOIN child_workers b ON b.child_id=c.id WHERE s.task_id=? AND s.id=?')
263
+ .get(task, step);
264
+ if (!row)
265
+ return;
266
+ const binding = JSON.parse(String(row.binding));
267
+ if (!binding.tools.includes('salaam_files'))
268
+ return;
269
+ if (!this.store.db
270
+ .prepare("SELECT 1 FROM worker_integrations WHERE child_id=? AND state='applied'")
271
+ .get(String(row.id)))
272
+ throw new ServiceError('integration_required', 'Integrate the exact writing-worker proposal before step verification or completion');
273
+ }
274
+ }
@@ -220,7 +220,7 @@ export class Workspaces {
220
220
  if (digest(readTree(root)) !== digest(tree))
221
221
  throw new ServiceError('workspace_conflict', 'Occurrence workspace changed before publication');
222
222
  const baseline = this.artifacts.prepare(session, JSON.stringify(tree));
223
- this.store.transaction(() => {
223
+ const publish = () => {
224
224
  baseline.commit();
225
225
  this.store.db
226
226
  .prepare("INSERT INTO workspaces VALUES (?,?,?,?,0,?,?,'ready')")
@@ -231,7 +231,11 @@ export class Workspaces {
231
231
  digest: digest(tree),
232
232
  cloned: true,
233
233
  });
234
- });
234
+ };
235
+ if (this.store.db.isTransaction)
236
+ publish();
237
+ else
238
+ this.store.transaction(publish);
235
239
  return this.get(session);
236
240
  }
237
241
  inspect(session) {
@@ -0,0 +1,10 @@
1
+ {
2
+ "linux-arm64": {
3
+ "url": "https://registry.npmjs.org/@openai/codex/-/codex-0.163.0-linux-arm64.tgz",
4
+ "integrity": "IH2/R+4OarjGvsAf1ll3fdyLwrPgYLl3uzp6u9CyD9sj2Lw+ViDSe3QBZVHdcHJs0eIiZFg6Wprcuy4CRZaUGw=="
5
+ },
6
+ "linux-x64": {
7
+ "url": "https://registry.npmjs.org/@openai/codex/-/codex-0.163.0-linux-x64.tgz",
8
+ "integrity": "uwRaOsrYogLQhcxAM/GoeWrw0QIWEMRo7c9gM8sKAviVkZQHlu9kRLJ5PkufbV+ABGjyZgIwiFdJ0LCJ0N6e8w=="
9
+ }
10
+ }