@stevenvincentone/intidev-agentloops 0.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.
@@ -0,0 +1,101 @@
1
+ import { Ticket } from "./types";
2
+ export declare const KNOWLEDGE_SCHEMA_VERSION: 1;
3
+ export interface KnowledgeEntry {
4
+ id: string;
5
+ alias: string;
6
+ kind: string;
7
+ source: string;
8
+ family: string;
9
+ severity: string;
10
+ tags: string[];
11
+ title: string;
12
+ /** The original symptom (ticket summary). */
13
+ problem: string;
14
+ /** How it was fixed (ticket resolutionSummary). */
15
+ resolution: string;
16
+ verification?: string;
17
+ /** True when both a resolution and a verification record are present. */
18
+ verified: boolean;
19
+ guardStatus?: string;
20
+ guardSummary?: string;
21
+ resolvedAt?: string;
22
+ }
23
+ export interface KnowledgeSearchOptions {
24
+ family?: string;
25
+ kind?: string;
26
+ source?: string;
27
+ tag?: string;
28
+ /** Free-text query; every whitespace-separated term must appear. */
29
+ query?: string;
30
+ limit?: number;
31
+ }
32
+ export interface ResolutionKnowledgeReport {
33
+ schemaVersion: typeof KNOWLEDGE_SCHEMA_VERSION;
34
+ generatedAt: string;
35
+ filters: {
36
+ family: string | null;
37
+ kind: string | null;
38
+ source: string | null;
39
+ tag: string | null;
40
+ query: string | null;
41
+ };
42
+ summary: {
43
+ /** Resolved tickets that carry a resolution summary (the corpus size). */
44
+ resolvedWithKnowledge: number;
45
+ /** Of those, how many also have verification evidence. */
46
+ verified: number;
47
+ /** Entries returned after filters (before any limit). */
48
+ matched: number;
49
+ };
50
+ entries: KnowledgeEntry[];
51
+ }
52
+ /**
53
+ * Resolution-knowledge corpus (ported concept from Inti's resolution knowledge):
54
+ * the reusable record of how each resolved ticket was fixed, so an agent facing
55
+ * a new ticket can retrieve prior art by family/kind/source/tag/free text.
56
+ *
57
+ * Pure and deterministic apart from `generatedAt`. Newest resolutions first.
58
+ */
59
+ export declare function resolutionKnowledge(tickets: Ticket[], options?: KnowledgeSearchOptions): ResolutionKnowledgeReport;
60
+ export type KnowledgeGapReason = "no_resolution" | "unverified";
61
+ export interface KnowledgeGapsOptions {
62
+ family?: string;
63
+ severity?: string;
64
+ source?: string;
65
+ }
66
+ export interface KnowledgeGap {
67
+ id: string;
68
+ alias: string;
69
+ kind: string;
70
+ source: string;
71
+ family: string;
72
+ severity: string;
73
+ title: string;
74
+ reason: KnowledgeGapReason;
75
+ resolvedAt?: string;
76
+ }
77
+ export interface KnowledgeGapsReport {
78
+ schemaVersion: typeof KNOWLEDGE_SCHEMA_VERSION;
79
+ generatedAt: string;
80
+ filters: {
81
+ family: string | null;
82
+ severity: string | null;
83
+ source: string | null;
84
+ };
85
+ summary: {
86
+ resolved: number;
87
+ complete: number;
88
+ gaps: number;
89
+ noResolution: number;
90
+ unverified: number;
91
+ };
92
+ gaps: KnowledgeGap[];
93
+ }
94
+ /**
95
+ * Resolved tickets whose knowledge is incomplete for reuse: missing a resolution
96
+ * summary, or resolved without verification evidence. The contracts doc's
97
+ * `knowledge-gaps` cleanup backlog, scoped by family/severity/source.
98
+ *
99
+ * Pure and deterministic apart from `generatedAt`.
100
+ */
101
+ export declare function knowledgeGaps(tickets: Ticket[], options?: KnowledgeGapsOptions): KnowledgeGapsReport;
@@ -0,0 +1,155 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.KNOWLEDGE_SCHEMA_VERSION = void 0;
4
+ exports.resolutionKnowledge = resolutionKnowledge;
5
+ exports.knowledgeGaps = knowledgeGaps;
6
+ exports.KNOWLEDGE_SCHEMA_VERSION = 1;
7
+ function hasText(value) {
8
+ return Boolean(value && value.trim());
9
+ }
10
+ function toEntry(ticket) {
11
+ return {
12
+ id: ticket.id,
13
+ alias: ticket.aliases[0] ?? ticket.id,
14
+ kind: ticket.kind,
15
+ source: ticket.source,
16
+ family: ticket.family,
17
+ severity: ticket.severity,
18
+ tags: ticket.tags,
19
+ title: ticket.title,
20
+ problem: ticket.summary,
21
+ resolution: ticket.resolutionSummary ?? "",
22
+ verification: ticket.verification,
23
+ verified: hasText(ticket.resolutionSummary) && hasText(ticket.verification),
24
+ guardStatus: ticket.guardStatus,
25
+ guardSummary: ticket.guardSummary,
26
+ resolvedAt: ticket.resolvedAt,
27
+ };
28
+ }
29
+ function matchesQuery(entry, query) {
30
+ const haystack = [entry.title, entry.problem, entry.resolution, entry.tags.join(" ")]
31
+ .join(" ")
32
+ .toLowerCase();
33
+ return query
34
+ .toLowerCase()
35
+ .split(/\s+/)
36
+ .filter(Boolean)
37
+ .every((term) => haystack.includes(term));
38
+ }
39
+ /**
40
+ * Resolution-knowledge corpus (ported concept from Inti's resolution knowledge):
41
+ * the reusable record of how each resolved ticket was fixed, so an agent facing
42
+ * a new ticket can retrieve prior art by family/kind/source/tag/free text.
43
+ *
44
+ * Pure and deterministic apart from `generatedAt`. Newest resolutions first.
45
+ */
46
+ function resolutionKnowledge(tickets, options = {}) {
47
+ const corpus = tickets
48
+ .filter((ticket) => ticket.status === "resolved" && hasText(ticket.resolutionSummary))
49
+ .map(toEntry);
50
+ let entries = corpus;
51
+ if (options.family)
52
+ entries = entries.filter((entry) => entry.family === options.family);
53
+ if (options.kind)
54
+ entries = entries.filter((entry) => entry.kind === options.kind);
55
+ if (options.source)
56
+ entries = entries.filter((entry) => entry.source === options.source);
57
+ if (options.tag)
58
+ entries = entries.filter((entry) => entry.tags.includes(options.tag));
59
+ if (hasText(options.query)) {
60
+ entries = entries.filter((entry) => matchesQuery(entry, options.query));
61
+ }
62
+ entries = [...entries].sort((a, b) => (b.resolvedAt ?? "").localeCompare(a.resolvedAt ?? "") || a.id.localeCompare(b.id));
63
+ const matched = entries.length;
64
+ if (typeof options.limit === "number" && options.limit >= 0) {
65
+ entries = entries.slice(0, options.limit);
66
+ }
67
+ return {
68
+ schemaVersion: exports.KNOWLEDGE_SCHEMA_VERSION,
69
+ generatedAt: new Date().toISOString(),
70
+ filters: {
71
+ family: options.family ?? null,
72
+ kind: options.kind ?? null,
73
+ source: options.source ?? null,
74
+ tag: options.tag ?? null,
75
+ query: hasText(options.query) ? options.query : null,
76
+ },
77
+ summary: {
78
+ resolvedWithKnowledge: corpus.length,
79
+ verified: corpus.filter((entry) => entry.verified).length,
80
+ matched,
81
+ },
82
+ entries,
83
+ };
84
+ }
85
+ /**
86
+ * Resolved tickets whose knowledge is incomplete for reuse: missing a resolution
87
+ * summary, or resolved without verification evidence. The contracts doc's
88
+ * `knowledge-gaps` cleanup backlog, scoped by family/severity/source.
89
+ *
90
+ * Pure and deterministic apart from `generatedAt`.
91
+ */
92
+ function knowledgeGaps(tickets, options = {}) {
93
+ const resolved = tickets.filter((ticket) => {
94
+ if (ticket.status !== "resolved")
95
+ return false;
96
+ if (options.family && ticket.family !== options.family)
97
+ return false;
98
+ if (options.severity && ticket.severity !== options.severity)
99
+ return false;
100
+ if (options.source && ticket.source !== options.source)
101
+ return false;
102
+ return true;
103
+ });
104
+ let complete = 0;
105
+ let noResolution = 0;
106
+ let unverified = 0;
107
+ const gaps = [];
108
+ for (const ticket of resolved) {
109
+ const resolution = hasText(ticket.resolutionSummary);
110
+ const verification = hasText(ticket.verification);
111
+ if (resolution && verification) {
112
+ complete += 1;
113
+ continue;
114
+ }
115
+ const reason = resolution ? "unverified" : "no_resolution";
116
+ if (reason === "unverified")
117
+ unverified += 1;
118
+ else
119
+ noResolution += 1;
120
+ gaps.push({
121
+ id: ticket.id,
122
+ alias: ticket.aliases[0] ?? ticket.id,
123
+ kind: ticket.kind,
124
+ source: ticket.source,
125
+ family: ticket.family,
126
+ severity: ticket.severity,
127
+ title: ticket.title,
128
+ reason,
129
+ resolvedAt: ticket.resolvedAt,
130
+ });
131
+ }
132
+ gaps.sort((a, b) => {
133
+ if (a.reason !== b.reason)
134
+ return a.reason === "no_resolution" ? -1 : 1;
135
+ return a.id.localeCompare(b.id);
136
+ });
137
+ return {
138
+ schemaVersion: exports.KNOWLEDGE_SCHEMA_VERSION,
139
+ generatedAt: new Date().toISOString(),
140
+ filters: {
141
+ family: options.family ?? null,
142
+ severity: options.severity ?? null,
143
+ source: options.source ?? null,
144
+ },
145
+ summary: {
146
+ resolved: resolved.length,
147
+ complete,
148
+ gaps: gaps.length,
149
+ noResolution,
150
+ unverified,
151
+ },
152
+ gaps,
153
+ };
154
+ }
155
+ //# sourceMappingURL=knowledge.js.map
package/dist/mcp.d.ts ADDED
@@ -0,0 +1,130 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import { AgentLoopStore } from "./store";
3
+ import { StateBackend } from "./backend";
4
+ import { Confidence, GuardStatus, NoteType, Pattern, ProjectConfig, Severity, Ticket } from "./types";
5
+ /**
6
+ * Schema version for the MCP tool envelopes. Bump only on breaking changes;
7
+ * add fields freely during dogfood (see docs/tickets agent JSON contracts).
8
+ */
9
+ export declare const MCP_SCHEMA_VERSION: 1;
10
+ export declare const MCP_SERVER_NAME = "agentloop";
11
+ interface Envelope {
12
+ schemaVersion: typeof MCP_SCHEMA_VERSION;
13
+ generatedAt: string;
14
+ }
15
+ export interface SummaryResult extends Envelope {
16
+ summary: Awaited<ReturnType<AgentLoopStore["summary"]>>;
17
+ }
18
+ export interface ListResult extends Envelope {
19
+ filters: {
20
+ status: string;
21
+ kind: string | null;
22
+ };
23
+ count: number;
24
+ tickets: Ticket[];
25
+ }
26
+ export interface ShowTicketResult extends Envelope {
27
+ kind: "ticket";
28
+ ticket: Ticket;
29
+ }
30
+ export interface ShowPatternResult extends Envelope {
31
+ kind: "pattern";
32
+ pattern: Pattern;
33
+ }
34
+ export type ShowResult = ShowTicketResult | ShowPatternResult;
35
+ export interface HandoffResult extends Envelope {
36
+ ticketId: string;
37
+ aliases: string[];
38
+ prompt: string;
39
+ }
40
+ /**
41
+ * Pure read-only tool implementations. These are transport-agnostic and
42
+ * deterministic apart from `generatedAt`, so they can be unit-tested directly
43
+ * without standing up an MCP transport.
44
+ */
45
+ export declare function summaryTool(store: AgentLoopStore): Promise<SummaryResult>;
46
+ export declare function listTool(store: AgentLoopStore, args?: {
47
+ status?: string;
48
+ kind?: string;
49
+ }): Promise<ListResult>;
50
+ export declare function showTool(store: AgentLoopStore, args: {
51
+ id: string;
52
+ }): Promise<ShowResult>;
53
+ export declare function handoffTool(store: AgentLoopStore, args: {
54
+ id: string;
55
+ }): Promise<HandoffResult>;
56
+ /**
57
+ * Write tools (opt-in via `allowWrites`). These mutate the ledger and are
58
+ * disabled by default; an agent gets the read-only surface unless the operator
59
+ * explicitly enables writes.
60
+ */
61
+ export type WriteAction = "created" | "noted" | "workflow" | "resolved" | "guard";
62
+ export interface WriteResult extends Envelope {
63
+ action: WriteAction;
64
+ ticket: Ticket;
65
+ }
66
+ export declare const SEVERITIES: readonly ["low", "medium", "high", "critical"];
67
+ export declare const CONFIDENCES: readonly ["low", "medium", "high"];
68
+ export declare const NOTE_TYPES: readonly ["hypothesis", "related_history", "prior_fix", "triage", "investigation"];
69
+ export declare const GUARD_STATUSES: readonly ["guard_added", "guard_existing", "guard_waived", "guard_deferred", "none"];
70
+ /** Workflow transitions exposed over MCP. `resolved` has its own tool. */
71
+ export declare const WORKFLOW_STATUSES: readonly ["active", "reopened", "deferred"];
72
+ /** Source recorded for tickets/notes created by an MCP agent client. */
73
+ export declare const MCP_ACTOR_SOURCE = "agent";
74
+ export declare function createTicketTool(store: AgentLoopStore, args: {
75
+ summary: string;
76
+ title?: string;
77
+ family?: string;
78
+ kind?: string;
79
+ source?: string;
80
+ severity?: Severity;
81
+ confidence?: Confidence;
82
+ tags?: string[];
83
+ handoff?: string;
84
+ }): Promise<WriteResult>;
85
+ export declare function noteTool(store: AgentLoopStore, args: {
86
+ id: string;
87
+ body: string;
88
+ type?: NoteType;
89
+ author?: string;
90
+ }): Promise<WriteResult>;
91
+ export declare function workflowTool(store: AgentLoopStore, args: {
92
+ id: string;
93
+ status: (typeof WORKFLOW_STATUSES)[number];
94
+ reason?: string;
95
+ }): Promise<WriteResult>;
96
+ export declare function resolveTool(store: AgentLoopStore, args: {
97
+ id: string;
98
+ summary: string;
99
+ verification?: string;
100
+ guardStatus?: GuardStatus;
101
+ guardSummary?: string;
102
+ }): Promise<WriteResult>;
103
+ export declare function guardTool(store: AgentLoopStore, args: {
104
+ id: string;
105
+ guardStatus: GuardStatus;
106
+ guardSummary?: string;
107
+ }): Promise<WriteResult>;
108
+ export interface CreateMcpServerOptions {
109
+ version?: string;
110
+ /** Register the mutating write tools. Off by default (read-only surface). */
111
+ allowWrites?: boolean;
112
+ }
113
+ /**
114
+ * Build an MCP server over the given store. By default only the read-only tools
115
+ * are exposed; pass `allowWrites: true` to also register the guarded write
116
+ * tools (create / note / workflow / resolve / guard).
117
+ */
118
+ export declare function createMcpServer(store: AgentLoopStore, options?: CreateMcpServerOptions): McpServer;
119
+ /**
120
+ * Start the AgentLoops MCP server over stdio. Reads/writes JSON-RPC on
121
+ * stdin/stdout, so nothing else may be written to stdout while it runs.
122
+ */
123
+ export declare function startStdioMcpServer(opts: {
124
+ cwd: string;
125
+ config: ProjectConfig;
126
+ version?: string;
127
+ allowWrites?: boolean;
128
+ backend?: StateBackend;
129
+ }): Promise<void>;
130
+ export {};