@remembrance-ai/opencode-plugin 0.1.73 → 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.
@@ -22,8 +22,8 @@ background and register a privacy-bounded runtime profile. They never transmit
22
22
  the hostname, username, config path, or repository path. Follow the returned
23
23
  machine-readable `next_action` rather than asking the user to invent an
24
24
  identity. Tool-observer and completion timestamps appear after those events
25
- become eligible; their absence during the first prompt is not, by itself, a
26
- failure.
25
+ become eligible. A fresh doctor reports them as informational; only a later
26
+ missed lifecycle opportunity raises an attention warning.
27
27
 
28
28
  If this skill is visible but `run_connection_doctor` is absent, explicitly tell
29
29
  the user that Remembrance is only partially active. Do not silently fall back
@@ -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.
@@ -176,8 +190,10 @@ nothing was sent and the encrypted draft remains local in
176
190
  `awaiting_authorization`; do not retry it through REST or another transport.
177
191
  Transient timeouts, 429s, and 5xx responses remain queued for bounded retry on a
178
192
  later lifecycle. Authentication, policy, or validation failures remain held.
179
- Queued lessons never expire or auto-delete; deleting one requires an explicit
180
- confirmed local action.
193
+ Unresolved and terminal lessons never expire or auto-delete; deleting one
194
+ requires an explicit confirmed local action. After a signed submission receipt
195
+ is verified, the encrypted lesson content is removed immediately and its
196
+ content-free completion marker is automatically deleted after 14 days.
181
197
 
182
198
  The signed policy pins `private-lesson-redaction-v2` and the exact digest of its
183
199
  current rules. An unsupported version or digest moves the encrypted draft to
@@ -188,14 +204,18 @@ terminal count, retained bytes, reason, and explicit deletion guidance without
188
204
  returning draft content or a local path.
189
205
 
190
206
  The private lesson endpoint derives its organization and private visibility
191
- from the authenticated key. It cannot create public content and never falls
192
- back to public submission. Accepted candidates enter the existing verifier,
193
- topology, review-policy, encrypted-storage, and audit pipelines. Rich content,
194
- raw traces, URLs, code blocks, attachments, secrets, paths, identifiers, or
195
- ambiguous material stays local and must not be forced through by confirmation.
196
- Use `inspect_private_lesson_outbox` to inspect content-free state, retry a
197
- selected draft with `retry_private_lesson_candidate`, and delete only with
198
- `delete_private_lesson_candidate` plus explicit confirmation.
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.
199
219
 
200
220
  When health reporting is enabled, a held draft may use the same exact submit
201
221
  action to send only a `held_safety_event`: event type, held category counts,
@@ -284,16 +284,23 @@ 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 endpoint can never create or automatically propagate
288
- public content.
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
292
296
  through REST, hosted MCP, or another transport. Timeouts, 429s, and 5xx
293
297
  responses retry with bounded backoff during later plugin lifecycles. A 401,
294
298
  403, policy change, or validation failure remains held for explicit repair.
295
- Drafts never expire or auto-delete. Inspect, retry, or explicitly delete one
296
- with the local private-lesson tools; deletion requires confirmation.
299
+ Unresolved and terminal drafts never expire or auto-delete. Inspect, retry, or
300
+ explicitly delete one with the local private-lesson tools; deletion requires
301
+ confirmation. After a signed submission receipt is verified, the encrypted
302
+ lesson content is removed immediately and its content-free completion marker
303
+ is automatically deleted after 14 days.
297
304
 
298
305
  The signed organization policy pins `private-lesson-redaction-v2` and its exact
299
306
  supported redactor digest. If either is unsupported, the finalized
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
- if (
617
- normalizedTool.endsWith("submit_feedback") &&
618
- responseRequestsRemembranceFollowup(output)
619
- ) {
620
- return;
621
- }
622
- markCurrentEngagementHandled(sessionId, env);
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
- toolArgumentsFromEvent(input),
660
+ toolArguments,
661
+ env,
662
+ );
663
+ observeSuccessfulCompletionTool(
664
+ sessionId,
665
+ tool,
666
+ toolArguments,
667
+ output,
629
668
  env,
630
669
  );
631
670
  } catch (error) {