maka-agent 0.2.0-dev.3.20260830 → 0.2.0-dev.4.20260830
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.
- package/dist/cli-core.js +1 -0
- package/dist/runtime-host-cli.js +37 -3
- package/dist/runtime-host-peer-mesh-management-command.js +17 -0
- package/dist/runtime-host-setup-command.js +33 -15
- package/dist/runtime-host-systemd-service.js +9 -3
- package/native/runtime-host-peer/prebuilds/darwin-arm64/maka_runtime_host_peer.node +0 -0
- package/native/runtime-host-peer/prebuilds/linux-arm64/maka_runtime_host_peer.node +0 -0
- package/native/runtime-host-peer/prebuilds/linux-x64/maka_runtime_host_peer.node +0 -0
- package/native/runtime-host-peer/prebuilds/win32-x64/maka_runtime_host_peer.node +0 -0
- package/node_modules/@maka/runtime/dist/sandbox/macos-seatbelt.js +68 -9
- package/node_modules/@maka/runtime-host/dist/client/peer-client.js +22 -3
- package/node_modules/@maka/runtime-host/dist/operator/peer-mesh-management-frame.js +14 -0
- package/node_modules/@maka/runtime-host/dist/peer-mesh/display-name.js +30 -0
- package/node_modules/@maka/runtime-host/dist/peer-mesh/model.js +32 -21
- package/node_modules/@maka/runtime-host/dist/peer-mesh/node.js +207 -47
- package/node_modules/@maka/runtime-host/dist/peer-mesh/owner.js +2 -0
- package/node_modules/@maka/runtime-host/dist/peer-mesh/store.js +18 -5
- package/node_modules/@maka/runtime-host/dist/protocol/index.js +5 -1
- package/node_modules/@maka/runtime-host/dist/protocol/peer-mesh.js +59 -2
- package/node_modules/@maka/runtime-host/dist/server/access-authority.js +11 -7
- package/node_modules/@maka/runtime-host/dist/server/connection-session.js +3 -0
- package/node_modules/@maka/runtime-host/dist/server/execution-service.js +1 -0
- package/node_modules/@maka/runtime-host/dist/server/host-kernel.js +1 -1
- package/node_modules/@maka/runtime-host/dist/server/peer-mesh-authority.js +19 -0
- package/package.json +1 -1
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
*/
|
|
19
19
|
import { assertExactKeys, requireCount, requireExactRecord, requireRecord, requireString, } from './codec.js';
|
|
20
20
|
import { defineOperation } from './operation-spec.js';
|
|
21
|
+
import { canonicalPeerMeshDisplayName } from '../peer-mesh/display-name.js';
|
|
21
22
|
import { PEER_MESH_MAX_MEMBERS, PEER_MESH_MAX_MESHES, PEER_MESH_MAX_ROUTE_HINTS, } from '../peer-mesh/limits.js';
|
|
22
23
|
const PEER_ID_MAX_BYTES = 256;
|
|
23
24
|
const MESH_ID_MAX_BYTES = 128;
|
|
@@ -93,6 +94,20 @@ export const PEER_MESH_OPERATION_SPECS = {
|
|
|
93
94
|
decodeInput: decodePeerMeshTransitSetInput,
|
|
94
95
|
decodeOutput: decodePeerMeshQueryResult,
|
|
95
96
|
}),
|
|
97
|
+
'peer.mesh.display-name.set': defineOperation({
|
|
98
|
+
mode: 'command',
|
|
99
|
+
availability: 'ready',
|
|
100
|
+
errors: MUTATION_ERRORS,
|
|
101
|
+
decodeInput: decodePeerMeshDisplayNameSetInput,
|
|
102
|
+
decodeOutput: decodePeerMeshQueryResult,
|
|
103
|
+
}),
|
|
104
|
+
'peer.mesh.rename': defineOperation({
|
|
105
|
+
mode: 'command',
|
|
106
|
+
availability: 'ready',
|
|
107
|
+
errors: MUTATION_ERRORS,
|
|
108
|
+
decodeInput: decodePeerMeshRenameInput,
|
|
109
|
+
decodeOutput: decodePeerMeshQueryResult,
|
|
110
|
+
}),
|
|
96
111
|
};
|
|
97
112
|
function decodeEmptyInput(value) {
|
|
98
113
|
requireExactRecord(value, 'Peer Mesh operation input', []);
|
|
@@ -104,6 +119,19 @@ function decodePeerMeshTargetInput(value) {
|
|
|
104
119
|
meshId: requireString(record.meshId, 'Peer Mesh meshId', MESH_ID_MAX_BYTES),
|
|
105
120
|
};
|
|
106
121
|
}
|
|
122
|
+
function decodePeerMeshDisplayNameSetInput(value) {
|
|
123
|
+
const record = requireExactRecord(value, 'Peer Mesh display name input', ['displayName']);
|
|
124
|
+
return {
|
|
125
|
+
displayName: record.displayName === null ? null : canonicalPeerMeshDisplayName(record.displayName),
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
function decodePeerMeshRenameInput(value) {
|
|
129
|
+
const record = requireExactRecord(value, 'Peer Mesh rename input', ['meshId', 'displayName']);
|
|
130
|
+
return {
|
|
131
|
+
meshId: requireString(record.meshId, 'Peer Mesh meshId', MESH_ID_MAX_BYTES),
|
|
132
|
+
displayName: record.displayName === null ? null : canonicalPeerMeshDisplayName(record.displayName),
|
|
133
|
+
};
|
|
134
|
+
}
|
|
107
135
|
function decodePeerMeshInviteInput(value) {
|
|
108
136
|
return decodePeerMeshTargetInput(value);
|
|
109
137
|
}
|
|
@@ -171,7 +199,13 @@ export function decodePeerMeshQueryResult(value) {
|
|
|
171
199
|
const record = requireRecord(value, 'Peer Mesh query result');
|
|
172
200
|
assertExactKeys(record, 'Peer Mesh query result', record.localPeerId === undefined
|
|
173
201
|
? ['available', 'meshes']
|
|
174
|
-
: [
|
|
202
|
+
: [
|
|
203
|
+
'available',
|
|
204
|
+
'localPeerId',
|
|
205
|
+
...(record.localDisplayName === undefined ? [] : ['localDisplayName']),
|
|
206
|
+
'meshes',
|
|
207
|
+
'transit',
|
|
208
|
+
]);
|
|
175
209
|
if (typeof record.available !== 'boolean' ||
|
|
176
210
|
!Array.isArray(record.meshes) ||
|
|
177
211
|
record.meshes.length > PEER_MESH_MAX_MESHES) {
|
|
@@ -187,14 +221,19 @@ export function decodePeerMeshQueryResult(value) {
|
|
|
187
221
|
? {}
|
|
188
222
|
: {
|
|
189
223
|
localPeerId: requireString(localPeerId, 'Peer Mesh localPeerId', PEER_ID_MAX_BYTES),
|
|
224
|
+
...(record.localDisplayName === undefined
|
|
225
|
+
? {}
|
|
226
|
+
: { localDisplayName: canonicalPeerMeshDisplayName(record.localDisplayName) }),
|
|
190
227
|
transit: decodePeerMeshTransitProjection(record.transit),
|
|
191
228
|
}),
|
|
192
229
|
meshes: Object.freeze(record.meshes.map(decodePeerMeshProjection)),
|
|
193
230
|
};
|
|
194
231
|
}
|
|
195
232
|
export function decodePeerMeshProjection(value) {
|
|
233
|
+
const valueRecord = requireRecord(value, 'Peer Mesh projection');
|
|
196
234
|
const record = requireExactRecord(value, 'Peer Mesh projection', [
|
|
197
235
|
'meshId',
|
|
236
|
+
...(valueRecord.displayName === undefined ? [] : ['displayName']),
|
|
198
237
|
'role',
|
|
199
238
|
'authorityPeerId',
|
|
200
239
|
'revision',
|
|
@@ -214,6 +253,9 @@ export function decodePeerMeshProjection(value) {
|
|
|
214
253
|
}
|
|
215
254
|
return {
|
|
216
255
|
meshId: requireString(record.meshId, 'Peer Mesh meshId', MESH_ID_MAX_BYTES),
|
|
256
|
+
...(record.displayName === undefined
|
|
257
|
+
? {}
|
|
258
|
+
: { displayName: canonicalPeerMeshDisplayName(record.displayName) }),
|
|
217
259
|
role: record.role,
|
|
218
260
|
authorityPeerId: requireString(record.authorityPeerId, 'Peer Mesh authorityPeerId', PEER_ID_MAX_BYTES),
|
|
219
261
|
revision: requireCount(record.revision, 'Peer Mesh revision'),
|
|
@@ -250,7 +292,13 @@ function decodePeerMeshTransitProjection(value) {
|
|
|
250
292
|
}
|
|
251
293
|
function decodePeerMeshMemberProjection(value) {
|
|
252
294
|
const record = requireRecord(value, 'Peer Mesh member route');
|
|
253
|
-
assertExactKeys(record, 'Peer Mesh member route',
|
|
295
|
+
assertExactKeys(record, 'Peer Mesh member route', [
|
|
296
|
+
'peerId',
|
|
297
|
+
'state',
|
|
298
|
+
...(record.endpointKind === undefined ? [] : ['endpointKind']),
|
|
299
|
+
...(record.displayName === undefined ? [] : ['displayName']),
|
|
300
|
+
...(record.expiresAt === undefined ? [] : ['expiresAt']),
|
|
301
|
+
]);
|
|
254
302
|
if (record.state !== 'local' &&
|
|
255
303
|
record.state !== 'route_available' &&
|
|
256
304
|
record.state !== 'coordination_only' &&
|
|
@@ -258,8 +306,17 @@ function decodePeerMeshMemberProjection(value) {
|
|
|
258
306
|
record.state !== 'unknown') {
|
|
259
307
|
throw new Error('Invalid Peer Mesh member route state');
|
|
260
308
|
}
|
|
309
|
+
if (record.endpointKind !== undefined &&
|
|
310
|
+
record.endpointKind !== 'client' &&
|
|
311
|
+
record.endpointKind !== 'host') {
|
|
312
|
+
throw new Error('Invalid Peer Mesh member endpoint kind');
|
|
313
|
+
}
|
|
261
314
|
return {
|
|
262
315
|
peerId: requireString(record.peerId, 'Peer Mesh member route peerId', PEER_ID_MAX_BYTES),
|
|
316
|
+
...(record.endpointKind === undefined ? {} : { endpointKind: record.endpointKind }),
|
|
317
|
+
...(record.displayName === undefined
|
|
318
|
+
? {}
|
|
319
|
+
: { displayName: canonicalPeerMeshDisplayName(record.displayName) }),
|
|
263
320
|
state: record.state,
|
|
264
321
|
...(record.expiresAt === undefined
|
|
265
322
|
? {}
|
|
@@ -78,7 +78,9 @@ class FileRuntimeHostAccessAuthority {
|
|
|
78
78
|
credentialId: match.credentialId,
|
|
79
79
|
operationGrants: match.bindClientInstanceOnFinalize
|
|
80
80
|
? ['host.status', 'access.credential.finalize']
|
|
81
|
-
: match.
|
|
81
|
+
: match.clientInstanceId
|
|
82
|
+
? [...match.operationGrants, 'access.credential.finalize']
|
|
83
|
+
: match.operationGrants,
|
|
82
84
|
canPublishClientCapabilities: !match.bindClientInstanceOnFinalize && match.canPublishClientCapabilities,
|
|
83
85
|
canUseHostPaths: !match.bindClientInstanceOnFinalize && match.canUseHostPaths,
|
|
84
86
|
...(match.clientInstanceId ? { clientInstanceId: match.clientInstanceId } : {}),
|
|
@@ -476,21 +478,23 @@ class FileRuntimeHostAccessAuthority {
|
|
|
476
478
|
await this.#commit(createNextAccessCredentialFile(this.#file, credentials, this.#file.sessionGrants), [current, ...pendingForPrincipal].map((credential) => credential.credentialId));
|
|
477
479
|
return { credentialId, revoked: true };
|
|
478
480
|
}
|
|
479
|
-
finalize(credentialId, clientInstanceId) {
|
|
481
|
+
finalize(credentialId, clientInstanceId, connectionAlreadyFinalized) {
|
|
480
482
|
return this.#mutate(async () => {
|
|
481
483
|
const retained = this.#file.credentials.find((credential) => credential.credentialId === credentialId);
|
|
482
484
|
if (!retained || retained.status === 'revoked') {
|
|
483
485
|
throw new RuntimeHostAccessInputError('The current access credential is no longer active');
|
|
484
486
|
}
|
|
485
|
-
return this.#finalize(retained, clientInstanceId);
|
|
487
|
+
return this.#finalize(retained, clientInstanceId, connectionAlreadyFinalized);
|
|
486
488
|
});
|
|
487
489
|
}
|
|
488
|
-
async #finalize(retained, clientInstanceId) {
|
|
490
|
+
async #finalize(retained, clientInstanceId, connectionAlreadyFinalized) {
|
|
489
491
|
if (retained.status === 'active') {
|
|
490
492
|
if (retained.clientInstanceId && retained.clientInstanceId !== clientInstanceId) {
|
|
491
493
|
throw new RuntimeHostAccessInputError('The pairing candidate was claimed by another Client');
|
|
492
494
|
}
|
|
493
|
-
return {
|
|
495
|
+
return {
|
|
496
|
+
reconnectRequired: retained.clientInstanceId !== undefined && !connectionAlreadyFinalized,
|
|
497
|
+
};
|
|
494
498
|
}
|
|
495
499
|
if (Date.parse(retained.expiresAt) <= Date.now()) {
|
|
496
500
|
await this.#expirePending();
|
|
@@ -776,7 +780,7 @@ export async function revokeAccessCredentialRotation(authority, input) {
|
|
|
776
780
|
return accessPersistenceFailure(error, 'Access credential rotation revocation outcome is unknown', 'Access credential could not be revoked');
|
|
777
781
|
}
|
|
778
782
|
}
|
|
779
|
-
export async function finalizeAccessCredential(authority, credentialId, clientInstanceId) {
|
|
783
|
+
export async function finalizeAccessCredential(authority, credentialId, clientInstanceId, credentialClientInstanceId) {
|
|
780
784
|
if (!authority)
|
|
781
785
|
return unavailable('finalize');
|
|
782
786
|
if (!credentialId) {
|
|
@@ -800,7 +804,7 @@ export async function finalizeAccessCredential(authority, credentialId, clientIn
|
|
|
800
804
|
try {
|
|
801
805
|
return {
|
|
802
806
|
ok: true,
|
|
803
|
-
result: await authority.finalize(credentialId, clientInstanceId),
|
|
807
|
+
result: await authority.finalize(credentialId, clientInstanceId, credentialClientInstanceId === clientInstanceId),
|
|
804
808
|
};
|
|
805
809
|
}
|
|
806
810
|
catch (error) {
|
|
@@ -164,6 +164,9 @@ export class RuntimeHostConnectionSession {
|
|
|
164
164
|
...(this.#options.connection.authority.credentialId
|
|
165
165
|
? { credentialId: this.#options.connection.authority.credentialId }
|
|
166
166
|
: {}),
|
|
167
|
+
...(this.#options.connection.authority.clientInstanceId
|
|
168
|
+
? { credentialClientInstanceId: this.#options.connection.authority.clientInstanceId }
|
|
169
|
+
: {}),
|
|
167
170
|
acquireResidency: () => admission.acquireResidency(),
|
|
168
171
|
});
|
|
169
172
|
admission.seal();
|
|
@@ -524,7 +524,7 @@ export class RuntimeHostKernel {
|
|
|
524
524
|
'access.principal.revoke': async (input) => this.#settleAccessCredentialMutation(revokeAccessPrincipal(this.#options.accessAuthority, input)),
|
|
525
525
|
'access.credential.rotation.prepare': async (input) => this.#settleAccessCredentialMutation(prepareAccessCredentialRotation(this.#options.accessAuthority, input)),
|
|
526
526
|
'access.credential.rotation.revoke': async (input) => this.#settleAccessCredentialMutation(revokeAccessCredentialRotation(this.#options.accessAuthority, input)),
|
|
527
|
-
'access.credential.finalize': async (_input, context) => this.#settleAccessCredentialMutation(finalizeAccessCredential(this.#options.accessAuthority, context.credentialId, context.clientInstanceId)),
|
|
527
|
+
'access.credential.finalize': async (_input, context) => this.#settleAccessCredentialMutation(finalizeAccessCredential(this.#options.accessAuthority, context.credentialId, context.clientInstanceId, context.credentialClientInstanceId)),
|
|
528
528
|
'collaboration.invitation.prepare': async (input) => this.#settleAccessCredentialMutation(prepareCollaborationInvitation(this.#options.accessAuthority, this.rootId, input)),
|
|
529
529
|
'collaboration.access.query': async (input) => this.#options.accessAuthority
|
|
530
530
|
? {
|
|
@@ -128,11 +128,28 @@ export function createPeerMeshOperationHandlers(mesh, options = {}) {
|
|
|
128
128
|
return { ok: true, result: query() };
|
|
129
129
|
});
|
|
130
130
|
},
|
|
131
|
+
'peer.mesh.display-name.set': async (input) => {
|
|
132
|
+
if (!mesh)
|
|
133
|
+
return unavailable();
|
|
134
|
+
return mutate(async () => {
|
|
135
|
+
await mesh.setDisplayName(input.displayName);
|
|
136
|
+
return { ok: true, result: query() };
|
|
137
|
+
});
|
|
138
|
+
},
|
|
139
|
+
'peer.mesh.rename': async (input) => {
|
|
140
|
+
if (!mesh)
|
|
141
|
+
return unavailable();
|
|
142
|
+
return mutate(async () => {
|
|
143
|
+
await mesh.setMeshDisplayName(input.meshId, input.displayName);
|
|
144
|
+
return { ok: true, result: query() };
|
|
145
|
+
});
|
|
146
|
+
},
|
|
131
147
|
};
|
|
132
148
|
}
|
|
133
149
|
export function projectPeerMeshStatus(status) {
|
|
134
150
|
return Object.freeze({
|
|
135
151
|
meshId: status.roster.roster.meshId,
|
|
152
|
+
...(status.roster.roster.displayName ? { displayName: status.roster.roster.displayName } : {}),
|
|
136
153
|
role: status.role,
|
|
137
154
|
authorityPeerId: status.authority.peerId,
|
|
138
155
|
revision: status.roster.roster.revision,
|
|
@@ -144,9 +161,11 @@ export function projectPeerMeshStatus(status) {
|
|
|
144
161
|
export function projectPeerMeshQuery(mesh) {
|
|
145
162
|
if (!mesh)
|
|
146
163
|
return { available: false, meshes: [] };
|
|
164
|
+
const displayName = mesh.displayName();
|
|
147
165
|
return Object.freeze({
|
|
148
166
|
available: true,
|
|
149
167
|
localPeerId: mesh.localPeerId(),
|
|
168
|
+
...(displayName ? { localDisplayName: displayName } : {}),
|
|
150
169
|
meshes: Object.freeze(mesh.status().map(projectPeerMeshStatus)),
|
|
151
170
|
transit: projectTransitSnapshot(mesh.transitMeshId(), mesh.transitSnapshot()),
|
|
152
171
|
});
|