@jacques-ai/core 0.0.7-alpha.1
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/dist/archive/archive-store.d.ts +166 -0
- package/dist/archive/archive-store.d.ts.map +1 -0
- package/dist/archive/archive-store.js +612 -0
- package/dist/archive/archive-store.js.map +1 -0
- package/dist/archive/bulk-archive.d.ts +63 -0
- package/dist/archive/bulk-archive.d.ts.map +1 -0
- package/dist/archive/bulk-archive.js +315 -0
- package/dist/archive/bulk-archive.js.map +1 -0
- package/dist/archive/filename-utils.d.ts +39 -0
- package/dist/archive/filename-utils.d.ts.map +1 -0
- package/dist/archive/filename-utils.js +78 -0
- package/dist/archive/filename-utils.js.map +1 -0
- package/dist/archive/index.d.ts +21 -0
- package/dist/archive/index.d.ts.map +1 -0
- package/dist/archive/index.js +45 -0
- package/dist/archive/index.js.map +1 -0
- package/dist/archive/manifest-extractor.d.ts +40 -0
- package/dist/archive/manifest-extractor.d.ts.map +1 -0
- package/dist/archive/manifest-extractor.js +456 -0
- package/dist/archive/manifest-extractor.js.map +1 -0
- package/dist/archive/migration.d.ts +59 -0
- package/dist/archive/migration.d.ts.map +1 -0
- package/dist/archive/migration.js +172 -0
- package/dist/archive/migration.js.map +1 -0
- package/dist/archive/plan-cataloger.d.ts +24 -0
- package/dist/archive/plan-cataloger.d.ts.map +1 -0
- package/dist/archive/plan-cataloger.js +100 -0
- package/dist/archive/plan-cataloger.js.map +1 -0
- package/dist/archive/plan-extractor.d.ts +84 -0
- package/dist/archive/plan-extractor.d.ts.map +1 -0
- package/dist/archive/plan-extractor.js +371 -0
- package/dist/archive/plan-extractor.js.map +1 -0
- package/dist/archive/search-indexer.d.ts +50 -0
- package/dist/archive/search-indexer.d.ts.map +1 -0
- package/dist/archive/search-indexer.js +294 -0
- package/dist/archive/search-indexer.js.map +1 -0
- package/dist/archive/subagent-store.d.ts +113 -0
- package/dist/archive/subagent-store.d.ts.map +1 -0
- package/dist/archive/subagent-store.js +173 -0
- package/dist/archive/subagent-store.js.map +1 -0
- package/dist/archive/types.d.ts +236 -0
- package/dist/archive/types.d.ts.map +1 -0
- package/dist/archive/types.js +30 -0
- package/dist/archive/types.js.map +1 -0
- package/dist/branding.d.ts +9 -0
- package/dist/branding.d.ts.map +1 -0
- package/dist/branding.js +50 -0
- package/dist/branding.js.map +1 -0
- package/dist/cache/git-utils.d.ts +36 -0
- package/dist/cache/git-utils.d.ts.map +1 -0
- package/dist/cache/git-utils.js +160 -0
- package/dist/cache/git-utils.js.map +1 -0
- package/dist/cache/hidden-projects.d.ts +19 -0
- package/dist/cache/hidden-projects.d.ts.map +1 -0
- package/dist/cache/hidden-projects.js +48 -0
- package/dist/cache/hidden-projects.js.map +1 -0
- package/dist/cache/index.d.ts +15 -0
- package/dist/cache/index.d.ts.map +1 -0
- package/dist/cache/index.js +20 -0
- package/dist/cache/index.js.map +1 -0
- package/dist/cache/metadata-extractor.d.ts +62 -0
- package/dist/cache/metadata-extractor.d.ts.map +1 -0
- package/dist/cache/metadata-extractor.js +574 -0
- package/dist/cache/metadata-extractor.js.map +1 -0
- package/dist/cache/mode-detector.d.ts +19 -0
- package/dist/cache/mode-detector.d.ts.map +1 -0
- package/dist/cache/mode-detector.js +161 -0
- package/dist/cache/mode-detector.js.map +1 -0
- package/dist/cache/persistence.d.ts +39 -0
- package/dist/cache/persistence.d.ts.map +1 -0
- package/dist/cache/persistence.js +98 -0
- package/dist/cache/persistence.js.map +1 -0
- package/dist/cache/project-discovery.d.ts +41 -0
- package/dist/cache/project-discovery.d.ts.map +1 -0
- package/dist/cache/project-discovery.js +212 -0
- package/dist/cache/project-discovery.js.map +1 -0
- package/dist/cache/session-index.d.ts +258 -0
- package/dist/cache/session-index.d.ts.map +1 -0
- package/dist/cache/session-index.js +1030 -0
- package/dist/cache/session-index.js.map +1 -0
- package/dist/cache/types.d.ts +159 -0
- package/dist/cache/types.d.ts.map +1 -0
- package/dist/cache/types.js +29 -0
- package/dist/cache/types.js.map +1 -0
- package/dist/catalog/bulk-extractor.d.ts +18 -0
- package/dist/catalog/bulk-extractor.d.ts.map +1 -0
- package/dist/catalog/bulk-extractor.js +150 -0
- package/dist/catalog/bulk-extractor.js.map +1 -0
- package/dist/catalog/extractor.d.ts +53 -0
- package/dist/catalog/extractor.d.ts.map +1 -0
- package/dist/catalog/extractor.js +522 -0
- package/dist/catalog/extractor.js.map +1 -0
- package/dist/catalog/index.d.ts +10 -0
- package/dist/catalog/index.d.ts.map +1 -0
- package/dist/catalog/index.js +11 -0
- package/dist/catalog/index.js.map +1 -0
- package/dist/catalog/types.d.ts +134 -0
- package/dist/catalog/types.d.ts.map +1 -0
- package/dist/catalog/types.js +8 -0
- package/dist/catalog/types.js.map +1 -0
- package/dist/client/index.d.ts +6 -0
- package/dist/client/index.d.ts.map +1 -0
- package/dist/client/index.js +5 -0
- package/dist/client/index.js.map +1 -0
- package/dist/client/websocket-client.d.ts +96 -0
- package/dist/client/websocket-client.d.ts.map +1 -0
- package/dist/client/websocket-client.js +222 -0
- package/dist/client/websocket-client.js.map +1 -0
- package/dist/context/index.d.ts +13 -0
- package/dist/context/index.d.ts.map +1 -0
- package/dist/context/index.js +26 -0
- package/dist/context/index.js.map +1 -0
- package/dist/context/indexer.d.ts +73 -0
- package/dist/context/indexer.d.ts.map +1 -0
- package/dist/context/indexer.js +233 -0
- package/dist/context/indexer.js.map +1 -0
- package/dist/context/manager.d.ts +66 -0
- package/dist/context/manager.d.ts.map +1 -0
- package/dist/context/manager.js +310 -0
- package/dist/context/manager.js.map +1 -0
- package/dist/context/types.d.ts +149 -0
- package/dist/context/types.d.ts.map +1 -0
- package/dist/context/types.js +36 -0
- package/dist/context/types.js.map +1 -0
- package/dist/handoff/catalog.d.ts +54 -0
- package/dist/handoff/catalog.d.ts.map +1 -0
- package/dist/handoff/catalog.js +121 -0
- package/dist/handoff/catalog.js.map +1 -0
- package/dist/handoff/generator.d.ts +107 -0
- package/dist/handoff/generator.d.ts.map +1 -0
- package/dist/handoff/generator.js +603 -0
- package/dist/handoff/generator.js.map +1 -0
- package/dist/handoff/index.d.ts +13 -0
- package/dist/handoff/index.d.ts.map +1 -0
- package/dist/handoff/index.js +12 -0
- package/dist/handoff/index.js.map +1 -0
- package/dist/handoff/llm-generator.d.ts +77 -0
- package/dist/handoff/llm-generator.d.ts.map +1 -0
- package/dist/handoff/llm-generator.js +513 -0
- package/dist/handoff/llm-generator.js.map +1 -0
- package/dist/handoff/prompts.d.ts +18 -0
- package/dist/handoff/prompts.d.ts.map +1 -0
- package/dist/handoff/prompts.js +22 -0
- package/dist/handoff/prompts.js.map +1 -0
- package/dist/handoff/types.d.ts +28 -0
- package/dist/handoff/types.d.ts.map +1 -0
- package/dist/handoff/types.js +7 -0
- package/dist/handoff/types.js.map +1 -0
- package/dist/index.d.ts +56 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +132 -0
- package/dist/index.js.map +1 -0
- package/dist/logging/claude-operations.d.ts +111 -0
- package/dist/logging/claude-operations.d.ts.map +1 -0
- package/dist/logging/claude-operations.js +132 -0
- package/dist/logging/claude-operations.js.map +1 -0
- package/dist/logging/error-utils.d.ts +18 -0
- package/dist/logging/error-utils.d.ts.map +1 -0
- package/dist/logging/error-utils.js +37 -0
- package/dist/logging/error-utils.js.map +1 -0
- package/dist/logging/index.d.ts +11 -0
- package/dist/logging/index.d.ts.map +1 -0
- package/dist/logging/index.js +10 -0
- package/dist/logging/index.js.map +1 -0
- package/dist/logging/logger.d.ts +25 -0
- package/dist/logging/logger.d.ts.map +1 -0
- package/dist/logging/logger.js +39 -0
- package/dist/logging/logger.js.map +1 -0
- package/dist/notifications/constants.d.ts +16 -0
- package/dist/notifications/constants.d.ts.map +1 -0
- package/dist/notifications/constants.js +49 -0
- package/dist/notifications/constants.js.map +1 -0
- package/dist/notifications/index.d.ts +9 -0
- package/dist/notifications/index.d.ts.map +1 -0
- package/dist/notifications/index.js +8 -0
- package/dist/notifications/index.js.map +1 -0
- package/dist/notifications/types.d.ts +28 -0
- package/dist/notifications/types.d.ts.map +1 -0
- package/dist/notifications/types.js +7 -0
- package/dist/notifications/types.js.map +1 -0
- package/dist/notifications/utils.d.ts +20 -0
- package/dist/notifications/utils.d.ts.map +1 -0
- package/dist/notifications/utils.js +37 -0
- package/dist/notifications/utils.js.map +1 -0
- package/dist/plan/index.d.ts +12 -0
- package/dist/plan/index.d.ts.map +1 -0
- package/dist/plan/index.js +15 -0
- package/dist/plan/index.js.map +1 -0
- package/dist/plan/plan-parser.d.ts +33 -0
- package/dist/plan/plan-parser.d.ts.map +1 -0
- package/dist/plan/plan-parser.js +189 -0
- package/dist/plan/plan-parser.js.map +1 -0
- package/dist/plan/progress-computer.d.ts +34 -0
- package/dist/plan/progress-computer.d.ts.map +1 -0
- package/dist/plan/progress-computer.js +211 -0
- package/dist/plan/progress-computer.js.map +1 -0
- package/dist/plan/progress-matcher.d.ts +34 -0
- package/dist/plan/progress-matcher.d.ts.map +1 -0
- package/dist/plan/progress-matcher.js +297 -0
- package/dist/plan/progress-matcher.js.map +1 -0
- package/dist/plan/task-extractor.d.ts +30 -0
- package/dist/plan/task-extractor.d.ts.map +1 -0
- package/dist/plan/task-extractor.js +435 -0
- package/dist/plan/task-extractor.js.map +1 -0
- package/dist/plan/types.d.ts +131 -0
- package/dist/plan/types.d.ts.map +1 -0
- package/dist/plan/types.js +8 -0
- package/dist/plan/types.js.map +1 -0
- package/dist/project/aggregator.d.ts +43 -0
- package/dist/project/aggregator.d.ts.map +1 -0
- package/dist/project/aggregator.js +218 -0
- package/dist/project/aggregator.js.map +1 -0
- package/dist/project/index.d.ts +9 -0
- package/dist/project/index.d.ts.map +1 -0
- package/dist/project/index.js +9 -0
- package/dist/project/index.js.map +1 -0
- package/dist/project/types.d.ts +65 -0
- package/dist/project/types.d.ts.map +1 -0
- package/dist/project/types.js +27 -0
- package/dist/project/types.js.map +1 -0
- package/dist/session/detector.d.ts +113 -0
- package/dist/session/detector.d.ts.map +1 -0
- package/dist/session/detector.js +333 -0
- package/dist/session/detector.js.map +1 -0
- package/dist/session/filters.d.ts +32 -0
- package/dist/session/filters.d.ts.map +1 -0
- package/dist/session/filters.js +100 -0
- package/dist/session/filters.js.map +1 -0
- package/dist/session/format-title.d.ts +16 -0
- package/dist/session/format-title.d.ts.map +1 -0
- package/dist/session/format-title.js +54 -0
- package/dist/session/format-title.js.map +1 -0
- package/dist/session/index.d.ts +16 -0
- package/dist/session/index.d.ts.map +1 -0
- package/dist/session/index.js +10 -0
- package/dist/session/index.js.map +1 -0
- package/dist/session/parser.d.ts +264 -0
- package/dist/session/parser.d.ts.map +1 -0
- package/dist/session/parser.js +588 -0
- package/dist/session/parser.js.map +1 -0
- package/dist/session/token-estimator.d.ts +32 -0
- package/dist/session/token-estimator.d.ts.map +1 -0
- package/dist/session/token-estimator.js +139 -0
- package/dist/session/token-estimator.js.map +1 -0
- package/dist/session/transformer.d.ts +126 -0
- package/dist/session/transformer.d.ts.map +1 -0
- package/dist/session/transformer.js +158 -0
- package/dist/session/transformer.js.map +1 -0
- package/dist/setup/hooks-config.d.ts +35 -0
- package/dist/setup/hooks-config.d.ts.map +1 -0
- package/dist/setup/hooks-config.js +107 -0
- package/dist/setup/hooks-config.js.map +1 -0
- package/dist/setup/hooks-symlink.d.ts +17 -0
- package/dist/setup/hooks-symlink.d.ts.map +1 -0
- package/dist/setup/hooks-symlink.js +89 -0
- package/dist/setup/hooks-symlink.js.map +1 -0
- package/dist/setup/index.d.ts +13 -0
- package/dist/setup/index.d.ts.map +1 -0
- package/dist/setup/index.js +12 -0
- package/dist/setup/index.js.map +1 -0
- package/dist/setup/prerequisites.d.ts +11 -0
- package/dist/setup/prerequisites.d.ts.map +1 -0
- package/dist/setup/prerequisites.js +72 -0
- package/dist/setup/prerequisites.js.map +1 -0
- package/dist/setup/settings-merge.d.ts +33 -0
- package/dist/setup/settings-merge.d.ts.map +1 -0
- package/dist/setup/settings-merge.js +131 -0
- package/dist/setup/settings-merge.js.map +1 -0
- package/dist/setup/skills-install.d.ts +17 -0
- package/dist/setup/skills-install.d.ts.map +1 -0
- package/dist/setup/skills-install.js +60 -0
- package/dist/setup/skills-install.js.map +1 -0
- package/dist/setup/types.d.ts +39 -0
- package/dist/setup/types.d.ts.map +1 -0
- package/dist/setup/types.js +7 -0
- package/dist/setup/types.js.map +1 -0
- package/dist/setup/verification.d.ts +9 -0
- package/dist/setup/verification.d.ts.map +1 -0
- package/dist/setup/verification.js +91 -0
- package/dist/setup/verification.js.map +1 -0
- package/dist/shortcuts/index.d.ts +8 -0
- package/dist/shortcuts/index.d.ts.map +1 -0
- package/dist/shortcuts/index.js +6 -0
- package/dist/shortcuts/index.js.map +1 -0
- package/dist/shortcuts/key-utils.d.ts +54 -0
- package/dist/shortcuts/key-utils.d.ts.map +1 -0
- package/dist/shortcuts/key-utils.js +129 -0
- package/dist/shortcuts/key-utils.js.map +1 -0
- package/dist/shortcuts/shortcut-registry.d.ts +37 -0
- package/dist/shortcuts/shortcut-registry.d.ts.map +1 -0
- package/dist/shortcuts/shortcut-registry.js +322 -0
- package/dist/shortcuts/shortcut-registry.js.map +1 -0
- package/dist/sources/config.d.ts +91 -0
- package/dist/sources/config.d.ts.map +1 -0
- package/dist/sources/config.js +229 -0
- package/dist/sources/config.js.map +1 -0
- package/dist/sources/googledocs.d.ts +43 -0
- package/dist/sources/googledocs.d.ts.map +1 -0
- package/dist/sources/googledocs.js +298 -0
- package/dist/sources/googledocs.js.map +1 -0
- package/dist/sources/index.d.ts +14 -0
- package/dist/sources/index.d.ts.map +1 -0
- package/dist/sources/index.js +19 -0
- package/dist/sources/index.js.map +1 -0
- package/dist/sources/notion.d.ts +35 -0
- package/dist/sources/notion.d.ts.map +1 -0
- package/dist/sources/notion.js +352 -0
- package/dist/sources/notion.js.map +1 -0
- package/dist/sources/obsidian.d.ts +38 -0
- package/dist/sources/obsidian.d.ts.map +1 -0
- package/dist/sources/obsidian.js +228 -0
- package/dist/sources/obsidian.js.map +1 -0
- package/dist/sources/types.d.ts +133 -0
- package/dist/sources/types.d.ts.map +1 -0
- package/dist/sources/types.js +19 -0
- package/dist/sources/types.js.map +1 -0
- package/dist/storage/index.d.ts +6 -0
- package/dist/storage/index.d.ts.map +1 -0
- package/dist/storage/index.js +5 -0
- package/dist/storage/index.js.map +1 -0
- package/dist/storage/writer.d.ts +86 -0
- package/dist/storage/writer.d.ts.map +1 -0
- package/dist/storage/writer.js +137 -0
- package/dist/storage/writer.js.map +1 -0
- package/dist/types.d.ts +203 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +8 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/claude-token.d.ts +49 -0
- package/dist/utils/claude-token.d.ts.map +1 -0
- package/dist/utils/claude-token.js +169 -0
- package/dist/utils/claude-token.js.map +1 -0
- package/dist/utils/index.d.ts +7 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +13 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/settings.d.ts +100 -0
- package/dist/utils/settings.d.ts.map +1 -0
- package/dist/utils/settings.js +206 -0
- package/dist/utils/settings.js.map +1 -0
- package/package.json +54 -0
|
@@ -0,0 +1,371 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Plan Extractor
|
|
3
|
+
*
|
|
4
|
+
* Detects and extracts embedded plans from user messages in sessions.
|
|
5
|
+
* Plans are often embedded when starting from plan mode with "Implement the following plan:".
|
|
6
|
+
*/
|
|
7
|
+
import { promises as fs } from "fs";
|
|
8
|
+
import { createHash } from "crypto";
|
|
9
|
+
import { join } from "path";
|
|
10
|
+
import { readProjectIndex, addPlanToIndex } from "../context/indexer.js";
|
|
11
|
+
import { generatePlanFilename, generateVersionedFilename } from "./filename-utils.js";
|
|
12
|
+
import { extractKeywords } from "../plan/plan-parser.js";
|
|
13
|
+
/** Patterns that indicate an embedded plan */
|
|
14
|
+
export const PLAN_TRIGGER_PATTERNS = [
|
|
15
|
+
/^implement the following plan[:\s]*/i,
|
|
16
|
+
/^here is the plan[:\s]*/i,
|
|
17
|
+
/^follow this plan[:\s]*/i,
|
|
18
|
+
];
|
|
19
|
+
/** Minimum content length after trigger phrase to be considered a valid plan */
|
|
20
|
+
const MIN_PLAN_LENGTH = 100;
|
|
21
|
+
/** Minimum similarity score (0-1) for fuzzy deduplication */
|
|
22
|
+
const MIN_SIMILARITY = 0.75;
|
|
23
|
+
/**
|
|
24
|
+
* Detect embedded plans in session entries.
|
|
25
|
+
* Checks all user messages for plan trigger patterns.
|
|
26
|
+
*/
|
|
27
|
+
export function detectEmbeddedPlans(entries) {
|
|
28
|
+
const detected = [];
|
|
29
|
+
entries.forEach((entry, messageIndex) => {
|
|
30
|
+
if (entry.type === "user_message" && entry.content.text) {
|
|
31
|
+
const text = entry.content.text.trim();
|
|
32
|
+
// Check for trigger patterns
|
|
33
|
+
for (const pattern of PLAN_TRIGGER_PATTERNS) {
|
|
34
|
+
const match = text.match(pattern);
|
|
35
|
+
if (match) {
|
|
36
|
+
// Extract content after trigger phrase
|
|
37
|
+
const planContent = text.substring(match[0].length).trim();
|
|
38
|
+
// Validate plan content
|
|
39
|
+
if (planContent.length < MIN_PLAN_LENGTH) {
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
// Check for markdown heading (basic structure check)
|
|
43
|
+
if (!planContent.includes("#")) {
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
// Check if this message contains multiple plans
|
|
47
|
+
const plans = splitMultiplePlans(planContent);
|
|
48
|
+
plans.forEach((content, planIndex) => {
|
|
49
|
+
detected.push({
|
|
50
|
+
planContent: content,
|
|
51
|
+
messageIndex,
|
|
52
|
+
planIndex,
|
|
53
|
+
triggeredBy: match[0].trim(),
|
|
54
|
+
});
|
|
55
|
+
});
|
|
56
|
+
// Only match first trigger pattern per message
|
|
57
|
+
break;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
return detected;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Split content that contains multiple plans by top-level headings.
|
|
66
|
+
*/
|
|
67
|
+
export function splitMultiplePlans(content) {
|
|
68
|
+
const plans = [];
|
|
69
|
+
const lines = content.split("\n");
|
|
70
|
+
let currentPlan = [];
|
|
71
|
+
let foundFirstHeading = false;
|
|
72
|
+
for (const line of lines) {
|
|
73
|
+
// Check if this is a top-level heading
|
|
74
|
+
if (line.match(/^#\s+/)) {
|
|
75
|
+
// If we already have a plan, save it
|
|
76
|
+
if (foundFirstHeading && currentPlan.length > 0) {
|
|
77
|
+
plans.push(currentPlan.join("\n").trim());
|
|
78
|
+
currentPlan = [];
|
|
79
|
+
}
|
|
80
|
+
foundFirstHeading = true;
|
|
81
|
+
}
|
|
82
|
+
if (foundFirstHeading) {
|
|
83
|
+
currentPlan.push(line);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
// Save the last plan
|
|
87
|
+
if (currentPlan.length > 0) {
|
|
88
|
+
plans.push(currentPlan.join("\n").trim());
|
|
89
|
+
}
|
|
90
|
+
// If no headings found, treat entire content as one plan
|
|
91
|
+
if (plans.length === 0 && content.trim().length > 0) {
|
|
92
|
+
return [content.trim()];
|
|
93
|
+
}
|
|
94
|
+
return plans;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Extract title from plan content.
|
|
98
|
+
* Prefers first markdown heading, falls back to first line.
|
|
99
|
+
*/
|
|
100
|
+
export function extractPlanTitle(content) {
|
|
101
|
+
// Try to find first markdown heading
|
|
102
|
+
const headingMatch = content.match(/^#\s+(.+)$/m);
|
|
103
|
+
if (headingMatch) {
|
|
104
|
+
// Strip "Plan:" prefix if present — titles should be just the name
|
|
105
|
+
return headingMatch[1].trim().replace(/^Plan:\s*/i, "");
|
|
106
|
+
}
|
|
107
|
+
// Fallback: use first line
|
|
108
|
+
const firstLine = content.split("\n")[0].trim();
|
|
109
|
+
if (firstLine.length <= 80) {
|
|
110
|
+
return firstLine;
|
|
111
|
+
}
|
|
112
|
+
// Truncate if too long
|
|
113
|
+
return firstLine.substring(0, 77) + "...";
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Extract plan body (content without the title heading).
|
|
117
|
+
* Strips the first markdown heading line and returns the rest.
|
|
118
|
+
*/
|
|
119
|
+
export function extractPlanBody(content) {
|
|
120
|
+
const lines = content.split("\n");
|
|
121
|
+
let foundFirstHeading = false;
|
|
122
|
+
const bodyLines = [];
|
|
123
|
+
for (const line of lines) {
|
|
124
|
+
// Skip the first heading line
|
|
125
|
+
if (!foundFirstHeading && line.match(/^#\s+/)) {
|
|
126
|
+
foundFirstHeading = true;
|
|
127
|
+
continue;
|
|
128
|
+
}
|
|
129
|
+
bodyLines.push(line);
|
|
130
|
+
}
|
|
131
|
+
// If no heading found, return entire content
|
|
132
|
+
if (!foundFirstHeading) {
|
|
133
|
+
return content.trim();
|
|
134
|
+
}
|
|
135
|
+
return bodyLines.join("\n").trim();
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Generate a hash of the plan body only (excludes title).
|
|
139
|
+
* Used for detecting duplicates with different titles but same content.
|
|
140
|
+
*/
|
|
141
|
+
export function generateBodyHash(content) {
|
|
142
|
+
const body = extractPlanBody(content);
|
|
143
|
+
const normalized = body
|
|
144
|
+
.replace(/\s+/g, " ")
|
|
145
|
+
.toLowerCase()
|
|
146
|
+
.trim();
|
|
147
|
+
return createHash("sha256").update(normalized).digest("hex");
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Generate a plan fingerprint for deduplication.
|
|
151
|
+
* Normalizes content to ignore whitespace differences.
|
|
152
|
+
*/
|
|
153
|
+
export function generatePlanFingerprint(content) {
|
|
154
|
+
// Normalize content: remove extra whitespace, lowercase
|
|
155
|
+
const normalized = content
|
|
156
|
+
.replace(/\s+/g, " ")
|
|
157
|
+
.toLowerCase()
|
|
158
|
+
.trim();
|
|
159
|
+
// Generate full content hash
|
|
160
|
+
const contentHash = createHash("sha256")
|
|
161
|
+
.update(normalized)
|
|
162
|
+
.digest("hex");
|
|
163
|
+
// Generate body-only hash (for cross-title dedup)
|
|
164
|
+
const bodyHash = generateBodyHash(content);
|
|
165
|
+
// Extract and normalize title
|
|
166
|
+
const title = extractPlanTitle(content);
|
|
167
|
+
const titleNormalized = title
|
|
168
|
+
.toLowerCase()
|
|
169
|
+
.replace(/[^a-z0-9]+/g, "-")
|
|
170
|
+
.replace(/^-+|-+$/g, "");
|
|
171
|
+
// Calculate length range bucket
|
|
172
|
+
const length = content.length;
|
|
173
|
+
let lengthRange;
|
|
174
|
+
if (length <= 500) {
|
|
175
|
+
lengthRange = "0-500";
|
|
176
|
+
}
|
|
177
|
+
else if (length <= 2000) {
|
|
178
|
+
lengthRange = "501-2000";
|
|
179
|
+
}
|
|
180
|
+
else {
|
|
181
|
+
lengthRange = "2001+";
|
|
182
|
+
}
|
|
183
|
+
return {
|
|
184
|
+
contentHash,
|
|
185
|
+
bodyHash,
|
|
186
|
+
titleNormalized,
|
|
187
|
+
lengthRange,
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Calculate text similarity using simple word overlap (Jaccard similarity).
|
|
192
|
+
* Returns a score between 0 (no overlap) and 1 (identical).
|
|
193
|
+
*/
|
|
194
|
+
export function calculateSimilarity(text1, text2) {
|
|
195
|
+
const words1 = extractKeywords(text1);
|
|
196
|
+
const words2 = extractKeywords(text2);
|
|
197
|
+
if (words1.size === 0 || words2.size === 0) {
|
|
198
|
+
return 0;
|
|
199
|
+
}
|
|
200
|
+
const intersection = new Set([...words1].filter((w) => words2.has(w)));
|
|
201
|
+
const union = new Set([...words1, ...words2]);
|
|
202
|
+
return intersection.size / union.size;
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* Find a duplicate plan in the existing catalog.
|
|
206
|
+
* Uses a two-tier approach:
|
|
207
|
+
* 1. Exact contentHash match (full content identical)
|
|
208
|
+
* 2. Exact bodyHash match (same body, different title)
|
|
209
|
+
* 3. Fuzzy similarity >= 75% within same length range (no title gate)
|
|
210
|
+
*
|
|
211
|
+
* Returns the PlanEntry if found, null otherwise.
|
|
212
|
+
*/
|
|
213
|
+
export async function findDuplicatePlan(content, projectPath) {
|
|
214
|
+
const fingerprint = generatePlanFingerprint(content);
|
|
215
|
+
const index = await readProjectIndex(projectPath);
|
|
216
|
+
// First pass: check indexed hashes (fast path)
|
|
217
|
+
for (const planEntry of index.plans) {
|
|
218
|
+
// Tier 1: Exact content hash match from index
|
|
219
|
+
if (planEntry.contentHash === fingerprint.contentHash) {
|
|
220
|
+
return planEntry;
|
|
221
|
+
}
|
|
222
|
+
// Tier 2: Body hash match from index (same body, different title)
|
|
223
|
+
if (planEntry.bodyHash === fingerprint.bodyHash) {
|
|
224
|
+
return planEntry;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
// Second pass: read files and check computed hashes + similarity
|
|
228
|
+
for (const planEntry of index.plans) {
|
|
229
|
+
try {
|
|
230
|
+
// Read the plan file - construct absolute path from relative path in index
|
|
231
|
+
const absolutePath = join(projectPath, ".jacques", planEntry.path);
|
|
232
|
+
const planContent = await fs.readFile(absolutePath, "utf-8");
|
|
233
|
+
const existingFingerprint = generatePlanFingerprint(planContent);
|
|
234
|
+
// Tier 1: Exact content hash match (computed)
|
|
235
|
+
if (fingerprint.contentHash === existingFingerprint.contentHash) {
|
|
236
|
+
return planEntry;
|
|
237
|
+
}
|
|
238
|
+
// Tier 2: Body hash match (computed) - catches different titles, same body
|
|
239
|
+
if (fingerprint.bodyHash === existingFingerprint.bodyHash) {
|
|
240
|
+
return planEntry;
|
|
241
|
+
}
|
|
242
|
+
// Tier 3: Fuzzy similarity within same length range (no title gate!)
|
|
243
|
+
if (fingerprint.lengthRange === existingFingerprint.lengthRange) {
|
|
244
|
+
const similarity = calculateSimilarity(content, planContent);
|
|
245
|
+
if (similarity >= MIN_SIMILARITY) {
|
|
246
|
+
return planEntry;
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
catch (error) {
|
|
251
|
+
// Plan file not found or unreadable, skip
|
|
252
|
+
continue;
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
return null;
|
|
256
|
+
}
|
|
257
|
+
/**
|
|
258
|
+
* Index an embedded plan in the project index.
|
|
259
|
+
* Creates or updates the PlanEntry with session link.
|
|
260
|
+
*/
|
|
261
|
+
export async function indexEmbeddedPlan(content, filename, sessionId, projectPath) {
|
|
262
|
+
const plansDir = join(projectPath, ".jacques", "plans");
|
|
263
|
+
await fs.mkdir(plansDir, { recursive: true });
|
|
264
|
+
const planPath = join(plansDir, filename);
|
|
265
|
+
const title = extractPlanTitle(content);
|
|
266
|
+
const now = new Date().toISOString();
|
|
267
|
+
// Check if plan already exists in index
|
|
268
|
+
const index = await readProjectIndex(projectPath);
|
|
269
|
+
const existingPlan = index.plans.find((p) => p.filename === filename);
|
|
270
|
+
if (existingPlan) {
|
|
271
|
+
// Update existing plan: merge session IDs
|
|
272
|
+
const updatedPlan = {
|
|
273
|
+
...existingPlan,
|
|
274
|
+
updatedAt: now,
|
|
275
|
+
sessions: [...new Set([...existingPlan.sessions, sessionId])],
|
|
276
|
+
};
|
|
277
|
+
// For existing plans, we're just updating sessions array - no file write needed
|
|
278
|
+
await addPlanToIndex(projectPath, updatedPlan);
|
|
279
|
+
return updatedPlan;
|
|
280
|
+
}
|
|
281
|
+
else {
|
|
282
|
+
// Create new plan entry
|
|
283
|
+
const planEntry = {
|
|
284
|
+
id: filename.replace(".md", ""),
|
|
285
|
+
title,
|
|
286
|
+
filename,
|
|
287
|
+
path: `plans/${filename}`, // Relative path (consistent with Write tool plans)
|
|
288
|
+
createdAt: now,
|
|
289
|
+
updatedAt: now,
|
|
290
|
+
sessions: [sessionId],
|
|
291
|
+
};
|
|
292
|
+
// Write file FIRST - this can fail
|
|
293
|
+
try {
|
|
294
|
+
await fs.writeFile(planPath, content, "utf-8");
|
|
295
|
+
}
|
|
296
|
+
catch (error) {
|
|
297
|
+
throw new Error(`Failed to write plan file to ${planPath}: ${error instanceof Error ? error.message : String(error)}`);
|
|
298
|
+
}
|
|
299
|
+
// THEN update index - only if file write succeeded
|
|
300
|
+
await addPlanToIndex(projectPath, planEntry);
|
|
301
|
+
return planEntry;
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
/**
|
|
305
|
+
* Extract embedded plans from session entries and save to project.
|
|
306
|
+
* Returns array of PlanReference objects for the manifest.
|
|
307
|
+
*/
|
|
308
|
+
export async function extractEmbeddedPlans(entries, projectPath, sessionId) {
|
|
309
|
+
const detected = detectEmbeddedPlans(entries);
|
|
310
|
+
if (detected.length === 0) {
|
|
311
|
+
return [];
|
|
312
|
+
}
|
|
313
|
+
const references = [];
|
|
314
|
+
const seenHashes = new Set();
|
|
315
|
+
for (const { planContent } of detected) {
|
|
316
|
+
try {
|
|
317
|
+
// Check for duplicates within this session
|
|
318
|
+
const fingerprint = generatePlanFingerprint(planContent);
|
|
319
|
+
if (seenHashes.has(fingerprint.contentHash)) {
|
|
320
|
+
continue; // Skip duplicate within same session
|
|
321
|
+
}
|
|
322
|
+
seenHashes.add(fingerprint.contentHash);
|
|
323
|
+
// Check for duplicate in existing catalog
|
|
324
|
+
const duplicate = await findDuplicatePlan(planContent, projectPath);
|
|
325
|
+
let planEntry;
|
|
326
|
+
let filename;
|
|
327
|
+
if (duplicate) {
|
|
328
|
+
// Reuse existing plan, add session link
|
|
329
|
+
planEntry = await indexEmbeddedPlan(planContent, duplicate.filename, sessionId, projectPath);
|
|
330
|
+
filename = duplicate.filename;
|
|
331
|
+
}
|
|
332
|
+
else {
|
|
333
|
+
// Create new plan
|
|
334
|
+
const title = extractPlanTitle(planContent);
|
|
335
|
+
filename = generatePlanFilename(title);
|
|
336
|
+
// Check for filename collision
|
|
337
|
+
const plansDir = join(projectPath, ".jacques", "plans");
|
|
338
|
+
const planPath = join(plansDir, filename);
|
|
339
|
+
try {
|
|
340
|
+
await fs.access(planPath);
|
|
341
|
+
// File exists with different content, create versioned filename
|
|
342
|
+
filename = await generateVersionedFilename(plansDir, filename);
|
|
343
|
+
}
|
|
344
|
+
catch {
|
|
345
|
+
// File doesn't exist, we can use this filename
|
|
346
|
+
}
|
|
347
|
+
planEntry = await indexEmbeddedPlan(planContent, filename, sessionId, projectPath);
|
|
348
|
+
}
|
|
349
|
+
// Create reference for manifest
|
|
350
|
+
// Note: path must be absolute for actual file access, even though index stores relative path
|
|
351
|
+
const absolutePath = join(projectPath, ".jacques", "plans", filename);
|
|
352
|
+
references.push({
|
|
353
|
+
path: absolutePath,
|
|
354
|
+
name: filename,
|
|
355
|
+
archivedPath: `plans/${filename}`,
|
|
356
|
+
source: "embedded",
|
|
357
|
+
});
|
|
358
|
+
}
|
|
359
|
+
catch (error) {
|
|
360
|
+
// Non-blocking: log and continue with detailed error info
|
|
361
|
+
console.error("Failed to extract embedded plan:", {
|
|
362
|
+
error: error instanceof Error ? error.message : String(error),
|
|
363
|
+
planContent: planContent.substring(0, 100) + "...",
|
|
364
|
+
projectPath,
|
|
365
|
+
sessionId,
|
|
366
|
+
});
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
return references;
|
|
370
|
+
}
|
|
371
|
+
//# sourceMappingURL=plan-extractor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plan-extractor.js","sourceRoot":"","sources":["../../src/archive/plan-extractor.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Search Indexer
|
|
3
|
+
*
|
|
4
|
+
* Builds and maintains a keyword inverted index for conversation search.
|
|
5
|
+
*/
|
|
6
|
+
import type { ConversationManifest, SearchIndex } from "./types.js";
|
|
7
|
+
/**
|
|
8
|
+
* Tokenize text into keywords.
|
|
9
|
+
*/
|
|
10
|
+
export declare function tokenize(text: string): string[];
|
|
11
|
+
/**
|
|
12
|
+
* Extract keywords from a file path.
|
|
13
|
+
* "src/auth/jwt.ts" → ["src", "auth", "jwt", "ts"]
|
|
14
|
+
*/
|
|
15
|
+
export declare function extractPathKeywords(filePath: string): string[];
|
|
16
|
+
/**
|
|
17
|
+
* Extract all keywords from a manifest with field attribution.
|
|
18
|
+
*/
|
|
19
|
+
export declare function extractKeywordsWithFields(manifest: ConversationManifest): Array<{
|
|
20
|
+
keyword: string;
|
|
21
|
+
field: string;
|
|
22
|
+
score: number;
|
|
23
|
+
}>;
|
|
24
|
+
/**
|
|
25
|
+
* Add a conversation to the search index.
|
|
26
|
+
*/
|
|
27
|
+
export declare function addToIndex(index: SearchIndex, manifest: ConversationManifest): SearchIndex;
|
|
28
|
+
/**
|
|
29
|
+
* Remove a conversation from the search index.
|
|
30
|
+
* @param projectId The projectId (encoded path) or projectSlug for old data
|
|
31
|
+
*/
|
|
32
|
+
export declare function removeFromIndex(index: SearchIndex, manifestId: string, projectId: string): SearchIndex;
|
|
33
|
+
/**
|
|
34
|
+
* Search the index for matching conversations.
|
|
35
|
+
* Returns manifest IDs sorted by relevance score.
|
|
36
|
+
*/
|
|
37
|
+
export declare function searchIndex(index: SearchIndex, query: string): Array<{
|
|
38
|
+
id: string;
|
|
39
|
+
score: number;
|
|
40
|
+
}>;
|
|
41
|
+
/**
|
|
42
|
+
* Get index statistics.
|
|
43
|
+
*/
|
|
44
|
+
export declare function getIndexStats(index: SearchIndex): {
|
|
45
|
+
totalConversations: number;
|
|
46
|
+
totalKeywords: number;
|
|
47
|
+
totalProjects: number;
|
|
48
|
+
averageKeywordsPerConversation: number;
|
|
49
|
+
};
|
|
50
|
+
//# sourceMappingURL=search-indexer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search-indexer.d.ts","sourceRoot":"","sources":["../../src/archive/search-indexer.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EACV,oBAAoB,EACpB,WAAW,EAEZ,MAAM,YAAY,CAAC;AAuGpB;;GAEG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAO/C;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE,CAK9D;AAED;;GAEG;AACH,wBAAgB,yBAAyB,CACvC,QAAQ,EAAE,oBAAoB,GAC7B,KAAK,CAAC;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CA+D1D;AAED;;GAEG;AACH,wBAAgB,UAAU,CACxB,KAAK,EAAE,WAAW,EAClB,QAAQ,EAAE,oBAAoB,GAC7B,WAAW,CAuDb;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAC7B,KAAK,EAAE,WAAW,EAClB,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,MAAM,GAChB,WAAW,CAgCb;AAED;;;GAGG;AACH,wBAAgB,WAAW,CACzB,KAAK,EAAE,WAAW,EAClB,KAAK,EAAE,MAAM,GACZ,KAAK,CAAC;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CA2BtC;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,WAAW,GAAG;IACjD,kBAAkB,EAAE,MAAM,CAAC;IAC3B,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;IACtB,8BAA8B,EAAE,MAAM,CAAC;CACxC,CAaA"}
|