@devspecai/pi-plugin 0.0.0-stage → 0.10.3

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 (106) hide show
  1. package/CHANGELOG.md +899 -0
  2. package/LICENSE +21 -0
  3. package/README.md +103 -2
  4. package/extensions/.gitkeep +0 -0
  5. package/extensions/core/activation-recovery.ts +135 -0
  6. package/extensions/core/active-deliveries.ts +171 -0
  7. package/extensions/core/active-session-plans.ts +374 -0
  8. package/extensions/core/adapter-overlap.ts +247 -0
  9. package/extensions/core/assistant-speech.ts +44 -0
  10. package/extensions/core/attach-context.ts +25 -0
  11. package/extensions/core/attachment-limits.ts +20 -0
  12. package/extensions/core/attachments.ts +487 -0
  13. package/extensions/core/auth-store.ts +91 -0
  14. package/extensions/core/automation-run-retry.ts +31 -0
  15. package/extensions/core/background-journal.ts +85 -0
  16. package/extensions/core/background-observer.ts +279 -0
  17. package/extensions/core/bond-recovery.ts +65 -0
  18. package/extensions/core/bond-state.ts +80 -0
  19. package/extensions/core/clear-conversation.ts +53 -0
  20. package/extensions/core/client-versions.ts +56 -0
  21. package/extensions/core/client.ts +704 -0
  22. package/extensions/core/command-offer.ts +88 -0
  23. package/extensions/core/command-runner.ts +62 -0
  24. package/extensions/core/command-turn.ts +88 -0
  25. package/extensions/core/commit-ledger.ts +195 -0
  26. package/extensions/core/commit-stamp.ts +98 -0
  27. package/extensions/core/config.ts +63 -0
  28. package/extensions/core/connection-context.ts +28 -0
  29. package/extensions/core/context-budget.ts +175 -0
  30. package/extensions/core/control-result-outbox.ts +80 -0
  31. package/extensions/core/control.ts +156 -0
  32. package/extensions/core/ctx-guard.ts +33 -0
  33. package/extensions/core/debug.ts +136 -0
  34. package/extensions/core/delivery-queue.ts +92 -0
  35. package/extensions/core/dispatch.ts +108 -0
  36. package/extensions/core/duck.ts +128 -0
  37. package/extensions/core/git-observer.ts +382 -0
  38. package/extensions/core/github-identity.ts +26 -0
  39. package/extensions/core/implementation-contract.ts +773 -0
  40. package/extensions/core/instructions.ts +40 -0
  41. package/extensions/core/interaction-events.ts +834 -0
  42. package/extensions/core/json-schema.ts +16 -0
  43. package/extensions/core/local-activity.ts +34 -0
  44. package/extensions/core/mcp-config-guard.ts +117 -0
  45. package/extensions/core/model-catalog.ts +76 -0
  46. package/extensions/core/model-surface.ts +125 -0
  47. package/extensions/core/notice-reply.ts +215 -0
  48. package/extensions/core/owner-inject.ts +148 -0
  49. package/extensions/core/post-session-receipt.ts +70 -0
  50. package/extensions/core/preempt.ts +100 -0
  51. package/extensions/core/project-choice.ts +145 -0
  52. package/extensions/core/project-scope.ts +335 -0
  53. package/extensions/core/project-selection-ui.ts +202 -0
  54. package/extensions/core/provenance-refs.ts +158 -0
  55. package/extensions/core/push-channel.ts +281 -0
  56. package/extensions/core/question-receipt-lifecycle.ts +158 -0
  57. package/extensions/core/recall.ts +121 -0
  58. package/extensions/core/remote-payload.ts +1329 -0
  59. package/extensions/core/remote-session-arg.ts +24 -0
  60. package/extensions/core/repository-context.ts +35 -0
  61. package/extensions/core/request-chain.ts +1244 -0
  62. package/extensions/core/result-projection.ts +939 -0
  63. package/extensions/core/result.ts +100 -0
  64. package/extensions/core/review-context.ts +70 -0
  65. package/extensions/core/review-watch.ts +94 -0
  66. package/extensions/core/room-access.ts +12 -0
  67. package/extensions/core/room-context.ts +178 -0
  68. package/extensions/core/room-reader.ts +308 -0
  69. package/extensions/core/room-store.ts +381 -0
  70. package/extensions/core/room-sync.ts +79 -0
  71. package/extensions/core/room-tools.ts +86 -0
  72. package/extensions/core/room-unread.ts +173 -0
  73. package/extensions/core/session-events.ts +62 -0
  74. package/extensions/core/session-polls.ts +292 -0
  75. package/extensions/core/settings.ts +39 -0
  76. package/extensions/core/status-line.ts +432 -0
  77. package/extensions/core/still-to-discuss.ts +124 -0
  78. package/extensions/core/subagent-fleet.ts +238 -0
  79. package/extensions/core/system-notice.ts +227 -0
  80. package/extensions/core/telemetry.ts +177 -0
  81. package/extensions/core/tool-selection.ts +72 -0
  82. package/extensions/core/trail-events.ts +247 -0
  83. package/extensions/core/trail-projection.ts +373 -0
  84. package/extensions/core/trail.ts +465 -0
  85. package/extensions/core/turn-lifecycle.ts +472 -0
  86. package/extensions/core/version-mismatch.ts +165 -0
  87. package/extensions/core/work-prompt.ts +44 -0
  88. package/extensions/core/work-state.ts +179 -0
  89. package/extensions/devspec-adapter-guard.ts +106 -0
  90. package/extensions/devspec-auth.ts +191 -0
  91. package/extensions/devspec-brand.ts +140 -0
  92. package/extensions/devspec-commit-ledger.ts +477 -0
  93. package/extensions/devspec-context.ts +146 -0
  94. package/extensions/devspec-memory.ts +136 -0
  95. package/extensions/devspec-provenance-assistance.ts +233 -0
  96. package/extensions/devspec-remote.ts +5152 -0
  97. package/extensions/devspec-tools.ts +552 -0
  98. package/extensions/devspec-work.ts +244 -0
  99. package/extensions/generated/README.md +18 -0
  100. package/extensions/generated/mcp-catalog.ts +15811 -0
  101. package/package.json +71 -4
  102. package/prompts/.gitkeep +0 -0
  103. package/runtime/commit-stamp.mjs +279 -0
  104. package/runtime/git-observer-shim.mjs +390 -0
  105. package/skills/.gitkeep +0 -0
  106. package/themes/.gitkeep +0 -0
@@ -0,0 +1,121 @@
1
+ /**
2
+ * DevSpec Pi — proactive memory recall (pure helpers, unit-tested).
3
+ *
4
+ * The flagship of the intelligence layer: recall happens BEFORE the model
5
+ * thinks, not when it remembers to search. Each substantive turn's prompt is
6
+ * searched against project memory mechanically; new snapshots append as tail
7
+ * messages. Revision/finding-aware dedupe avoids repeating unchanged context
8
+ * without hiding later changes or rewriting old message bytes.
9
+ */
10
+
11
+ import { disagreementBlock, reviewData, snapshotHash } from "./review-context.ts";
12
+
13
+ export interface MemoryCard extends Record<string, unknown> {
14
+ id?: string;
15
+ title?: string;
16
+ summary?: string;
17
+ type?: string;
18
+ state?: string;
19
+ }
20
+
21
+ /** A prompt shorter than this ("ok", "yes do it") is not worth the search a recall costs. */
22
+ const MIN_PROMPT_CHARS = 40;
23
+ /**
24
+ * Automatic recall rides every substantive turn, so it injects only the few
25
+ * highest-ranked agreed memories and says the rest of the ranking is one
26
+ * search_memories call away. A bound on per-turn cost; the model's own searches
27
+ * are not affected by it.
28
+ */
29
+ const MAX_CARDS = 4;
30
+
31
+ /** Only substantive prompts are worth a recall search (and its ~300ms). */
32
+ export function shouldRecall(prompt: string): boolean {
33
+ const p = prompt.trim();
34
+ if (p.length < MIN_PROMPT_CHARS) return false;
35
+ if (p.startsWith("/")) return false; // slash commands aren't topics
36
+ return true;
37
+ }
38
+
39
+ /** The whole prompt, on one line: what the person asked is the query, not its first few hundred characters. */
40
+ export function recallQuery(prompt: string): string {
41
+ return prompt.replace(/\s+/g, " ").trim();
42
+ }
43
+
44
+ /**
45
+ * Automatic context is agreed-only (DevSpec decision a9e001e7e): a memory still
46
+ * in discussion is not recalled unasked. It stays one search_memories call away.
47
+ */
48
+ export function isAgreed(card: MemoryCard): boolean {
49
+ return card.state === "decided";
50
+ }
51
+
52
+ /** Extract cards from a search_memories payload, defensively. */
53
+ export function extractCards(payload: unknown): MemoryCard[] {
54
+ const d = payload as { memories?: unknown; results?: unknown } | null;
55
+ const rows = (Array.isArray(d?.memories) ? d.memories : Array.isArray(d?.results) ? d.results : []) as MemoryCard[];
56
+ return rows.filter((r) => r && typeof r === "object");
57
+ }
58
+
59
+ /**
60
+ * Which of these cards have we not yet injected this session?
61
+ * `seen` holds exact snapshot keys already injected in this account/project/session.
62
+ */
63
+ export function unseenCards(cards: MemoryCard[], seen: Set<string>): MemoryCard[] {
64
+ const out: MemoryCard[] = [];
65
+ const selected = new Set(seen);
66
+ for (const c of cards) {
67
+ const key = cardKey(c);
68
+ if (!key || selected.has(key)) continue;
69
+ selected.add(key);
70
+ out.push(c);
71
+ if (out.length >= MAX_CARDS) break;
72
+ }
73
+ return out;
74
+ }
75
+
76
+ export function cardKey(c: MemoryCard): string | null {
77
+ if (!c.id && !c.title) return null;
78
+ // Includes version, assessment, permissions and proposal changes. A same-ID
79
+ // changed finding is a NEW tail snapshot, never an edit of an earlier message.
80
+ // updated_at is a row-maintenance clock (indexing, review stamps, flags),
81
+ // not a knowledge revision. Keep all other context, including nested finding
82
+ // evidence, so genuine changes still reinject. Follow-up 8effd88f.
83
+ const { updated_at: _maintenanceClock, ...snapshot } = c;
84
+ return `${c.id ?? c.title}:${snapshotHash(snapshot)}`;
85
+ }
86
+
87
+ /** Card fields rendered by their own blocks, or a row-maintenance clock that is not knowledge. */
88
+ const CARD_KEYS_RENDERED_APART = new Set(["id", "title", "summary", "type", "unresolved_disagreements", "disagreements_not_shown", "pending_proposals", "updated_at"]);
89
+
90
+ function cardDetails(c: MemoryCard): Record<string, unknown> {
91
+ const rest: Record<string, unknown> = {};
92
+ for (const [key, value] of Object.entries(c)) {
93
+ if (CARD_KEYS_RENDERED_APART.has(key) || value === null || value === undefined) continue;
94
+ if ((Array.isArray(value) && value.length === 0) || (typeof value === "string" && value.trim() === "")) continue;
95
+ rest[key] = value;
96
+ }
97
+ return rest;
98
+ }
99
+
100
+ /**
101
+ * Each card as DevSpec sent it — its state, delivery label, companions, pending
102
+ * versions — with only the row-maintenance clock left out. `notAgreed` counts the
103
+ * ranked memories still in discussion that were left out of automatic recall.
104
+ */
105
+ export function formatRecallBlock(cards: MemoryCard[], notAgreed = 0): string {
106
+ const lines = cards.map((c) => {
107
+ const type = c.type ? `[${c.type}]` : "[memory]";
108
+ const summary = c.summary ? ` — ${c.summary}` : "";
109
+ const id = c.id ? ` (${c.id})` : "";
110
+ const disagreement = disagreementBlock(c);
111
+ const proposals = Array.isArray(c.pending_proposals) && c.pending_proposals.length
112
+ ? reviewData({ pending_proposals: c.pending_proposals }) : "";
113
+ return [reviewData({ memory: `- ${type} ${c.title ?? "untitled"}${id}${summary}`, ...cardDetails(c) }), disagreement, proposals].filter(Boolean).join("\n");
114
+ });
115
+ return [
116
+ "### DevSpec memory — auto-recall",
117
+ "The project's agreed memories that rank highest against this turn's prompt. The ranking orders every memory by words and meaning; it does not judge that these apply, so decide which do. One that applies binds the work outside any disputed clause: read it in full with get_memory before relying on it. Disagreement data is not a ruling: preserve unaffected requirements and consult the served authority contract if this task depends on the disputed claim.",
118
+ ...lines,
119
+ `${notAgreed > 0 ? `${notAgreed} more ranked memor${notAgreed === 1 ? "y is" : "ies are"} still in discussion and not recalled automatically. ` : ""}search_memories with your own query shows the rest of the ranking.`,
120
+ ].join("\n");
121
+ }