fuli-context 0.4.0 → 0.7.2

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 (207) hide show
  1. package/README.en.md +5 -0
  2. package/README.md +411 -173
  3. package/README.zh-CN.md +448 -0
  4. package/compose.graphiti.yml +6 -6
  5. package/dist/web/assets/AboutPage-DXh7Fwxt.css +1 -0
  6. package/dist/web/assets/AboutPage-DfnZo7Lo.js +1 -0
  7. package/dist/web/assets/ConnectionsPage-BloaSKmt.js +1 -0
  8. package/dist/web/assets/ConnectionsPage-CBHAdZXT.css +1 -0
  9. package/dist/web/assets/KnowledgeInspector-Bjhdu2mf.css +1 -0
  10. package/dist/web/assets/KnowledgeInspector-QvNpv0_k.js +1 -0
  11. package/dist/web/assets/KnowledgeOrganizerPage-Cx1w1jb2.css +1 -0
  12. package/dist/web/assets/KnowledgeOrganizerPage-DKq1jVD5.js +1 -0
  13. package/dist/web/assets/KnowledgePage-BWL0jT01.js +1 -0
  14. package/dist/web/assets/KnowledgeWorkspace-Czq6aZ7b.js +4 -0
  15. package/dist/web/assets/OverviewPage-5sJoO1Gh.js +1 -0
  16. package/dist/web/assets/{PersonalProfilePage-S8ZcG2LU.css → PersonalProfilePage-CdmEzyvZ.css} +1 -1
  17. package/dist/web/assets/PersonalProfilePage-tVChM9ik.js +1 -0
  18. package/dist/web/assets/PersonalProjectsPage-BPFrup4V.js +1 -0
  19. package/dist/web/assets/PublicProjectsPage-BPJSeREN.js +1 -0
  20. package/dist/web/assets/ReviewPage-B7EN817i.js +1 -0
  21. package/dist/web/assets/SearchableSelect-ClLN0rIb.js +1 -0
  22. package/dist/web/assets/SettingsPage-C6ouU0sR.css +1 -0
  23. package/dist/web/assets/SettingsPage-Chd_B3eH.js +1 -0
  24. package/dist/web/assets/_plugin-vue_export-helper-BDNMzG2s.js +1 -0
  25. package/dist/web/assets/console-CbDsKrsO.js +1 -0
  26. package/dist/web/assets/fuli-logo-Bu9WBuQe.js +1 -0
  27. package/dist/web/assets/fuli-logo-ER1wQ8Kk.png +0 -0
  28. package/dist/web/assets/i18n-BQcns1PH.js +5 -0
  29. package/dist/web/assets/identity-B8K4VYg6.js +1 -0
  30. package/dist/web/assets/index-CB8Xmsc2.js +2 -0
  31. package/dist/web/assets/index-CZeuPh-U.css +1 -0
  32. package/dist/web/assets/model-eF52GgPF.js +1 -0
  33. package/dist/web/assets/paths-hwz-Ac1g.js +1 -0
  34. package/dist/web/assets/useMinimumLoadingDisplay-BpCyBeko.css +1 -0
  35. package/dist/web/assets/useMinimumLoadingDisplay-wCgGDmHg.js +1 -0
  36. package/dist/web/assets/vue-router-BsEp_XwI.js +1 -0
  37. package/dist/web/index.html +9 -6
  38. package/docs/external-knowledge-architecture.md +279 -0
  39. package/examples/external-knowledge/markdown-folder.mjs +235 -0
  40. package/graph-provider/fuli_graph/app.py +57 -1
  41. package/graph-provider/fuli_graph/graph_models.py +3 -0
  42. package/graph-provider/fuli_graph/graph_query.py +62 -16
  43. package/graph-provider/fuli_graph/knowledge_review.py +612 -0
  44. package/graph-provider/fuli_graph/knowledge_review_models.py +127 -0
  45. package/graph-provider/fuli_graph/knowledge_search.py +51 -4
  46. package/graph-provider/fuli_graph/models.py +19 -0
  47. package/graph-provider/fuli_graph/runtime.py +15 -0
  48. package/graph-provider/fuli_graph/store_knowledge.py +2 -1
  49. package/graph-provider/pyproject.toml +1 -1
  50. package/npm-shrinkwrap.json +5 -407
  51. package/package.json +7 -4
  52. package/skills/capturing-session-knowledge/SKILL.md +24 -4
  53. package/skills/flreview/SKILL.md +73 -0
  54. package/skills/flreview/agents/openai.yaml +6 -0
  55. package/src/agent-tools/graph-definitions.js +79 -4
  56. package/src/agent-tools/graph-handlers.js +12 -0
  57. package/src/cli/command-registry.js +3 -3
  58. package/src/cli/local-runtime-command.js +60 -23
  59. package/src/cli/local-runtime-options.js +16 -6
  60. package/src/cli/setup-agent-selection.js +12 -12
  61. package/src/cli/setup-command.js +41 -18
  62. package/src/cli/shell-argument.js +10 -0
  63. package/src/cli/uninstall-command.js +17 -15
  64. package/src/cli/update-command.js +38 -30
  65. package/src/external-knowledge/catalog.js +61 -0
  66. package/src/external-knowledge/conflict-policy.js +58 -0
  67. package/src/external-knowledge/connected-search.js +166 -0
  68. package/src/external-knowledge/connectors/custom.js +133 -0
  69. package/src/external-knowledge/connectors/feishu.js +461 -0
  70. package/src/external-knowledge/connectors/mcp.js +438 -0
  71. package/src/external-knowledge/connectors/notion.js +307 -0
  72. package/src/external-knowledge/connectors/retrieval-api.js +222 -0
  73. package/src/external-knowledge/document-mapping.js +151 -0
  74. package/src/external-knowledge/graph-projection.js +17 -0
  75. package/src/external-knowledge/index.js +8 -0
  76. package/src/external-knowledge/registry.js +91 -0
  77. package/src/external-knowledge/runtime.js +68 -0
  78. package/src/external-knowledge/safe-diagnostic.js +14 -0
  79. package/src/external-knowledge/service.js +811 -0
  80. package/src/graphiti/agent-knowledge-workflows.js +7 -2
  81. package/src/graphiti/federated-application.js +66 -41
  82. package/src/graphiti/knowledge-item-role.js +21 -0
  83. package/src/graphiti/knowledge-review.js +43 -0
  84. package/src/graphiti/project-profile-mapping.js +32 -0
  85. package/src/graphiti/provider-client.js +22 -1
  86. package/src/graphiti/source-marker.js +54 -3
  87. package/src/graphiti/task-knowledge-recall.js +250 -0
  88. package/src/http/api-router.js +23 -108
  89. package/src/http/external-knowledge-api-router.js +104 -0
  90. package/src/http/graph-api-router.js +12 -1
  91. package/src/http/request-policy.js +38 -3
  92. package/src/local-runtime/lifecycle.js +37 -16
  93. package/src/mcp/create-mcp-server.js +1 -0
  94. package/src/mcp/instructions.js +7 -7
  95. package/src/mcp/tool-annotations.js +6 -0
  96. package/src/mcp/tool-result.js +1 -0
  97. package/src/server/application-lifecycle.js +2 -11
  98. package/src/server/blocked-ports.js +11 -0
  99. package/src/server/lan-access.js +52 -0
  100. package/src/server.js +103 -25
  101. package/src/setup/agent-installation-status.js +2 -1
  102. package/src/setup/agents.js +2 -1
  103. package/src/setup/claude-code-config.js +2 -1
  104. package/src/setup/codex-bootstrap.js +12 -7
  105. package/src/setup/container-runtime.js +25 -21
  106. package/src/setup/graph-runtime.js +219 -58
  107. package/src/setup/node-runtime.js +3 -3
  108. package/src/setup/options.js +2 -4
  109. package/src/setup/paths.js +18 -3
  110. package/src/setup/review-skill-adapters.js +49 -0
  111. package/src/setup/setup.js +26 -2
  112. package/src/setup/uninstall.js +4 -2
  113. package/src/system/resource-monitor.js +317 -0
  114. package/src/system/runtime-settings.js +131 -0
  115. package/src/system/system-service.js +119 -0
  116. package/dist/web/assets/ConnectionsPage-CCKWm-6p.js +0 -1
  117. package/dist/web/assets/KnowledgeInspector-BZkB2wJn.js +0 -1
  118. package/dist/web/assets/KnowledgeInspector-CrGYxEob.css +0 -1
  119. package/dist/web/assets/KnowledgeOrganizerPage-CJCNI2Wd.css +0 -1
  120. package/dist/web/assets/KnowledgeOrganizerPage-PXH-TlGt.js +0 -1
  121. package/dist/web/assets/KnowledgePage-CNQXd15y.js +0 -1
  122. package/dist/web/assets/KnowledgeWorkspace-CXPE4GCD.js +0 -4
  123. package/dist/web/assets/OverviewPage-ul7g7HXh.js +0 -1
  124. package/dist/web/assets/PersonalProfilePage-CC40Pw2L.js +0 -1
  125. package/dist/web/assets/PersonalProjectsPage-CPIEcShD.js +0 -1
  126. package/dist/web/assets/PublicProjectsPage-C700sR7z.js +0 -1
  127. package/dist/web/assets/ReviewPage-7MDDUDgA.js +0 -1
  128. package/dist/web/assets/console-B_Ena2DS.js +0 -5
  129. package/dist/web/assets/fuli-logo-DGuyqchQ.png +0 -0
  130. package/dist/web/assets/identity-CjBwYSMX.js +0 -1
  131. package/dist/web/assets/index-BQRkOwPx.js +0 -2
  132. package/dist/web/assets/index-CpLDx3of.css +0 -1
  133. package/dist/web/assets/model-C-5RVIJ2.js +0 -1
  134. package/dist/web/assets/paths-BkULqmGI.js +0 -1
  135. package/dist/web/assets/vue-router-DnD3hUm7.js +0 -1
  136. package/src/agent/candidate-read-service.js +0 -53
  137. package/src/agent/context-pack-service.js +0 -83
  138. package/src/agent/public-read-policy.js +0 -39
  139. package/src/agent/public-read-service.js +0 -69
  140. package/src/agent/read-projection.js +0 -107
  141. package/src/agent/search-service.js +0 -61
  142. package/src/agent/space-boundary.js +0 -33
  143. package/src/app/bootstrap.js +0 -8
  144. package/src/app/create-application.js +0 -143
  145. package/src/app/state-service.js +0 -38
  146. package/src/candidates.js +0 -78
  147. package/src/classifier.js +0 -63
  148. package/src/cli/command-arguments.js +0 -14
  149. package/src/context-pack.js +0 -206
  150. package/src/extractor.js +0 -77
  151. package/src/fact-history.js +0 -39
  152. package/src/facts/fact-service.js +0 -89
  153. package/src/http/bounded-json-array.js +0 -19
  154. package/src/http/lens-route.js +0 -50
  155. package/src/ingestion.js +0 -161
  156. package/src/lens/lens-correction-service.js +0 -81
  157. package/src/lens/lens-fact-writer.js +0 -85
  158. package/src/lens/lens-input.js +0 -62
  159. package/src/lens/lens-query-projection.js +0 -87
  160. package/src/lens/lens-query-ranking.js +0 -62
  161. package/src/lens/lens-query.js +0 -143
  162. package/src/lens/lens-resource-projection.js +0 -93
  163. package/src/lens/lens-resource-selection.js +0 -45
  164. package/src/lens/lens-resource-service.js +0 -103
  165. package/src/lens/lens-search-query.js +0 -122
  166. package/src/lens/lens-service.js +0 -183
  167. package/src/models.js +0 -44
  168. package/src/observer.js +0 -83
  169. package/src/project-rules.js +0 -33
  170. package/src/publication/outbox-service.js +0 -46
  171. package/src/publication/publication-envelope-schema.js +0 -75
  172. package/src/publication/publication-envelope.js +0 -37
  173. package/src/publication/publication-policy.js +0 -82
  174. package/src/publication/publication-service.js +0 -48
  175. package/src/router.js +0 -58
  176. package/src/runtime-options.js +0 -138
  177. package/src/security/episode-visibility.js +0 -14
  178. package/src/security/fact-visibility.js +0 -15
  179. package/src/security/source-metadata-policy.js +0 -8
  180. package/src/storage/episode-evidence-preview.js +0 -100
  181. package/src/storage/fact-search-order.js +0 -18
  182. package/src/storage/file/episode-evidence.js +0 -37
  183. package/src/storage/file/episode-index.js +0 -59
  184. package/src/storage/file/fact-search.js +0 -60
  185. package/src/storage/file-store.js +0 -437
  186. package/src/storage/migrate.js +0 -128
  187. package/src/storage/migrations/001-initial.sql +0 -83
  188. package/src/storage/migrations/002-storage-integrity.sql +0 -113
  189. package/src/storage/record-validation.js +0 -46
  190. package/src/storage/snapshot-defaults.js +0 -54
  191. package/src/storage/sqlite/candidates-repository.js +0 -84
  192. package/src/storage/sqlite/episode-evidence-repository.js +0 -154
  193. package/src/storage/sqlite/episode-privacy-sql.js +0 -33
  194. package/src/storage/sqlite/episodes-repository.js +0 -52
  195. package/src/storage/sqlite/fact-search-repository.js +0 -162
  196. package/src/storage/sqlite/facts-repository.js +0 -146
  197. package/src/storage/sqlite/imports-repository.js +0 -39
  198. package/src/storage/sqlite/mapper.js +0 -84
  199. package/src/storage/sqlite/open-database.js +0 -15
  200. package/src/storage/sqlite/outbox-repository.js +0 -103
  201. package/src/storage/sqlite/snapshot-repository.js +0 -69
  202. package/src/storage/sqlite/spaces-repository.js +0 -52
  203. package/src/storage/sqlite/subscriptions-repository.js +0 -54
  204. package/src/storage/sqlite-store.js +0 -159
  205. package/src/storage/stable-json.js +0 -24
  206. package/src/storage/store-port.js +0 -20
  207. package/src/store.js +0 -2
@@ -1,107 +0,0 @@
1
- import { isCurrentFact } from '../models.js';
2
- import {
3
- getAgentReadablePublicSource,
4
- getAgentReadableReplacementId,
5
- isAgentReadablePublicFact
6
- } from './public-read-policy.js';
7
-
8
- export function projectPersonalMatch(item, spaceName) {
9
- return {
10
- spaceId: item.fact.spaceId,
11
- spaceName,
12
- current: item.current,
13
- fact: item.fact,
14
- source: projectEpisode(item.sourceEpisode)
15
- };
16
- }
17
-
18
- export function projectPublicMatch(store, fact) {
19
- if (!isAgentReadablePublicFact(store, fact)) return null;
20
- const source = projectEpisode(getAgentReadablePublicSource(store, fact));
21
- return {
22
- spaceId: fact.spaceId,
23
- spaceName: store.getSpace(fact.spaceId)?.name ?? fact.spaceId,
24
- current: isCurrentFact(fact),
25
- fact: projectPublicFact(store, fact, source),
26
- source
27
- };
28
- }
29
-
30
- export function compactMatch(match) {
31
- return {
32
- spaceId: match.spaceId,
33
- spaceName: match.spaceName,
34
- current: match.current,
35
- fact: {
36
- id: match.fact.id,
37
- spaceId: match.fact.spaceId,
38
- subject: match.fact.subject,
39
- predicate: match.fact.predicate,
40
- object: match.fact.object,
41
- status: match.fact.status,
42
- validAt: match.fact.validAt,
43
- invalidAt: match.fact.invalidAt
44
- },
45
- source: compactSource(match.source)
46
- };
47
- }
48
-
49
- export function compactHistoryFact(store, fact) {
50
- return {
51
- id: fact.id,
52
- spaceId: fact.spaceId,
53
- spaceName: store.getSpace(fact.spaceId)?.name ?? fact.spaceId,
54
- subject: fact.subject,
55
- predicate: fact.predicate,
56
- object: fact.object,
57
- status: fact.status,
58
- current: fact.current,
59
- validAt: fact.validAt,
60
- invalidAt: fact.invalidAt,
61
- source: compactSource(fact.source)
62
- };
63
- }
64
-
65
- export function compactSource(source) {
66
- if (!source) return null;
67
- return {
68
- id: source.id,
69
- kind: source.kind ?? source.sourceKind,
70
- uri: source.uri ?? source.sourceUri,
71
- createdAt: source.createdAt,
72
- preview: firstLine(source.body)
73
- };
74
- }
75
-
76
- function projectPublicFact(store, fact, source) {
77
- return {
78
- id: fact.id,
79
- spaceId: fact.spaceId,
80
- subject: fact.subject,
81
- predicate: fact.predicate,
82
- object: fact.object,
83
- sourceEpisodeId: source?.id ?? null,
84
- validAt: fact.validAt,
85
- invalidAt: fact.invalidAt,
86
- replacedByFactId: getAgentReadableReplacementId(store, fact),
87
- confidence: fact.confidence,
88
- sensitivity: fact.sensitivity,
89
- scope: fact.scope,
90
- status: fact.status
91
- };
92
- }
93
-
94
- function projectEpisode(episode) {
95
- if (!episode) return null;
96
- return {
97
- id: episode.id,
98
- kind: episode.sourceKind,
99
- uri: episode.sourceUri,
100
- body: episode.body,
101
- createdAt: episode.createdAt
102
- };
103
- }
104
-
105
- function firstLine(value) {
106
- return value === undefined ? undefined : String(value).split(/\r?\n/)[0].slice(0, 160);
107
- }
@@ -1,61 +0,0 @@
1
- import { FactScope } from '../models.js';
2
- import { projectPersonalMatch, projectPublicMatch } from './read-projection.js';
3
- import { requirePersonalSpace } from './space-boundary.js';
4
-
5
- export class AgentSearchService {
6
- constructor(store, lensQuery) {
7
- this.store = store;
8
- this.lensQuery = lensQuery;
9
- }
10
-
11
- search({ personalSpaceId, query, includeHistorical = false }) {
12
- const personal = requirePersonalSpace(this.store, personalSpaceId);
13
- const publicSpaceIds = this.#subscribedPublicSpaceIds(personalSpaceId);
14
- const matches = [
15
- ...this.personalMatches({ personalSpaceId, query, includeHistorical }, personal.name),
16
- ...this.publicMatches(publicSpaceIds, query, includeHistorical)
17
- ];
18
- const facts = matches.map((match) => match.fact);
19
- return {
20
- query,
21
- spaceIds: [personalSpaceId, ...publicSpaceIds],
22
- matches,
23
- facts,
24
- answer: formatAnswer(facts)
25
- };
26
- }
27
-
28
- personalMatches(input, spaceName) {
29
- const personal = spaceName ?? requirePersonalSpace(this.store, input.personalSpaceId).name;
30
- return this.lensQuery.searchUserContext({
31
- ...input,
32
- includeRestricted: false
33
- }).facts.map((item) => projectPersonalMatch(item, personal));
34
- }
35
-
36
- publicMatches(spaceIds, query, includeHistorical = false) {
37
- if (!spaceIds.length) return [];
38
- return this.store.searchFacts(spaceIds, query, { includeHistorical })
39
- .filter((fact) => fact.scope === FactScope.PUBLIC)
40
- .map((fact) => projectPublicMatch(this.store, fact))
41
- .filter(Boolean);
42
- }
43
-
44
- #subscribedPublicSpaceIds(personalSpaceId) {
45
- return this.store.subscriptionsFor(personalSpaceId)
46
- .map((subscription) => this.store.getSpace(subscription.spaceId))
47
- .filter((space) => space?.kind === 'public')
48
- .map((space) => space.id);
49
- }
50
- }
51
-
52
- function formatAnswer(facts) {
53
- if (!facts.length) return '没有找到相关当前事实';
54
- return facts
55
- .map((fact) => `${fact.subject}:${humanPredicate(fact.predicate)} 是 ${fact.object}`)
56
- .join('\n');
57
- }
58
-
59
- function humanPredicate(predicate) {
60
- return predicate.startsWith('has_') ? predicate.slice(4) : predicate;
61
- }
@@ -1,33 +0,0 @@
1
- import { ApplicationError, ApplicationErrorCode } from '../app/application-error.js';
2
- import { SpaceKind } from '../models.js';
3
-
4
- export function requirePublicSpace(store, spaceId) {
5
- const space = store.getSpace(spaceId);
6
- if (!space) {
7
- throw new ApplicationError(ApplicationErrorCode.NOT_FOUND, `Space not found: ${spaceId}`);
8
- }
9
- if (space.kind !== SpaceKind.PUBLIC) {
10
- throw new ApplicationError(
11
- ApplicationErrorCode.VALIDATION,
12
- `Agent project reads require a public space: ${spaceId}`
13
- );
14
- }
15
- return space;
16
- }
17
-
18
- export function requirePersonalSpace(store, spaceId) {
19
- const space = store.getSpace(spaceId);
20
- if (!space) {
21
- throw new ApplicationError(
22
- ApplicationErrorCode.NOT_FOUND,
23
- `Personal space not found: ${spaceId}`
24
- );
25
- }
26
- if (space.kind !== SpaceKind.PERSONAL) {
27
- throw new ApplicationError(
28
- ApplicationErrorCode.VALIDATION,
29
- `Space is not personal: ${spaceId}`
30
- );
31
- }
32
- return space;
33
- }
@@ -1,8 +0,0 @@
1
- import { SpaceKind } from '../models.js';
2
-
3
- export function bootstrapStarterSpaces(store) {
4
- const personal = store.createSpace('我', SpaceKind.PERSONAL);
5
- const space = store.createSpace('工作', SpaceKind.PUBLIC);
6
- const subscription = store.subscribe(personal.id, space.id);
7
- return { personal, space, subscription };
8
- }
@@ -1,143 +0,0 @@
1
- import { assertStorePort } from '../storage/store-port.js';
2
- import { AgentCandidateReadService } from '../agent/candidate-read-service.js';
3
- import { AgentContextPackService } from '../agent/context-pack-service.js';
4
- import { AgentPublicReadService } from '../agent/public-read-service.js';
5
- import { AgentSearchService } from '../agent/search-service.js';
6
- import { ContextRouter } from '../router.js';
7
- import { IngestionService } from '../ingestion.js';
8
- import { observeGitDiff } from '../observer.js';
9
- import { decideCandidate } from '../candidates.js';
10
- import { buildContextPack } from '../context-pack.js';
11
- import { FactService } from '../facts/fact-service.js';
12
- import { ApplicationError, ApplicationErrorCode } from './application-error.js';
13
- import { StateService } from './state-service.js';
14
- import { bootstrapStarterSpaces } from './bootstrap.js';
15
- import { LensService } from '../lens/lens-service.js';
16
- import { LensQuery } from '../lens/lens-query.js';
17
- import { LensResourceService } from '../lens/lens-resource-service.js';
18
- import { PublicationService } from '../publication/publication-service.js';
19
- import { OutboxService } from '../publication/outbox-service.js';
20
-
21
- const CANDIDATE_DECISIONS = new Set(['sync', 'personal_only', 'ignore']);
22
-
23
- export function createApplication({ store, activePersonalSpaceName = '我' }) {
24
- assertStorePort(store);
25
- const facts = new FactService(store);
26
- const lensService = new LensService(store);
27
- const lensQuery = new LensQuery(store);
28
- const publicationService = new PublicationService(store);
29
- const outboxService = new OutboxService(store);
30
- const ingestion = new IngestionService(store, {
31
- facts,
32
- lens: lensService,
33
- publication: publicationService
34
- });
35
- const context = new ContextRouter(store);
36
- const state = new StateService(store);
37
- const agentReads = new AgentPublicReadService(store);
38
- const agentSearch = new AgentSearchService(store, lensQuery);
39
- const agentCandidates = new AgentCandidateReadService(store);
40
- const agentContextPack = new AgentContextPackService(
41
- store,
42
- agentReads,
43
- agentSearch,
44
- agentCandidates
45
- );
46
- const applyCandidateDecision = (candidateId, decision) => {
47
- if (!CANDIDATE_DECISIONS.has(decision)) {
48
- throw new ApplicationError(
49
- ApplicationErrorCode.VALIDATION,
50
- `Unknown candidate decision: ${decision}`
51
- );
52
- }
53
- if (!store.getCandidate(candidateId)) {
54
- throw new ApplicationError(
55
- ApplicationErrorCode.NOT_FOUND,
56
- `Candidate not found: ${candidateId}`
57
- );
58
- }
59
- return decideCandidate(store, candidateId, decision, { ingestion });
60
- };
61
- const lens = Object.freeze({
62
- rememberUserFact: (input) => lensService.rememberUserFact(input),
63
- submitUserObservation: (input) => lensService.submitUserObservation(input),
64
- confirmObservation: (input) => lensService.confirmObservation(input),
65
- correctUserFact: (input) => lensService.correctUserFact(input),
66
- getUserLens: (input) => lensQuery.getUserLens(input),
67
- getUserLensView: (input) => lensQuery.getUserLensView(input),
68
- searchUserContext: (input) => lensQuery.searchUserContext(input)
69
- });
70
- const lensResourceService = new LensResourceService({
71
- store,
72
- lens,
73
- activePersonalSpace: () => requireActivePersonalSpace(store, activePersonalSpaceName)
74
- });
75
- const publication = Object.freeze({
76
- prepare: (input) => publicationService.prepare(input),
77
- verify: (envelope) => publicationService.verify(envelope),
78
- pending: (at) => outboxService.pending(at),
79
- markFailed: (id, error) => outboxService.markFailed(id, error),
80
- markSent: (id) => outboxService.markSent(id)
81
- });
82
- const lensResources = Object.freeze({
83
- current: () => lensResourceService.current(),
84
- history: () => lensResourceService.history(),
85
- subscribed: () => lensResourceService.subscribed()
86
- });
87
- const agent = Object.freeze({
88
- remember: (input) => ingestion.remember(input),
89
- search: (input) => agentSearch.search(input),
90
- currentFacts: (spaceId) => agentReads.currentFacts(spaceId),
91
- timeline: (spaceId, subject) => agentReads.timeline(spaceId, subject),
92
- projectRules: (spaceId) => agentReads.projectRules(spaceId),
93
- factHistory: (input) => agentReads.factHistory(input),
94
- contextPack: (input) => agentContextPack.build(input),
95
- observe: (input) => observeGitDiff({ store, ...input }),
96
- listCandidates: (personalSpaceId) => agentCandidates.list(personalSpaceId),
97
- decideCandidate: applyCandidateDecision
98
- });
99
-
100
- return {
101
- bootstrap: () => bootstrapStarterSpaces(store),
102
- createSpace: (name, kind, description = null) =>
103
- store.createSpace(name, kind, description),
104
- resolveSpace: ({ id, name } = {}) => {
105
- if (id) return store.getSpace(id);
106
- return name ? store.findSpaceByName(name) : null;
107
- },
108
- requireSpaceId: ({ id, name, label }) => {
109
- const space = id ? store.getSpace(id) : (name ? store.findSpaceByName(name) : null);
110
- if (space) return space.id;
111
- throw new ApplicationError(
112
- ApplicationErrorCode.NOT_FOUND,
113
- `${label} not found: ${name || id || 'missing'}`
114
- );
115
- },
116
- subscribe: (personalSpaceId, spaceId, mode = 'latest') =>
117
- store.subscribe(personalSpaceId, spaceId, mode),
118
- remember: agent.remember,
119
- agent,
120
- lens,
121
- lensResources,
122
- publication,
123
- observe: agent.observe,
124
- decideCandidate: agent.decideCandidate,
125
- search: (input) => context.searchContext(input),
126
- contextPack: (input) => buildContextPack(store, input),
127
- state: () => state.build(),
128
- activePersonalSpace: () => requireActivePersonalSpace(store, activePersonalSpaceName),
129
- requireActivePersonalSpace: () => requireActivePersonalSpace(store, activePersonalSpaceName),
130
- close: () => store.close()
131
- };
132
- }
133
-
134
- function requireActivePersonalSpace(store, name) {
135
- const space = store.findSpaceByName(name);
136
- if (!space || space.kind !== 'personal') {
137
- throw new ApplicationError(
138
- ApplicationErrorCode.NOT_FOUND,
139
- `Active personal space not found: ${name}`
140
- );
141
- }
142
- return space;
143
- }
@@ -1,38 +0,0 @@
1
- import { enrichCandidate } from '../candidates.js';
2
-
3
- export class StateService {
4
- constructor(store) {
5
- this.store = store;
6
- }
7
-
8
- build() {
9
- const spaces = this.store.listSpaces();
10
- const currentFacts = spaces.flatMap((space) =>
11
- this.store.currentFacts(space.id).map((fact) => this.#enrichFact(fact))
12
- );
13
- const historicalFacts = this.store
14
- .listFacts({ includeHistorical: true })
15
- .filter((fact) => fact.invalidAt)
16
- .map((fact) => this.#enrichFact(fact));
17
- const candidates = this.store.listCandidates().map((candidate) =>
18
- enrichCandidate(this.store, candidate)
19
- );
20
-
21
- return {
22
- spaces,
23
- subscriptions: this.store.listSubscriptions(),
24
- episodes: this.store.listEpisodes(),
25
- currentFacts,
26
- historicalFacts,
27
- candidates
28
- };
29
- }
30
-
31
- #enrichFact(fact) {
32
- return {
33
- ...fact,
34
- spaceName: this.store.getSpace(fact.spaceId)?.name ?? fact.spaceId,
35
- episode: this.store.getEpisode(fact.sourceEpisodeId)
36
- };
37
- }
38
- }
package/src/candidates.js DELETED
@@ -1,78 +0,0 @@
1
- import { IngestionService } from './ingestion.js';
2
- import { ApplicationError, ApplicationErrorCode } from './app/application-error.js';
3
- import { CandidateStatus } from './models.js';
4
-
5
- export function listCandidates(store, personalSpaceId) {
6
- return store.pendingCandidates(personalSpaceId).map((candidate) => enrichCandidate(store, candidate));
7
- }
8
-
9
- export function decideCandidate(store, candidateId, decision, { ingestion = new IngestionService(store) } = {}) {
10
- return store.transaction(
11
- () => decideCandidateInCurrentTransaction(store, candidateId, decision, ingestion),
12
- { mode: 'immediate' }
13
- );
14
- }
15
-
16
- function decideCandidateInCurrentTransaction(store, candidateId, decision, ingestion) {
17
- const candidate = store.getCandidate(candidateId);
18
- if (!candidate) {
19
- throw new Error(`Candidate not found: ${candidateId}`);
20
- }
21
- if (candidate.status !== CandidateStatus.PENDING) {
22
- throw new ApplicationError(
23
- ApplicationErrorCode.VALIDATION,
24
- `Candidate already decided: ${candidateId}`
25
- );
26
- }
27
-
28
- if (decision === 'sync') {
29
- if (!candidate.targetSpaceId) {
30
- throw new ApplicationError(
31
- ApplicationErrorCode.VALIDATION,
32
- 'Syncing a candidate requires a target space'
33
- );
34
- }
35
- const episode = episodeFor(store, candidate);
36
- if (episode) {
37
- ingestion.publishConfirmedInCurrentTransaction({
38
- targetSpaceId: candidate.targetSpaceId,
39
- sourceKind: episode.sourceKind,
40
- body: episode.body,
41
- sourceUri: episode.sourceUri
42
- });
43
- }
44
- return store.updateCandidateStatus(candidate.id, CandidateStatus.SYNCED);
45
- }
46
-
47
- if (decision === 'personal_only') {
48
- const episode = episodeFor(store, candidate);
49
- if (episode) {
50
- ingestion.confirmEpisodeInCurrentTransaction({
51
- spaceId: candidate.personalSpaceId,
52
- episode
53
- });
54
- }
55
- return store.updateCandidateStatus(candidate.id, CandidateStatus.PERSONAL_ONLY);
56
- }
57
-
58
- if (decision === 'ignore') {
59
- return store.updateCandidateStatus(candidate.id, CandidateStatus.IGNORED);
60
- }
61
-
62
- throw new Error(`Unknown candidate decision: ${decision}`);
63
- }
64
-
65
- export function enrichCandidate(store, candidate) {
66
- return {
67
- ...candidate,
68
- personalSpaceName: store.getSpace(candidate.personalSpaceId)?.name ?? candidate.personalSpaceId,
69
- targetSpaceName: candidate.targetSpaceId
70
- ? store.getSpace(candidate.targetSpaceId)?.name ?? candidate.targetSpaceId
71
- : null,
72
- episode: episodeFor(store, candidate)
73
- };
74
- }
75
-
76
- function episodeFor(store, candidate) {
77
- return store.getEpisode(candidate.episodeId);
78
- }
package/src/classifier.js DELETED
@@ -1,63 +0,0 @@
1
- import { PublishRoute } from './models.js';
2
-
3
- const PUBLIC_SOURCE_KINDS = new Set(['prd', 'git', 'config', 'docs']);
4
- const PERSONAL_SOURCE_KINDS = new Set(['personal']);
5
- const PERSONAL_MARKERS = [
6
- '我觉得',
7
- '我认为',
8
- '我希望',
9
- '我想',
10
- '我打算',
11
- '我更喜欢',
12
- '我喜欢',
13
- '我不喜欢',
14
- '我的',
15
- '个人',
16
- '偏好',
17
- '判断'
18
- ];
19
- const UNCERTAIN_MARKERS = ['可能', '也许', '不确定', '待确认', '以后要', '似乎'];
20
-
21
- export function classifyEpisode({ sourceKind, body }) {
22
- if (PERSONAL_SOURCE_KINDS.has(sourceKind)) {
23
- return PublishRoute.PERSONAL;
24
- }
25
-
26
- if (hasAny(body, PERSONAL_MARKERS)) {
27
- return PublishRoute.PERSONAL;
28
- }
29
-
30
- if (hasAny(body, UNCERTAIN_MARKERS)) {
31
- return PublishRoute.CANDIDATE;
32
- }
33
-
34
- if (PUBLIC_SOURCE_KINDS.has(sourceKind) && looksLikeFact(body)) {
35
- return PublishRoute.PUBLIC;
36
- }
37
-
38
- return PublishRoute.CANDIDATE;
39
- }
40
-
41
- function looksLikeFact(body) {
42
- return (
43
- body.includes(':') ||
44
- body.includes(':') ||
45
- body.includes('=>') ||
46
- /https?:\/\//.test(body) ||
47
- looksLikeForbiddenRule(body)
48
- );
49
- }
50
-
51
- function looksLikeForbiddenRule(body) {
52
- return body
53
- .split(/\r?\n/)
54
- .some((line) =>
55
- /^(?:这个项目|本项目|项目)?\s*(?:禁止|不要|不允许)\s*(?:使用|采用|引入|用)?\s*\S+/.test(
56
- line.trim()
57
- )
58
- );
59
- }
60
-
61
- function hasAny(body, markers) {
62
- return markers.some((marker) => body.includes(marker));
63
- }
@@ -1,14 +0,0 @@
1
- export function option(args, flag) {
2
- const index = args.indexOf(flag);
3
- return index === -1 ? null : args[index + 1];
4
- }
5
-
6
- export function requireSpace(app, name) {
7
- const space = app.resolveSpace({ name });
8
- if (!space) throw new Error(`Space not found: ${name}`);
9
- return space;
10
- }
11
-
12
- export function humanPredicate(predicate) {
13
- return predicate.startsWith('has_') ? predicate.slice(4) : predicate;
14
- }