hivemind-context-governance 1.3.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.
Files changed (139) hide show
  1. package/CHANGELOG.md +95 -0
  2. package/LICENSE +21 -0
  3. package/README.md +218 -0
  4. package/dist/cli/init.d.ts +23 -0
  5. package/dist/cli/init.d.ts.map +1 -0
  6. package/dist/cli/init.js +175 -0
  7. package/dist/cli/init.js.map +1 -0
  8. package/dist/cli.d.ts +14 -0
  9. package/dist/cli.d.ts.map +1 -0
  10. package/dist/cli.js +162 -0
  11. package/dist/cli.js.map +1 -0
  12. package/dist/dashboard/i18n/en.d.ts +43 -0
  13. package/dist/dashboard/i18n/en.d.ts.map +1 -0
  14. package/dist/dashboard/i18n/en.js +43 -0
  15. package/dist/dashboard/i18n/en.js.map +1 -0
  16. package/dist/dashboard/i18n/index.d.ts +10 -0
  17. package/dist/dashboard/i18n/index.d.ts.map +1 -0
  18. package/dist/dashboard/i18n/index.js +14 -0
  19. package/dist/dashboard/i18n/index.js.map +1 -0
  20. package/dist/dashboard/i18n/vi.d.ts +43 -0
  21. package/dist/dashboard/i18n/vi.d.ts.map +1 -0
  22. package/dist/dashboard/i18n/vi.js +43 -0
  23. package/dist/dashboard/i18n/vi.js.map +1 -0
  24. package/dist/dashboard/server.d.ts +23 -0
  25. package/dist/dashboard/server.d.ts.map +1 -0
  26. package/dist/dashboard/server.js +282 -0
  27. package/dist/dashboard/server.js.map +1 -0
  28. package/dist/hooks/compaction.d.ts +21 -0
  29. package/dist/hooks/compaction.d.ts.map +1 -0
  30. package/dist/hooks/compaction.js +79 -0
  31. package/dist/hooks/compaction.js.map +1 -0
  32. package/dist/hooks/index.d.ts +8 -0
  33. package/dist/hooks/index.d.ts.map +1 -0
  34. package/dist/hooks/index.js +7 -0
  35. package/dist/hooks/index.js.map +1 -0
  36. package/dist/hooks/session-lifecycle.d.ts +28 -0
  37. package/dist/hooks/session-lifecycle.d.ts.map +1 -0
  38. package/dist/hooks/session-lifecycle.js +94 -0
  39. package/dist/hooks/session-lifecycle.js.map +1 -0
  40. package/dist/hooks/tool-gate.d.ts +28 -0
  41. package/dist/hooks/tool-gate.d.ts.map +1 -0
  42. package/dist/hooks/tool-gate.js +152 -0
  43. package/dist/hooks/tool-gate.js.map +1 -0
  44. package/dist/index.d.ts +19 -0
  45. package/dist/index.d.ts.map +1 -0
  46. package/dist/index.js +159 -0
  47. package/dist/index.js.map +1 -0
  48. package/dist/lib/complexity.d.ts +41 -0
  49. package/dist/lib/complexity.d.ts.map +1 -0
  50. package/dist/lib/complexity.js +67 -0
  51. package/dist/lib/complexity.js.map +1 -0
  52. package/dist/lib/context-refresh.d.ts +46 -0
  53. package/dist/lib/context-refresh.d.ts.map +1 -0
  54. package/dist/lib/context-refresh.js +77 -0
  55. package/dist/lib/context-refresh.js.map +1 -0
  56. package/dist/lib/index.d.ts +10 -0
  57. package/dist/lib/index.d.ts.map +1 -0
  58. package/dist/lib/index.js +10 -0
  59. package/dist/lib/index.js.map +1 -0
  60. package/dist/lib/logging.d.ts +13 -0
  61. package/dist/lib/logging.d.ts.map +1 -0
  62. package/dist/lib/logging.js +40 -0
  63. package/dist/lib/logging.js.map +1 -0
  64. package/dist/lib/persistence.d.ts +15 -0
  65. package/dist/lib/persistence.d.ts.map +1 -0
  66. package/dist/lib/persistence.js +62 -0
  67. package/dist/lib/persistence.js.map +1 -0
  68. package/dist/lib/planning-fs.d.ts +34 -0
  69. package/dist/lib/planning-fs.d.ts.map +1 -0
  70. package/dist/lib/planning-fs.js +134 -0
  71. package/dist/lib/planning-fs.js.map +1 -0
  72. package/dist/lib/sentiment.d.ts +31 -0
  73. package/dist/lib/sentiment.d.ts.map +1 -0
  74. package/dist/lib/sentiment.js +158 -0
  75. package/dist/lib/sentiment.js.map +1 -0
  76. package/dist/schemas/brain-state.d.ts +60 -0
  77. package/dist/schemas/brain-state.d.ts.map +1 -0
  78. package/dist/schemas/brain-state.js +176 -0
  79. package/dist/schemas/brain-state.js.map +1 -0
  80. package/dist/schemas/config.d.ts +51 -0
  81. package/dist/schemas/config.d.ts.map +1 -0
  82. package/dist/schemas/config.js +128 -0
  83. package/dist/schemas/config.js.map +1 -0
  84. package/dist/schemas/hierarchy.d.ts +22 -0
  85. package/dist/schemas/hierarchy.d.ts.map +1 -0
  86. package/dist/schemas/hierarchy.js +27 -0
  87. package/dist/schemas/hierarchy.js.map +1 -0
  88. package/dist/schemas/index.d.ts +7 -0
  89. package/dist/schemas/index.d.ts.map +1 -0
  90. package/dist/schemas/index.js +7 -0
  91. package/dist/schemas/index.js.map +1 -0
  92. package/dist/tools/compact-session.d.ts +15 -0
  93. package/dist/tools/compact-session.d.ts.map +1 -0
  94. package/dist/tools/compact-session.js +76 -0
  95. package/dist/tools/compact-session.js.map +1 -0
  96. package/dist/tools/declare-intent.d.ts +15 -0
  97. package/dist/tools/declare-intent.d.ts.map +1 -0
  98. package/dist/tools/declare-intent.js +83 -0
  99. package/dist/tools/declare-intent.js.map +1 -0
  100. package/dist/tools/index.d.ts +14 -0
  101. package/dist/tools/index.d.ts.map +1 -0
  102. package/dist/tools/index.js +14 -0
  103. package/dist/tools/index.js.map +1 -0
  104. package/dist/tools/map-context.d.ts +15 -0
  105. package/dist/tools/map-context.d.ts.map +1 -0
  106. package/dist/tools/map-context.js +85 -0
  107. package/dist/tools/map-context.js.map +1 -0
  108. package/dist/tools/self-rate.d.ts +15 -0
  109. package/dist/tools/self-rate.d.ts.map +1 -0
  110. package/dist/tools/self-rate.js +76 -0
  111. package/dist/tools/self-rate.js.map +1 -0
  112. package/package.json +71 -0
  113. package/src/cli/init.ts +214 -0
  114. package/src/cli.ts +178 -0
  115. package/src/dashboard/i18n/en.ts +43 -0
  116. package/src/dashboard/i18n/index.ts +20 -0
  117. package/src/dashboard/i18n/vi.ts +43 -0
  118. package/src/dashboard/server.ts +372 -0
  119. package/src/hooks/compaction.ts +104 -0
  120. package/src/hooks/index.ts +8 -0
  121. package/src/hooks/session-lifecycle.ts +133 -0
  122. package/src/hooks/tool-gate.ts +205 -0
  123. package/src/index.ts +206 -0
  124. package/src/lib/complexity.ts +96 -0
  125. package/src/lib/context-refresh.ts +107 -0
  126. package/src/lib/index.ts +10 -0
  127. package/src/lib/logging.ts +53 -0
  128. package/src/lib/persistence.ts +83 -0
  129. package/src/lib/planning-fs.ts +187 -0
  130. package/src/lib/sentiment.ts +183 -0
  131. package/src/schemas/brain-state.ts +257 -0
  132. package/src/schemas/config.ts +184 -0
  133. package/src/schemas/hierarchy.ts +58 -0
  134. package/src/schemas/index.ts +7 -0
  135. package/src/tools/compact-session.ts +97 -0
  136. package/src/tools/declare-intent.ts +104 -0
  137. package/src/tools/index.ts +14 -0
  138. package/src/tools/map-context.ts +105 -0
  139. package/src/tools/self-rate.ts +86 -0
@@ -0,0 +1,97 @@
1
+ /**
2
+ * compact_session — Archive completed work and reset for next session.
3
+ *
4
+ * Agent Thought: "I'm done, archive this session"
5
+ *
6
+ * Design: Agent-Native lifecycle verb.
7
+ * 1. Iceberg — 0-1 args, system handles archive + reset + index update
8
+ * 2. Context Inference — reads active session from brain state
9
+ * 3. Signal-to-Noise — 1-line summary output
10
+ * 4. No-Shadowing — description matches agent intent
11
+ * 5. Native Parallelism — single call, atomic archival
12
+ */
13
+
14
+ import { tool, type ToolDefinition } from "@opencode-ai/plugin/tool"
15
+ import { createStateManager, loadConfig } from "../lib/persistence.js"
16
+ import {
17
+ createBrainState,
18
+ generateSessionId,
19
+ lockSession,
20
+ } from "../schemas/brain-state.js"
21
+ import {
22
+ readActiveMd,
23
+ archiveSession,
24
+ updateIndexMd,
25
+ resetActiveMd,
26
+ listArchives,
27
+ } from "../lib/planning-fs.js"
28
+
29
+ export function createCompactSessionTool(directory: string): ToolDefinition {
30
+ return tool({
31
+ description:
32
+ "Archive completed work and reset for next session. " +
33
+ "Call this when you're done with your current work.",
34
+ args: {
35
+ summary: tool.schema
36
+ .string()
37
+ .optional()
38
+ .describe("Optional 1-line summary of what was accomplished"),
39
+ },
40
+ async execute(args) {
41
+ const stateManager = createStateManager(directory)
42
+ const config = await loadConfig(directory)
43
+
44
+ // Load brain state
45
+ const state = await stateManager.load()
46
+ if (!state) {
47
+ return "ERROR: No active session to compact."
48
+ }
49
+
50
+ // Read current active.md content for archival
51
+ const activeMd = await readActiveMd(directory)
52
+ const archiveContent = [
53
+ `# Archived Session: ${state.session.id}`,
54
+ "",
55
+ `**Mode**: ${state.session.mode}`,
56
+ `**Started**: ${new Date(state.session.start_time).toISOString()}`,
57
+ `**Archived**: ${new Date().toISOString()}`,
58
+ `**Turns**: ${state.metrics.turn_count}`,
59
+ `**Drift Score**: ${state.metrics.drift_score}/100`,
60
+ `**Files Touched**: ${state.metrics.files_touched.length}`,
61
+ `**Context Updates**: ${state.metrics.context_updates}`,
62
+ "",
63
+ "## Hierarchy at Archive",
64
+ state.hierarchy.trajectory ? `- **Trajectory**: ${state.hierarchy.trajectory}` : "",
65
+ state.hierarchy.tactic ? `- **Tactic**: ${state.hierarchy.tactic}` : "",
66
+ state.hierarchy.action ? `- **Action**: ${state.hierarchy.action}` : "",
67
+ "",
68
+ "## Session Content",
69
+ activeMd.body,
70
+ ]
71
+ .filter(Boolean)
72
+ .join("\n")
73
+
74
+ // Archive the session
75
+ await archiveSession(directory, state.session.id, archiveContent)
76
+
77
+ // Update index.md with summary
78
+ const summaryLine =
79
+ args.summary ||
80
+ `Session ${state.session.id}: ${state.metrics.turn_count} turns, ${state.metrics.files_touched.length} files`
81
+ await updateIndexMd(directory, summaryLine)
82
+
83
+ // Reset active.md to template
84
+ await resetActiveMd(directory)
85
+
86
+ // Create fresh brain state (new session, locked)
87
+ const newSessionId = generateSessionId()
88
+ const newState = createBrainState(newSessionId, config)
89
+ await stateManager.save(lockSession(newState))
90
+
91
+ // Count archives for output
92
+ const archives = await listArchives(directory)
93
+
94
+ return `Archived. ${state.metrics.turn_count} turns, ${state.metrics.files_touched.length} files saved. ${archives.length} total archives. Session reset.`
95
+ },
96
+ })
97
+ }
@@ -0,0 +1,104 @@
1
+ /**
2
+ * declare_intent — Unlock session by declaring work mode and focus.
3
+ *
4
+ * Agent Thought: "I want to start working on something"
5
+ *
6
+ * Design: Agent-Native lifecycle verb.
7
+ * 1. Iceberg — 2 args, system handles state machine + file writes
8
+ * 2. Context Inference — session ID from context, governance mode from config
9
+ * 3. Signal-to-Noise — 1-line output
10
+ * 4. No-Shadowing — description matches agent intent
11
+ * 5. Native Parallelism — idempotent, safe to call repeatedly
12
+ */
13
+
14
+ import { tool, type ToolDefinition } from "@opencode-ai/plugin/tool"
15
+ import { createStateManager, loadConfig } from "../lib/persistence.js"
16
+ import {
17
+ createBrainState,
18
+ generateSessionId,
19
+ unlockSession,
20
+ resetComplexityNudge,
21
+ } from "../schemas/brain-state.js"
22
+ import type { SessionMode } from "../schemas/brain-state.js"
23
+ import {
24
+ writeActiveMd,
25
+ readActiveMd,
26
+ initializePlanningDirectory,
27
+ } from "../lib/planning-fs.js"
28
+
29
+ const VALID_MODES: SessionMode[] = ["plan_driven", "quick_fix", "exploration"]
30
+
31
+ export function createDeclareIntentTool(directory: string): ToolDefinition {
32
+ return tool({
33
+ description:
34
+ "Unlock the session by declaring your work mode and focus. " +
35
+ "Call this before doing any work to set your intent.",
36
+ args: {
37
+ mode: tool.schema
38
+ .enum(VALID_MODES)
39
+ .describe("How are you approaching this work? plan_driven | quick_fix | exploration"),
40
+ focus: tool.schema
41
+ .string()
42
+ .describe("What are you working on? (1 sentence)"),
43
+ reason: tool.schema
44
+ .string()
45
+ .optional()
46
+ .describe("Why this mode? (optional context)"),
47
+ },
48
+ async execute(args) {
49
+ const config = await loadConfig(directory)
50
+ const stateManager = createStateManager(directory)
51
+
52
+ // Ensure planning directory exists
53
+ await initializePlanningDirectory(directory)
54
+
55
+ // Load or create brain state
56
+ let state = await stateManager.load()
57
+ if (!state) {
58
+ const sessionId = generateSessionId()
59
+ state = createBrainState(sessionId, config, args.mode)
60
+ }
61
+
62
+ // Unlock session
63
+ state = unlockSession(state)
64
+ state.session.mode = args.mode
65
+ state.hierarchy.trajectory = args.focus
66
+
67
+ // Reset complexity nudge on new intent declaration
68
+ state = resetComplexityNudge(state)
69
+
70
+ // Save state
71
+ await stateManager.save(state)
72
+
73
+ // Update active.md with session info
74
+ const activeMd = await readActiveMd(directory)
75
+ activeMd.frontmatter = {
76
+ session_id: state.session.id,
77
+ mode: args.mode,
78
+ governance_status: "OPEN",
79
+ start_time: state.session.start_time,
80
+ last_updated: Date.now(),
81
+ }
82
+ activeMd.body = [
83
+ "# Active Session",
84
+ "",
85
+ "## Current Focus",
86
+ `**Mode**: ${args.mode}`,
87
+ `**Focus**: ${args.focus}`,
88
+ args.reason ? `**Reason**: ${args.reason}` : "",
89
+ "",
90
+ "## Completed",
91
+ "<!-- Items marked [x] get archived -->",
92
+ "",
93
+ "## Notes",
94
+ "<!-- Scratchpad - anything goes -->",
95
+ ]
96
+ .filter(Boolean)
97
+ .join("\n")
98
+
99
+ await writeActiveMd(directory, activeMd)
100
+
101
+ return `Session: "${args.focus}". Mode: ${args.mode}. Status: OPEN.`
102
+ },
103
+ })
104
+ }
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Tool barrel exports — HiveMind lifecycle verbs
3
+ *
4
+ * 4 tools total:
5
+ * declare_intent — unlock session, set mode/focus
6
+ * map_context — update hierarchy level
7
+ * compact_session — archive + reset
8
+ * self_rate — agent self-assessment
9
+ */
10
+
11
+ export { createDeclareIntentTool } from "./declare-intent.js"
12
+ export { createMapContextTool } from "./map-context.js"
13
+ export { createCompactSessionTool } from "./compact-session.js"
14
+ export { createSelfRateTool } from "./self-rate.js"
@@ -0,0 +1,105 @@
1
+ /**
2
+ * map_context — Update focus in the 3-level hierarchy.
3
+ *
4
+ * Agent Thought: "I need to update what I'm focused on"
5
+ *
6
+ * Design: Agent-Native lifecycle verb.
7
+ * 1. Iceberg — 2 args, system handles hierarchy state + file sync
8
+ * 2. Context Inference — reads current hierarchy from brain state
9
+ * 3. Signal-to-Noise — 1-line output with visual beacon
10
+ * 4. No-Shadowing — description matches agent intent
11
+ * 5. Native Parallelism — can update different levels independently
12
+ */
13
+
14
+ import { tool, type ToolDefinition } from "@opencode-ai/plugin/tool"
15
+ import { createStateManager } from "../lib/persistence.js"
16
+ import {
17
+ resetTurnCount,
18
+ updateHierarchy,
19
+ } from "../schemas/brain-state.js"
20
+ import type { HierarchyLevel, ContextStatus } from "../schemas/hierarchy.js"
21
+ import {
22
+ readActiveMd,
23
+ writeActiveMd,
24
+ updateIndexMd,
25
+ } from "../lib/planning-fs.js"
26
+
27
+ const VALID_LEVELS: HierarchyLevel[] = ["trajectory", "tactic", "action"]
28
+ const VALID_STATUSES: ContextStatus[] = ["pending", "active", "complete", "blocked"]
29
+
30
+ export function createMapContextTool(directory: string): ToolDefinition {
31
+ return tool({
32
+ description:
33
+ "Update your current focus in the 3-level hierarchy. " +
34
+ "Call this when changing what you're working on.",
35
+ args: {
36
+ level: tool.schema
37
+ .enum(VALID_LEVELS)
38
+ .describe("Which level to update: trajectory | tactic | action"),
39
+ content: tool.schema
40
+ .string()
41
+ .describe("The new focus (1-2 sentences)"),
42
+ status: tool.schema
43
+ .enum(VALID_STATUSES)
44
+ .optional()
45
+ .describe("Status of this context item (default: active)"),
46
+ },
47
+ async execute(args) {
48
+ const stateManager = createStateManager(directory)
49
+ const status = args.status ?? "active"
50
+
51
+ // Load brain state
52
+ let state = await stateManager.load()
53
+ if (!state) {
54
+ return "ERROR: No active session. Call declare_intent first."
55
+ }
56
+
57
+ // Update hierarchy
58
+ state = updateHierarchy(state, { [args.level]: args.content })
59
+
60
+ // Reset turn count on context update (re-engagement signal)
61
+ state = resetTurnCount(state)
62
+
63
+ // Save state
64
+ await stateManager.save(state)
65
+
66
+ // Sync to planning files
67
+ if (args.level === "trajectory") {
68
+ // Update index.md for trajectory-level changes
69
+ await updateIndexMd(directory, `[${status.toUpperCase()}] ${args.content}`)
70
+ } else {
71
+ // Update active.md for tactic/action level changes
72
+ const activeMd = await readActiveMd(directory)
73
+ const levelLabel = args.level === "tactic" ? "Tactic" : "Action"
74
+ const focusLine = `**${levelLabel}**: ${args.content} [${status.toUpperCase()}]`
75
+
76
+ // Append to current focus section
77
+ if (activeMd.body.includes("## Current Focus")) {
78
+ const parts = activeMd.body.split("## Current Focus")
79
+ const afterFocus = parts[1] || ""
80
+ const nextSection = afterFocus.indexOf("\n## ")
81
+ const focusContent =
82
+ nextSection > -1 ? afterFocus.substring(0, nextSection) : afterFocus
83
+ const rest =
84
+ nextSection > -1 ? afterFocus.substring(nextSection) : ""
85
+
86
+ activeMd.body =
87
+ parts[0] +
88
+ "## Current Focus" +
89
+ focusContent.trimEnd() +
90
+ "\n" +
91
+ focusLine +
92
+ "\n" +
93
+ rest
94
+ } else {
95
+ activeMd.body += `\n## Current Focus\n${focusLine}\n`
96
+ }
97
+
98
+ activeMd.frontmatter.last_updated = Date.now()
99
+ await writeActiveMd(directory, activeMd)
100
+ }
101
+
102
+ return `[${args.level}] "${args.content}" → ${status}`
103
+ },
104
+ })
105
+ }
@@ -0,0 +1,86 @@
1
+ /**
2
+ * self_rate — Agent self-assessment tool for drift detection.
3
+ *
4
+ * Agent Thought: "How well am I doing? Let me rate my performance."
5
+ *
6
+ * Design: Agent-Native lifecycle verb.
7
+ * 1. Iceberg — 1-3 args, system handles storage
8
+ * 2. Context Inference — turn number from state
9
+ * 3. Signal-to-Noise — 1-line output
10
+ * 4. No-Shadowing — description matches agent intent
11
+ * 5. Native Parallelism — safe to call multiple times
12
+ */
13
+
14
+ import { tool, type ToolDefinition } from "@opencode-ai/plugin/tool"
15
+ import { createStateManager } from "../lib/persistence.js"
16
+ import { addSelfRating } from "../schemas/brain-state.js"
17
+ import { createLogger } from "../lib/logging.js"
18
+ import { join } from "node:path"
19
+
20
+ export function createSelfRateTool(directory: string): ToolDefinition {
21
+ return tool({
22
+ description:
23
+ "Rate your own performance on the current task. " +
24
+ "Call this periodically to help detect drift and track progress.",
25
+ args: {
26
+ score: tool.schema
27
+ .number()
28
+ .min(1)
29
+ .max(10)
30
+ .describe("Your self-assessment score from 1-10 (10 = excellent)"),
31
+ reason: tool.schema
32
+ .string()
33
+ .optional()
34
+ .describe("Why you gave this score (optional)"),
35
+ turn_context: tool.schema
36
+ .string()
37
+ .optional()
38
+ .describe("What you're working on right now (optional)"),
39
+ },
40
+ async execute(args) {
41
+ const stateManager = createStateManager(directory)
42
+ const log = await createLogger(
43
+ join(directory, ".opencode", "planning", "logs"),
44
+ "self-rate"
45
+ )
46
+
47
+ // Load current state
48
+ let state = await stateManager.load()
49
+ if (!state) {
50
+ return "ERROR: No active session. Call declare_intent first."
51
+ }
52
+
53
+ // Add the rating
54
+ state = addSelfRating(state, {
55
+ score: args.score,
56
+ reason: args.reason,
57
+ turn_context: args.turn_context,
58
+ })
59
+
60
+ // Save state
61
+ await stateManager.save(state)
62
+
63
+ // Log to TUI
64
+ const turnNumber = state.metrics.turn_count
65
+ const logMessage = `[SelfRate] Turn ${turnNumber}: ${args.score}/10`
66
+ await log.info(logMessage)
67
+
68
+ // Build response
69
+ let response = `Rating recorded: ${args.score}/10 at turn ${turnNumber}`
70
+ if (args.reason) {
71
+ response += ` — "${args.reason}"`
72
+ }
73
+
74
+ // Provide feedback based on score
75
+ if (args.score <= 3) {
76
+ response += "\n⚠️ Low score detected. Consider using compact_session to reset context."
77
+ } else if (args.score <= 7) {
78
+ response += "\n💡 Score suggests some drift. Consider map_context to refocus."
79
+ } else {
80
+ response += "\n✅ Good progress!"
81
+ }
82
+
83
+ return response
84
+ },
85
+ })
86
+ }