@aria_asi/cli 0.2.32 → 0.2.33
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/aria-connector/src/connectors/codebase-awareness.d.ts +8 -1
- package/dist/aria-connector/src/connectors/codebase-awareness.d.ts.map +1 -1
- package/dist/aria-connector/src/connectors/codebase-awareness.js +126 -71
- package/dist/aria-connector/src/connectors/codebase-awareness.js.map +1 -1
- package/dist/aria-connector/src/connectors/codex.d.ts.map +1 -1
- package/dist/aria-connector/src/connectors/codex.js +51 -0
- package/dist/aria-connector/src/connectors/codex.js.map +1 -1
- package/dist/aria-connector/src/setup-wizard.d.ts.map +1 -1
- package/dist/aria-connector/src/setup-wizard.js +91 -24
- package/dist/aria-connector/src/setup-wizard.js.map +1 -1
- package/dist/assets/hooks/aria-harness-via-sdk.mjs +10 -5
- package/dist/assets/hooks/aria-pre-tool-gate.mjs +19 -0
- package/dist/assets/hooks/aria-stop-gate.mjs +27 -2
- package/dist/assets/hooks/lib/domain-output-quality.mjs +103 -0
- package/dist/assets/hooks/lib/skill-autoload-gate.mjs +1 -0
- package/dist/assets/opencode-plugins/harness-gate/index.js +67 -3
- package/dist/assets/opencode-plugins/harness-gate/lib/skill-autoload-gate.js +1 -0
- package/dist/assets/opencode-plugins/harness-outcome/index.js +39 -0
- package/dist/assets/opencode-plugins/harness-stop/index.js +61 -1
- package/dist/assets/opencode-plugins/harness-stop/lib/domain-output-quality.js +103 -0
- package/dist/assets/opencode-plugins/harness-stop/lib/skill-autoload-gate.js +1 -0
- package/dist/runtime/codex-bridge.mjs +71 -8
- package/dist/runtime/harness-daemon.mjs +50 -2
- package/dist/runtime/manifest.json +1 -1
- package/dist/runtime/sdk/BUNDLED.json +1 -1
- package/dist/runtime/sdk/index.d.ts +9 -0
- package/dist/runtime/sdk/index.js +23 -1
- package/dist/runtime/sdk/index.js.map +1 -1
- package/dist/runtime/service.mjs +339 -10
- package/dist/sdk/BUNDLED.json +1 -1
- package/dist/sdk/index.d.ts +9 -0
- package/dist/sdk/index.js +23 -1
- package/dist/sdk/index.js.map +1 -1
- package/hooks/aria-harness-via-sdk.mjs +10 -5
- package/hooks/aria-pre-tool-gate.mjs +19 -0
- package/hooks/aria-stop-gate.mjs +27 -2
- package/hooks/lib/domain-output-quality.mjs +103 -0
- package/hooks/lib/skill-autoload-gate.mjs +1 -0
- package/opencode-plugins/harness-gate/index.js +67 -3
- package/opencode-plugins/harness-gate/lib/skill-autoload-gate.js +1 -0
- package/opencode-plugins/harness-outcome/index.js +39 -0
- package/opencode-plugins/harness-stop/index.js +61 -1
- package/opencode-plugins/harness-stop/lib/domain-output-quality.js +103 -0
- package/opencode-plugins/harness-stop/lib/skill-autoload-gate.js +1 -0
- package/package.json +1 -1
- package/runtime-src/codex-bridge.mjs +71 -8
- package/runtime-src/harness-daemon.mjs +50 -2
- package/runtime-src/service.mjs +339 -10
- package/src/connectors/codebase-awareness.ts +141 -77
- package/src/connectors/codex.ts +51 -0
- package/src/setup-wizard.ts +105 -25
package/runtime-src/service.mjs
CHANGED
|
@@ -68,6 +68,7 @@ const OFFLINE_BUNDLE_PATH = join(STATE_DIR, 'offline-policy-bundle.enc');
|
|
|
68
68
|
const RUNTIME_META_PATH = join(STATE_DIR, 'runtime-meta.json');
|
|
69
69
|
const AUTONOMY_STATE_PATH = join(STATE_DIR, 'autonomy.json');
|
|
70
70
|
const COGNITION_STATE_PATH = join(STATE_DIR, 'cognition-state.enc');
|
|
71
|
+
const HIVE_FILE_LEASES_PATH = join(STATE_DIR, 'hive-file-leases.json');
|
|
71
72
|
const REVOCATION_LOCK_PATH = join(STATE_DIR, 'revoked.json');
|
|
72
73
|
const CONFIG_PATH = join(process.env.HOME || '', '.aria', 'config.json');
|
|
73
74
|
const CODEBASE_AWARENESS_STATE_PATH = join(process.env.HOME || '', '.aria', 'codebase-awareness-state.json');
|
|
@@ -906,6 +907,248 @@ function writeJsonFile(filePath, payload, mode = 0o600) {
|
|
|
906
907
|
writeFileSync(filePath, JSON.stringify(payload, null, 2) + '\n', { mode });
|
|
907
908
|
}
|
|
908
909
|
|
|
910
|
+
function readHiveFileLeaseState() {
|
|
911
|
+
const state = readJsonFile(HIVE_FILE_LEASES_PATH, { leases: [] });
|
|
912
|
+
return {
|
|
913
|
+
leases: Array.isArray(state.leases) ? state.leases : [],
|
|
914
|
+
};
|
|
915
|
+
}
|
|
916
|
+
|
|
917
|
+
function writeHiveFileLeaseState(state) {
|
|
918
|
+
writeJsonFile(HIVE_FILE_LEASES_PATH, {
|
|
919
|
+
updatedAt: new Date().toISOString(),
|
|
920
|
+
leases: Array.isArray(state.leases) ? state.leases : [],
|
|
921
|
+
});
|
|
922
|
+
}
|
|
923
|
+
|
|
924
|
+
function normalizeLeasePath(value) {
|
|
925
|
+
const raw = String(value || '').trim();
|
|
926
|
+
if (!raw) return '';
|
|
927
|
+
return raw.replace(/\\/g, '/').replace(/\/+/g, '/');
|
|
928
|
+
}
|
|
929
|
+
|
|
930
|
+
function pathsOverlap(left, right) {
|
|
931
|
+
const a = normalizeLeasePath(left);
|
|
932
|
+
const b = normalizeLeasePath(right);
|
|
933
|
+
if (!a || !b) return false;
|
|
934
|
+
return a === b || a.startsWith(`${b}/`) || b.startsWith(`${a}/`);
|
|
935
|
+
}
|
|
936
|
+
|
|
937
|
+
function coerceTargetFiles(body) {
|
|
938
|
+
const files = [];
|
|
939
|
+
const push = (value) => {
|
|
940
|
+
const normalized = normalizeLeasePath(value);
|
|
941
|
+
if (normalized && !files.includes(normalized)) files.push(normalized);
|
|
942
|
+
};
|
|
943
|
+
|
|
944
|
+
if (Array.isArray(body.files)) body.files.forEach(push);
|
|
945
|
+
if (Array.isArray(body.targetFiles)) body.targetFiles.forEach(push);
|
|
946
|
+
if (typeof body.filePath === 'string') push(body.filePath);
|
|
947
|
+
if (typeof body.target === 'string') {
|
|
948
|
+
try {
|
|
949
|
+
const parsed = JSON.parse(body.target);
|
|
950
|
+
if (typeof parsed?.filePath === 'string') push(parsed.filePath);
|
|
951
|
+
if (Array.isArray(parsed?.files)) parsed.files.forEach(push);
|
|
952
|
+
if (Array.isArray(parsed?.targetFiles)) parsed.targetFiles.forEach(push);
|
|
953
|
+
} catch {}
|
|
954
|
+
}
|
|
955
|
+
return files;
|
|
956
|
+
}
|
|
957
|
+
|
|
958
|
+
function extractVerifyText(body) {
|
|
959
|
+
const candidates = [body.verifyText, body.verifyBlock, body.text, body.target];
|
|
960
|
+
for (const candidate of candidates) {
|
|
961
|
+
if (typeof candidate === 'string' && candidate.trim()) return candidate;
|
|
962
|
+
}
|
|
963
|
+
return '';
|
|
964
|
+
}
|
|
965
|
+
|
|
966
|
+
function actionRequiresExplicitVerify(action, body) {
|
|
967
|
+
if (body.requireVerify === true) return true;
|
|
968
|
+
return /^(?:delete|deploy|db_mutation|infra_mutation)$/i.test(String(action || ''));
|
|
969
|
+
}
|
|
970
|
+
|
|
971
|
+
function buildObservedVerify(action, files, sessionId, roleProfile) {
|
|
972
|
+
const observations = files.slice(0, 12).map((filePath) => {
|
|
973
|
+
try {
|
|
974
|
+
const stats = statSync(filePath);
|
|
975
|
+
return {
|
|
976
|
+
path: filePath,
|
|
977
|
+
exists: true,
|
|
978
|
+
isFile: stats.isFile(),
|
|
979
|
+
isDirectory: stats.isDirectory(),
|
|
980
|
+
size: stats.size,
|
|
981
|
+
mtimeMs: stats.mtimeMs,
|
|
982
|
+
};
|
|
983
|
+
} catch {
|
|
984
|
+
return { path: filePath, exists: false };
|
|
985
|
+
}
|
|
986
|
+
});
|
|
987
|
+
return {
|
|
988
|
+
target: files,
|
|
989
|
+
role: roleProfile || 'unknown',
|
|
990
|
+
verified: [
|
|
991
|
+
'runtime observed target file metadata before action',
|
|
992
|
+
'Hive file lease check completed before mutation',
|
|
993
|
+
],
|
|
994
|
+
observations,
|
|
995
|
+
rollback: 'Use VCS diff or prior file snapshot for rollback; no destructive rollback was inferred by runtime.',
|
|
996
|
+
axiom: 'truth_over_deception/no_harm/sacred_trust/reflection_before_action',
|
|
997
|
+
sessionId,
|
|
998
|
+
action,
|
|
999
|
+
};
|
|
1000
|
+
}
|
|
1001
|
+
|
|
1002
|
+
function acquireHiveFileLease({ sessionId, actor, roleProfile, action, files, ttlMs = 120000 }) {
|
|
1003
|
+
const now = Date.now();
|
|
1004
|
+
const expiresAt = new Date(now + ttlMs).toISOString();
|
|
1005
|
+
const normalizedFiles = files.map(normalizeLeasePath).filter(Boolean);
|
|
1006
|
+
const state = readHiveFileLeaseState();
|
|
1007
|
+
const activeLeases = state.leases.filter((lease) => Date.parse(lease.expiresAt || '') > now);
|
|
1008
|
+
const conflicts = activeLeases.filter((lease) => {
|
|
1009
|
+
if (lease.sessionId === sessionId) return false;
|
|
1010
|
+
const leaseFiles = Array.isArray(lease.files) ? lease.files : [];
|
|
1011
|
+
return normalizedFiles.some((file) => leaseFiles.some((leaseFile) => pathsOverlap(file, leaseFile)));
|
|
1012
|
+
});
|
|
1013
|
+
|
|
1014
|
+
if (conflicts.length > 0) {
|
|
1015
|
+
writeHiveFileLeaseState({ leases: activeLeases });
|
|
1016
|
+
return {
|
|
1017
|
+
status: 'blocked',
|
|
1018
|
+
leaseId: null,
|
|
1019
|
+
expiresAt: null,
|
|
1020
|
+
conflicts: conflicts.map((lease) => ({
|
|
1021
|
+
leaseId: lease.leaseId,
|
|
1022
|
+
sessionId: lease.sessionId,
|
|
1023
|
+
actor: lease.actor,
|
|
1024
|
+
roleProfile: lease.roleProfile,
|
|
1025
|
+
action: lease.action,
|
|
1026
|
+
files: lease.files,
|
|
1027
|
+
expiresAt: lease.expiresAt,
|
|
1028
|
+
})),
|
|
1029
|
+
};
|
|
1030
|
+
}
|
|
1031
|
+
|
|
1032
|
+
const existing = activeLeases.filter((lease) => lease.sessionId !== sessionId);
|
|
1033
|
+
const lease = {
|
|
1034
|
+
leaseId: `hive_lease_${randomUUID()}`,
|
|
1035
|
+
sessionId,
|
|
1036
|
+
actor: actor || 'unknown',
|
|
1037
|
+
roleProfile: roleProfile || 'unknown',
|
|
1038
|
+
action,
|
|
1039
|
+
files: normalizedFiles,
|
|
1040
|
+
grantedAt: new Date(now).toISOString(),
|
|
1041
|
+
expiresAt,
|
|
1042
|
+
};
|
|
1043
|
+
writeHiveFileLeaseState({ leases: [...existing, lease] });
|
|
1044
|
+
return { status: 'granted', leaseId: lease.leaseId, expiresAt, conflicts: [] };
|
|
1045
|
+
}
|
|
1046
|
+
|
|
1047
|
+
function releaseHiveFileLease(sessionId, files = []) {
|
|
1048
|
+
const normalizedFiles = files.map(normalizeLeasePath).filter(Boolean);
|
|
1049
|
+
const state = readHiveFileLeaseState();
|
|
1050
|
+
const now = Date.now();
|
|
1051
|
+
const leases = state.leases.filter((lease) => {
|
|
1052
|
+
if (Date.parse(lease.expiresAt || '') <= now) return false;
|
|
1053
|
+
if (lease.sessionId !== sessionId) return true;
|
|
1054
|
+
if (normalizedFiles.length === 0) return false;
|
|
1055
|
+
const leaseFiles = Array.isArray(lease.files) ? lease.files : [];
|
|
1056
|
+
return !normalizedFiles.some((file) => leaseFiles.some((leaseFile) => pathsOverlap(file, leaseFile)));
|
|
1057
|
+
});
|
|
1058
|
+
writeHiveFileLeaseState({ leases });
|
|
1059
|
+
return { released: state.leases.length - leases.length, active: leases.length };
|
|
1060
|
+
}
|
|
1061
|
+
|
|
1062
|
+
function validateVerifyAndHive({ req, body, action }) {
|
|
1063
|
+
const sessionId = deriveSessionId(req, body, 'runtime-action');
|
|
1064
|
+
const files = coerceTargetFiles(body);
|
|
1065
|
+
const roleProfile = body.roleProfile || body.role_profile || body?.metadata?.roleProfile || body?.metadata?.role_profile || null;
|
|
1066
|
+
const actor = body.actor || body?.metadata?.actor || req.headers['x-aria-actor'] || 'runtime-client';
|
|
1067
|
+
const explicitVerifyRequired = actionRequiresExplicitVerify(action, body);
|
|
1068
|
+
const verifyText = extractVerifyText(body);
|
|
1069
|
+
const hasVerifyBlock = VERIFY_BLOCK_RX.test(verifyText);
|
|
1070
|
+
const canUseObservedVerify = !explicitVerifyRequired && files.length > 0 && /^(?:write|edit|bash)$/i.test(String(action || ''));
|
|
1071
|
+
|
|
1072
|
+
if (explicitVerifyRequired && !hasVerifyBlock) {
|
|
1073
|
+
return {
|
|
1074
|
+
allowed: false,
|
|
1075
|
+
reason: 'verify block required before this high-risk action. Include <verify> with target, role, verified, rollback, and axiom.',
|
|
1076
|
+
requiredGates: ['verify-block'],
|
|
1077
|
+
verify: { status: 'missing', required: true },
|
|
1078
|
+
hive: { status: 'not_checked', conflicts: [] },
|
|
1079
|
+
};
|
|
1080
|
+
}
|
|
1081
|
+
|
|
1082
|
+
if (!hasVerifyBlock && !canUseObservedVerify && explicitVerifyRequired) {
|
|
1083
|
+
return {
|
|
1084
|
+
allowed: false,
|
|
1085
|
+
reason: 'verify block required before mutation, or target files must be provided so runtime can perform observed verification.',
|
|
1086
|
+
requiredGates: ['verify-block-or-observed-target-files'],
|
|
1087
|
+
verify: { status: 'missing', required: true },
|
|
1088
|
+
hive: { status: 'not_checked', conflicts: [] },
|
|
1089
|
+
};
|
|
1090
|
+
}
|
|
1091
|
+
|
|
1092
|
+
if (!hasVerifyBlock && !canUseObservedVerify && files.length === 0) {
|
|
1093
|
+
return {
|
|
1094
|
+
allowed: true,
|
|
1095
|
+
reason: 'no target files supplied for Hive lease; remote action gate will still evaluate the action',
|
|
1096
|
+
requiredGates: [],
|
|
1097
|
+
verify: { status: 'skipped', required: false },
|
|
1098
|
+
hive: { status: 'skipped', leaseId: null, expiresAt: null, conflicts: [] },
|
|
1099
|
+
};
|
|
1100
|
+
}
|
|
1101
|
+
|
|
1102
|
+
const hive = files.length > 0
|
|
1103
|
+
? acquireHiveFileLease({ sessionId, actor, roleProfile, action, files })
|
|
1104
|
+
: { status: 'skipped', leaseId: null, expiresAt: null, conflicts: [] };
|
|
1105
|
+
if (hive.status === 'blocked') {
|
|
1106
|
+
const verify = hasVerifyBlock
|
|
1107
|
+
? { status: 'provided', required: explicitVerifyRequired }
|
|
1108
|
+
: { status: 'observed', required: false, block: buildObservedVerify(action, files, sessionId, roleProfile) };
|
|
1109
|
+
const queued = enqueueAutonomyJob({
|
|
1110
|
+
kind: 'tool_lane:queued_action',
|
|
1111
|
+
surface: 'tool_lane',
|
|
1112
|
+
sessionId,
|
|
1113
|
+
priority: 15,
|
|
1114
|
+
message: 'Tool lane contention queued this action instead of failing it.',
|
|
1115
|
+
payload: { action, files, verify },
|
|
1116
|
+
metadata: {
|
|
1117
|
+
actor,
|
|
1118
|
+
roleProfile,
|
|
1119
|
+
conflicts: hive.conflicts,
|
|
1120
|
+
recovery: {
|
|
1121
|
+
mode: 'queued_not_failed',
|
|
1122
|
+
reason: 'overlapping_hive_file_lease',
|
|
1123
|
+
next: 'Retry when the overlapping Hive lease expires or a tool-lane worker claims this queued action.',
|
|
1124
|
+
},
|
|
1125
|
+
},
|
|
1126
|
+
});
|
|
1127
|
+
return {
|
|
1128
|
+
allowed: false,
|
|
1129
|
+
queued: true,
|
|
1130
|
+
queue: {
|
|
1131
|
+
jobId: queued.job.jobId,
|
|
1132
|
+
kind: queued.job.kind,
|
|
1133
|
+
status: queued.job.status,
|
|
1134
|
+
queueDepth: queued.stats.queued,
|
|
1135
|
+
},
|
|
1136
|
+
reason: `Tool lane queued this action because another active session is editing overlapping file(s): ${hive.conflicts.map((c) => `${c.sessionId}:${(c.files || []).join(',')}`).join(' | ')}`,
|
|
1137
|
+
requiredGates: ['hive-file-lease'],
|
|
1138
|
+
verify,
|
|
1139
|
+
hive,
|
|
1140
|
+
};
|
|
1141
|
+
}
|
|
1142
|
+
|
|
1143
|
+
return {
|
|
1144
|
+
allowed: true,
|
|
1145
|
+
reason: 'verify and Hive pre-action checks passed',
|
|
1146
|
+
requiredGates: [],
|
|
1147
|
+
verify: hasVerifyBlock ? { status: 'provided', required: explicitVerifyRequired } : { status: 'observed', required: false, block: buildObservedVerify(action, files, sessionId, roleProfile) },
|
|
1148
|
+
hive,
|
|
1149
|
+
};
|
|
1150
|
+
}
|
|
1151
|
+
|
|
909
1152
|
function ensureRuntimeMeta() {
|
|
910
1153
|
const existing = readJsonFile(RUNTIME_META_PATH, null);
|
|
911
1154
|
if (existing?.runtimeId) return existing;
|
|
@@ -972,6 +1215,33 @@ function queueStats(state) {
|
|
|
972
1215
|
};
|
|
973
1216
|
}
|
|
974
1217
|
|
|
1218
|
+
function enqueueAutonomyJob(jobDef) {
|
|
1219
|
+
const state = sweepAutonomyState(loadAutonomyState());
|
|
1220
|
+
const now = new Date().toISOString();
|
|
1221
|
+
const job = {
|
|
1222
|
+
jobId: randomUUID(),
|
|
1223
|
+
kind: jobDef.kind,
|
|
1224
|
+
surface: jobDef.surface || 'tool_lane',
|
|
1225
|
+
sessionId: jobDef.sessionId || null,
|
|
1226
|
+
payload: jobDef.payload || {},
|
|
1227
|
+
metadata: jobDef.metadata || {},
|
|
1228
|
+
priority: Number.isFinite(Number(jobDef.priority)) ? Number(jobDef.priority) : 25,
|
|
1229
|
+
status: 'queued',
|
|
1230
|
+
attempts: 0,
|
|
1231
|
+
maxAttempts: Number.isFinite(Number(jobDef.maxAttempts)) ? Number(jobDef.maxAttempts) : 3,
|
|
1232
|
+
createdAt: now,
|
|
1233
|
+
updatedAt: now,
|
|
1234
|
+
workerId: null,
|
|
1235
|
+
claimedAt: null,
|
|
1236
|
+
claimExpiresAt: null,
|
|
1237
|
+
progress: [{ at: now, status: 'queued', message: jobDef.message || 'Queued for tool lane execution.' }],
|
|
1238
|
+
garden: null,
|
|
1239
|
+
};
|
|
1240
|
+
state.jobs.push(job);
|
|
1241
|
+
saveAutonomyState(state);
|
|
1242
|
+
return { job, stats: queueStats(state) };
|
|
1243
|
+
}
|
|
1244
|
+
|
|
975
1245
|
function asJsonPayload(value) {
|
|
976
1246
|
if (value == null) return null;
|
|
977
1247
|
if (typeof value === 'string') {
|
|
@@ -1459,7 +1729,7 @@ function buildOwnerBypassPacket(message, reason = 'owner-local-bypass') {
|
|
|
1459
1729
|
}
|
|
1460
1730
|
|
|
1461
1731
|
async function loadRuntimePacket(req, body, client, packetRequest, message) {
|
|
1462
|
-
if (body.packet) return body.packet;
|
|
1732
|
+
if (body.packet) return enrichPacketWithCodebaseSnapshot(body.packet);
|
|
1463
1733
|
const apiKey = resolveApiKey(req, body);
|
|
1464
1734
|
ensureOfflineBundleSeeded(apiKey, leaseCache.get(hashKey(apiKey)) || loadEncryptedLease(apiKey));
|
|
1465
1735
|
try {
|
|
@@ -1474,7 +1744,7 @@ async function loadRuntimePacket(req, body, client, packetRequest, message) {
|
|
|
1474
1744
|
doctrineBundleHash: lease?.claims?.doctrine_bundle_hash || null,
|
|
1475
1745
|
lastUpstreamError: null,
|
|
1476
1746
|
});
|
|
1477
|
-
return packet;
|
|
1747
|
+
return enrichPacketWithCodebaseSnapshot(packet);
|
|
1478
1748
|
} catch (error) {
|
|
1479
1749
|
const bundle = ensureOfflineBundleSeeded(apiKey, leaseCache.get(hashKey(apiKey)) || loadEncryptedLease(apiKey)) || loadEncryptedOfflineBundle(apiKey);
|
|
1480
1750
|
const bundleStatus = computeOfflineBundleStatus(bundle);
|
|
@@ -1486,19 +1756,52 @@ async function loadRuntimePacket(req, body, client, packetRequest, message) {
|
|
|
1486
1756
|
lastUpstreamError: error instanceof Error ? error.message : String(error),
|
|
1487
1757
|
lastUpstreamOkAt: bundle.lastUpstreamOkAt || bundle.cachedAt || new Date().toISOString(),
|
|
1488
1758
|
});
|
|
1489
|
-
return fallbackPacket;
|
|
1759
|
+
return enrichPacketWithCodebaseSnapshot(fallbackPacket);
|
|
1490
1760
|
}
|
|
1491
1761
|
}
|
|
1492
1762
|
if (!isOwnerBypassRequest(req, body)) {
|
|
1493
1763
|
throw error;
|
|
1494
1764
|
}
|
|
1495
|
-
return buildOwnerBypassPacket(
|
|
1765
|
+
return enrichPacketWithCodebaseSnapshot(buildOwnerBypassPacket(
|
|
1496
1766
|
message || packetRequest?.message || '',
|
|
1497
1767
|
error instanceof Error ? error.message : 'owner-local-bypass',
|
|
1498
|
-
);
|
|
1768
|
+
));
|
|
1499
1769
|
}
|
|
1500
1770
|
}
|
|
1501
1771
|
|
|
1772
|
+
function enrichPacketWithCodebaseSnapshot(packet) {
|
|
1773
|
+
if (!packet || typeof packet !== 'object') return packet;
|
|
1774
|
+
const codebase = compactCodebaseSnapshot();
|
|
1775
|
+
return {
|
|
1776
|
+
...packet,
|
|
1777
|
+
runtime: {
|
|
1778
|
+
...(packet.runtime && typeof packet.runtime === 'object' ? packet.runtime : {}),
|
|
1779
|
+
codebase_awareness: codebase,
|
|
1780
|
+
},
|
|
1781
|
+
};
|
|
1782
|
+
}
|
|
1783
|
+
|
|
1784
|
+
function buildMizanPacketRequest(body = {}) {
|
|
1785
|
+
const context = body.context && typeof body.context === 'object' ? body.context : body;
|
|
1786
|
+
const existing = body.packetRequest && typeof body.packetRequest === 'object' ? body.packetRequest : {};
|
|
1787
|
+
const message = String(
|
|
1788
|
+
context.message ||
|
|
1789
|
+
context.intendedAction ||
|
|
1790
|
+
body.message ||
|
|
1791
|
+
body.text ||
|
|
1792
|
+
''
|
|
1793
|
+
);
|
|
1794
|
+
const platform = String(context.platform || context.surface || body.platform || body.client || 'mounted-runtime');
|
|
1795
|
+
return {
|
|
1796
|
+
stage: 'preflight',
|
|
1797
|
+
actor: String(context.actor || platform || 'mizan'),
|
|
1798
|
+
system: String(context.system || platform || 'aria-mounted-runtime'),
|
|
1799
|
+
platform,
|
|
1800
|
+
message,
|
|
1801
|
+
...existing,
|
|
1802
|
+
};
|
|
1803
|
+
}
|
|
1804
|
+
|
|
1502
1805
|
async function buildRuntimeTurnContext(req, body, client) {
|
|
1503
1806
|
const sessionId = deriveSessionId(req, body, body.provider === 'anthropic' ? 'anthropic' : 'openai');
|
|
1504
1807
|
const userId = deriveUserId(req, body);
|
|
@@ -2100,6 +2403,8 @@ function compactCodebaseSnapshot() {
|
|
|
2100
2403
|
? config.schemaImages
|
|
2101
2404
|
: {};
|
|
2102
2405
|
const repoSnapshots = Array.isArray(awareness.repoSnapshots) ? awareness.repoSnapshots : [];
|
|
2406
|
+
const heartbeatAt = awareness?.daemon?.heartbeatAt || null;
|
|
2407
|
+
const heartbeatAgeMs = heartbeatAt ? Date.now() - Date.parse(heartbeatAt) : null;
|
|
2103
2408
|
return {
|
|
2104
2409
|
repositories: repositories.slice(0, 6).map((repo) => ({
|
|
2105
2410
|
name: repo?.name || null,
|
|
@@ -2112,6 +2417,8 @@ function compactCodebaseSnapshot() {
|
|
|
2112
2417
|
awareness: {
|
|
2113
2418
|
status: awareness.status || 'idle',
|
|
2114
2419
|
updatedAt: awareness.updatedAt || null,
|
|
2420
|
+
daemon: awareness.daemon || null,
|
|
2421
|
+
stale: typeof heartbeatAgeMs === 'number' ? heartbeatAgeMs > 120000 : true,
|
|
2115
2422
|
repoSnapshots: repoSnapshots.slice(0, 4).map((repo) => ({
|
|
2116
2423
|
repoName: repo?.repoName || repo?.name || null,
|
|
2117
2424
|
filesIndexed: repo?.filesIndexed || repo?.fileCount || null,
|
|
@@ -3365,7 +3672,8 @@ async function handleRoute(req, res) {
|
|
|
3365
3672
|
|
|
3366
3673
|
if (url.pathname === '/phase/pre' || url.pathname === '/mizan/pre') {
|
|
3367
3674
|
const apiKey = resolveApiKey(req, body);
|
|
3368
|
-
const
|
|
3675
|
+
const packetRequest = buildMizanPacketRequest(body);
|
|
3676
|
+
const packet = body.packet || await loadRuntimePacket(req, body, client, packetRequest, packetRequest.message || body.text || '');
|
|
3369
3677
|
const bundle = evaluateMizanPre(packet, body.context || body, {
|
|
3370
3678
|
sessionId: body.sessionId || body.context?.sessionId || deriveSessionId(req, body, 'mizan-pre'),
|
|
3371
3679
|
runtimeId: ensureRuntimeMeta().runtimeId,
|
|
@@ -3385,7 +3693,8 @@ async function handleRoute(req, res) {
|
|
|
3385
3693
|
|
|
3386
3694
|
if (url.pathname === '/phase/mid' || url.pathname === '/mizan/mid') {
|
|
3387
3695
|
const apiKey = resolveApiKey(req, body);
|
|
3388
|
-
const
|
|
3696
|
+
const packetRequest = buildMizanPacketRequest(body);
|
|
3697
|
+
const packet = body.packet || await loadRuntimePacket(req, body, client, packetRequest, packetRequest.message || body.message || '');
|
|
3389
3698
|
const bundle = evaluateMizanMid(body.message || '', body.plannedApproach || '', packet, body.context || body, {
|
|
3390
3699
|
sessionId: body.sessionId || body.context?.sessionId || deriveSessionId(req, body, 'mizan-mid'),
|
|
3391
3700
|
runtimeId: ensureRuntimeMeta().runtimeId,
|
|
@@ -3405,7 +3714,8 @@ async function handleRoute(req, res) {
|
|
|
3405
3714
|
|
|
3406
3715
|
if (url.pathname === '/phase/post' || url.pathname === '/mizan/post') {
|
|
3407
3716
|
const apiKey = resolveApiKey(req, body);
|
|
3408
|
-
const
|
|
3717
|
+
const packetRequest = buildMizanPacketRequest(body);
|
|
3718
|
+
const packet = body.packet || await loadRuntimePacket(req, body, client, packetRequest, packetRequest.message || body.text || '');
|
|
3409
3719
|
const bundle = evaluateMizanPost(body.text || '', body.evidence || {}, packet, body.context || body, {
|
|
3410
3720
|
sessionId: body.sessionId || body.context?.sessionId || deriveSessionId(req, body, 'mizan-post'),
|
|
3411
3721
|
runtimeId: ensureRuntimeMeta().runtimeId,
|
|
@@ -3595,8 +3905,27 @@ async function handleRoute(req, res) {
|
|
|
3595
3905
|
}
|
|
3596
3906
|
|
|
3597
3907
|
if (url.pathname === '/check-action') {
|
|
3598
|
-
const
|
|
3599
|
-
|
|
3908
|
+
const action = body.action || 'write';
|
|
3909
|
+
const localGate = validateVerifyAndHive({ req, body, action });
|
|
3910
|
+
if (!localGate.allowed) {
|
|
3911
|
+
return json(res, 200, { ok: true, allowed: false, ...localGate });
|
|
3912
|
+
}
|
|
3913
|
+
let result;
|
|
3914
|
+
try {
|
|
3915
|
+
result = await client.checkAction(action, body.target || '');
|
|
3916
|
+
} catch (error) {
|
|
3917
|
+
releaseHiveFileLease(deriveSessionId(req, body, 'runtime-action'), coerceTargetFiles(body));
|
|
3918
|
+
throw error;
|
|
3919
|
+
}
|
|
3920
|
+
if (result?.allowed === false) {
|
|
3921
|
+
releaseHiveFileLease(deriveSessionId(req, body, 'runtime-action'), coerceTargetFiles(body));
|
|
3922
|
+
}
|
|
3923
|
+
return json(res, 200, { ok: true, ...result, verify: localGate.verify, hive: localGate.hive });
|
|
3924
|
+
}
|
|
3925
|
+
|
|
3926
|
+
if (url.pathname === '/hive/release') {
|
|
3927
|
+
const sessionId = deriveSessionId(req, body, 'runtime-action');
|
|
3928
|
+
return json(res, 200, { ok: true, hive: releaseHiveFileLease(sessionId, coerceTargetFiles(body)) });
|
|
3600
3929
|
}
|
|
3601
3930
|
|
|
3602
3931
|
if (url.pathname === '/validate-output' || url.pathname === '/api/harness/validate') {
|