lifeos 1.0.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.
- package/LICENSE +21 -0
- package/README.en.md +202 -0
- package/README.md +202 -0
- package/assets/lifeos-rules.en.md +162 -0
- package/assets/lifeos-rules.zh.md +162 -0
- package/assets/lifeos.yaml +56 -0
- package/assets/prompts/AI_LLMResearch_Prompt.en.md +120 -0
- package/assets/prompts/AI_LLMResearch_Prompt.zh.md +120 -0
- package/assets/prompts/Art_ChinesePainting_Prompt.en.md +147 -0
- package/assets/prompts/Art_ChinesePainting_Prompt.zh.md +148 -0
- package/assets/prompts/Cryptography_Prompt.en.md +148 -0
- package/assets/prompts/Cryptography_Prompt.zh.md +147 -0
- package/assets/prompts/History_ChineseCulture_Prompt.en.md +98 -0
- package/assets/prompts/History_ChineseCulture_Prompt.zh.md +98 -0
- package/assets/prompts/Math_HigherMathematics_Prompt.en.md +117 -0
- package/assets/prompts/Math_HigherMathematics_Prompt.zh.md +116 -0
- package/assets/schema/Frontmatter_Schema.md +139 -0
- package/assets/skills/_shared/completion-report.en.md +30 -0
- package/assets/skills/_shared/completion-report.zh.md +30 -0
- package/assets/skills/_shared/dual-agent-orchestrator.en.md +40 -0
- package/assets/skills/_shared/dual-agent-orchestrator.zh.md +40 -0
- package/assets/skills/_shared/learning-lifecycle.en.md +53 -0
- package/assets/skills/_shared/learning-lifecycle.zh.md +53 -0
- package/assets/skills/_shared/lifecycle.en.md +84 -0
- package/assets/skills/_shared/lifecycle.zh.md +84 -0
- package/assets/skills/_shared/memory-protocol.en.md +36 -0
- package/assets/skills/_shared/memory-protocol.zh.md +36 -0
- package/assets/skills/_shared/template-loading.en.md +26 -0
- package/assets/skills/_shared/template-loading.zh.md +26 -0
- package/assets/skills/archive/SKILL.en.md +300 -0
- package/assets/skills/archive/SKILL.zh.md +300 -0
- package/assets/skills/ask/SKILL.en.md +164 -0
- package/assets/skills/ask/SKILL.zh.md +164 -0
- package/assets/skills/brainstorm/SKILL.en.md +242 -0
- package/assets/skills/brainstorm/SKILL.zh.md +242 -0
- package/assets/skills/brainstorm/references/action-options.en.md +65 -0
- package/assets/skills/brainstorm/references/action-options.zh.md +65 -0
- package/assets/skills/knowledge/SKILL.en.md +202 -0
- package/assets/skills/knowledge/SKILL.zh.md +202 -0
- package/assets/skills/project/SKILL.en.md +133 -0
- package/assets/skills/project/SKILL.zh.md +133 -0
- package/assets/skills/project/references/execution-agent-prompt.en.md +148 -0
- package/assets/skills/project/references/execution-agent-prompt.zh.md +148 -0
- package/assets/skills/project/references/planning-agent-prompt.en.md +162 -0
- package/assets/skills/project/references/planning-agent-prompt.zh.md +162 -0
- package/assets/skills/read-pdf/SKILL.en.md +199 -0
- package/assets/skills/read-pdf/SKILL.zh.md +199 -0
- package/assets/skills/read-pdf/scripts/read_pdf.py +354 -0
- package/assets/skills/research/SKILL.en.md +107 -0
- package/assets/skills/research/SKILL.zh.md +107 -0
- package/assets/skills/research/references/execution-agent-prompt.en.md +166 -0
- package/assets/skills/research/references/execution-agent-prompt.zh.md +166 -0
- package/assets/skills/research/references/planning-agent-prompt.en.md +129 -0
- package/assets/skills/research/references/planning-agent-prompt.zh.md +129 -0
- package/assets/skills/revise/SKILL.en.md +258 -0
- package/assets/skills/revise/SKILL.zh.md +258 -0
- package/assets/skills/revise/references/grading-protocol.en.md +99 -0
- package/assets/skills/revise/references/grading-protocol.zh.md +99 -0
- package/assets/skills/today/SKILL.en.md +211 -0
- package/assets/skills/today/SKILL.zh.md +211 -0
- package/assets/templates/en/Daily_Template.md +25 -0
- package/assets/templates/en/Draft_Template.md +29 -0
- package/assets/templates/en/Knowledge_Template.md +86 -0
- package/assets/templates/en/Project_Template.md +110 -0
- package/assets/templates/en/Research_Template.md +46 -0
- package/assets/templates/en/Retrospective_Template.md +89 -0
- package/assets/templates/en/Revise_Template.md +24 -0
- package/assets/templates/en/Wiki_Template.md +35 -0
- package/assets/templates/zh/Daily_Template.md +26 -0
- package/assets/templates/zh/Draft_Template.md +29 -0
- package/assets/templates/zh/Knowledge_Template.md +86 -0
- package/assets/templates/zh/Project_Template.md +110 -0
- package/assets/templates/zh/Research_Template.md +46 -0
- package/assets/templates/zh/Retrospective_Template.md +89 -0
- package/assets/templates/zh/Revise_Template.md +24 -0
- package/assets/templates/zh/Wiki_Template.md +35 -0
- package/bin/lifeos.js +24 -0
- package/dist/active-docs/citations.d.ts +20 -0
- package/dist/active-docs/citations.js +74 -0
- package/dist/active-docs/citations.js.map +1 -0
- package/dist/active-docs/derived-memory.d.ts +57 -0
- package/dist/active-docs/derived-memory.js +161 -0
- package/dist/active-docs/derived-memory.js.map +1 -0
- package/dist/active-docs/index.d.ts +51 -0
- package/dist/active-docs/index.js +165 -0
- package/dist/active-docs/index.js.map +1 -0
- package/dist/active-docs/long-term-profile.d.ts +24 -0
- package/dist/active-docs/long-term-profile.js +75 -0
- package/dist/active-docs/long-term-profile.js.map +1 -0
- package/dist/active-docs/taskboard.d.ts +12 -0
- package/dist/active-docs/taskboard.js +146 -0
- package/dist/active-docs/taskboard.js.map +1 -0
- package/dist/active-docs/userprofile.d.ts +12 -0
- package/dist/active-docs/userprofile.js +169 -0
- package/dist/active-docs/userprofile.js.map +1 -0
- package/dist/cli/commands/doctor.d.ts +9 -0
- package/dist/cli/commands/doctor.js +125 -0
- package/dist/cli/commands/doctor.js.map +1 -0
- package/dist/cli/commands/init.d.ts +1 -0
- package/dist/cli/commands/init.js +129 -0
- package/dist/cli/commands/init.js.map +1 -0
- package/dist/cli/commands/rename.d.ts +7 -0
- package/dist/cli/commands/rename.js +188 -0
- package/dist/cli/commands/rename.js.map +1 -0
- package/dist/cli/commands/upgrade.d.ts +6 -0
- package/dist/cli/commands/upgrade.js +66 -0
- package/dist/cli/commands/upgrade.js.map +1 -0
- package/dist/cli/index.d.ts +1 -0
- package/dist/cli/index.js +52 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/utils/assets.d.ts +3 -0
- package/dist/cli/utils/assets.js +20 -0
- package/dist/cli/utils/assets.js.map +1 -0
- package/dist/cli/utils/install-assets.d.ts +39 -0
- package/dist/cli/utils/install-assets.js +141 -0
- package/dist/cli/utils/install-assets.js.map +1 -0
- package/dist/cli/utils/lang.d.ts +1 -0
- package/dist/cli/utils/lang.js +32 -0
- package/dist/cli/utils/lang.js.map +1 -0
- package/dist/cli/utils/managed-assets.d.ts +9 -0
- package/dist/cli/utils/managed-assets.js +20 -0
- package/dist/cli/utils/managed-assets.js.map +1 -0
- package/dist/cli/utils/mcp-register.d.ts +2 -0
- package/dist/cli/utils/mcp-register.js +132 -0
- package/dist/cli/utils/mcp-register.js.map +1 -0
- package/dist/cli/utils/sync-vault.d.ts +14 -0
- package/dist/cli/utils/sync-vault.js +132 -0
- package/dist/cli/utils/sync-vault.js.map +1 -0
- package/dist/cli/utils/ui.d.ts +14 -0
- package/dist/cli/utils/ui.js +78 -0
- package/dist/cli/utils/ui.js.map +1 -0
- package/dist/cli/utils/version.d.ts +1 -0
- package/dist/cli/utils/version.js +4 -0
- package/dist/cli/utils/version.js.map +1 -0
- package/dist/config.d.ts +127 -0
- package/dist/config.js +356 -0
- package/dist/config.js.map +1 -0
- package/dist/core.d.ts +106 -0
- package/dist/core.js +286 -0
- package/dist/core.js.map +1 -0
- package/dist/db/consolidation.d.ts +14 -0
- package/dist/db/consolidation.js +28 -0
- package/dist/db/consolidation.js.map +1 -0
- package/dist/db/index.d.ts +22 -0
- package/dist/db/index.js +39 -0
- package/dist/db/index.js.map +1 -0
- package/dist/db/schema.d.ts +7 -0
- package/dist/db/schema.js +175 -0
- package/dist/db/schema.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -0
- package/dist/server.d.ts +6 -0
- package/dist/server.js +303 -0
- package/dist/server.js.map +1 -0
- package/dist/services/capture.d.ts +101 -0
- package/dist/services/capture.js +297 -0
- package/dist/services/capture.js.map +1 -0
- package/dist/services/enhance.d.ts +51 -0
- package/dist/services/enhance.js +184 -0
- package/dist/services/enhance.js.map +1 -0
- package/dist/services/layer0.d.ts +24 -0
- package/dist/services/layer0.js +90 -0
- package/dist/services/layer0.js.map +1 -0
- package/dist/services/maintenance.d.ts +27 -0
- package/dist/services/maintenance.js +73 -0
- package/dist/services/maintenance.js.map +1 -0
- package/dist/services/retrieval.d.ts +120 -0
- package/dist/services/retrieval.js +571 -0
- package/dist/services/retrieval.js.map +1 -0
- package/dist/services/startup.d.ts +28 -0
- package/dist/services/startup.js +112 -0
- package/dist/services/startup.js.map +1 -0
- package/dist/skill-context/ask-global.d.ts +8 -0
- package/dist/skill-context/ask-global.js +21 -0
- package/dist/skill-context/ask-global.js.map +1 -0
- package/dist/skill-context/base.d.ts +48 -0
- package/dist/skill-context/base.js +5 -0
- package/dist/skill-context/base.js.map +1 -0
- package/dist/skill-context/daily-global.d.ts +8 -0
- package/dist/skill-context/daily-global.js +25 -0
- package/dist/skill-context/daily-global.js.map +1 -0
- package/dist/skill-context/index.d.ts +32 -0
- package/dist/skill-context/index.js +171 -0
- package/dist/skill-context/index.js.map +1 -0
- package/dist/skill-context/knowledge-strict.d.ts +8 -0
- package/dist/skill-context/knowledge-strict.js +26 -0
- package/dist/skill-context/knowledge-strict.js.map +1 -0
- package/dist/skill-context/review-strict.d.ts +8 -0
- package/dist/skill-context/review-strict.js +26 -0
- package/dist/skill-context/review-strict.js.map +1 -0
- package/dist/skill-context/revise-strict.d.ts +8 -0
- package/dist/skill-context/revise-strict.js +26 -0
- package/dist/skill-context/revise-strict.js.map +1 -0
- package/dist/skill-context/seed-profiles.d.ts +21 -0
- package/dist/skill-context/seed-profiles.js +80 -0
- package/dist/skill-context/seed-profiles.js.map +1 -0
- package/dist/types.d.ts +165 -0
- package/dist/types.js +76 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/context-policy.d.ts +57 -0
- package/dist/utils/context-policy.js +333 -0
- package/dist/utils/context-policy.js.map +1 -0
- package/dist/utils/scan-state.d.ts +41 -0
- package/dist/utils/scan-state.js +79 -0
- package/dist/utils/scan-state.js.map +1 -0
- package/dist/utils/segmenter.d.ts +19 -0
- package/dist/utils/segmenter.js +75 -0
- package/dist/utils/segmenter.js.map +1 -0
- package/dist/utils/shared.d.ts +103 -0
- package/dist/utils/shared.js +313 -0
- package/dist/utils/shared.js.map +1 -0
- package/dist/utils/vault-indexer.d.ts +53 -0
- package/dist/utils/vault-indexer.js +256 -0
- package/dist/utils/vault-indexer.js.map +1 -0
- package/package.json +59 -0
|
@@ -0,0 +1,333 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* context-policy.ts — ContextPolicy.md 读取与策略解析。
|
|
3
|
+
*
|
|
4
|
+
* Reads the ContextPolicy markdown file from the vault memory directory
|
|
5
|
+
* and provides runtime policy resolution for scenes and skill profiles.
|
|
6
|
+
*/
|
|
7
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
8
|
+
import { join } from 'node:path';
|
|
9
|
+
import { getVaultConfig, resolveConfig } from '../config.js';
|
|
10
|
+
// ─── Default skill profile policies ──────────────────────────────────────────
|
|
11
|
+
export const DEFAULT_SKILL_PROFILE_POLICIES = {
|
|
12
|
+
revise_strict: {
|
|
13
|
+
load_taskboard: false,
|
|
14
|
+
allow_domain_tag_fallback: false,
|
|
15
|
+
ranking_bias: { revise: 50, knowledge: 30, correction: 90 },
|
|
16
|
+
recent_event_bias: { correction: 40, skill_completion: 20, milestone: 15 },
|
|
17
|
+
},
|
|
18
|
+
ask_global: {
|
|
19
|
+
load_taskboard: false,
|
|
20
|
+
allow_domain_tag_fallback: true,
|
|
21
|
+
ranking_bias: {},
|
|
22
|
+
recent_event_bias: { decision: 20, correction: 20, preference: 10 },
|
|
23
|
+
},
|
|
24
|
+
daily_global: {
|
|
25
|
+
load_taskboard: false,
|
|
26
|
+
allow_domain_tag_fallback: false,
|
|
27
|
+
ranking_bias: { project: 60, revise: 45, daily: 30 },
|
|
28
|
+
recent_event_bias: { decision: 35, skill_completion: 15, milestone: 10 },
|
|
29
|
+
},
|
|
30
|
+
research_seed: {
|
|
31
|
+
load_taskboard: false,
|
|
32
|
+
allow_domain_tag_fallback: true,
|
|
33
|
+
ranking_bias: { draft: 60, research: 50, resource: 40 },
|
|
34
|
+
recent_event_bias: { decision: 20, preference: 15, skill_completion: 15, milestone: 10 },
|
|
35
|
+
},
|
|
36
|
+
project_seed: {
|
|
37
|
+
load_taskboard: false,
|
|
38
|
+
allow_domain_tag_fallback: true,
|
|
39
|
+
ranking_bias: { project: 60, research: 45, resource: 35, draft: 20 },
|
|
40
|
+
recent_event_bias: { decision: 30, milestone: 20, skill_completion: 15, correction: 10 },
|
|
41
|
+
},
|
|
42
|
+
knowledge_strict: {
|
|
43
|
+
load_taskboard: false,
|
|
44
|
+
allow_domain_tag_fallback: false,
|
|
45
|
+
ranking_bias: { knowledge: 70, project: 35, resource: 25 },
|
|
46
|
+
recent_event_bias: { correction: 35, decision: 15, skill_completion: 10 },
|
|
47
|
+
},
|
|
48
|
+
};
|
|
49
|
+
// ─── Default policy markdown template ────────────────────────────────────────
|
|
50
|
+
function defaultContextPolicyMarkdown(created) {
|
|
51
|
+
return `---
|
|
52
|
+
type: context-policy
|
|
53
|
+
created: "${created}"
|
|
54
|
+
---
|
|
55
|
+
|
|
56
|
+
# ContextPolicy
|
|
57
|
+
|
|
58
|
+
本文件由 LifeOS 记忆系统自动生成,用于控制 Layer 0 上下文的预算和场景策略。
|
|
59
|
+
可手动编辑以调整行为。
|
|
60
|
+
|
|
61
|
+
## Layer 0 预算
|
|
62
|
+
|
|
63
|
+
layer0_total: 1200
|
|
64
|
+
userprofile_summary: 400
|
|
65
|
+
taskboard_focus: 800
|
|
66
|
+
userprofile_doc_limit: 2000
|
|
67
|
+
taskboard_doc_limit: 3000
|
|
68
|
+
|
|
69
|
+
## 场景策略
|
|
70
|
+
|
|
71
|
+
/today: citation_required taskboard
|
|
72
|
+
/research: domain_fallback research draft resource
|
|
73
|
+
/project: domain_fallback project research resource draft
|
|
74
|
+
/knowledge: knowledge project resource
|
|
75
|
+
/revise: citation_required revise knowledge correction
|
|
76
|
+
/ask: domain_fallback
|
|
77
|
+
/brainstorm: domain_fallback draft research
|
|
78
|
+
/publish: knowledge project research
|
|
79
|
+
/ppt: knowledge project research
|
|
80
|
+
|
|
81
|
+
## 技能画像策略
|
|
82
|
+
|
|
83
|
+
revise_strict: load_taskboard=false domain_fallback=false
|
|
84
|
+
ask_global: load_taskboard=false domain_fallback=true
|
|
85
|
+
daily_global: load_taskboard=false domain_fallback=false
|
|
86
|
+
research_seed: load_taskboard=false domain_fallback=true
|
|
87
|
+
project_seed: load_taskboard=false domain_fallback=true
|
|
88
|
+
knowledge_strict: load_taskboard=false domain_fallback=false
|
|
89
|
+
|
|
90
|
+
## 强制引用场景
|
|
91
|
+
|
|
92
|
+
/today
|
|
93
|
+
/revise
|
|
94
|
+
|
|
95
|
+
## 活文档体积约束
|
|
96
|
+
|
|
97
|
+
TaskBoard: 3000
|
|
98
|
+
UserProfile: 2000
|
|
99
|
+
`;
|
|
100
|
+
}
|
|
101
|
+
// ─── Path helpers ─────────────────────────────────────────────────────────────
|
|
102
|
+
/**
|
|
103
|
+
* Resolve the absolute path to ContextPolicy.md for the given vault root.
|
|
104
|
+
* Uses the global VaultConfig singleton when available; otherwise falls back
|
|
105
|
+
* to the zh preset.
|
|
106
|
+
*/
|
|
107
|
+
export function contextPolicyPath(vaultRoot) {
|
|
108
|
+
const vc = getVaultConfig();
|
|
109
|
+
if (vc !== null) {
|
|
110
|
+
return join(vc.memoryDir(), 'ContextPolicy.md');
|
|
111
|
+
}
|
|
112
|
+
// Fall back: build a temporary config without registering as singleton
|
|
113
|
+
const tempVc = resolveConfig(vaultRoot);
|
|
114
|
+
return join(tempVc.memoryDir(), 'ContextPolicy.md');
|
|
115
|
+
}
|
|
116
|
+
// ─── Ensure file exists ───────────────────────────────────────────────────────
|
|
117
|
+
/**
|
|
118
|
+
* Ensure ContextPolicy.md exists at the correct location.
|
|
119
|
+
* Creates the file with default content when missing.
|
|
120
|
+
* Returns the absolute path.
|
|
121
|
+
*/
|
|
122
|
+
export function ensureContextPolicyExists(vaultRoot) {
|
|
123
|
+
const path = contextPolicyPath(vaultRoot);
|
|
124
|
+
const dir = path.substring(0, path.lastIndexOf('/'));
|
|
125
|
+
mkdirSync(dir, { recursive: true });
|
|
126
|
+
if (!existsSync(path)) {
|
|
127
|
+
const created = new Date().toISOString().slice(0, 10);
|
|
128
|
+
writeFileSync(path, defaultContextPolicyMarkdown(created), 'utf-8');
|
|
129
|
+
}
|
|
130
|
+
return path;
|
|
131
|
+
}
|
|
132
|
+
// ─── Section extraction ───────────────────────────────────────────────────────
|
|
133
|
+
/**
|
|
134
|
+
* Extract non-empty content lines from a named markdown H2 section.
|
|
135
|
+
* Stops at the next H2 heading (## ...) or end of file.
|
|
136
|
+
*/
|
|
137
|
+
function extractSectionLines(content, sectionTitle) {
|
|
138
|
+
const lines = content.split('\n');
|
|
139
|
+
let inSection = false;
|
|
140
|
+
const result = [];
|
|
141
|
+
for (const line of lines) {
|
|
142
|
+
if (line.startsWith('## ')) {
|
|
143
|
+
if (inSection)
|
|
144
|
+
break; // reached next section
|
|
145
|
+
if (line === `## ${sectionTitle}`) {
|
|
146
|
+
inSection = true;
|
|
147
|
+
}
|
|
148
|
+
continue;
|
|
149
|
+
}
|
|
150
|
+
if (inSection) {
|
|
151
|
+
const trimmed = line.trim();
|
|
152
|
+
// Skip frontmatter-style separators and empty lines
|
|
153
|
+
if (trimmed && !trimmed.startsWith('---')) {
|
|
154
|
+
result.push(trimmed);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
return result;
|
|
159
|
+
}
|
|
160
|
+
// ─── Budget parsing ───────────────────────────────────────────────────────────
|
|
161
|
+
/**
|
|
162
|
+
* Parse context budget values from the "Layer 0 预算" section.
|
|
163
|
+
* Falls back to VaultConfig.contextBudgets() when the vault root is provided.
|
|
164
|
+
*/
|
|
165
|
+
function loadContextBudgets(content, vaultRoot) {
|
|
166
|
+
// Try to parse from the markdown section first
|
|
167
|
+
const lines = extractSectionLines(content, 'Layer 0 预算');
|
|
168
|
+
const parsed = {};
|
|
169
|
+
for (const line of lines) {
|
|
170
|
+
if (!line.includes(':'))
|
|
171
|
+
continue;
|
|
172
|
+
const colonIdx = line.indexOf(':');
|
|
173
|
+
const key = line.slice(0, colonIdx).trim();
|
|
174
|
+
const val = Number.parseInt(line.slice(colonIdx + 1).trim(), 10);
|
|
175
|
+
if (key && !Number.isNaN(val)) {
|
|
176
|
+
parsed[key] = val;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
// Fall back to VaultConfig for any missing keys
|
|
180
|
+
const vc = getVaultConfig() ?? resolveConfig(vaultRoot);
|
|
181
|
+
const defaults = vc.contextBudgets();
|
|
182
|
+
return { ...defaults, ...parsed };
|
|
183
|
+
}
|
|
184
|
+
// ─── Skill profile parsing ────────────────────────────────────────────────────
|
|
185
|
+
/**
|
|
186
|
+
* Parse a skill profile rule string into a partial SkillProfilePolicy.
|
|
187
|
+
* Recognises tokens: load_taskboard=true/false, domain_fallback=true/false
|
|
188
|
+
*/
|
|
189
|
+
function parseSkillProfileRule(rule) {
|
|
190
|
+
const result = {};
|
|
191
|
+
const tokens = rule.split(/\s+/);
|
|
192
|
+
for (const token of tokens) {
|
|
193
|
+
if (token.startsWith('load_taskboard=')) {
|
|
194
|
+
result.load_taskboard = token.endsWith('true');
|
|
195
|
+
}
|
|
196
|
+
else if (token.startsWith('domain_fallback=')) {
|
|
197
|
+
result.allow_domain_tag_fallback = token.endsWith('true');
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
return result;
|
|
201
|
+
}
|
|
202
|
+
// ─── Load ─────────────────────────────────────────────────────────────────────
|
|
203
|
+
/**
|
|
204
|
+
* Load and parse the ContextPolicy.md file from the vault.
|
|
205
|
+
* Creates the file with defaults if it does not exist.
|
|
206
|
+
*/
|
|
207
|
+
export function loadContextPolicy(vaultRoot) {
|
|
208
|
+
const path = ensureContextPolicyExists(vaultRoot);
|
|
209
|
+
const content = readFileSync(path, 'utf-8');
|
|
210
|
+
// Parse scenes
|
|
211
|
+
const scenes = {};
|
|
212
|
+
for (const line of extractSectionLines(content, '场景策略')) {
|
|
213
|
+
if (!line.includes(':'))
|
|
214
|
+
continue;
|
|
215
|
+
const colonIdx = line.indexOf(':');
|
|
216
|
+
const name = line.slice(0, colonIdx).trim();
|
|
217
|
+
const rule = line.slice(colonIdx + 1).trim();
|
|
218
|
+
if (name)
|
|
219
|
+
scenes[name] = rule;
|
|
220
|
+
}
|
|
221
|
+
// Parse skill profiles
|
|
222
|
+
const skillProfiles = {};
|
|
223
|
+
for (const line of extractSectionLines(content, '技能画像策略')) {
|
|
224
|
+
if (!line.includes(':'))
|
|
225
|
+
continue;
|
|
226
|
+
const colonIdx = line.indexOf(':');
|
|
227
|
+
const name = line.slice(0, colonIdx).trim();
|
|
228
|
+
const rule = line.slice(colonIdx + 1).trim();
|
|
229
|
+
if (name)
|
|
230
|
+
skillProfiles[name] = parseSkillProfileRule(rule);
|
|
231
|
+
}
|
|
232
|
+
// Parse citation_required lines
|
|
233
|
+
const citationRequired = extractSectionLines(content, '强制引用场景');
|
|
234
|
+
// Parse budgets
|
|
235
|
+
const budgets = loadContextBudgets(content, vaultRoot);
|
|
236
|
+
return {
|
|
237
|
+
layer0_total: budgets.layer0_total ?? 1200,
|
|
238
|
+
userprofile_summary: budgets.userprofile_summary ?? 400,
|
|
239
|
+
taskboard_focus: budgets.taskboard_focus ?? 800,
|
|
240
|
+
userprofile_doc_limit: budgets.userprofile_doc_limit ?? 2000,
|
|
241
|
+
taskboard_doc_limit: budgets.taskboard_doc_limit ?? 3000,
|
|
242
|
+
scenes,
|
|
243
|
+
citation_required: citationRequired,
|
|
244
|
+
skill_profiles: skillProfiles,
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
// ─── Scene policy resolution ──────────────────────────────────────────────────
|
|
248
|
+
/**
|
|
249
|
+
* Keyword → bias bucket mappings for scene rule text.
|
|
250
|
+
* Each keyword maps to a { bucket: weight } pair to inject into ranking_bias
|
|
251
|
+
* or recent_event_bias.
|
|
252
|
+
*/
|
|
253
|
+
const SCENE_RANKING_KEYWORDS = {
|
|
254
|
+
taskboard: { project: 40, daily: 20 },
|
|
255
|
+
project: { project: 50 },
|
|
256
|
+
research: { research: 50 },
|
|
257
|
+
draft: { draft: 40 },
|
|
258
|
+
resource: { resource: 35 },
|
|
259
|
+
knowledge: { knowledge: 50 },
|
|
260
|
+
revise: { revise: 45 },
|
|
261
|
+
daily: { daily: 30 },
|
|
262
|
+
};
|
|
263
|
+
const SCENE_EVENT_KEYWORDS = {
|
|
264
|
+
citation_required: { correction: 30, decision: 25 },
|
|
265
|
+
taskboard: { skill_completion: 15, milestone: 10 },
|
|
266
|
+
project: { decision: 30, milestone: 20 },
|
|
267
|
+
research: { decision: 20, preference: 15 },
|
|
268
|
+
revise: { correction: 40, skill_completion: 20 },
|
|
269
|
+
};
|
|
270
|
+
/**
|
|
271
|
+
* Derive a runtime ScenePolicy from the stored rule text for a given scene name.
|
|
272
|
+
*/
|
|
273
|
+
export function resolveScenePolicy(policy, scene) {
|
|
274
|
+
const sceneName = String(scene);
|
|
275
|
+
const rule = String(policy.scenes?.[sceneName] ?? '').trim();
|
|
276
|
+
if (!rule) {
|
|
277
|
+
return {
|
|
278
|
+
scene: sceneName,
|
|
279
|
+
citation_required: false,
|
|
280
|
+
load_taskboard: false,
|
|
281
|
+
ranking_bias: {},
|
|
282
|
+
recent_event_bias: {},
|
|
283
|
+
};
|
|
284
|
+
}
|
|
285
|
+
const tokens = rule.split(/\s+/).filter(Boolean);
|
|
286
|
+
const citationRequired = tokens.includes('citation_required');
|
|
287
|
+
const loadTaskboard = tokens.includes('taskboard');
|
|
288
|
+
const rankingBias = {};
|
|
289
|
+
const recentEventBias = {};
|
|
290
|
+
for (const token of tokens) {
|
|
291
|
+
const rb = SCENE_RANKING_KEYWORDS[token];
|
|
292
|
+
if (rb) {
|
|
293
|
+
for (const [k, v] of Object.entries(rb)) {
|
|
294
|
+
rankingBias[k] = Math.max(rankingBias[k] ?? 0, v);
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
const eb = SCENE_EVENT_KEYWORDS[token];
|
|
298
|
+
if (eb) {
|
|
299
|
+
for (const [k, v] of Object.entries(eb)) {
|
|
300
|
+
recentEventBias[k] = Math.max(recentEventBias[k] ?? 0, v);
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
return {
|
|
305
|
+
scene: sceneName,
|
|
306
|
+
citation_required: citationRequired,
|
|
307
|
+
load_taskboard: loadTaskboard,
|
|
308
|
+
ranking_bias: rankingBias,
|
|
309
|
+
recent_event_bias: recentEventBias,
|
|
310
|
+
};
|
|
311
|
+
}
|
|
312
|
+
// ─── Skill profile policy resolution ─────────────────────────────────────────
|
|
313
|
+
/**
|
|
314
|
+
* Merge loaded skill profile settings with built-in defaults.
|
|
315
|
+
* Loaded values take precedence over defaults.
|
|
316
|
+
*/
|
|
317
|
+
export function resolveSkillProfilePolicy(policy, skillProfile) {
|
|
318
|
+
const loaded = policy.skill_profiles?.[skillProfile] ?? {};
|
|
319
|
+
const base = DEFAULT_SKILL_PROFILE_POLICIES[skillProfile] ?? {
|
|
320
|
+
load_taskboard: false,
|
|
321
|
+
allow_domain_tag_fallback: false,
|
|
322
|
+
ranking_bias: {},
|
|
323
|
+
recent_event_bias: {},
|
|
324
|
+
};
|
|
325
|
+
return {
|
|
326
|
+
skill_profile: skillProfile,
|
|
327
|
+
load_taskboard: loaded.load_taskboard ?? base.load_taskboard,
|
|
328
|
+
allow_domain_tag_fallback: loaded.allow_domain_tag_fallback ?? base.allow_domain_tag_fallback,
|
|
329
|
+
ranking_bias: { ...base.ranking_bias, ...(loaded.ranking_bias ?? {}) },
|
|
330
|
+
recent_event_bias: { ...base.recent_event_bias, ...(loaded.recent_event_bias ?? {}) },
|
|
331
|
+
};
|
|
332
|
+
}
|
|
333
|
+
//# sourceMappingURL=context-policy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context-policy.js","sourceRoot":"","sources":["../../src/utils/context-policy.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* scan-state.ts — 扫描状态管理。
|
|
3
|
+
*
|
|
4
|
+
* Tracks file mtime/size to avoid re-indexing unchanged files during
|
|
5
|
+
* incremental vault scans.
|
|
6
|
+
*/
|
|
7
|
+
import type Database from 'better-sqlite3';
|
|
8
|
+
export interface ScanStateEntry {
|
|
9
|
+
file_path: string;
|
|
10
|
+
last_seen_hash: string | null;
|
|
11
|
+
last_seen_mtime: number;
|
|
12
|
+
last_seen_size: number;
|
|
13
|
+
last_indexed_at: string | null;
|
|
14
|
+
}
|
|
15
|
+
/** Tuple layout: [file_path, content_hash, mtime, size, indexed_at] */
|
|
16
|
+
export type ScanStateRow = [string, string | null, number, number, string | null];
|
|
17
|
+
/**
|
|
18
|
+
* Load all scan state rows from the database.
|
|
19
|
+
* Returns a Record keyed by file_path.
|
|
20
|
+
*/
|
|
21
|
+
export declare function loadScanState(db: Database.Database): Record<string, ScanStateEntry>;
|
|
22
|
+
/**
|
|
23
|
+
* Return true when the stored scan state matches the given mtime and size.
|
|
24
|
+
* Both values must match exactly (float comparison for mtime, int for size).
|
|
25
|
+
*/
|
|
26
|
+
export declare function isSameObservedState(state: ScanStateEntry | null | undefined, mtime: number, size: number): boolean;
|
|
27
|
+
/**
|
|
28
|
+
* Build a scan state row tuple ready for insertion.
|
|
29
|
+
* Layout: [file_path, content_hash, mtime, size, indexed_at]
|
|
30
|
+
*/
|
|
31
|
+
export declare function buildScanStateRow(filePath: string, contentHash: string | null, mtime: number, size: number, indexedAt: string | null): ScanStateRow;
|
|
32
|
+
/**
|
|
33
|
+
* Batch-upsert scan state rows into the database.
|
|
34
|
+
* No-op when rows array is empty.
|
|
35
|
+
*/
|
|
36
|
+
export declare function upsertScanStateRows(db: Database.Database, rows: ScanStateRow[]): void;
|
|
37
|
+
/**
|
|
38
|
+
* Batch-delete scan state rows by file path.
|
|
39
|
+
* No-op when filePaths array is empty.
|
|
40
|
+
*/
|
|
41
|
+
export declare function deleteScanStateRows(db: Database.Database, filePaths: string[]): void;
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* scan-state.ts — 扫描状态管理。
|
|
3
|
+
*
|
|
4
|
+
* Tracks file mtime/size to avoid re-indexing unchanged files during
|
|
5
|
+
* incremental vault scans.
|
|
6
|
+
*/
|
|
7
|
+
// ─── Load ─────────────────────────────────────────────────────────────────────
|
|
8
|
+
/**
|
|
9
|
+
* Load all scan state rows from the database.
|
|
10
|
+
* Returns a Record keyed by file_path.
|
|
11
|
+
*/
|
|
12
|
+
export function loadScanState(db) {
|
|
13
|
+
const rows = db
|
|
14
|
+
.prepare('SELECT file_path, last_seen_hash, last_seen_mtime, last_seen_size, last_indexed_at FROM scan_state')
|
|
15
|
+
.all();
|
|
16
|
+
const result = {};
|
|
17
|
+
for (const row of rows) {
|
|
18
|
+
result[row.file_path] = {
|
|
19
|
+
file_path: row.file_path,
|
|
20
|
+
last_seen_hash: row.last_seen_hash,
|
|
21
|
+
last_seen_mtime: Number(row.last_seen_mtime),
|
|
22
|
+
last_seen_size: Number(row.last_seen_size),
|
|
23
|
+
last_indexed_at: row.last_indexed_at,
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
return result;
|
|
27
|
+
}
|
|
28
|
+
// ─── Compare ──────────────────────────────────────────────────────────────────
|
|
29
|
+
/**
|
|
30
|
+
* Return true when the stored scan state matches the given mtime and size.
|
|
31
|
+
* Both values must match exactly (float comparison for mtime, int for size).
|
|
32
|
+
*/
|
|
33
|
+
export function isSameObservedState(state, mtime, size) {
|
|
34
|
+
if (!state)
|
|
35
|
+
return false;
|
|
36
|
+
return (Number.parseFloat(String(state.last_seen_mtime ?? 0)) === Number.parseFloat(String(mtime)) &&
|
|
37
|
+
Number.parseInt(String(state.last_seen_size ?? -1), 10) === Number.parseInt(String(size), 10));
|
|
38
|
+
}
|
|
39
|
+
// ─── Build ────────────────────────────────────────────────────────────────────
|
|
40
|
+
/**
|
|
41
|
+
* Build a scan state row tuple ready for insertion.
|
|
42
|
+
* Layout: [file_path, content_hash, mtime, size, indexed_at]
|
|
43
|
+
*/
|
|
44
|
+
export function buildScanStateRow(filePath, contentHash, mtime, size, indexedAt) {
|
|
45
|
+
return [filePath, contentHash, Number(mtime), Number(size), indexedAt];
|
|
46
|
+
}
|
|
47
|
+
// ─── Upsert ───────────────────────────────────────────────────────────────────
|
|
48
|
+
/**
|
|
49
|
+
* Batch-upsert scan state rows into the database.
|
|
50
|
+
* No-op when rows array is empty.
|
|
51
|
+
*/
|
|
52
|
+
export function upsertScanStateRows(db, rows) {
|
|
53
|
+
if (rows.length === 0)
|
|
54
|
+
return;
|
|
55
|
+
const stmt = db.prepare('INSERT OR REPLACE INTO scan_state (file_path, last_seen_hash, last_seen_mtime, last_seen_size, last_indexed_at) VALUES (?, ?, ?, ?, ?)');
|
|
56
|
+
const upsertMany = db.transaction((batch) => {
|
|
57
|
+
for (const row of batch) {
|
|
58
|
+
stmt.run(row);
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
upsertMany(rows);
|
|
62
|
+
}
|
|
63
|
+
// ─── Delete ───────────────────────────────────────────────────────────────────
|
|
64
|
+
/**
|
|
65
|
+
* Batch-delete scan state rows by file path.
|
|
66
|
+
* No-op when filePaths array is empty.
|
|
67
|
+
*/
|
|
68
|
+
export function deleteScanStateRows(db, filePaths) {
|
|
69
|
+
if (filePaths.length === 0)
|
|
70
|
+
return;
|
|
71
|
+
const stmt = db.prepare('DELETE FROM scan_state WHERE file_path = ?');
|
|
72
|
+
const deleteMany = db.transaction((paths) => {
|
|
73
|
+
for (const fp of paths) {
|
|
74
|
+
stmt.run(fp);
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
deleteMany(filePaths);
|
|
78
|
+
}
|
|
79
|
+
//# sourceMappingURL=scan-state.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scan-state.js","sourceRoot":"","sources":["../../src/utils/scan-state.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAiBH,iFAAiF;AAEjF;;;GAGG;AACH,MAAM,UAAU,aAAa,CAAC,EAAqB;IAClD,MAAM,IAAI,GAAG,EAAE;SACb,OAAO,CACP,oGAAoG,CACpG;SACA,GAAG,EAMH,CAAC;IAEH,MAAM,MAAM,GAAmC,EAAE,CAAC;IAClD,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACxB,MAAM,CAAC,GAAG,CAAC,SAAS,CAAC,GAAG;YACvB,SAAS,EAAE,GAAG,CAAC,SAAS;YACxB,cAAc,EAAE,GAAG,CAAC,cAAc;YAClC,eAAe,EAAE,MAAM,CAAC,GAAG,CAAC,eAAe,CAAC;YAC5C,cAAc,EAAE,MAAM,CAAC,GAAG,CAAC,cAAc,CAAC;YAC1C,eAAe,EAAE,GAAG,CAAC,eAAe;SACpC,CAAC;IACH,CAAC;IACD,OAAO,MAAM,CAAC;AACf,CAAC;AAED,iFAAiF;AAEjF;;;GAGG;AACH,MAAM,UAAU,mBAAmB,CAClC,KAAwC,EACxC,KAAa,EACb,IAAY;IAEZ,IAAI,CAAC,KAAK;QAAE,OAAO,KAAK,CAAC;IACzB,OAAO,CACN,MAAM,CAAC,UAAU,CAAC,MAAM,CAAC,KAAK,CAAC,eAAe,IAAI,CAAC,CAAC,CAAC,KAAK,MAAM,CAAC,UAAU,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QAC1F,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,cAAc,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC,CAC7F,CAAC;AACH,CAAC;AAED,iFAAiF;AAEjF;;;GAGG;AACH,MAAM,UAAU,iBAAiB,CAChC,QAAgB,EAChB,WAA0B,EAC1B,KAAa,EACb,IAAY,EACZ,SAAwB;IAExB,OAAO,CAAC,QAAQ,EAAE,WAAW,EAAE,MAAM,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC,IAAI,CAAC,EAAE,SAAS,CAAC,CAAC;AACxE,CAAC;AAED,iFAAiF;AAEjF;;;GAGG;AACH,MAAM,UAAU,mBAAmB,CAAC,EAAqB,EAAE,IAAoB;IAC9E,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO;IAC9B,MAAM,IAAI,GAAG,EAAE,CAAC,OAAO,CACtB,wIAAwI,CACxI,CAAC;IACF,MAAM,UAAU,GAAG,EAAE,CAAC,WAAW,CAAC,CAAC,KAAqB,EAAE,EAAE;QAC3D,KAAK,MAAM,GAAG,IAAI,KAAK,EAAE,CAAC;YACzB,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACf,CAAC;IACF,CAAC,CAAC,CAAC;IACH,UAAU,CAAC,IAAI,CAAC,CAAC;AAClB,CAAC;AAED,iFAAiF;AAEjF;;;GAGG;AACH,MAAM,UAAU,mBAAmB,CAAC,EAAqB,EAAE,SAAmB;IAC7E,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO;IACnC,MAAM,IAAI,GAAG,EAAE,CAAC,OAAO,CAAC,4CAA4C,CAAC,CAAC;IACtE,MAAM,UAAU,GAAG,EAAE,CAAC,WAAW,CAAC,CAAC,KAAe,EAAE,EAAE;QACrD,KAAK,MAAM,EAAE,IAAI,KAAK,EAAE,CAAC;YACxB,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACd,CAAC;IACF,CAAC,CAAC,CAAC;IACH,UAAU,CAAC,SAAS,CAAC,CAAC;AACvB,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Load a custom dictionary file into the jieba instance.
|
|
3
|
+
* File format: one word per line, optionally followed by frequency and POS tag.
|
|
4
|
+
* Example: "四元数群 5 n"
|
|
5
|
+
*
|
|
6
|
+
* Converts the text-based dict to the binary format jieba expects.
|
|
7
|
+
*/
|
|
8
|
+
export declare function loadCustomDict(dictPath: string): void;
|
|
9
|
+
/**
|
|
10
|
+
* Tokenize text into words using jieba.
|
|
11
|
+
* Handles Chinese, English, and mixed text.
|
|
12
|
+
* Returns deduplicated, lowercased word tokens.
|
|
13
|
+
*/
|
|
14
|
+
export declare function tokenize(text: string): string[];
|
|
15
|
+
/**
|
|
16
|
+
* Build space-separated search tokens from multiple text sources.
|
|
17
|
+
* Accepts strings, arrays, or null values.
|
|
18
|
+
*/
|
|
19
|
+
export declare function buildSearchTokens(...parts: (string | string[] | null | undefined)[]): string;
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { readFileSync } from 'node:fs';
|
|
2
|
+
import { createRequire } from 'node:module';
|
|
3
|
+
import { Jieba } from '@node-rs/jieba';
|
|
4
|
+
// @node-rs/jieba/dict is CJS-only (no ESM exports), so we use createRequire
|
|
5
|
+
const require = createRequire(import.meta.url);
|
|
6
|
+
const { dict } = require('@node-rs/jieba/dict');
|
|
7
|
+
// Singleton jieba instance with default dictionary
|
|
8
|
+
const jieba = Jieba.withDict(dict);
|
|
9
|
+
// Regex for meaningful characters (Chinese, alphanumeric, underscore)
|
|
10
|
+
const MEANINGFUL_CHAR_RE = /[\u4e00-\u9fffA-Za-z0-9_]/;
|
|
11
|
+
/**
|
|
12
|
+
* Normalize markdown text for tokenization.
|
|
13
|
+
* Removes wikilink brackets and hash symbols.
|
|
14
|
+
*/
|
|
15
|
+
function normalizeSearchText(text) {
|
|
16
|
+
let normalized = text.replace(/\[\[([^\]]+)\]\]/g, '$1');
|
|
17
|
+
normalized = normalized.replace(/#/g, ' ');
|
|
18
|
+
return normalized;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Load a custom dictionary file into the jieba instance.
|
|
22
|
+
* File format: one word per line, optionally followed by frequency and POS tag.
|
|
23
|
+
* Example: "四元数群 5 n"
|
|
24
|
+
*
|
|
25
|
+
* Converts the text-based dict to the binary format jieba expects.
|
|
26
|
+
*/
|
|
27
|
+
export function loadCustomDict(dictPath) {
|
|
28
|
+
const content = readFileSync(dictPath);
|
|
29
|
+
jieba.loadDict(content);
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Tokenize text into words using jieba.
|
|
33
|
+
* Handles Chinese, English, and mixed text.
|
|
34
|
+
* Returns deduplicated, lowercased word tokens.
|
|
35
|
+
*/
|
|
36
|
+
export function tokenize(text) {
|
|
37
|
+
const normalized = normalizeSearchText(text).trim();
|
|
38
|
+
if (!normalized)
|
|
39
|
+
return [];
|
|
40
|
+
const words = jieba.cut(normalized, false);
|
|
41
|
+
const tokens = [];
|
|
42
|
+
const seen = new Set();
|
|
43
|
+
for (const word of words) {
|
|
44
|
+
const trimmed = word.trim().toLowerCase();
|
|
45
|
+
if (!trimmed || seen.has(trimmed))
|
|
46
|
+
continue;
|
|
47
|
+
if (!MEANINGFUL_CHAR_RE.test(trimmed))
|
|
48
|
+
continue;
|
|
49
|
+
seen.add(trimmed);
|
|
50
|
+
tokens.push(trimmed);
|
|
51
|
+
}
|
|
52
|
+
return tokens;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Build space-separated search tokens from multiple text sources.
|
|
56
|
+
* Accepts strings, arrays, or null values.
|
|
57
|
+
*/
|
|
58
|
+
export function buildSearchTokens(...parts) {
|
|
59
|
+
const chunks = [];
|
|
60
|
+
for (const part of parts) {
|
|
61
|
+
if (part == null)
|
|
62
|
+
continue;
|
|
63
|
+
if (Array.isArray(part)) {
|
|
64
|
+
for (const item of part) {
|
|
65
|
+
if (item != null)
|
|
66
|
+
chunks.push(String(item));
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
chunks.push(String(part));
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return tokenize(chunks.join(' ')).join(' ');
|
|
74
|
+
}
|
|
75
|
+
//# sourceMappingURL=segmenter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"segmenter.js","sourceRoot":"","sources":["../../src/utils/segmenter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAEvC,4EAA4E;AAC5E,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC/C,MAAM,EAAE,IAAI,EAAE,GAAG,OAAO,CAAC,qBAAqB,CAAyB,CAAC;AAExE,mDAAmD;AACnD,MAAM,KAAK,GAAG,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;AAEnC,sEAAsE;AACtE,MAAM,kBAAkB,GAAG,2BAA2B,CAAC;AAEvD;;;GAGG;AACH,SAAS,mBAAmB,CAAC,IAAY;IACxC,IAAI,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC,mBAAmB,EAAE,IAAI,CAAC,CAAC;IACzD,UAAU,GAAG,UAAU,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;IAC3C,OAAO,UAAU,CAAC;AACnB,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,cAAc,CAAC,QAAgB;IAC9C,MAAM,OAAO,GAAG,YAAY,CAAC,QAAQ,CAAC,CAAC;IACvC,KAAK,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;AACzB,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,QAAQ,CAAC,IAAY;IACpC,MAAM,UAAU,GAAG,mBAAmB,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC;IACpD,IAAI,CAAC,UAAU;QAAE,OAAO,EAAE,CAAC;IAE3B,MAAM,KAAK,GAAG,KAAK,CAAC,GAAG,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC;IAC3C,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAE/B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QAC1B,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QAC1C,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC;YAAE,SAAS;QAC5C,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,OAAO,CAAC;YAAE,SAAS;QAChD,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QAClB,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACtB,CAAC;IAED,OAAO,MAAM,CAAC;AACf,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,iBAAiB,CAAC,GAAG,KAA+C;IACnF,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QAC1B,IAAI,IAAI,IAAI,IAAI;YAAE,SAAS;QAC3B,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;YACzB,KAAK,MAAM,IAAI,IAAI,IAAI,EAAE,CAAC;gBACzB,IAAI,IAAI,IAAI,IAAI;oBAAE,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC;YAC7C,CAAC;QACF,CAAC;aAAM,CAAC;YACP,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC;QAC3B,CAAC;IACF,CAAC;IACD,OAAO,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC7C,CAAC"}
|