ultra-builder-pro-cli 0.24.1 → 0.24.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.
@@ -81,7 +81,11 @@ function expandTask(db, {
81
81
  });
82
82
 
83
83
  return ops.tx(db, () => {
84
- changes.assertTaskCreationAllowed(db, { change_id: parent.change_id }, { rootDir });
84
+ const admission = changes.assertTaskCreationAllowed(
85
+ db,
86
+ { change_id: parent.change_id },
87
+ { rootDir },
88
+ );
85
89
  for (const child of normalized) {
86
90
  ops.createTask(db, child);
87
91
  }
@@ -89,6 +93,7 @@ function expandTask(db, {
89
93
  return {
90
94
  parent_id: parent.id,
91
95
  children: normalized,
96
+ diagnostics: admission.diagnostics,
92
97
  };
93
98
  });
94
99
  }
@@ -135,6 +135,48 @@ function rememberResult(db, {
135
135
  });
136
136
  }
137
137
 
138
+ function rememberRejectedAttempt(db, tool, input, result) {
139
+ if (!db || result?.accepted !== false) return result;
140
+ const nested = Array.isArray(result.results)
141
+ ? result.results.flatMap((item) => item.diagnostics || [])
142
+ : [];
143
+ const diagnostics = [...(result.diagnostics || []), ...nested]
144
+ .map((item) => ({
145
+ code: item.code || 'NEEDS_ATTENTION',
146
+ severity: item.severity || 'needs_attention',
147
+ message: item.message || null,
148
+ ...(item.details === undefined ? {} : { details: item.details }),
149
+ }));
150
+ const entries = Array.isArray(input.entries) ? input.entries : [];
151
+ const changeIds = [...new Set(entries.flatMap((entry) => [
152
+ entry.data?.change_id,
153
+ entry.kind === 'change_contract' ? entry.data?.id : null,
154
+ ]).filter(Boolean))];
155
+ const taskIds = [...new Set(entries.flatMap((entry) => [
156
+ entry.kind.startsWith('task_') ? entry.data?.id : null,
157
+ input.scope?.task_id,
158
+ ]).filter(Boolean))];
159
+ const scopeChangeId = input.scope?.change_id || input.change_id || null;
160
+ ops.appendEvent(db, {
161
+ type: 'ultra_kernel_attempt',
162
+ change_id: changeIds.length === 1 ? changeIds[0] : scopeChangeId,
163
+ task_id: taskIds.length === 1 ? taskIds[0] : null,
164
+ payload: {
165
+ tool,
166
+ accepted: false,
167
+ mutable: result.mutable !== false,
168
+ operations: entries.map((entry) => `${entry.kind}:${entry.action}`),
169
+ idempotency_keys: entries.length > 0
170
+ ? entries.map((entry) => entry.idempotency_key).filter(Boolean)
171
+ : [input.idempotency_key].filter(Boolean),
172
+ scope: input.scope || (input.change_id ? { change_id: input.change_id } : {}),
173
+ blockers: result.blockers || [],
174
+ diagnostics,
175
+ },
176
+ });
177
+ return result;
178
+ }
179
+
138
180
  function diagnostic(error, severity = 'needs_attention') {
139
181
  return {
140
182
  code: errorCode(error),
@@ -144,6 +186,34 @@ function diagnostic(error, severity = 'needs_attention') {
144
186
  };
145
187
  }
146
188
 
189
+ function rejectedAttemptAudit(db) {
190
+ return db.prepare(
191
+ `SELECT id, ts, task_id, change_id, payload_json
192
+ FROM events
193
+ WHERE type = 'ultra_kernel_attempt'
194
+ ORDER BY id DESC
195
+ LIMIT 5`,
196
+ ).all().map((row) => {
197
+ const payload = parseJson(row.payload_json, {});
198
+ return {
199
+ event_id: row.id,
200
+ recorded_at: row.ts,
201
+ tool: payload.tool || null,
202
+ task_id: row.task_id || null,
203
+ change_id: row.change_id || null,
204
+ operations: (payload.operations || []).slice(0, 12),
205
+ blockers: (payload.blockers || []).slice(0, 12),
206
+ diagnostics: (payload.diagnostics || []).slice(0, 8).map((item) => ({
207
+ code: item.code || 'NEEDS_ATTENTION',
208
+ severity: item.severity || 'needs_attention',
209
+ message: typeof item.message === 'string'
210
+ ? item.message.slice(0, 500)
211
+ : null,
212
+ })),
213
+ };
214
+ });
215
+ }
216
+
147
217
  function selectedScope(db, input = {}) {
148
218
  const scope = input.scope || {};
149
219
  const task = scope.task_id ? ops.readTask(db, scope.task_id) : null;
@@ -197,7 +267,28 @@ function readContext(db, input = {}, {
197
267
  rootDir = process.cwd(),
198
268
  runtime = 'unknown',
199
269
  } = {}) {
200
- return contextEnvelope.buildEnvelope(db, input, { rootDir, runtime });
270
+ const result = contextEnvelope.buildEnvelope(db, input, { rootDir, runtime });
271
+ const rejectedAttempts = rejectedAttemptAudit(db);
272
+ let visible = {
273
+ ...result,
274
+ audit: {
275
+ rejected_attempts: rejectedAttempts,
276
+ },
277
+ };
278
+ delete visible.bytes;
279
+ const limit = input.detail === 'full'
280
+ ? contextEnvelope.FULL_LIMIT
281
+ : contextEnvelope.SUMMARY_LIMIT;
282
+ while (Buffer.byteLength(JSON.stringify(visible)) > limit
283
+ && rejectedAttempts.length > 0) {
284
+ rejectedAttempts.pop();
285
+ }
286
+ if (Buffer.byteLength(JSON.stringify(visible)) > limit) {
287
+ visible = { ...result };
288
+ delete visible.bytes;
289
+ }
290
+ visible.bytes = Buffer.byteLength(JSON.stringify(visible));
291
+ return visible;
201
292
  }
202
293
 
203
294
  function initializeProject(data = {}) {
@@ -241,7 +332,7 @@ function baselineRecord(db, action, data, rootDir) {
241
332
 
242
333
  function changeContractRecord(db, action, data, rootDir) {
243
334
  if (action === 'open') {
244
- return changes.createChange(db, data, { rootDir, kernelMode: true });
335
+ return changes.createChange(db, data, { rootDir });
245
336
  }
246
337
  if (action === 'revise') {
247
338
  return {
@@ -249,7 +340,7 @@ function changeContractRecord(db, action, data, rootDir) {
249
340
  db,
250
341
  data.id,
251
342
  data.patch || {},
252
- { rootDir, kernelMode: true },
343
+ { rootDir },
253
344
  ),
254
345
  };
255
346
  }
@@ -259,7 +350,7 @@ function changeContractRecord(db, action, data, rootDir) {
259
350
  db,
260
351
  data.id,
261
352
  { status: 'cancelled' },
262
- { rootDir, kernelMode: true },
353
+ { rootDir },
263
354
  ),
264
355
  };
265
356
  }
@@ -374,6 +465,17 @@ function applyRecord(db, entry, { rootDir }) {
374
465
  if (kind === 'task_contract') return taskContractRecord(db, action, data);
375
466
  if (kind === 'task_outcome') return taskOutcomeRecord(db, action, data, rootDir);
376
467
  if (kind === 'artifact' && action === 'bind') {
468
+ const legacyWorkflowReference = data.owner_type === 'workflow'
469
+ || [...(data.source_refs || []), ...(data.consumer_refs || [])]
470
+ .some((reference) => reference?.type === 'workflow');
471
+ if (legacyWorkflowReference) {
472
+ throw Object.assign(
473
+ new Error(
474
+ 'workflow-owned artifact authority is retired and remains read-only history',
475
+ ),
476
+ { code: 'LEGACY_AUTHORITY_READ_ONLY' },
477
+ );
478
+ }
377
479
  return artifactRegistry.recordArtifact(db, data, { rootDir });
378
480
  }
379
481
  if (kind === 'event' && action === 'append') {
@@ -897,7 +999,7 @@ async function archive(db, input = {}, {
897
999
  const result = changes.archiveChange(
898
1000
  db,
899
1001
  { id: input.change_id, ...(input.payload || {}) },
900
- { rootDir, kernelMode: true },
1002
+ { rootDir },
901
1003
  );
902
1004
  const output = {
903
1005
  accepted: true,
@@ -929,22 +1031,26 @@ async function archive(db, input = {}, {
929
1031
  }
930
1032
 
931
1033
  async function dispatch(name, input, db, context = {}) {
932
- if (name === 'ultra.context') return readContext(db, input, context);
933
- if (name === 'ultra.record') return record(db, input, context);
934
- if (name === 'ultra.checkpoint') return checkpoint(db, input, context);
935
- if (name === 'ultra.sync') return sync(db, input, context);
936
- if (name === 'ultra.session') return session(db, input, context);
937
- if (name === 'ultra.archive') return archive(db, input, context);
1034
+ let result;
1035
+ if (name === 'ultra.context') result = readContext(db, input, context);
1036
+ else if (name === 'ultra.record') result = await record(db, input, context);
1037
+ else if (name === 'ultra.checkpoint') result = await checkpoint(db, input, context);
1038
+ else if (name === 'ultra.sync') result = sync(db, input, context);
1039
+ else if (name === 'ultra.session') result = await session(db, input, context);
1040
+ else if (name === 'ultra.archive') result = await archive(db, input, context);
938
1041
  if (name === 'ultra.doctor') {
939
- return doctor.runDoctor(db, {
1042
+ result = doctor.runDoctor(db, {
940
1043
  rootDir: context.rootDir || process.cwd(),
941
1044
  repair: input.repair === true,
942
1045
  project: context.projector,
943
1046
  });
944
1047
  }
945
- const error = new Error(`unhandled public tool ${name}`);
946
- error.code = 'UNKNOWN_TOOL';
947
- throw error;
1048
+ if (result === undefined) {
1049
+ const error = new Error(`unhandled public tool ${name}`);
1050
+ error.code = 'UNKNOWN_TOOL';
1051
+ throw error;
1052
+ }
1053
+ return rememberRejectedAttempt(db, name, input, result);
948
1054
  }
949
1055
 
950
1056
  module.exports = {
@@ -284,7 +284,7 @@ function startServer({
284
284
  );
285
285
  const own = processed.jobs.find((item) => item.id === job.id);
286
286
  runtimeMeta = {
287
- state_commit: 'committed',
287
+ projection_commit: 'committed',
288
288
  projection_status: own?.status || 'failed',
289
289
  projection_job_id: job.id,
290
290
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ultra-builder-pro-cli",
3
- "version": "0.24.1",
3
+ "version": "0.24.2",
4
4
  "description": "Explicitly invoked Ultra Builder Pro workflows for Claude Code, OpenCode, Codex CLI, Kimi Code, and Grok Build, with a project-local MCP persistence and safety kernel.",
5
5
  "bin": {
6
6
  "ultra-builder-pro-cli": "bin/install.js",