@remembrance-ai/opencode-plugin 0.1.63 → 0.1.66
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/opencode.json +2 -2
- package/package.json +1 -1
- package/scripts/hook-core.mjs +89 -77
- package/servers/remembrance-mcp.mjs +55 -15
package/opencode.json
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
"command": [
|
|
7
7
|
"npx",
|
|
8
8
|
"-y",
|
|
9
|
-
"@remembrance-ai/mcp-server@0.1.
|
|
9
|
+
"@remembrance-ai/mcp-server@0.1.66"
|
|
10
10
|
],
|
|
11
11
|
"enabled": true,
|
|
12
12
|
"environment": {
|
|
@@ -16,6 +16,6 @@
|
|
|
16
16
|
}
|
|
17
17
|
},
|
|
18
18
|
"plugin": [
|
|
19
|
-
"@remembrance-ai/opencode-plugin@0.1.
|
|
19
|
+
"@remembrance-ai/opencode-plugin@0.1.66"
|
|
20
20
|
]
|
|
21
21
|
}
|
package/package.json
CHANGED
package/scripts/hook-core.mjs
CHANGED
|
@@ -3078,6 +3078,7 @@ async function registerHookIdentity(identity, fetchImpl, access, signal) {
|
|
|
3078
3078
|
// Registration remains fail-open; an existing same-scope key can still use
|
|
3079
3079
|
// the legacy proof while new organization claims require the binding.
|
|
3080
3080
|
}
|
|
3081
|
+
if (signal.aborted) return false;
|
|
3081
3082
|
const signedAt = new Date().toISOString();
|
|
3082
3083
|
const publicKeyHash = `sha256:${createHash("sha256")
|
|
3083
3084
|
.update(identity.public_key)
|
|
@@ -3118,7 +3119,7 @@ async function registerHookIdentity(identity, fetchImpl, access, signal) {
|
|
|
3118
3119
|
signal,
|
|
3119
3120
|
},
|
|
3120
3121
|
);
|
|
3121
|
-
return response?.ok === true;
|
|
3122
|
+
return !signal.aborted && response?.ok === true;
|
|
3122
3123
|
}
|
|
3123
3124
|
|
|
3124
3125
|
function principalSessionCachePath(
|
|
@@ -3287,90 +3288,101 @@ async function warmPrincipalSessionUncached(
|
|
|
3287
3288
|
env,
|
|
3288
3289
|
) {
|
|
3289
3290
|
const controller = new AbortController();
|
|
3290
|
-
const
|
|
3291
|
-
|
|
3292
|
-
|
|
3293
|
-
|
|
3294
|
-
|
|
3295
|
-
|
|
3296
|
-
|
|
3297
|
-
|
|
3291
|
+
const operation = (async () => {
|
|
3292
|
+
try {
|
|
3293
|
+
if (
|
|
3294
|
+
!(await registerHookIdentity(
|
|
3295
|
+
identity,
|
|
3296
|
+
fetchImpl,
|
|
3297
|
+
apiAccess,
|
|
3298
|
+
controller.signal,
|
|
3299
|
+
))
|
|
3300
|
+
) {
|
|
3301
|
+
return null;
|
|
3302
|
+
}
|
|
3303
|
+
if (controller.signal.aborted) return null;
|
|
3304
|
+
const memberLinkToken = apiAccess.memberLinkToken;
|
|
3305
|
+
const profileKey = createHash("sha256")
|
|
3306
|
+
.update(
|
|
3307
|
+
[
|
|
3308
|
+
identity.key_id,
|
|
3309
|
+
normalizedRuntime,
|
|
3310
|
+
normalizedHostSurface,
|
|
3311
|
+
"plugin_hook",
|
|
3312
|
+
].join(":"),
|
|
3313
|
+
"utf8",
|
|
3314
|
+
)
|
|
3315
|
+
.digest("base64url");
|
|
3316
|
+
const challengePayload = {
|
|
3317
|
+
action: "challenge",
|
|
3318
|
+
provider: identity.provider,
|
|
3319
|
+
key_id: identity.key_id,
|
|
3320
|
+
runtime_profile: {
|
|
3321
|
+
runtime: normalizedRuntime,
|
|
3322
|
+
surface: "plugin_hook",
|
|
3323
|
+
host_surface: normalizedHostSurface,
|
|
3324
|
+
client_name: runtimeDisplayName(normalizedRuntime),
|
|
3325
|
+
client_version: safeText(clientVersion ?? "unknown", 64),
|
|
3326
|
+
runtime_version: safeText(hostVersion ?? "", 64) || null,
|
|
3327
|
+
profile_key: `rpf_${profileKey}`,
|
|
3328
|
+
},
|
|
3329
|
+
...(memberLinkToken ? { member_link_token: memberLinkToken } : {}),
|
|
3330
|
+
};
|
|
3331
|
+
let challenge = await postPrincipalSession(
|
|
3332
|
+
challengePayload,
|
|
3298
3333
|
fetchImpl,
|
|
3299
3334
|
apiAccess,
|
|
3300
3335
|
controller.signal,
|
|
3301
|
-
)
|
|
3302
|
-
|
|
3303
|
-
|
|
3304
|
-
|
|
3305
|
-
|
|
3306
|
-
|
|
3307
|
-
|
|
3308
|
-
|
|
3309
|
-
|
|
3310
|
-
|
|
3311
|
-
|
|
3312
|
-
|
|
3313
|
-
|
|
3314
|
-
|
|
3315
|
-
|
|
3316
|
-
.
|
|
3317
|
-
|
|
3318
|
-
|
|
3319
|
-
|
|
3320
|
-
|
|
3321
|
-
|
|
3322
|
-
|
|
3323
|
-
|
|
3324
|
-
|
|
3325
|
-
client_name: runtimeDisplayName(normalizedRuntime),
|
|
3326
|
-
client_version: safeText(clientVersion ?? "unknown", 64),
|
|
3327
|
-
runtime_version: safeText(hostVersion ?? "", 64) || null,
|
|
3328
|
-
profile_key: `rpf_${profileKey}`,
|
|
3329
|
-
},
|
|
3330
|
-
...(memberLinkToken ? { member_link_token: memberLinkToken } : {}),
|
|
3331
|
-
};
|
|
3332
|
-
let challenge = await postPrincipalSession(
|
|
3333
|
-
challengePayload,
|
|
3334
|
-
fetchImpl,
|
|
3335
|
-
apiAccess,
|
|
3336
|
-
controller.signal,
|
|
3337
|
-
);
|
|
3338
|
-
if (!challenge && memberLinkToken) {
|
|
3339
|
-
challenge = await postPrincipalSession(
|
|
3340
|
-
{ ...challengePayload, member_link_token: undefined },
|
|
3336
|
+
);
|
|
3337
|
+
if (!challenge && memberLinkToken) {
|
|
3338
|
+
challenge = await postPrincipalSession(
|
|
3339
|
+
{ ...challengePayload, member_link_token: undefined },
|
|
3340
|
+
fetchImpl,
|
|
3341
|
+
apiAccess,
|
|
3342
|
+
controller.signal,
|
|
3343
|
+
);
|
|
3344
|
+
}
|
|
3345
|
+
if (controller.signal.aborted) return null;
|
|
3346
|
+
if (!challenge?.challenge_id || !challenge?.signing_payload) return null;
|
|
3347
|
+
const signature = signPayload(
|
|
3348
|
+
null,
|
|
3349
|
+
Buffer.from(challenge.signing_payload),
|
|
3350
|
+
createPrivateKey(identity.private_key),
|
|
3351
|
+
).toString("base64url");
|
|
3352
|
+
const session = await postPrincipalSession(
|
|
3353
|
+
{
|
|
3354
|
+
action: "exchange",
|
|
3355
|
+
provider: identity.provider,
|
|
3356
|
+
key_id: identity.key_id,
|
|
3357
|
+
challenge_id: challenge.challenge_id,
|
|
3358
|
+
signature,
|
|
3359
|
+
},
|
|
3341
3360
|
fetchImpl,
|
|
3342
3361
|
apiAccess,
|
|
3343
3362
|
controller.signal,
|
|
3344
3363
|
);
|
|
3364
|
+
if (controller.signal.aborted) return null;
|
|
3365
|
+
if (!session?.session_token || !session?.expires_at) return null;
|
|
3366
|
+
const stored = {
|
|
3367
|
+
token: session.session_token,
|
|
3368
|
+
expires_at: session.expires_at,
|
|
3369
|
+
member_linked: session.member_linked === true,
|
|
3370
|
+
};
|
|
3371
|
+
writeHookPrincipalSession(warmupKey, stored);
|
|
3372
|
+
return stored;
|
|
3373
|
+
} catch {
|
|
3374
|
+
return null;
|
|
3345
3375
|
}
|
|
3346
|
-
|
|
3347
|
-
|
|
3348
|
-
|
|
3349
|
-
|
|
3350
|
-
|
|
3351
|
-
|
|
3352
|
-
|
|
3353
|
-
|
|
3354
|
-
|
|
3355
|
-
|
|
3356
|
-
key_id: identity.key_id,
|
|
3357
|
-
challenge_id: challenge.challenge_id,
|
|
3358
|
-
signature,
|
|
3359
|
-
},
|
|
3360
|
-
fetchImpl,
|
|
3361
|
-
apiAccess,
|
|
3362
|
-
controller.signal,
|
|
3363
|
-
);
|
|
3364
|
-
if (!session?.session_token || !session?.expires_at) return null;
|
|
3365
|
-
const stored = {
|
|
3366
|
-
token: session.session_token,
|
|
3367
|
-
expires_at: session.expires_at,
|
|
3368
|
-
member_linked: session.member_linked === true,
|
|
3369
|
-
};
|
|
3370
|
-
writeHookPrincipalSession(warmupKey, stored);
|
|
3371
|
-
return stored;
|
|
3372
|
-
} catch {
|
|
3373
|
-
return null;
|
|
3376
|
+
})();
|
|
3377
|
+
let timeout;
|
|
3378
|
+
const deadline = new Promise((resolve) => {
|
|
3379
|
+
timeout = setTimeout(() => {
|
|
3380
|
+
controller.abort();
|
|
3381
|
+
resolve(null);
|
|
3382
|
+
}, PRINCIPAL_SESSION_TIMEOUT_MS);
|
|
3383
|
+
});
|
|
3384
|
+
try {
|
|
3385
|
+
return await Promise.race([operation, deadline]);
|
|
3374
3386
|
} finally {
|
|
3375
3387
|
clearTimeout(timeout);
|
|
3376
3388
|
}
|
|
@@ -10702,8 +10702,9 @@ function localPluginLifecycleHealth(options) {
|
|
|
10702
10702
|
if (paths.length === 0) {
|
|
10703
10703
|
return missingPluginLifecycleHealth(surface);
|
|
10704
10704
|
}
|
|
10705
|
-
|
|
10706
|
-
|
|
10705
|
+
const nowMs = (options.now ?? /* @__PURE__ */ new Date()).getTime();
|
|
10706
|
+
const genericPath = join3(healthDir, `${surface}.json`);
|
|
10707
|
+
const markerEntries = [];
|
|
10707
10708
|
for (const path of paths) {
|
|
10708
10709
|
try {
|
|
10709
10710
|
const parsed = JSON.parse(
|
|
@@ -10712,15 +10713,20 @@ function localPluginLifecycleHealth(options) {
|
|
|
10712
10713
|
if (!isRecord3(parsed) || parsed.surface !== surface) {
|
|
10713
10714
|
continue;
|
|
10714
10715
|
}
|
|
10715
|
-
const
|
|
10716
|
-
|
|
10717
|
-
|
|
10718
|
-
|
|
10719
|
-
|
|
10716
|
+
const components2 = isRecord3(parsed.components) ? parsed.components : {};
|
|
10717
|
+
markerEntries.push({
|
|
10718
|
+
path,
|
|
10719
|
+
marker: parsed,
|
|
10720
|
+
lastSeenMs: validLifecycleTimestamp(parsed.last_seen_at, nowMs),
|
|
10721
|
+
sessionStartMs: validLifecycleTimestamp(
|
|
10722
|
+
components2.session_start,
|
|
10723
|
+
nowMs
|
|
10724
|
+
)
|
|
10725
|
+
});
|
|
10720
10726
|
} catch {
|
|
10721
10727
|
}
|
|
10722
10728
|
}
|
|
10723
|
-
if (
|
|
10729
|
+
if (markerEntries.length === 0) {
|
|
10724
10730
|
return {
|
|
10725
10731
|
...missingPluginLifecycleHealth(surface),
|
|
10726
10732
|
issues: [
|
|
@@ -10731,8 +10737,40 @@ function localPluginLifecycleHealth(options) {
|
|
|
10731
10737
|
]
|
|
10732
10738
|
};
|
|
10733
10739
|
}
|
|
10734
|
-
const
|
|
10735
|
-
const
|
|
10740
|
+
const genericEntry = markerEntries.find((entry) => entry.path === genericPath);
|
|
10741
|
+
const currentSessionStartMs = genericEntry?.sessionStartMs;
|
|
10742
|
+
const currentSessionEntries = typeof currentSessionStartMs === "number" ? markerEntries.filter(
|
|
10743
|
+
(entry) => entry.sessionStartMs >= currentSessionStartMs
|
|
10744
|
+
) : [];
|
|
10745
|
+
const cohort = currentSessionEntries.length > 0 ? currentSessionEntries : [
|
|
10746
|
+
markerEntries.reduce(
|
|
10747
|
+
(latest, candidate) => candidate.lastSeenMs > latest.lastSeenMs ? candidate : latest
|
|
10748
|
+
)
|
|
10749
|
+
];
|
|
10750
|
+
const newestEntry = cohort.reduce(
|
|
10751
|
+
(latest, candidate) => candidate.lastSeenMs > latest.lastSeenMs ? candidate : latest
|
|
10752
|
+
);
|
|
10753
|
+
const mergedComponents = {};
|
|
10754
|
+
for (const component of PLUGIN_HEALTH_COMPONENTS) {
|
|
10755
|
+
let latestValue;
|
|
10756
|
+
let latestMs = Number.NEGATIVE_INFINITY;
|
|
10757
|
+
for (const entry of cohort) {
|
|
10758
|
+
const components2 = isRecord3(entry.marker.components) ? entry.marker.components : {};
|
|
10759
|
+
const value = components2[component];
|
|
10760
|
+
const valueMs = validLifecycleTimestamp(value, nowMs);
|
|
10761
|
+
if (valueMs > latestMs) {
|
|
10762
|
+
latestMs = valueMs;
|
|
10763
|
+
latestValue = value;
|
|
10764
|
+
}
|
|
10765
|
+
}
|
|
10766
|
+
if (Number.isFinite(latestMs)) mergedComponents[component] = latestValue;
|
|
10767
|
+
}
|
|
10768
|
+
const marker = {
|
|
10769
|
+
...newestEntry.marker,
|
|
10770
|
+
components: mergedComponents,
|
|
10771
|
+
last_seen_at: Number.isFinite(newestEntry.lastSeenMs) ? new Date(newestEntry.lastSeenMs).toISOString() : newestEntry.marker.last_seen_at
|
|
10772
|
+
};
|
|
10773
|
+
const componentRecord = mergedComponents;
|
|
10736
10774
|
const sessionStartMs = validLifecycleTimestamp(
|
|
10737
10775
|
componentRecord.session_start,
|
|
10738
10776
|
nowMs
|
|
@@ -10840,7 +10878,7 @@ function localPluginLifecycleHealth(options) {
|
|
|
10840
10878
|
hook_trust: hookTrust,
|
|
10841
10879
|
components,
|
|
10842
10880
|
issues,
|
|
10843
|
-
explanation: "Each host session is tracked independently.
|
|
10881
|
+
explanation: "Each host process session is tracked independently. Turn-specific prompt, tool, and completion observations are combined only when they share the current SessionStart marker."
|
|
10844
10882
|
};
|
|
10845
10883
|
}
|
|
10846
10884
|
function normalizedPluginHookTrust(value) {
|
|
@@ -10918,6 +10956,7 @@ function emptyPluginComponents() {
|
|
|
10918
10956
|
}
|
|
10919
10957
|
function lifecycleMarkerPaths(surface, healthDir, fileSystem) {
|
|
10920
10958
|
const legacyPath = join3(healthDir, `${surface}.json`);
|
|
10959
|
+
const paths = fileSystem.exists(legacyPath) ? [legacyPath] : [];
|
|
10921
10960
|
const listed = fileSystem.list ? (() => {
|
|
10922
10961
|
try {
|
|
10923
10962
|
return fileSystem.list(healthDir);
|
|
@@ -10927,9 +10966,9 @@ function lifecycleMarkerPaths(surface, healthDir, fileSystem) {
|
|
|
10927
10966
|
})() : [];
|
|
10928
10967
|
const sessionPaths = listed.filter(
|
|
10929
10968
|
(name) => name.startsWith(`${surface}.`) && name.endsWith(".json") && /^[a-z_]+\.[a-f0-9]{24}\.json$/.test(name)
|
|
10930
|
-
).slice(0, MAX_LOCAL_LIFECYCLE_MARKERS).map((name) => join3(healthDir, name));
|
|
10931
|
-
|
|
10932
|
-
return [...new Set(
|
|
10969
|
+
).slice(0, MAX_LOCAL_LIFECYCLE_MARKERS - paths.length).map((name) => join3(healthDir, name));
|
|
10970
|
+
paths.push(...sessionPaths);
|
|
10971
|
+
return [...new Set(paths)].slice(0, MAX_LOCAL_LIFECYCLE_MARKERS);
|
|
10933
10972
|
}
|
|
10934
10973
|
function normalizeConfig(value) {
|
|
10935
10974
|
if (!isRecord3(value)) return {};
|
|
@@ -11083,7 +11122,7 @@ async function checkClientUpdate(input) {
|
|
|
11083
11122
|
// src/server.ts
|
|
11084
11123
|
var MAX_REMOTE_RESPONSE_BYTES = 4 * 1024 * 1024;
|
|
11085
11124
|
var DOCTOR_PROBE_TIMEOUT_MS = 7500;
|
|
11086
|
-
var SERVER_VERSION = true ? "0.1.
|
|
11125
|
+
var SERVER_VERSION = true ? "0.1.66" : "0.0.0-dev";
|
|
11087
11126
|
var tools = toolDefinitions;
|
|
11088
11127
|
var doctorCliRequested = process.argv[2] === "doctor";
|
|
11089
11128
|
var inputBuffer = Buffer.alloc(0);
|
|
@@ -11098,6 +11137,7 @@ var PRINCIPAL_SESSION_REQUIRED_TOOLS = /* @__PURE__ */ new Set([
|
|
|
11098
11137
|
]);
|
|
11099
11138
|
var PRINCIPAL_SESSION_AWAITED_TOOLS = /* @__PURE__ */ new Set([
|
|
11100
11139
|
...PRINCIPAL_SESSION_REQUIRED_TOOLS,
|
|
11140
|
+
"get_effective_preferences",
|
|
11101
11141
|
"report_task_outcome"
|
|
11102
11142
|
]);
|
|
11103
11143
|
function apiAccessKey(access) {
|