@pixelguild/loom 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.
Files changed (117) hide show
  1. package/dist/cli/index.d.ts +3 -0
  2. package/dist/cli/index.d.ts.map +1 -0
  3. package/dist/cli/index.js +45 -0
  4. package/dist/cli/index.js.map +1 -0
  5. package/dist/cli/init.d.ts +9 -0
  6. package/dist/cli/init.d.ts.map +1 -0
  7. package/dist/cli/init.js +129 -0
  8. package/dist/cli/init.js.map +1 -0
  9. package/dist/cli/output.d.ts +6 -0
  10. package/dist/cli/output.d.ts.map +1 -0
  11. package/dist/cli/output.js +20 -0
  12. package/dist/cli/output.js.map +1 -0
  13. package/dist/cli/status.d.ts +13 -0
  14. package/dist/cli/status.d.ts.map +1 -0
  15. package/dist/cli/status.js +69 -0
  16. package/dist/cli/status.js.map +1 -0
  17. package/dist/config/config-loader.d.ts +9 -0
  18. package/dist/config/config-loader.d.ts.map +1 -0
  19. package/dist/config/config-loader.js +64 -0
  20. package/dist/config/config-loader.js.map +1 -0
  21. package/dist/config/types.d.ts +32 -0
  22. package/dist/config/types.d.ts.map +1 -0
  23. package/dist/config/types.js +2 -0
  24. package/dist/config/types.js.map +1 -0
  25. package/dist/index.d.ts +2 -0
  26. package/dist/index.d.ts.map +1 -0
  27. package/dist/index.js +32 -0
  28. package/dist/index.js.map +1 -0
  29. package/dist/lib/slugify.d.ts +2 -0
  30. package/dist/lib/slugify.d.ts.map +1 -0
  31. package/dist/lib/slugify.js +9 -0
  32. package/dist/lib/slugify.js.map +1 -0
  33. package/dist/lib/tokens.d.ts +2 -0
  34. package/dist/lib/tokens.d.ts.map +1 -0
  35. package/dist/lib/tokens.js +15 -0
  36. package/dist/lib/tokens.js.map +1 -0
  37. package/dist/providers/ollama-provider.d.ts +11 -0
  38. package/dist/providers/ollama-provider.d.ts.map +1 -0
  39. package/dist/providers/ollama-provider.js +37 -0
  40. package/dist/providers/ollama-provider.js.map +1 -0
  41. package/dist/providers/openai-provider.d.ts +10 -0
  42. package/dist/providers/openai-provider.d.ts.map +1 -0
  43. package/dist/providers/openai-provider.js +25 -0
  44. package/dist/providers/openai-provider.js.map +1 -0
  45. package/dist/providers/provider-factory.d.ts +5 -0
  46. package/dist/providers/provider-factory.d.ts.map +1 -0
  47. package/dist/providers/provider-factory.js +19 -0
  48. package/dist/providers/provider-factory.js.map +1 -0
  49. package/dist/providers/types.d.ts +11 -0
  50. package/dist/providers/types.d.ts.map +1 -0
  51. package/dist/providers/types.js +2 -0
  52. package/dist/providers/types.js.map +1 -0
  53. package/dist/providers/vertex-provider.d.ts +12 -0
  54. package/dist/providers/vertex-provider.d.ts.map +1 -0
  55. package/dist/providers/vertex-provider.js +32 -0
  56. package/dist/providers/vertex-provider.js.map +1 -0
  57. package/dist/server.d.ts +4 -0
  58. package/dist/server.d.ts.map +1 -0
  59. package/dist/server.js +143 -0
  60. package/dist/server.js.map +1 -0
  61. package/dist/storage/archive.d.ts +22 -0
  62. package/dist/storage/archive.d.ts.map +1 -0
  63. package/dist/storage/archive.js +114 -0
  64. package/dist/storage/archive.js.map +1 -0
  65. package/dist/storage/context-file.d.ts +16 -0
  66. package/dist/storage/context-file.d.ts.map +1 -0
  67. package/dist/storage/context-file.js +68 -0
  68. package/dist/storage/context-file.js.map +1 -0
  69. package/dist/storage/database.d.ts +28 -0
  70. package/dist/storage/database.d.ts.map +1 -0
  71. package/dist/storage/database.js +195 -0
  72. package/dist/storage/database.js.map +1 -0
  73. package/dist/storage/intelligent-archive.d.ts +36 -0
  74. package/dist/storage/intelligent-archive.d.ts.map +1 -0
  75. package/dist/storage/intelligent-archive.js +183 -0
  76. package/dist/storage/intelligent-archive.js.map +1 -0
  77. package/dist/tools/archive-context.d.ts +7 -0
  78. package/dist/tools/archive-context.d.ts.map +1 -0
  79. package/dist/tools/archive-context.js +60 -0
  80. package/dist/tools/archive-context.js.map +1 -0
  81. package/dist/tools/consult-peer.d.ts +18 -0
  82. package/dist/tools/consult-peer.d.ts.map +1 -0
  83. package/dist/tools/consult-peer.js +48 -0
  84. package/dist/tools/consult-peer.js.map +1 -0
  85. package/dist/tools/create-manifest.d.ts +14 -0
  86. package/dist/tools/create-manifest.d.ts.map +1 -0
  87. package/dist/tools/create-manifest.js +23 -0
  88. package/dist/tools/create-manifest.js.map +1 -0
  89. package/dist/tools/find-pattern.d.ts +14 -0
  90. package/dist/tools/find-pattern.d.ts.map +1 -0
  91. package/dist/tools/find-pattern.js +13 -0
  92. package/dist/tools/find-pattern.js.map +1 -0
  93. package/dist/tools/get-context.d.ts +9 -0
  94. package/dist/tools/get-context.d.ts.map +1 -0
  95. package/dist/tools/get-context.js +11 -0
  96. package/dist/tools/get-context.js.map +1 -0
  97. package/dist/tools/get-manifest.d.ts +21 -0
  98. package/dist/tools/get-manifest.d.ts.map +1 -0
  99. package/dist/tools/get-manifest.js +53 -0
  100. package/dist/tools/get-manifest.js.map +1 -0
  101. package/dist/tools/get-session-status.d.ts +3 -0
  102. package/dist/tools/get-session-status.d.ts.map +1 -0
  103. package/dist/tools/get-session-status.js +20 -0
  104. package/dist/tools/get-session-status.js.map +1 -0
  105. package/dist/tools/log-context.d.ts +13 -0
  106. package/dist/tools/log-context.d.ts.map +1 -0
  107. package/dist/tools/log-context.js +29 -0
  108. package/dist/tools/log-context.js.map +1 -0
  109. package/dist/tools/save-pattern.d.ts +15 -0
  110. package/dist/tools/save-pattern.d.ts.map +1 -0
  111. package/dist/tools/save-pattern.js +19 -0
  112. package/dist/tools/save-pattern.js.map +1 -0
  113. package/dist/types.d.ts +54 -0
  114. package/dist/types.d.ts.map +1 -0
  115. package/dist/types.js +2 -0
  116. package/dist/types.js.map +1 -0
  117. package/package.json +53 -0
@@ -0,0 +1,10 @@
1
+ import type { PeerProvider, PeerResponse } from './types.js';
2
+ import type { OpenAIProviderConfig } from '../config/types.js';
3
+ export declare class OpenAIProvider implements PeerProvider {
4
+ readonly name = "openai";
5
+ private readonly model;
6
+ constructor(config?: OpenAIProviderConfig);
7
+ isAvailable(): boolean;
8
+ call(prompt: string): Promise<PeerResponse>;
9
+ }
10
+ //# sourceMappingURL=openai-provider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openai-provider.d.ts","sourceRoot":"","sources":["../../src/providers/openai-provider.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC7D,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAE/D,qBAAa,cAAe,YAAW,YAAY;IACjD,QAAQ,CAAC,IAAI,YAAY;IACzB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAS;gBAEnB,MAAM,CAAC,EAAE,oBAAoB;IAIzC,WAAW,IAAI,OAAO;IAKhB,IAAI,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;CAalD"}
@@ -0,0 +1,25 @@
1
+ import OpenAI from 'openai';
2
+ export class OpenAIProvider {
3
+ name = 'openai';
4
+ model;
5
+ constructor(config) {
6
+ this.model = config?.model ?? 'gpt-4o';
7
+ }
8
+ isAvailable() {
9
+ const key = process.env['LOOM_OPENAI_API_KEY'];
10
+ return typeof key === 'string' && key.length > 0;
11
+ }
12
+ async call(prompt) {
13
+ const client = new OpenAI({ apiKey: process.env['LOOM_OPENAI_API_KEY'] });
14
+ const response = await client.responses.create({
15
+ model: this.model,
16
+ input: prompt,
17
+ });
18
+ return {
19
+ response: response.output_text,
20
+ model: this.model,
21
+ tokens_used: response.usage?.total_tokens,
22
+ };
23
+ }
24
+ }
25
+ //# sourceMappingURL=openai-provider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openai-provider.js","sourceRoot":"","sources":["../../src/providers/openai-provider.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,QAAQ,CAAC;AAI5B,MAAM,OAAO,cAAc;IAChB,IAAI,GAAG,QAAQ,CAAC;IACR,KAAK,CAAS;IAE/B,YAAY,MAA6B;QACvC,IAAI,CAAC,KAAK,GAAG,MAAM,EAAE,KAAK,IAAI,QAAQ,CAAC;IACzC,CAAC;IAED,WAAW;QACT,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,qBAAqB,CAAC,CAAC;QAC/C,OAAO,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC;IACnD,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,MAAc;QACvB,MAAM,MAAM,GAAG,IAAI,MAAM,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,qBAAqB,CAAC,EAAE,CAAC,CAAC;QAC1E,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC;YAC7C,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,KAAK,EAAE,MAAM;SACd,CAAC,CAAC;QAEH,OAAO;YACL,QAAQ,EAAE,QAAQ,CAAC,WAAW;YAC9B,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,WAAW,EAAE,QAAQ,CAAC,KAAK,EAAE,YAAY;SAC1C,CAAC;IACJ,CAAC;CACF"}
@@ -0,0 +1,5 @@
1
+ import type { PeerProvider } from './types.js';
2
+ import type { LoomConfig } from '../config/types.js';
3
+ export declare function createProvider(name: string, config: LoomConfig): PeerProvider;
4
+ export declare function resolveProviderName(requested: string | undefined, config: LoomConfig): string;
5
+ //# sourceMappingURL=provider-factory.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provider-factory.d.ts","sourceRoot":"","sources":["../../src/providers/provider-factory.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC/C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAKrD,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,GAAG,YAAY,CAW7E;AAED,wBAAgB,mBAAmB,CACjC,SAAS,EAAE,MAAM,GAAG,SAAS,EAC7B,MAAM,EAAE,UAAU,GACjB,MAAM,CAER"}
@@ -0,0 +1,19 @@
1
+ import { OpenAIProvider } from './openai-provider.js';
2
+ import { VertexProvider } from './vertex-provider.js';
3
+ import { OllamaProvider } from './ollama-provider.js';
4
+ export function createProvider(name, config) {
5
+ switch (name) {
6
+ case 'openai':
7
+ return new OpenAIProvider(config.providers.openai);
8
+ case 'vertex':
9
+ return new VertexProvider(config.providers.vertex);
10
+ case 'ollama':
11
+ return new OllamaProvider(config.providers.ollama);
12
+ default:
13
+ throw new Error(`Unknown provider: ${name}`);
14
+ }
15
+ }
16
+ export function resolveProviderName(requested, config) {
17
+ return requested ?? config.default_provider;
18
+ }
19
+ //# sourceMappingURL=provider-factory.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provider-factory.js","sourceRoot":"","sources":["../../src/providers/provider-factory.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAEtD,MAAM,UAAU,cAAc,CAAC,IAAY,EAAE,MAAkB;IAC7D,QAAQ,IAAI,EAAE,CAAC;QACb,KAAK,QAAQ;YACX,OAAO,IAAI,cAAc,CAAC,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;QACrD,KAAK,QAAQ;YACX,OAAO,IAAI,cAAc,CAAC,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;QACrD,KAAK,QAAQ;YACX,OAAO,IAAI,cAAc,CAAC,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;QACrD;YACE,MAAM,IAAI,KAAK,CAAC,qBAAqB,IAAI,EAAE,CAAC,CAAC;IACjD,CAAC;AACH,CAAC;AAED,MAAM,UAAU,mBAAmB,CACjC,SAA6B,EAC7B,MAAkB;IAElB,OAAO,SAAS,IAAI,MAAM,CAAC,gBAAgB,CAAC;AAC9C,CAAC"}
@@ -0,0 +1,11 @@
1
+ export interface PeerResponse {
2
+ response: string;
3
+ model: string;
4
+ tokens_used?: number;
5
+ }
6
+ export interface PeerProvider {
7
+ readonly name: string;
8
+ isAvailable(): boolean;
9
+ call(prompt: string): Promise<PeerResponse>;
10
+ }
11
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/providers/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,WAAW,IAAI,OAAO,CAAC;IACvB,IAAI,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;CAC7C"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/providers/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,12 @@
1
+ import type { PeerProvider, PeerResponse } from './types.js';
2
+ import type { VertexProviderConfig } from '../config/types.js';
3
+ export declare class VertexProvider implements PeerProvider {
4
+ readonly name = "vertex";
5
+ private readonly model;
6
+ private readonly project;
7
+ private readonly location;
8
+ constructor(config?: VertexProviderConfig);
9
+ isAvailable(): boolean;
10
+ call(prompt: string): Promise<PeerResponse>;
11
+ }
12
+ //# sourceMappingURL=vertex-provider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vertex-provider.d.ts","sourceRoot":"","sources":["../../src/providers/vertex-provider.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC7D,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAE/D,qBAAa,cAAe,YAAW,YAAY;IACjD,QAAQ,CAAC,IAAI,YAAY;IACzB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAS;IAC/B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;gBAEtB,MAAM,CAAC,EAAE,oBAAoB;IAMzC,WAAW,IAAI,OAAO;IAIhB,IAAI,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;CAmBlD"}
@@ -0,0 +1,32 @@
1
+ import { VertexAI } from '@google-cloud/vertexai';
2
+ export class VertexProvider {
3
+ name = 'vertex';
4
+ model;
5
+ project;
6
+ location;
7
+ constructor(config) {
8
+ this.model = config?.model ?? 'gemini-2.0-flash';
9
+ this.project = config?.project ?? '';
10
+ this.location = config?.location ?? 'us-central1';
11
+ }
12
+ isAvailable() {
13
+ return this.project.length > 0;
14
+ }
15
+ async call(prompt) {
16
+ const vertexAI = new VertexAI({
17
+ project: this.project,
18
+ location: this.location,
19
+ });
20
+ const generativeModel = vertexAI.getGenerativeModel({ model: this.model });
21
+ const result = await generativeModel.generateContent(prompt);
22
+ const response = result.response;
23
+ const text = response.candidates?.[0]?.content?.parts?.[0]?.text ?? '';
24
+ const tokensUsed = response.usageMetadata?.totalTokenCount;
25
+ return {
26
+ response: text,
27
+ model: this.model,
28
+ tokens_used: tokensUsed,
29
+ };
30
+ }
31
+ }
32
+ //# sourceMappingURL=vertex-provider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vertex-provider.js","sourceRoot":"","sources":["../../src/providers/vertex-provider.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAIlD,MAAM,OAAO,cAAc;IAChB,IAAI,GAAG,QAAQ,CAAC;IACR,KAAK,CAAS;IACd,OAAO,CAAS;IAChB,QAAQ,CAAS;IAElC,YAAY,MAA6B;QACvC,IAAI,CAAC,KAAK,GAAG,MAAM,EAAE,KAAK,IAAI,kBAAkB,CAAC;QACjD,IAAI,CAAC,OAAO,GAAG,MAAM,EAAE,OAAO,IAAI,EAAE,CAAC;QACrC,IAAI,CAAC,QAAQ,GAAG,MAAM,EAAE,QAAQ,IAAI,aAAa,CAAC;IACpD,CAAC;IAED,WAAW;QACT,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC;IACjC,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,MAAc;QACvB,MAAM,QAAQ,GAAG,IAAI,QAAQ,CAAC;YAC5B,OAAO,EAAE,IAAI,CAAC,OAAO;YACrB,QAAQ,EAAE,IAAI,CAAC,QAAQ;SACxB,CAAC,CAAC;QAEH,MAAM,eAAe,GAAG,QAAQ,CAAC,kBAAkB,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC;QAC3E,MAAM,MAAM,GAAG,MAAM,eAAe,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC;QAC7D,MAAM,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC;QAEjC,MAAM,IAAI,GAAG,QAAQ,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,IAAI,EAAE,CAAC;QACvE,MAAM,UAAU,GAAG,QAAQ,CAAC,aAAa,EAAE,eAAe,CAAC;QAE3D,OAAO;YACL,QAAQ,EAAE,IAAI;YACd,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,WAAW,EAAE,UAAU;SACxB,CAAC;IACJ,CAAC;CACF"}
@@ -0,0 +1,4 @@
1
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ import type { LoomContext } from './types.js';
3
+ export declare function createServer(loomCtx: LoomContext): McpServer;
4
+ //# sourceMappingURL=server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAWpE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C,wBAAgB,YAAY,CAAC,OAAO,EAAE,WAAW,GAAG,SAAS,CAyL5D"}
package/dist/server.js ADDED
@@ -0,0 +1,143 @@
1
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ import { z } from 'zod';
3
+ import { handleLogContext } from './tools/log-context.js';
4
+ import { handleGetContext } from './tools/get-context.js';
5
+ import { handleGetSessionStatus } from './tools/get-session-status.js';
6
+ import { handleArchiveContext } from './tools/archive-context.js';
7
+ import { handleSavePattern } from './tools/save-pattern.js';
8
+ import { handleFindPattern } from './tools/find-pattern.js';
9
+ import { handleCreateManifest } from './tools/create-manifest.js';
10
+ import { handleGetManifest } from './tools/get-manifest.js';
11
+ import { handleConsultPeer } from './tools/consult-peer.js';
12
+ export function createServer(loomCtx) {
13
+ const server = new McpServer({
14
+ name: 'loom',
15
+ version: '0.1.0',
16
+ });
17
+ server.registerTool('loom_log_context', {
18
+ title: 'Log Context',
19
+ description: 'Append a structured log entry to the session context. Call after every significant action, decision, or discovery.',
20
+ inputSchema: {
21
+ type: z
22
+ .enum(['decision', 'action', 'issue', 'question', 'dead_end', 'session_end'])
23
+ .describe('The type of log entry'),
24
+ summary: z.string().describe('One-line description of what happened'),
25
+ detail: z.string().optional().describe('Optional longer explanation'),
26
+ },
27
+ }, async (input) => {
28
+ const result = await handleLogContext(loomCtx, input);
29
+ return {
30
+ content: [{ type: 'text', text: JSON.stringify(result) }],
31
+ };
32
+ });
33
+ server.registerTool('loom_get_context', {
34
+ title: 'Get Context',
35
+ description: 'Read the current session context. Call at the start of every session before doing any work.',
36
+ }, async () => {
37
+ const result = await handleGetContext(loomCtx);
38
+ return {
39
+ content: [{ type: 'text', text: JSON.stringify(result) }],
40
+ };
41
+ });
42
+ server.registerTool('loom_get_session_status', {
43
+ title: 'Get Session Status',
44
+ description: 'Return current context token count, archive count, and threshold status. Check periodically to monitor context health.',
45
+ }, async () => {
46
+ const result = await handleGetSessionStatus(loomCtx);
47
+ return {
48
+ content: [{ type: 'text', text: JSON.stringify(result) }],
49
+ };
50
+ });
51
+ server.registerTool('loom_archive_context', {
52
+ title: 'Archive Context',
53
+ description: 'Archive older context entries when context.md grows too large. Moves older entries to a timestamped archive file and keeps recent entries active.',
54
+ inputSchema: {
55
+ force: z
56
+ .boolean()
57
+ .optional()
58
+ .describe('Archive even if below token threshold'),
59
+ },
60
+ }, async (input) => {
61
+ const result = await handleArchiveContext(loomCtx, { force: input.force });
62
+ return {
63
+ content: [{ type: 'text', text: JSON.stringify(result) }],
64
+ };
65
+ });
66
+ server.registerTool('loom_save_pattern', {
67
+ title: 'Save Pattern',
68
+ description: 'Save a reusable implementation pattern to the global library. Patterns are searchable across all projects.',
69
+ inputSchema: {
70
+ name: z.string().describe('Human-readable name for the pattern'),
71
+ content: z.string().describe('The pattern content (code, config, explanation)'),
72
+ tags: z.array(z.string()).optional().describe('Tags for categorization (language, framework, topic)'),
73
+ },
74
+ }, async (input) => {
75
+ const result = await handleSavePattern(loomCtx, input);
76
+ return {
77
+ content: [{ type: 'text', text: JSON.stringify(result) }],
78
+ };
79
+ });
80
+ server.registerTool('loom_find_pattern', {
81
+ title: 'Find Pattern',
82
+ description: 'Search the global pattern library for reusable implementations. Call before implementing anything non-trivial.',
83
+ inputSchema: {
84
+ query: z.string().describe('Search terms'),
85
+ tags: z.array(z.string()).optional().describe('Filter by tags'),
86
+ project: z.string().optional().describe('Filter by source project path'),
87
+ limit: z.number().optional().describe('Max results (default 5)'),
88
+ },
89
+ }, async (input) => {
90
+ const result = await handleFindPattern(loomCtx, {
91
+ query: input.query,
92
+ tags: input.tags,
93
+ project: input.project,
94
+ limit: input.limit,
95
+ });
96
+ return {
97
+ content: [{ type: 'text', text: JSON.stringify(result) }],
98
+ };
99
+ });
100
+ server.registerTool('loom_create_manifest', {
101
+ title: 'Create Manifest',
102
+ description: 'Save a structured execution manifest for headless Claude Code runs. Provide the plan content — the tool generates header, footer, and launch command.',
103
+ inputSchema: {
104
+ name: z.string().describe('Human-readable name for the manifest (used as filename)'),
105
+ content: z.string().describe('Structured manifest body (decisions, ordered tasks, file targets, ambiguities, env requirements)'),
106
+ },
107
+ }, async (input) => {
108
+ const result = await handleCreateManifest(loomCtx, input);
109
+ return {
110
+ content: [{ type: 'text', text: JSON.stringify(result) }],
111
+ };
112
+ });
113
+ server.registerTool('loom_get_manifest', {
114
+ title: 'Get Manifest',
115
+ description: 'List available manifests (no arguments) or retrieve a specific manifest by name.',
116
+ inputSchema: {
117
+ name: z.string().optional().describe('Manifest name to retrieve. Omit to list all manifests.'),
118
+ },
119
+ }, async (input) => {
120
+ const result = await handleGetManifest(loomCtx, { name: input.name });
121
+ return {
122
+ content: [{ type: 'text', text: JSON.stringify(result) }],
123
+ };
124
+ });
125
+ server.registerTool('loom_consult_peer', {
126
+ title: 'Consult Peer LLM',
127
+ description: 'Ask a peer LLM (OpenAI, Vertex AI, or Ollama) for a second opinion on a problem. Useful for architecture decisions, debugging, or getting alternative perspectives.',
128
+ inputSchema: {
129
+ problem: z.string().describe('Brief description of the problem or decision'),
130
+ context: z.string().describe('Relevant context (project type, constraints, what you have tried)'),
131
+ code: z.string().optional().describe('Optional code snippet relevant to the question'),
132
+ question: z.string().describe('The specific question to ask the peer LLM'),
133
+ provider: z.string().optional().describe('Override default provider (openai, vertex, ollama)'),
134
+ },
135
+ }, async (input) => {
136
+ const result = await handleConsultPeer(loomCtx, input);
137
+ return {
138
+ content: [{ type: 'text', text: JSON.stringify(result) }],
139
+ };
140
+ });
141
+ return server;
142
+ }
143
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Splits the raw content of a context.md file into individual entries.
3
+ * Each entry starts with a ### [TYPE] timestamp header and ends before the next entry.
4
+ * Trailing separators (---) are included as part of each entry.
5
+ */
6
+ export declare function splitEntries(content: string): string[];
7
+ /**
8
+ * Generates an archive filename following the YYYY-MM-DD-NNN.md pattern.
9
+ * Increments the sequence number based on existing archives for the given date.
10
+ */
11
+ export declare function generateArchiveFilename(existingArchives: string[], dateStr: string): string;
12
+ /**
13
+ * Performs the archive operation on a project's context.md file.
14
+ * Moves the oldest ~60% of entries into an archive file and keeps
15
+ * the newest ~40% in context.md with an Active State header.
16
+ */
17
+ export declare function performMechanicalArchive(projectRoot: string): {
18
+ archived: boolean;
19
+ archiveFile?: string;
20
+ message?: string;
21
+ };
22
+ //# sourceMappingURL=archive.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"archive.d.ts","sourceRoot":"","sources":["../../src/storage/archive.ts"],"names":[],"mappings":"AAIA;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAwBtD;AAoBD;;;GAGG;AACH,wBAAgB,uBAAuB,CAAC,gBAAgB,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAW3F;AAED;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,WAAW,EAAE,MAAM,GAAG;IAC7D,QAAQ,EAAE,OAAO,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAmDA"}
@@ -0,0 +1,114 @@
1
+ import { ContextFile } from './context-file.js';
2
+ const ENTRY_HEADER_PATTERN = /^### \[\w+\] \d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}/;
3
+ /**
4
+ * Splits the raw content of a context.md file into individual entries.
5
+ * Each entry starts with a ### [TYPE] timestamp header and ends before the next entry.
6
+ * Trailing separators (---) are included as part of each entry.
7
+ */
8
+ export function splitEntries(content) {
9
+ const lines = content.split('\n');
10
+ const entries = [];
11
+ let current = [];
12
+ let inEntry = false;
13
+ for (const line of lines) {
14
+ if (ENTRY_HEADER_PATTERN.test(line)) {
15
+ if (inEntry && current.length > 0) {
16
+ entries.push(trimEntry(current));
17
+ }
18
+ current = [line];
19
+ inEntry = true;
20
+ }
21
+ else if (inEntry) {
22
+ current.push(line);
23
+ }
24
+ }
25
+ // Push the last entry
26
+ if (inEntry && current.length > 0) {
27
+ entries.push(trimEntry(current));
28
+ }
29
+ return entries;
30
+ }
31
+ /**
32
+ * Trims trailing whitespace and standalone separator lines from an entry,
33
+ * then returns the cleaned string.
34
+ */
35
+ function trimEntry(lines) {
36
+ // Remove trailing empty lines and standalone '---' lines
37
+ let end = lines.length;
38
+ while (end > 0) {
39
+ const line = lines[end - 1].trim();
40
+ if (line === '' || line === '---') {
41
+ end--;
42
+ }
43
+ else {
44
+ break;
45
+ }
46
+ }
47
+ return lines.slice(0, end).join('\n').trim();
48
+ }
49
+ /**
50
+ * Generates an archive filename following the YYYY-MM-DD-NNN.md pattern.
51
+ * Increments the sequence number based on existing archives for the given date.
52
+ */
53
+ export function generateArchiveFilename(existingArchives, dateStr) {
54
+ const todayArchives = existingArchives.filter(a => a.startsWith(dateStr));
55
+ let maxSeq = 0;
56
+ for (const archive of todayArchives) {
57
+ const match = archive.match(/-(\d{3})\.md$/);
58
+ if (match) {
59
+ maxSeq = Math.max(maxSeq, parseInt(match[1], 10));
60
+ }
61
+ }
62
+ const seq = String(maxSeq + 1).padStart(3, '0');
63
+ return `${dateStr}-${seq}.md`;
64
+ }
65
+ /**
66
+ * Performs the archive operation on a project's context.md file.
67
+ * Moves the oldest ~60% of entries into an archive file and keeps
68
+ * the newest ~40% in context.md with an Active State header.
69
+ */
70
+ export function performMechanicalArchive(projectRoot) {
71
+ const contextFile = new ContextFile(projectRoot);
72
+ const content = contextFile.read();
73
+ const entries = splitEntries(content);
74
+ if (entries.length < 2) {
75
+ return { archived: false, message: 'Not enough entries to archive' };
76
+ }
77
+ // Split: ~60% oldest go to archive, ~40% newest stay
78
+ const keepCount = Math.max(1, Math.ceil(entries.length * 0.4));
79
+ const archiveEntries = entries.slice(0, entries.length - keepCount);
80
+ const keepEntries = entries.slice(entries.length - keepCount);
81
+ // Generate archive filename
82
+ const existingArchives = contextFile.listArchives();
83
+ const today = new Date().toISOString().slice(0, 10);
84
+ const archiveFilename = generateArchiveFilename(existingArchives, today);
85
+ // Write archive file
86
+ const archiveContent = [
87
+ `# Archive: ${archiveFilename}`,
88
+ `Archived: ${new Date().toISOString()}`,
89
+ '',
90
+ archiveEntries.join('\n\n---\n\n'),
91
+ '',
92
+ ].join('\n');
93
+ contextFile.writeArchive(archiveFilename, archiveContent);
94
+ // Extract a summary from the first kept entry for the "continuing from" line
95
+ const firstKeptEntry = keepEntries[0];
96
+ const summaryMatch = firstKeptEntry.match(/^### \[.+\]\s.+\n(.+)/);
97
+ const continuingFrom = summaryMatch ? summaryMatch[1].trim() : 'previous session';
98
+ // Rewrite context.md with Active State header + kept entries
99
+ const newContent = [
100
+ '# Session Context',
101
+ '',
102
+ '## Active State',
103
+ `Archived to: ${archiveFilename}`,
104
+ `Continuing from: ${continuingFrom}`,
105
+ '',
106
+ ...keepEntries.map(entry => entry + '\n\n---\n'),
107
+ ].join('\n');
108
+ contextFile.write(newContent);
109
+ return {
110
+ archived: true,
111
+ archiveFile: archiveFilename,
112
+ };
113
+ }
114
+ //# sourceMappingURL=archive.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"archive.js","sourceRoot":"","sources":["../../src/storage/archive.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAEhD,MAAM,oBAAoB,GAAG,kDAAkD,CAAC;AAEhF;;;;GAIG;AACH,MAAM,UAAU,YAAY,CAAC,OAAe;IAC1C,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAClC,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,IAAI,OAAO,GAAa,EAAE,CAAC;IAC3B,IAAI,OAAO,GAAG,KAAK,CAAC;IAEpB,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,oBAAoB,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;YACpC,IAAI,OAAO,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAClC,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC;YACnC,CAAC;YACD,OAAO,GAAG,CAAC,IAAI,CAAC,CAAC;YACjB,OAAO,GAAG,IAAI,CAAC;QACjB,CAAC;aAAM,IAAI,OAAO,EAAE,CAAC;YACnB,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACrB,CAAC;IACH,CAAC;IAED,sBAAsB;IACtB,IAAI,OAAO,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAClC,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC;IACnC,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;;GAGG;AACH,SAAS,SAAS,CAAC,KAAe;IAChC,yDAAyD;IACzD,IAAI,GAAG,GAAG,KAAK,CAAC,MAAM,CAAC;IACvB,OAAO,GAAG,GAAG,CAAC,EAAE,CAAC;QACf,MAAM,IAAI,GAAG,KAAK,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QACnC,IAAI,IAAI,KAAK,EAAE,IAAI,IAAI,KAAK,KAAK,EAAE,CAAC;YAClC,GAAG,EAAE,CAAC;QACR,CAAC;aAAM,CAAC;YACN,MAAM;QACR,CAAC;IACH,CAAC;IACD,OAAO,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC;AAC/C,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,uBAAuB,CAAC,gBAA0B,EAAE,OAAe;IACjF,MAAM,aAAa,GAAG,gBAAgB,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC;IAC1E,IAAI,MAAM,GAAG,CAAC,CAAC;IACf,KAAK,MAAM,OAAO,IAAI,aAAa,EAAE,CAAC;QACpC,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC;QAC7C,IAAI,KAAK,EAAE,CAAC;YACV,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;QACpD,CAAC;IACH,CAAC;IACD,MAAM,GAAG,GAAG,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IAChD,OAAO,GAAG,OAAO,IAAI,GAAG,KAAK,CAAC;AAChC,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,wBAAwB,CAAC,WAAmB;IAK1D,MAAM,WAAW,GAAG,IAAI,WAAW,CAAC,WAAW,CAAC,CAAC;IACjD,MAAM,OAAO,GAAG,WAAW,CAAC,IAAI,EAAE,CAAC;IACnC,MAAM,OAAO,GAAG,YAAY,CAAC,OAAO,CAAC,CAAC;IAEtC,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACvB,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,OAAO,EAAE,+BAA+B,EAAE,CAAC;IACvE,CAAC;IAED,qDAAqD;IACrD,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,GAAG,CAAC,CAAC,CAAC;IAC/D,MAAM,cAAc,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IACpE,MAAM,WAAW,GAAG,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IAE9D,4BAA4B;IAC5B,MAAM,gBAAgB,GAAG,WAAW,CAAC,YAAY,EAAE,CAAC;IACpD,MAAM,KAAK,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IACpD,MAAM,eAAe,GAAG,uBAAuB,CAAC,gBAAgB,EAAE,KAAK,CAAC,CAAC;IAEzE,qBAAqB;IACrB,MAAM,cAAc,GAAG;QACrB,cAAc,eAAe,EAAE;QAC/B,aAAa,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,EAAE;QACvC,EAAE;QACF,cAAc,CAAC,IAAI,CAAC,aAAa,CAAC;QAClC,EAAE;KACH,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACb,WAAW,CAAC,YAAY,CAAC,eAAe,EAAE,cAAc,CAAC,CAAC;IAE1D,6EAA6E;IAC7E,MAAM,cAAc,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC;IACtC,MAAM,YAAY,GAAG,cAAc,CAAC,KAAK,CAAC,uBAAuB,CAAC,CAAC;IACnE,MAAM,cAAc,GAAG,YAAY,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,kBAAkB,CAAC;IAElF,6DAA6D;IAC7D,MAAM,UAAU,GAAG;QACjB,mBAAmB;QACnB,EAAE;QACF,iBAAiB;QACjB,gBAAgB,eAAe,EAAE;QACjC,oBAAoB,cAAc,EAAE;QACpC,EAAE;QACF,GAAG,WAAW,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,GAAG,WAAW,CAAC;KACjD,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAEb,WAAW,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;IAE9B,OAAO;QACL,QAAQ,EAAE,IAAI;QACd,WAAW,EAAE,eAAe;KAC7B,CAAC;AACJ,CAAC"}
@@ -0,0 +1,16 @@
1
+ import type { LogEntry } from '../types.js';
2
+ export declare class ContextFile {
3
+ private readonly loomDir;
4
+ private readonly contextFilePath;
5
+ private readonly archivesDir;
6
+ constructor(projectRoot: string);
7
+ initialize(): void;
8
+ read(): string;
9
+ append(entry: LogEntry): void;
10
+ write(content: string): void;
11
+ listArchives(): string[];
12
+ writeArchive(filename: string, content: string): void;
13
+ readArchive(filename: string): string | null;
14
+ getLastEntryTimestamp(): string | null;
15
+ }
16
+ //# sourceMappingURL=context-file.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context-file.d.ts","sourceRoot":"","sources":["../../src/storage/context-file.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAE5C,qBAAa,WAAW;IACtB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAS;IACzC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;gBAEzB,WAAW,EAAE,MAAM;IAM/B,UAAU,IAAI,IAAI;IAOlB,IAAI,IAAI,MAAM;IAOd,MAAM,CAAC,KAAK,EAAE,QAAQ,GAAG,IAAI;IAW7B,KAAK,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAK5B,YAAY,IAAI,MAAM,EAAE;IASxB,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI;IAKrD,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAQ5C,qBAAqB,IAAI,MAAM,GAAG,IAAI;CAUvC"}
@@ -0,0 +1,68 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ export class ContextFile {
4
+ loomDir;
5
+ contextFilePath;
6
+ archivesDir;
7
+ constructor(projectRoot) {
8
+ this.loomDir = path.join(projectRoot, 'docs', 'loom');
9
+ this.contextFilePath = path.join(this.loomDir, 'context.md');
10
+ this.archivesDir = path.join(this.loomDir, 'archives');
11
+ }
12
+ initialize() {
13
+ fs.mkdirSync(this.archivesDir, { recursive: true });
14
+ if (!fs.existsSync(this.contextFilePath)) {
15
+ fs.writeFileSync(this.contextFilePath, '# Session Context\n\n');
16
+ }
17
+ }
18
+ read() {
19
+ if (!fs.existsSync(this.contextFilePath)) {
20
+ return '';
21
+ }
22
+ return fs.readFileSync(this.contextFilePath, 'utf-8');
23
+ }
24
+ append(entry) {
25
+ this.initialize();
26
+ const typeLabel = entry.type.toUpperCase();
27
+ let block = `\n### [${typeLabel}] ${entry.timestamp}\n${entry.summary}\n`;
28
+ if (entry.detail) {
29
+ block += `\n${entry.detail}\n`;
30
+ }
31
+ block += '\n---\n';
32
+ fs.appendFileSync(this.contextFilePath, block);
33
+ }
34
+ write(content) {
35
+ fs.mkdirSync(this.loomDir, { recursive: true });
36
+ fs.writeFileSync(this.contextFilePath, content);
37
+ }
38
+ listArchives() {
39
+ if (!fs.existsSync(this.archivesDir)) {
40
+ return [];
41
+ }
42
+ return fs.readdirSync(this.archivesDir)
43
+ .filter(f => f.endsWith('.md'))
44
+ .sort();
45
+ }
46
+ writeArchive(filename, content) {
47
+ fs.mkdirSync(this.archivesDir, { recursive: true });
48
+ fs.writeFileSync(path.join(this.archivesDir, filename), content);
49
+ }
50
+ readArchive(filename) {
51
+ const archivePath = path.join(this.archivesDir, filename);
52
+ if (!fs.existsSync(archivePath)) {
53
+ return null;
54
+ }
55
+ return fs.readFileSync(archivePath, 'utf-8');
56
+ }
57
+ getLastEntryTimestamp() {
58
+ const content = this.read();
59
+ const matches = content.match(/### \[\w+\] (\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})/g);
60
+ if (!matches || matches.length === 0) {
61
+ return null;
62
+ }
63
+ const last = matches[matches.length - 1];
64
+ const tsMatch = last.match(/(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})/);
65
+ return tsMatch ? tsMatch[1] : null;
66
+ }
67
+ }
68
+ //# sourceMappingURL=context-file.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context-file.js","sourceRoot":"","sources":["../../src/storage/context-file.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,28 @@
1
+ import type { PatternRecord, ProjectRecord } from '../types.js';
2
+ export interface SavePatternInput {
3
+ name: string;
4
+ content: string;
5
+ tags: string[];
6
+ sourceProject: string | null;
7
+ }
8
+ export interface FindPatternsOptions {
9
+ tags?: string[];
10
+ project?: string;
11
+ limit?: number;
12
+ }
13
+ export declare class LoomDatabase {
14
+ private db;
15
+ constructor(dbPath: string);
16
+ private migrate;
17
+ savePattern(input: SavePatternInput): PatternRecord;
18
+ getPattern(id: string): PatternRecord | undefined;
19
+ findPatterns(query: string, opts?: FindPatternsOptions): PatternRecord[];
20
+ private findPatternsFts;
21
+ private findPatternsLike;
22
+ upsertProject(projectPath: string, name: string): void;
23
+ listProjects(): ProjectRecord[];
24
+ listTables(): string[];
25
+ close(): void;
26
+ private rowToPattern;
27
+ }
28
+ //# sourceMappingURL=database.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"database.d.ts","sourceRoot":"","sources":["../../src/storage/database.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAEhE,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;CAC9B;AAED,MAAM,WAAW,mBAAmB;IAClC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAcD,qBAAa,YAAY;IACvB,OAAO,CAAC,EAAE,CAAoB;gBAElB,MAAM,EAAE,MAAM;IAQ1B,OAAO,CAAC,OAAO;IAqDf,WAAW,CAAC,KAAK,EAAE,gBAAgB,GAAG,aAAa;IAuBnD,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS;IAMjD,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,mBAAmB,GAAG,aAAa,EAAE;IA+BxE,OAAO,CAAC,eAAe;IAmCvB,OAAO,CAAC,gBAAgB;IAkCxB,aAAa,CAAC,WAAW,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI;IAWtD,YAAY,IAAI,aAAa,EAAE;IAI/B,UAAU,IAAI,MAAM,EAAE;IAOtB,KAAK,IAAI,IAAI;IAIb,OAAO,CAAC,YAAY;CAMrB"}