@hivemagnus/magnus-agent 1.1.12 → 1.1.13

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.
@@ -33,7 +33,7 @@ async function main() {
33
33
  throw new Error('Offline Linux root controller required');
34
34
  const [mode, ...args] = process.argv.slice(2);
35
35
  if (!['inspect', 'apply'].includes(mode ?? '') || args.length % 2)
36
- throw new Error('Usage: inspect --output FILE | apply --before FILE --records UUID,UUID --approval-ref REF --output FILE');
36
+ throw new Error('Usage: inspect --output FILE [--records UUID,UUID] | apply --before FILE --records UUID,UUID --approval-ref REF --output FILE');
37
37
  const options = {};
38
38
  for (let i = 0; i < args.length; i += 2) {
39
39
  const key = args[i];
@@ -41,7 +41,7 @@ async function main() {
41
41
  throw new Error('Invalid or duplicate option');
42
42
  options[key] = args[i + 1];
43
43
  }
44
- if (!options['--output'] || (mode === 'inspect' && Object.keys(options).length !== 1) ||
44
+ if (!options['--output'] || (mode === 'inspect' && Object.keys(options).some(key => !['--output', '--records'].includes(key))) ||
45
45
  (mode === 'apply' && Object.keys(options).length !== 4))
46
46
  throw new Error('Exact mode options required');
47
47
  const install = await lstat('/opt/magnus-agent');
@@ -54,7 +54,7 @@ async function main() {
54
54
  const { MutationBarrier } = await import('./mutation-barrier.js');
55
55
  const barrier = new MutationBarrier('/opt/magnus-agent/.magnus/mutation-barrier');
56
56
  if (mode === 'inspect') {
57
- const observation = await barrier.historicalObservation();
57
+ const observation = await barrier.historicalObservation(options['--records']?.split(','));
58
58
  await writePrivate(options['--output'], observation);
59
59
  console.log(JSON.stringify({ mode, records: observation.records.length, boot: observation.boot,
60
60
  output: options['--output'], originalOutcomes: 'unknown' }));
@@ -30,7 +30,7 @@ export declare class MutationBarrier {
30
30
  private recordDigest;
31
31
  private historicalSettlement;
32
32
  /** Before-maintenance owner evidence; read-only and signed with the result key. */
33
- historicalObservation(): Promise<{
33
+ historicalObservation(recordIds?: readonly string[]): Promise<{
34
34
  version: 1;
35
35
  drain: {
36
36
  nodeId: string;
@@ -171,7 +171,11 @@ export class MutationBarrier {
171
171
  return receipt;
172
172
  }
173
173
  /** Before-maintenance owner evidence; read-only and signed with the result key. */
174
- async historicalObservation() {
174
+ async historicalObservation(recordIds) {
175
+ const selected = recordIds === undefined ? undefined
176
+ : z.array(z.string().guid()).min(1).max(16).parse(recordIds);
177
+ if (selected && new Set(selected).size !== selected.length)
178
+ throw new Error('Exact distinct historical record IDs required');
175
179
  return this.lockedRead(async () => {
176
180
  const drain = await this.identity();
177
181
  if (!drain)
@@ -184,12 +188,16 @@ export class MutationBarrier {
184
188
  const row = recordSchema.parse(await this.read(name));
185
189
  if (name !== 'request-' + row.id + '.json')
186
190
  throw new Error('Mutation record identity differs');
191
+ if (selected && !selected.includes(row.id))
192
+ continue;
187
193
  if (row.state === 'completed' || await this.historicalSettlement(row, drain))
188
194
  continue;
189
195
  if (this.active.has(row.id))
190
196
  throw new Error('Active operation cannot be retired');
191
197
  records.push({ id: row.id, recordSha256: await this.recordDigest(row.id), acceptedAt: row.acceptedAt, routeSha256: row.routeSha256 });
192
198
  }
199
+ if (selected && records.length !== selected.length)
200
+ throw new Error('Selected historical records must all remain unsettled');
193
201
  return signHistoricalObservation({ version: 1, drain, boot: await this.bootReader(), observedAt: Date.now(), records }, this.historicalKeys.result);
194
202
  });
195
203
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hivemagnus/magnus-agent",
3
- "version": "1.1.12",
3
+ "version": "1.1.13",
4
4
  "description": "Magnus node agent: a small daemon that enrolls a Linux host with a magnus-server and runs authenticated health, command, cron, file and skill management, with optional Hermes Agent, Codex and Ardent management.",
5
5
  "keywords": [
6
6
  "magnus",
@@ -60,7 +60,7 @@
60
60
  "clean": "node -e \"const fs=require('node:fs');fs.rmSync('dist',{recursive:true,force:true});fs.rmSync('tsconfig.tsbuildinfo',{force:true})\""
61
61
  },
62
62
  "dependencies": {
63
- "@hivemagnus/magnus-contracts": "1.1.12",
63
+ "@hivemagnus/magnus-contracts": "1.1.13",
64
64
  "@hono/node-server": "^2.1.5",
65
65
  "dotenv": "^18.0.9",
66
66
  "hono": "^4.13.16",