@remembrance-ai/opencode-plugin 0.1.74 → 0.1.76
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/README.md +9 -4
- package/opencode.json +2 -2
- package/package.json +1 -1
- package/scripts/hook-core.mjs +706 -40
- package/servers/remembrance-mcp.mjs +91 -20
- package/skills/remembrancer/SKILL.md +26 -8
- package/skills/remembrancer/references/remembrance-setup.md +6 -2
- package/src/index.mjs +50 -11
|
@@ -5570,9 +5570,9 @@ function builtInPreferenceDefinition(key) {
|
|
|
5570
5570
|
|
|
5571
5571
|
// ../core/src/agent-guidance.ts
|
|
5572
5572
|
var REMEMBRANCE_QUERY_TOOL_DESCRIPTION = "Call before non-trivial service, API, tool, library, workflow, UI, review, test, security, or deployment work to find relevant Remembrance skills and resources. For short context-dependent follow-ups, infer the concrete task from the full conversation, preserve any plugin-supplied client_context.directive_id/runtime/trigger_reason, and query anyway. Compare each candidate's bounded why_matched evidence and applicability conditions before opening it; discard stated unlikely or corner-case mismatches. High matches should be fetched before custom work; possible and exploratory matches remain optional. Do not use for broad web search or one-off facts.";
|
|
5573
|
-
var REMEMBRANCE_CONNECTION_STATUS_TOOL_DESCRIPTION = "Inspect the active Remembrance transport, credential source,
|
|
5573
|
+
var REMEMBRANCE_CONNECTION_STATUS_TOOL_DESCRIPTION = "Inspect the active Remembrance transport, credential source, authenticated registry scope, and content-free recent contribution outcomes for the current installation or API key without exposing credentials or lesson content. Call this before diagnosing authentication, checking environment variables, or making anonymous REST/browser probes. Local or bundled MCP can read REMEMBRANCE_API_KEY or ~/.config/remembrance/config.json; hosted MCP cannot read local files and authenticates from its request header. When a declared native lifecycle is degraded, local MCP may submit bounded, content-free health evidence unless REMEMBRANCE_HEALTH_REPORTING=0. Never infer the plugin's scope from REMEMBRANCE_API_KEY alone.";
|
|
5574
5574
|
var REMEMBRANCE_CONNECTION_DOCTOR_TOOL_DESCRIPTION = "Run a bounded, non-mutating Remembrance connection diagnostic. It verifies the active transport, a redacted registry destination, authenticated scope, query authorization, a real catalog read, and organization submission capability. Local MCP also checks shared-config permissions, destination consistency, native plugin lifecycle, and signing identity; hosted MCP marks local-only checks unavailable. It never submits content, creates query demand, opens a review item, or returns credentials, absolute paths, private registry URLs, prompts, or repository data.";
|
|
5575
|
-
var REMEMBRANCE_MCP_SERVER_INSTRUCTIONS = "Remembrance is shared operational memory for agents. Before claiming that Remembrance is anonymous, unconfigured, partially active, or missing an organization key, call run_connection_doctor for the transport you will actually use. It performs a safe catalog read and returns exact bounded remediation without submitting content. Use get_connection_status only when you need the underlying transport and lifecycle fields. An unset REMEMBRANCE_API_KEY does not prove that a local plugin is anonymous because local hooks and bundled MCP may read ~/.config/remembrance/config.json. Conversely, hosted MCP cannot read that local file. Anonymous curl or browser probes describe only those requests, not plugin authentication. Never print or request the raw key. When the user explicitly names an authorized Remembrance skill or supplies a remembrance://skills/{slug} URI, resolve ambiguous names with list_skills using its normalized slug-prefix filter, then call invoke_skill with an exact returned slug. Never guess a slug. list_skills is catalog resolution, not relevance search; use query_skills when the user wants relevant candidates rather than a known selection. invoke_skill rechecks authorization and organization policy, resolves the current reviewed version, and returns the only full instruction body. Catalog listings and MCP resource reads are lightweight handles, not skill use. Do not run query_skills merely to rediscover that explicit selection, and do not submit query-fit feedback for it. After meaningful direct use, follow the returned task-outcome and post-use feedback instructions once. BEFORE non-trivial service/API/tool/library/workflow/UI/review/test/security/deployment work, call query_skills to reuse proven skills and resources instead of rediscovering them. A local repository change still qualifies when it involves a reusable workflow or lesson; skip only genuinely trivial throwaway edits and one-off facts. For short follow-ups such as 'fix these issues', 'continue', or 'try again', infer the concrete task, domain, and constraints from the full conversation and still call query_skills; do not wait for the current prompt to repeat trigger keywords. Treat match_tier as a decision aid, then inspect why_matched and applicability before opening a result. These fields show bounded matched terms/capabilities, satisfied and missed constraints, qualitative lexical/semantic evidence, declared scope, use conditions, and exclusions without exposing unstable raw ranking scores. Discard an unlikely or irrelevant corner-case result and report fit: poor; do not force its use. For a remaining high match, call get_skill or get_resource before custom work and pass the returned query_id/result_id so the surfaced-to-fetch funnel closes; possible and exploratory matches are optional. The response also includes approximate context tokens, verified uses, risk, tags, permissions, dependencies, and contraindications so you can weigh the detour safely. Honor query_skills.skill_access on every response. When policy is org_only, use only returned organization skills and never substitute bundled or live public skill references; if an organization key is configured and the query is unavailable, fail closed because the policy cannot be confirmed. AFTER query_skills, call submit_query_feedback once with one complete set of explicit good/partial/poor judgments using the returned query_id and result_id values; leave unrated results neutral, and remember that a poor query match is not the same as a globally bad skill. Reuse the same organization or anonymous auth scope as the query. AFTER you actually use a skill or resource, close the post-use loop with submit_feedback (useful true/false plus a one-line lesson and the originating query_id/result_id; it returns a ready submit_remembrance payload), then submit_remembrance if the lesson is reusable. If nothing fit and you built a new workflow, use propose_private_skill for an organization-private candidate. With an organization key, propose_skill_idea also remains organization-private. Never remove, suppress, or bypass that key to force a public submission; submit privately, then use the reviewed public-propagation flow when the organization chooses to share it. When delegating, pass the selected slug, exact version, query_id, and result_id to the subagent; it should invoke/fetch that result or run its own full-context query. The parent reports the terminal outcome unless the subagent creates its own invocation. Before finishing any reusable task, self-check for a missed query. If you catch your own mistake, the user catches one, CI/deploy fails, a security issue appears, or you fix a release/versioning miss, submit a failure_report remembrance even if no skill was used; raw MCP clients have no plugin Stop hook to remind you later. A host privacy or tenant-policy denial happens before Remembrance receives the request. Tell the user: 'Remembrance was blocked by host policy before reaching Remembrance. Nothing was sent. Querying remains available.' Do not retry the blocked content through another transport or claim submission. Attach evidence (reproduction detail, artifact hashes, or an attestation); evidence-less public reports wait in unverified intake until corroborated. Redact secrets, private URLs, credentials, raw logs, and proprietary content; submit summaries and hashes, not raw traces.";
|
|
5575
|
+
var REMEMBRANCE_MCP_SERVER_INSTRUCTIONS = "Remembrance is shared operational memory for agents. Before claiming that Remembrance is anonymous, unconfigured, partially active, or missing an organization key, call run_connection_doctor for the transport you will actually use. It performs a safe catalog read and returns exact bounded remediation without submitting content. Use get_connection_status only when you need the underlying transport and lifecycle fields. An unset REMEMBRANCE_API_KEY does not prove that a local plugin is anonymous because local hooks and bundled MCP may read ~/.config/remembrance/config.json. Conversely, hosted MCP cannot read that local file. Anonymous curl or browser probes describe only those requests, not plugin authentication. Never print or request the raw key. When the user explicitly names an authorized Remembrance skill or supplies a remembrance://skills/{slug} URI, resolve ambiguous names with list_skills using its normalized slug-prefix filter, then call invoke_skill with an exact returned slug. Never guess a slug. list_skills is catalog resolution, not relevance search; use query_skills when the user wants relevant candidates rather than a known selection. invoke_skill rechecks authorization and organization policy, resolves the current reviewed version, and returns the only full instruction body. Catalog listings and MCP resource reads are lightweight handles, not skill use. Do not run query_skills merely to rediscover that explicit selection, and do not submit query-fit feedback for it. After meaningful direct use, follow the returned task-outcome and post-use feedback instructions once. BEFORE non-trivial service/API/tool/library/workflow/UI/review/test/security/deployment work, call query_skills to reuse proven skills and resources instead of rediscovering them. A local repository change still qualifies when it involves a reusable workflow or lesson; skip only genuinely trivial throwaway edits and one-off facts. For short follow-ups such as 'fix these issues', 'continue', or 'try again', infer the concrete task, domain, and constraints from the full conversation and still call query_skills; do not wait for the current prompt to repeat trigger keywords. Treat match_tier as a decision aid, then inspect why_matched and applicability before opening a result. These fields show bounded matched terms/capabilities, satisfied and missed constraints, qualitative lexical/semantic evidence, declared scope, use conditions, and exclusions without exposing unstable raw ranking scores. Discard an unlikely or irrelevant corner-case result and report fit: poor; do not force its use. For a remaining high match, call get_skill or get_resource before custom work and pass the returned query_id/result_id so the surfaced-to-fetch funnel closes; possible and exploratory matches are optional. The response also includes approximate context tokens, verified uses, risk, tags, permissions, dependencies, and contraindications so you can weigh the detour safely. Honor query_skills.skill_access on every response. When policy is org_only, use only returned organization skills and never substitute bundled or live public skill references; if an organization key is configured and the query is unavailable, fail closed because the policy cannot be confirmed. AFTER query_skills, call submit_query_feedback once with one complete set of explicit good/partial/poor judgments using the returned query_id and result_id values; leave unrated results neutral, and remember that a poor query match is not the same as a globally bad skill. Reuse the same organization or anonymous auth scope as the query. AFTER you actually use a skill or resource, close the post-use loop with submit_feedback (useful true/false plus a one-line lesson and the originating query_id/result_id; it returns a ready submit_remembrance payload), then submit_remembrance if the lesson is reusable. If nothing fit and you built a new workflow, use propose_private_skill for an organization-private candidate. With an organization key, propose_skill_idea also remains organization-private. Never remove, suppress, or bypass that key to force a public submission; submit privately, then use the reviewed public-propagation flow when the organization chooses to share it. When delegating, pass the selected slug, exact version, query_id, and result_id to the subagent; it should invoke/fetch that result or run its own full-context query. The parent reports the terminal outcome unless the subagent creates its own invocation. Route memory deliberately: host-local memory is for facts about this human, repository, or machine; Remembrance is for generalized lessons another approved organization agent would otherwise rediscover. A local-memory write does not satisfy organization-shared capture. Before finishing any reusable task, self-check for a missed query. If you catch your own mistake, the user catches one, CI/deploy fails, a security issue appears, or you fix a release/versioning miss, submit a failure_report remembrance even if no skill was used; raw MCP clients have no plugin Stop hook to remind you later. A host privacy or tenant-policy denial happens before Remembrance receives the request. Tell the user: 'Remembrance was blocked by host policy before reaching Remembrance. Nothing was sent. Querying remains available.' Do not retry the blocked content through another transport or claim submission. Attach evidence (reproduction detail, artifact hashes, or an attestation); evidence-less public reports wait in unverified intake until corroborated. Redact secrets, private URLs, credentials, raw logs, and proprietary content; submit summaries and hashes, not raw traces.";
|
|
5576
5576
|
|
|
5577
5577
|
// ../core/src/redaction.ts
|
|
5578
5578
|
var SECRET_PATTERN_SPECS = [
|
|
@@ -5731,6 +5731,20 @@ var PRIVATE_LESSON_TAG_IDENTITY_HINTS = /* @__PURE__ */ new Set([
|
|
|
5731
5731
|
"tenant",
|
|
5732
5732
|
"user"
|
|
5733
5733
|
]);
|
|
5734
|
+
var PRIVATE_LESSON_TAG_IDENTITY_LABEL_SUFFIXES = /* @__PURE__ */ new Set([
|
|
5735
|
+
"corp",
|
|
5736
|
+
"org",
|
|
5737
|
+
"organization"
|
|
5738
|
+
]);
|
|
5739
|
+
var PRIVATE_LESSON_TAG_RELATIONAL_PREFIXES = /* @__PURE__ */ new Set([
|
|
5740
|
+
"cross",
|
|
5741
|
+
"inter",
|
|
5742
|
+
"intra",
|
|
5743
|
+
"multi",
|
|
5744
|
+
"per",
|
|
5745
|
+
"single",
|
|
5746
|
+
"sub"
|
|
5747
|
+
]);
|
|
5734
5748
|
var privateLessonCanonicalTagSchema = privateLessonTagSyntaxSchema.superRefine((tag, ctx) => {
|
|
5735
5749
|
const inspected = inspectPrivateLessonTag(tag);
|
|
5736
5750
|
if (inspected.tag !== tag || inspected.held_reasons.length > 0) {
|
|
@@ -6125,8 +6139,14 @@ function computePrivateLessonRedactorDigest() {
|
|
|
6125
6139
|
metadata: {
|
|
6126
6140
|
correlation_ids: "domain-separated-sha256-v1",
|
|
6127
6141
|
tag_syntax: PRIVATE_LESSON_TAG_PATTERN.source,
|
|
6128
|
-
tag_safety: "redaction-plus-identity-hints-
|
|
6142
|
+
tag_safety: "redaction-plus-identity-hints-v2",
|
|
6129
6143
|
tag_identity_hints: [...PRIVATE_LESSON_TAG_IDENTITY_HINTS].sort(),
|
|
6144
|
+
tag_identity_label_suffixes: [
|
|
6145
|
+
...PRIVATE_LESSON_TAG_IDENTITY_LABEL_SUFFIXES
|
|
6146
|
+
].sort(),
|
|
6147
|
+
tag_relational_prefixes: [
|
|
6148
|
+
...PRIVATE_LESSON_TAG_RELATIONAL_PREFIXES
|
|
6149
|
+
].sort(),
|
|
6130
6150
|
tag_aliases: PRIVATE_LESSON_SAFE_TAG_ALIASES
|
|
6131
6151
|
},
|
|
6132
6152
|
rules: REPLACEMENTS.map(({ category, pattern, hold }) => ({
|
|
@@ -6150,7 +6170,10 @@ function inspectPrivateLessonTag(value) {
|
|
|
6150
6170
|
const identityHints = new Set(
|
|
6151
6171
|
aliased.split(/[-_]/u).filter((segment) => PRIVATE_LESSON_TAG_IDENTITY_HINTS.has(segment))
|
|
6152
6172
|
);
|
|
6153
|
-
|
|
6173
|
+
const segments = aliased.split(/[-_]/u);
|
|
6174
|
+
const isGenericOrganizationRelationship = segments.length === 2 && PRIVATE_LESSON_TAG_RELATIONAL_PREFIXES.has(segments[0] ?? "") && PRIVATE_LESSON_TAG_IDENTITY_LABEL_SUFFIXES.has(segments[1] ?? "");
|
|
6175
|
+
const hasLikelyIdentityLabel = segments.length >= 2 && !isGenericOrganizationRelationship && PRIVATE_LESSON_TAG_IDENTITY_LABEL_SUFFIXES.has(segments.at(-1) ?? "") && segments.slice(0, -1).some((segment) => !PRIVATE_LESSON_TAG_IDENTITY_HINTS.has(segment));
|
|
6176
|
+
if (!privateLessonTagSyntaxSchema.safeParse(aliased).success || redacted.text !== aliased || identityHints.size >= 2 || hasLikelyIdentityLabel) {
|
|
6154
6177
|
if (held.size === 0) {
|
|
6155
6178
|
counts.identifier = Math.min(999, (counts.identifier ?? 0) + 1);
|
|
6156
6179
|
held.add("identifier");
|
|
@@ -6177,12 +6200,18 @@ function pseudonymizeCorrelationId(value) {
|
|
|
6177
6200
|
return `corr_${digest.slice(0, 48)}`;
|
|
6178
6201
|
}
|
|
6179
6202
|
var CURRENT_PRIVATE_LESSON_REDACTOR_DIGEST = computePrivateLessonRedactorDigest();
|
|
6203
|
+
var PRIVATE_LESSON_LEGACY_V2_REDACTOR_DIGEST = "sha256:bca83ac50b0124a0401f806b3498bbb1ec977c02c1975d5345cb8d0b85c00b75";
|
|
6180
6204
|
var PRIVATE_LESSON_SUPPORTED_REDACTOR_PROFILES = Object.freeze({
|
|
6181
6205
|
[PRIVATE_LESSON_REDACTION_VERSION]: Object.freeze({
|
|
6182
6206
|
[CURRENT_PRIVATE_LESSON_REDACTOR_DIGEST]: Object.freeze({
|
|
6183
6207
|
version: PRIVATE_LESSON_REDACTION_VERSION,
|
|
6184
6208
|
digest: CURRENT_PRIVATE_LESSON_REDACTOR_DIGEST,
|
|
6185
6209
|
normalization: "unicode-nfc-lf-space-v1"
|
|
6210
|
+
}),
|
|
6211
|
+
[PRIVATE_LESSON_LEGACY_V2_REDACTOR_DIGEST]: Object.freeze({
|
|
6212
|
+
version: PRIVATE_LESSON_REDACTION_VERSION,
|
|
6213
|
+
digest: PRIVATE_LESSON_LEGACY_V2_REDACTOR_DIGEST,
|
|
6214
|
+
normalization: "unicode-nfc-lf-space-v1"
|
|
6186
6215
|
})
|
|
6187
6216
|
})
|
|
6188
6217
|
});
|
|
@@ -7610,7 +7639,7 @@ var seedSkills = [
|
|
|
7610
7639
|
summary: "Operational setup and troubleshooting workflow for Remembrance across Claude Code, Codex, OpenClaw, Cursor, Gemini, MCP, REST, skill-only installs, enterprise keys, and local agent identity.",
|
|
7611
7640
|
status: "active",
|
|
7612
7641
|
visibility: "public",
|
|
7613
|
-
version: "0.1.
|
|
7642
|
+
version: "0.1.25",
|
|
7614
7643
|
domains: ["agent-skills", "mcp", "resource-discovery"],
|
|
7615
7644
|
tags: [
|
|
7616
7645
|
"remembrance",
|
|
@@ -7661,7 +7690,7 @@ var seedSkills = [
|
|
|
7661
7690
|
"gemini",
|
|
7662
7691
|
"rest"
|
|
7663
7692
|
],
|
|
7664
|
-
version: "0.1.
|
|
7693
|
+
version: "0.1.25",
|
|
7665
7694
|
status: "active",
|
|
7666
7695
|
visibility: "public",
|
|
7667
7696
|
providers: ["codex", "claude", "cursor", "openclaw", "generic"],
|
|
@@ -8016,8 +8045,12 @@ This is the only host-visible network action in the flow. Approve or persist
|
|
|
8016
8045
|
approval for this exact action, not every Remembrance write. The server derives
|
|
8017
8046
|
the organization and private visibility from the authenticated key, verifies a
|
|
8018
8047
|
signed organization policy plus purpose-bound attestation, and returns a signed
|
|
8019
|
-
content-free receipt. The
|
|
8020
|
-
public
|
|
8048
|
+
content-free receipt. The action always submits privately and never falls back
|
|
8049
|
+
to anonymous or public submission. After an accepted private outcome, a
|
|
8050
|
+
separate server-owned process may create a freshly redacted public candidate
|
|
8051
|
+
only when the organization admin enabled the **Contribution propagation**
|
|
8052
|
+
setting; the submitting agent neither chooses nor sees that process, and the
|
|
8053
|
+
derivative must pass the complete public pipeline.
|
|
8021
8054
|
|
|
8022
8055
|
If the host denies the action, no candidate content was sent. The encrypted
|
|
8023
8056
|
draft remains on the device in \`awaiting_authorization\`; do not retry it
|
|
@@ -10859,7 +10892,7 @@ var toolDefinitions = [
|
|
|
10859
10892
|
),
|
|
10860
10893
|
tool(
|
|
10861
10894
|
"submit_private_lesson_candidate",
|
|
10862
|
-
"Submit exactly one canonical, challenge-attested organization-private lesson candidate or one content-free held-safety telemetry event. Local plugin clients normally pass only the draft_id returned by prepare_private_lesson_candidate; raw or hosted clients pass the strict candidate-or-hold union. The action
|
|
10895
|
+
"Submit exactly one canonical, challenge-attested organization-private lesson candidate or one content-free held-safety telemetry event. Local plugin clients normally pass only the draft_id returned by prepare_private_lesson_candidate; raw or hosted clients pass the strict candidate-or-hold union. The action always creates only an organization-private submission and never falls back to anonymous or public submission. Held telemetry contains no lesson prose and can never enter verification, review, topology, or skill materialization. Exact replay is idempotent; host denial leaves the local draft untouched.",
|
|
10863
10896
|
"/api/v1/agent/private-lessons",
|
|
10864
10897
|
privateLessonSubmissionToolSchema
|
|
10865
10898
|
),
|
|
@@ -12419,6 +12452,44 @@ async function readPrivateLessonSubmittedRecord(draftId, options = {}) {
|
|
|
12419
12452
|
);
|
|
12420
12453
|
});
|
|
12421
12454
|
}
|
|
12455
|
+
async function readPrivateLessonSubmissionSource(draftId, options = {}) {
|
|
12456
|
+
assertDraftId(draftId);
|
|
12457
|
+
const outbox = await readyOutbox(options);
|
|
12458
|
+
return withPrivateLessonOutboxLock(outbox.directory, async () => {
|
|
12459
|
+
await reconcileSubmittedRecordsUnlocked(
|
|
12460
|
+
outbox.directory,
|
|
12461
|
+
options.now ?? /* @__PURE__ */ new Date()
|
|
12462
|
+
);
|
|
12463
|
+
if (existsSync4(tombstonePath(outbox.directory, draftId))) {
|
|
12464
|
+
throw new Error("Private lesson draft was explicitly deleted.");
|
|
12465
|
+
}
|
|
12466
|
+
const completionPath = submittedRecordPath(outbox.directory, draftId);
|
|
12467
|
+
if (existsSync4(completionPath)) {
|
|
12468
|
+
await assertRegularPrivateFile(
|
|
12469
|
+
completionPath,
|
|
12470
|
+
PRIVATE_LESSON_SUBMITTED_RECORD_MAX_BYTES
|
|
12471
|
+
);
|
|
12472
|
+
return {
|
|
12473
|
+
kind: "submitted",
|
|
12474
|
+
completion: parseSubmittedRecord(
|
|
12475
|
+
await readBoundedFile(
|
|
12476
|
+
completionPath,
|
|
12477
|
+
PRIVATE_LESSON_SUBMITTED_RECORD_MAX_BYTES
|
|
12478
|
+
),
|
|
12479
|
+
draftId
|
|
12480
|
+
)
|
|
12481
|
+
};
|
|
12482
|
+
}
|
|
12483
|
+
return {
|
|
12484
|
+
kind: "draft",
|
|
12485
|
+
draft: await readPrivateLessonDraft(draftId, {
|
|
12486
|
+
...options,
|
|
12487
|
+
outboxDirectory: outbox.directory,
|
|
12488
|
+
encryption: outbox.encryption
|
|
12489
|
+
})
|
|
12490
|
+
};
|
|
12491
|
+
});
|
|
12492
|
+
}
|
|
12422
12493
|
async function reconcilePrivateLessonOutboxProfiles(options = {}) {
|
|
12423
12494
|
const outbox = await readyOutbox(options);
|
|
12424
12495
|
return withPrivateLessonOutboxLock(outbox.directory, async () => {
|
|
@@ -13529,7 +13600,7 @@ async function readConcurrentPrivateLessonFallbackKey(path) {
|
|
|
13529
13600
|
// src/server.ts
|
|
13530
13601
|
var MAX_REMOTE_RESPONSE_BYTES = 4 * 1024 * 1024;
|
|
13531
13602
|
var DOCTOR_PROBE_TIMEOUT_MS = 7500;
|
|
13532
|
-
var SERVER_VERSION = true ? "0.1.
|
|
13603
|
+
var SERVER_VERSION = true ? "0.1.76" : "0.0.0-dev";
|
|
13533
13604
|
var tools = toolDefinitions;
|
|
13534
13605
|
var doctorCliRequested = process.argv[2] === "doctor";
|
|
13535
13606
|
var inputBuffer = Buffer.alloc(0);
|
|
@@ -14016,13 +14087,13 @@ async function inspectPrivateLessonOutbox(input) {
|
|
|
14016
14087
|
};
|
|
14017
14088
|
}
|
|
14018
14089
|
async function submitPrivateLessonDraft(draftId, access, allowPolicyRefresh) {
|
|
14019
|
-
const
|
|
14020
|
-
if (
|
|
14021
|
-
return privateLessonSubmittedActionResult(completion, {
|
|
14090
|
+
const source = await readPrivateLessonSubmissionSource(draftId);
|
|
14091
|
+
if (source.kind === "submitted") {
|
|
14092
|
+
return privateLessonSubmittedActionResult(source.completion, {
|
|
14022
14093
|
status: "already_submitted"
|
|
14023
14094
|
});
|
|
14024
14095
|
}
|
|
14025
|
-
let draft =
|
|
14096
|
+
let draft = source.draft;
|
|
14026
14097
|
if (draft.state === "superseded_redactor") {
|
|
14027
14098
|
return privateLessonDraftActionResult(draft, {
|
|
14028
14099
|
status: "superseded_redactor",
|
|
@@ -14209,7 +14280,7 @@ async function submitPrivateLessonDraft(draftId, access, allowPolicyRefresh) {
|
|
|
14209
14280
|
"Private lesson submission omitted its processing state."
|
|
14210
14281
|
);
|
|
14211
14282
|
}
|
|
14212
|
-
const
|
|
14283
|
+
const completion = await completePrivateLessonSubmission(draft.draft_id, {
|
|
14213
14284
|
receipt_digest: receiptDigest,
|
|
14214
14285
|
remote_status: status,
|
|
14215
14286
|
processing_state: completionProcessingState
|
|
@@ -14217,18 +14288,18 @@ async function submitPrivateLessonDraft(draftId, access, allowPolicyRefresh) {
|
|
|
14217
14288
|
draft = {
|
|
14218
14289
|
...draft,
|
|
14219
14290
|
state: "submitted",
|
|
14220
|
-
attempts:
|
|
14291
|
+
attempts: completion.attempts,
|
|
14221
14292
|
next_retry_at: null,
|
|
14222
14293
|
last_error_code: null,
|
|
14223
|
-
submitted_at:
|
|
14224
|
-
receipt_digest:
|
|
14294
|
+
submitted_at: completion.submitted_at,
|
|
14295
|
+
receipt_digest: completion.receipt_digest,
|
|
14225
14296
|
policy: receiptPolicy,
|
|
14226
|
-
updated_at:
|
|
14297
|
+
updated_at: completion.updated_at
|
|
14227
14298
|
};
|
|
14228
14299
|
return {
|
|
14229
14300
|
...privateLessonDraftActionResult(draft, {
|
|
14230
14301
|
status,
|
|
14231
|
-
completion_expires_at:
|
|
14302
|
+
completion_expires_at: completion.expires_at
|
|
14232
14303
|
}),
|
|
14233
14304
|
receipt,
|
|
14234
14305
|
processing_state: processingState
|
|
@@ -97,6 +97,20 @@ Also use this skill when:
|
|
|
97
97
|
|
|
98
98
|
Do not directly mutate shared skills. Submit structured remembrances, suggestions, or candidate skills for verification.
|
|
99
99
|
|
|
100
|
+
Route memory by audience, not by which write tool is most convenient:
|
|
101
|
+
|
|
102
|
+
- Host-local memory is for facts about this human, repository, installation, or machine.
|
|
103
|
+
- Remembrance is for a generalized lesson another approved organization agent would otherwise rediscover the hard way.
|
|
104
|
+
- A local-memory write does not satisfy organization-shared capture. Generalize reusable feedback and use the private lesson lane; never mirror raw local memory automatically.
|
|
105
|
+
|
|
106
|
+
`get_connection_status` exposes content-free recent contribution outcomes for
|
|
107
|
+
the current installation principal, or for the current API key when an older
|
|
108
|
+
client has no principal. Use it when the user asks whether prior contributions
|
|
109
|
+
were accepted, recognized as duplicates, remain pending, need review, or were
|
|
110
|
+
rejected. It covers remembrances, private skill ideas, skill suggestions,
|
|
111
|
+
resource submissions, and resource reviews. It never returns lesson text,
|
|
112
|
+
titles, rejection prose, actor identity, or private payload data.
|
|
113
|
+
|
|
100
114
|
Do not use this skill when:
|
|
101
115
|
|
|
102
116
|
- The user asks for general web search, research, or current facts.
|
|
@@ -190,14 +204,18 @@ terminal count, retained bytes, reason, and explicit deletion guidance without
|
|
|
190
204
|
returning draft content or a local path.
|
|
191
205
|
|
|
192
206
|
The private lesson endpoint derives its organization and private visibility
|
|
193
|
-
from the authenticated key.
|
|
194
|
-
back to public submission. Accepted candidates enter the
|
|
195
|
-
topology, review-policy, encrypted-storage, and audit
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
207
|
+
from the authenticated key. The action always submits privately and never
|
|
208
|
+
falls back to anonymous or public submission. Accepted candidates enter the
|
|
209
|
+
existing verifier, topology, review-policy, encrypted-storage, and audit
|
|
210
|
+
pipelines. After an accepted private outcome, a separate server-owned process
|
|
211
|
+
may create a freshly redacted public candidate only when the organization admin
|
|
212
|
+
enabled **Contribution propagation**; the agent neither chooses nor sees that
|
|
213
|
+
process, and the derivative must pass the complete public pipeline. Rich
|
|
214
|
+
content, raw traces, URLs, code blocks, attachments, secrets, paths,
|
|
215
|
+
identifiers, or ambiguous material stays local and must not be forced through
|
|
216
|
+
by confirmation. Use `inspect_private_lesson_outbox` to inspect content-free
|
|
217
|
+
state, retry a selected draft with `retry_private_lesson_candidate`, and delete
|
|
218
|
+
only with `delete_private_lesson_candidate` plus explicit confirmation.
|
|
201
219
|
|
|
202
220
|
When health reporting is enabled, a held draft may use the same exact submit
|
|
203
221
|
action to send only a `held_safety_event`: event type, held category counts,
|
|
@@ -284,8 +284,12 @@ This is the only host-visible network action in the flow. Approve or persist
|
|
|
284
284
|
approval for this exact action, not every Remembrance write. The server derives
|
|
285
285
|
the organization and private visibility from the authenticated key, verifies a
|
|
286
286
|
signed organization policy plus purpose-bound attestation, and returns a signed
|
|
287
|
-
content-free receipt. The
|
|
288
|
-
public
|
|
287
|
+
content-free receipt. The action always submits privately and never falls back
|
|
288
|
+
to anonymous or public submission. After an accepted private outcome, a
|
|
289
|
+
separate server-owned process may create a freshly redacted public candidate
|
|
290
|
+
only when the organization admin enabled the **Contribution propagation**
|
|
291
|
+
setting; the submitting agent neither chooses nor sees that process, and the
|
|
292
|
+
derivative must pass the complete public pipeline.
|
|
289
293
|
|
|
290
294
|
If the host denies the action, no candidate content was sent. The encrypted
|
|
291
295
|
draft remains on the device in `awaiting_authorization`; do not retry it
|
package/src/index.mjs
CHANGED
|
@@ -45,21 +45,21 @@ import {
|
|
|
45
45
|
decideStop,
|
|
46
46
|
directSelectionFromResponse,
|
|
47
47
|
highMatchFromResponse,
|
|
48
|
-
markCurrentEngagementHandled,
|
|
49
48
|
markHostPolicyAlertDelivered,
|
|
49
|
+
observeSuccessfulCompletionTool,
|
|
50
50
|
recordDirectiveFollowThroughForTool,
|
|
51
51
|
recordDirectSelectionSurface,
|
|
52
52
|
recordDirectiveSurface,
|
|
53
53
|
recordHighMatchSurface,
|
|
54
54
|
recordPluginLifecycleHealth,
|
|
55
55
|
recordHostPolicyDenial,
|
|
56
|
+
recordQueryFeedbackObligation,
|
|
56
57
|
recordRegistryUse,
|
|
57
58
|
recordTaskEligibility,
|
|
58
59
|
recordValueEpisodeSurface,
|
|
59
60
|
queryResponseHasMatches,
|
|
60
61
|
reportDirectiveEvent,
|
|
61
62
|
reportTaskOutcomesOnStop,
|
|
62
|
-
responseRequestsRemembranceFollowup,
|
|
63
63
|
resolveApiCredential,
|
|
64
64
|
runPromptHook,
|
|
65
65
|
toolResponseIndicatesFailure,
|
|
@@ -76,6 +76,8 @@ const CONTRIBUTION_TOOLS = [
|
|
|
76
76
|
"submit_remembrance",
|
|
77
77
|
"propose_skill_idea",
|
|
78
78
|
"propose_private_skill",
|
|
79
|
+
"submit_private_lesson_candidate",
|
|
80
|
+
"retry_private_lesson_candidate",
|
|
79
81
|
"submit_suggestion",
|
|
80
82
|
"submit_resource",
|
|
81
83
|
"submit_resource_review",
|
|
@@ -371,6 +373,7 @@ export const Remembrance = async (context = {}) => {
|
|
|
371
373
|
highMatch: result?.highMatch ?? null,
|
|
372
374
|
text: guidance.trim(),
|
|
373
375
|
countsAsUse: Boolean(result?.consumed && result?.matched),
|
|
376
|
+
queryFeedback: result?.queryFeedback ?? null,
|
|
374
377
|
valueEpisode: result?.valueEpisode ?? null,
|
|
375
378
|
});
|
|
376
379
|
}
|
|
@@ -412,6 +415,11 @@ export const Remembrance = async (context = {}) => {
|
|
|
412
415
|
recordHighMatchSurface(sessionId, guidance.highMatch, env);
|
|
413
416
|
recordValueEpisodeSurface(sessionId, guidance.valueEpisode, env);
|
|
414
417
|
}
|
|
418
|
+
recordQueryFeedbackObligation(
|
|
419
|
+
sessionId,
|
|
420
|
+
guidance.queryFeedback,
|
|
421
|
+
env,
|
|
422
|
+
);
|
|
415
423
|
recordDirectiveSurface(sessionId, guidance.directive, env);
|
|
416
424
|
if (guidance.directive) {
|
|
417
425
|
await reportDirectiveEvent(
|
|
@@ -487,7 +495,6 @@ export const Remembrance = async (context = {}) => {
|
|
|
487
495
|
});
|
|
488
496
|
const decision = decideStop({ session_id: sessionId }, { env });
|
|
489
497
|
if (decision?.allow !== false || !decision?.reason) return;
|
|
490
|
-
markCurrentEngagementHandled(sessionId, env);
|
|
491
498
|
writePromptedCount(sessionId, decision.useCount ?? 1, env);
|
|
492
499
|
await notify(client, decision.reason);
|
|
493
500
|
} catch (error) {
|
|
@@ -555,6 +562,7 @@ export const Remembrance = async (context = {}) => {
|
|
|
555
562
|
const tool = toolNameFromEvent(input, output);
|
|
556
563
|
if (!tool) return;
|
|
557
564
|
const normalizedTool = tool.toLowerCase();
|
|
565
|
+
const toolArguments = toolArgumentsFromEvent(input);
|
|
558
566
|
if (toolResponseIndicatesFailure(output)) {
|
|
559
567
|
await observeHostPolicyDenial({
|
|
560
568
|
eventType: "tool.execute.after",
|
|
@@ -575,6 +583,13 @@ export const Remembrance = async (context = {}) => {
|
|
|
575
583
|
valueEpisodeFromResponse(output),
|
|
576
584
|
env,
|
|
577
585
|
);
|
|
586
|
+
observeSuccessfulCompletionTool(
|
|
587
|
+
sessionId,
|
|
588
|
+
tool,
|
|
589
|
+
toolArguments,
|
|
590
|
+
output,
|
|
591
|
+
env,
|
|
592
|
+
);
|
|
578
593
|
await recordDirectiveFollowThroughForTool(sessionId, tool, output, {
|
|
579
594
|
env,
|
|
580
595
|
});
|
|
@@ -599,6 +614,23 @@ export const Remembrance = async (context = {}) => {
|
|
|
599
614
|
selection.slug,
|
|
600
615
|
env,
|
|
601
616
|
);
|
|
617
|
+
observeSuccessfulCompletionTool(
|
|
618
|
+
sessionId,
|
|
619
|
+
tool,
|
|
620
|
+
toolArguments,
|
|
621
|
+
output,
|
|
622
|
+
env,
|
|
623
|
+
);
|
|
624
|
+
return;
|
|
625
|
+
}
|
|
626
|
+
if (normalizedTool.endsWith("prepare_private_lesson_candidate")) {
|
|
627
|
+
observeSuccessfulCompletionTool(
|
|
628
|
+
sessionId,
|
|
629
|
+
tool,
|
|
630
|
+
toolArguments,
|
|
631
|
+
output,
|
|
632
|
+
env,
|
|
633
|
+
);
|
|
602
634
|
return;
|
|
603
635
|
}
|
|
604
636
|
if (
|
|
@@ -613,19 +645,26 @@ export const Remembrance = async (context = {}) => {
|
|
|
613
645
|
normalizedTool.endsWith(candidate),
|
|
614
646
|
)
|
|
615
647
|
) {
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
648
|
+
observeSuccessfulCompletionTool(
|
|
649
|
+
sessionId,
|
|
650
|
+
tool,
|
|
651
|
+
toolArguments,
|
|
652
|
+
output,
|
|
653
|
+
env,
|
|
654
|
+
);
|
|
623
655
|
return;
|
|
624
656
|
}
|
|
625
657
|
clearHighMatchSurfaceIfOpened(
|
|
626
658
|
sessionId,
|
|
627
659
|
tool,
|
|
628
|
-
|
|
660
|
+
toolArguments,
|
|
661
|
+
env,
|
|
662
|
+
);
|
|
663
|
+
observeSuccessfulCompletionTool(
|
|
664
|
+
sessionId,
|
|
665
|
+
tool,
|
|
666
|
+
toolArguments,
|
|
667
|
+
output,
|
|
629
668
|
env,
|
|
630
669
|
);
|
|
631
670
|
} catch (error) {
|