opencode-team-memory 1.0.2 → 1.1.0

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/CHANGELOG.md CHANGED
@@ -1,5 +1,16 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.1.0
4
+
5
+ - Add `formatContinuation()` — generates role-aware continuation prompt
6
+ - Add `experimental.chat.system.transform` hook — injects role context at session start
7
+ - Add Context-Mode compatible JSON metadata to compaction snapshots
8
+ - Sessions now auto-restore role context on restart
9
+
10
+ ## 1.0.2
11
+
12
+ - Fix `scripts/preflight.sh` inclusion in npm tarball
13
+
3
14
  ## 1.0.1
4
15
 
5
16
  - Add `scripts/preflight.sh` — automated installation check
package/README.md CHANGED
@@ -3,6 +3,8 @@
3
3
  Persistent role-based memory for OpenCode + Oh-My-OpenCode(OmO) Team Mode.
4
4
  Context survives across sessions, Team Mode runs, and compaction.
5
5
 
6
+ **v1.1.0**: Auto-role restoration on session start — Agent recognizes its role without manual reload.
7
+
6
8
  ## Problem
7
9
 
8
10
  OmO Team Mode members are ephemeral — they die when the run ends (default: 120 min).
@@ -24,6 +26,39 @@ Override with `OPENCODE_TEAM_MEMORY_DIR` env var.
24
26
 
25
27
  Compaction hook injects compact summaries automatically — long sessions keep context.
26
28
 
29
+ ## Auto-Role Restoration (v1.1.0)
30
+
31
+ When opencode starts, the plugin checks saved role memory and injects a continuation prompt into the system prompt. The Agent automatically:
32
+
33
+ 1. Recognizes its role (engineer / tester / designer / director)
34
+ 2. Reads handoff state (who passed work and where it goes next)
35
+ 3. Sees recent NG items and critical decisions
36
+ 4. Knows confirmed and excluded scope
37
+
38
+ **No manual `role_memory_load` required.** The session starts with full context.
39
+
40
+ Output looks like:
41
+
42
+ ```
43
+ ## Team Continuation (opencode-team-memory)
44
+
45
+ ### Your Role: engineer
46
+ ### Handoff → tester
47
+ ### Status: ng_count=2
48
+ ### Critical Context
49
+ use postgres; adopt JWT; add rate limit
50
+ ### Recent NG Items
51
+ login redirect broken
52
+ token expiry too short
53
+ ### Confirmed Scope
54
+ - auth module
55
+
56
+ ### Instructions
57
+ 1. role_memory_load(role="engineer") before starting
58
+ 2. Handoff target is 'tester' — prepare output accordingly
59
+ 3. Address NG items first
60
+ ```
61
+
27
62
  ## Enable / Disable
28
63
 
29
64
  Toggle without editing config files. Restart `opencode` after switching.
package/index.ts CHANGED
@@ -2,7 +2,7 @@ import { type Plugin, tool } from "@opencode-ai/plugin"
2
2
  import { readFile, writeFile, mkdir, access } from "node:fs/promises"
3
3
  import { join } from "node:path"
4
4
  import { ALL_ROLES, EMPTY_MEMORY, type MemoryEntry, type Role, type SaveInput } from "./types"
5
- import { merge, format, formatCompact, formatSaveResult } from "./memory"
5
+ import { merge, format, formatCompact, formatSaveResult, formatContinuation } from "./memory"
6
6
 
7
7
  function getMemoryBase(directory: string): string {
8
8
  return process.env.OPENCODE_TEAM_MEMORY_DIR || join(directory, ".omo", "team-memory")
@@ -95,13 +95,43 @@ export const TeamMemoryPlugin: Plugin = async ({ directory }) => {
95
95
  for (const role of ALL_ROLES) {
96
96
  try {
97
97
  const entry = await load(role)
98
- if (entry) {
99
- output.context.push(formatCompact(entry))
100
- }
98
+ if (!entry) continue
99
+
100
+ // Human-readable compact summary
101
+ output.context.push(formatCompact(entry))
102
+
103
+ // Context-Mode compatible: structured metadata for FTS5 indexing
104
+ output.context.push(
105
+ JSON.stringify({
106
+ source: "opencode-team-memory",
107
+ role: entry.role,
108
+ handoff_to: entry.handoff_to,
109
+ ng_count: entry.ng_history.length,
110
+ decisions: entry.previous_decisions.slice(-3),
111
+ last_updated: entry.last_updated,
112
+ })
113
+ )
101
114
  } catch {
102
115
  // skip roles with no saved memory
103
116
  }
104
117
  }
105
118
  },
119
+
120
+ "experimental.chat.system.transform": async (_input, output) => {
121
+ const blocks: string[] = []
122
+ for (const role of ALL_ROLES) {
123
+ try {
124
+ const entry = await load(role)
125
+ if (!entry) continue
126
+ const block = formatContinuation(entry, role)
127
+ if (block) blocks.push(block)
128
+ } catch {
129
+ // skip corrupted files
130
+ }
131
+ }
132
+ if (blocks.length > 0) {
133
+ output.context.push(blocks.join("\n\n"))
134
+ }
135
+ },
106
136
  }
107
137
  }
package/memory.ts CHANGED
@@ -97,3 +97,50 @@ export function formatSaveResult(entry: MemoryEntry): string {
97
97
  entry.handoff_to ? ` Next: → ${entry.handoff_to}` : "",
98
98
  ].join("\n")
99
99
  }
100
+
101
+ export function formatContinuation(entry: MemoryEntry | null, role: Role): string {
102
+ if (!entry) return ""
103
+
104
+ const decisions = entry.previous_decisions.slice(-3).join("; ")
105
+ const ng = entry.ng_history.slice(-2)
106
+
107
+ const lines: string[] = [
108
+ "## Team Continuation (opencode-team-memory)",
109
+ "",
110
+ `### Your Role: ${role}`,
111
+ ]
112
+
113
+ if (entry.handoff_to) {
114
+ lines.push(`### Handoff → ${entry.handoff_to}`)
115
+ }
116
+
117
+ lines.push(`### Status: ng_count=${entry.ng_history.length}`)
118
+
119
+ if (decisions) {
120
+ lines.push(`### Critical Context\n${decisions}`)
121
+ }
122
+
123
+ if (ng.length > 0) {
124
+ lines.push(`### Recent NG Items\n${ng.join("\n")}`)
125
+ }
126
+
127
+ if (entry.confirmed_scope.length > 0) {
128
+ lines.push(`### Confirmed Scope\n${entry.confirmed_scope.map(s => `- ${s}`).join("\n")}`)
129
+ }
130
+
131
+ if (entry.excluded_scope.length > 0) {
132
+ lines.push(`### Excluded (DO NOT TOUCH)\n${entry.excluded_scope.map(s => `- ${s}`).join("\n")}`)
133
+ }
134
+
135
+ lines.push(
136
+ "",
137
+ "### Instructions",
138
+ `1. role_memory_load(role="${role}") before starting`,
139
+ entry.handoff_to ? `2. Handoff target is '${entry.handoff_to}' — prepare output accordingly` : "",
140
+ entry.ng_history.length > 0 ? `${entry.handoff_to ? "3" : "2"}. Address NG items first` : "",
141
+ "0. Resume work based on context above",
142
+ ""
143
+ )
144
+
145
+ return lines.filter(Boolean).join("\n")
146
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-team-memory",
3
- "version": "1.0.2",
3
+ "version": "1.1.0",
4
4
  "description": "Persistent role-based memory for OpenCode/OmO Team Mode — survives across sessions and runs",
5
5
  "type": "module",
6
6
  "main": "index.ts",
package/types.ts CHANGED
@@ -42,3 +42,14 @@ export interface SaveInput {
42
42
  handoff_to?: string
43
43
  raw?: string
44
44
  }
45
+
46
+ export interface ContinueState {
47
+ role: Role
48
+ handoff_to: string
49
+ last_action: string
50
+ ng_count: number
51
+ confirmed_scope: string[]
52
+ excluded_scope: string[]
53
+ decisions_summary: string
54
+ ng_summary: string
55
+ }