fuli-context 0.5.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 (206) hide show
  1. package/README.en.md +2 -333
  2. package/README.md +370 -202
  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 -5
  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 +51 -28
  59. package/src/cli/local-runtime-options.js +14 -8
  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 +1 -1
  92. package/src/local-runtime/lifecycle.js +26 -15
  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.js +36 -17
  100. package/src/setup/agent-installation-status.js +2 -1
  101. package/src/setup/agents.js +2 -1
  102. package/src/setup/claude-code-config.js +2 -1
  103. package/src/setup/codex-bootstrap.js +12 -7
  104. package/src/setup/container-runtime.js +25 -21
  105. package/src/setup/graph-runtime.js +148 -56
  106. package/src/setup/node-runtime.js +3 -3
  107. package/src/setup/options.js +2 -4
  108. package/src/setup/paths.js +18 -3
  109. package/src/setup/review-skill-adapters.js +49 -0
  110. package/src/setup/setup.js +26 -2
  111. package/src/setup/uninstall.js +4 -2
  112. package/src/system/resource-monitor.js +317 -0
  113. package/src/system/runtime-settings.js +131 -0
  114. package/src/system/system-service.js +119 -0
  115. package/dist/web/assets/ConnectionsPage-CCKWm-6p.js +0 -1
  116. package/dist/web/assets/KnowledgeInspector-BZkB2wJn.js +0 -1
  117. package/dist/web/assets/KnowledgeInspector-CrGYxEob.css +0 -1
  118. package/dist/web/assets/KnowledgeOrganizerPage-CZAF_OlN.css +0 -1
  119. package/dist/web/assets/KnowledgeOrganizerPage-DlvcLwlL.js +0 -1
  120. package/dist/web/assets/KnowledgePage-CNQXd15y.js +0 -1
  121. package/dist/web/assets/KnowledgeWorkspace-CXPE4GCD.js +0 -4
  122. package/dist/web/assets/OverviewPage-ul7g7HXh.js +0 -1
  123. package/dist/web/assets/PersonalProfilePage-CC40Pw2L.js +0 -1
  124. package/dist/web/assets/PersonalProjectsPage-CPIEcShD.js +0 -1
  125. package/dist/web/assets/PublicProjectsPage-C700sR7z.js +0 -1
  126. package/dist/web/assets/ReviewPage-7MDDUDgA.js +0 -1
  127. package/dist/web/assets/console-B_Ena2DS.js +0 -5
  128. package/dist/web/assets/fuli-logo-DGuyqchQ.png +0 -0
  129. package/dist/web/assets/identity-CjBwYSMX.js +0 -1
  130. package/dist/web/assets/index-CpLDx3of.css +0 -1
  131. package/dist/web/assets/index-DAzeFJSc.js +0 -2
  132. package/dist/web/assets/model-C-5RVIJ2.js +0 -1
  133. package/dist/web/assets/paths-BkULqmGI.js +0 -1
  134. package/dist/web/assets/vue-router-DnD3hUm7.js +0 -1
  135. package/src/agent/candidate-read-service.js +0 -53
  136. package/src/agent/context-pack-service.js +0 -83
  137. package/src/agent/public-read-policy.js +0 -39
  138. package/src/agent/public-read-service.js +0 -69
  139. package/src/agent/read-projection.js +0 -107
  140. package/src/agent/search-service.js +0 -61
  141. package/src/agent/space-boundary.js +0 -33
  142. package/src/app/bootstrap.js +0 -8
  143. package/src/app/create-application.js +0 -143
  144. package/src/app/state-service.js +0 -38
  145. package/src/candidates.js +0 -78
  146. package/src/classifier.js +0 -63
  147. package/src/cli/command-arguments.js +0 -14
  148. package/src/context-pack.js +0 -206
  149. package/src/extractor.js +0 -77
  150. package/src/fact-history.js +0 -39
  151. package/src/facts/fact-service.js +0 -89
  152. package/src/http/bounded-json-array.js +0 -19
  153. package/src/http/lens-route.js +0 -50
  154. package/src/ingestion.js +0 -161
  155. package/src/lens/lens-correction-service.js +0 -81
  156. package/src/lens/lens-fact-writer.js +0 -85
  157. package/src/lens/lens-input.js +0 -62
  158. package/src/lens/lens-query-projection.js +0 -87
  159. package/src/lens/lens-query-ranking.js +0 -62
  160. package/src/lens/lens-query.js +0 -143
  161. package/src/lens/lens-resource-projection.js +0 -93
  162. package/src/lens/lens-resource-selection.js +0 -45
  163. package/src/lens/lens-resource-service.js +0 -103
  164. package/src/lens/lens-search-query.js +0 -122
  165. package/src/lens/lens-service.js +0 -183
  166. package/src/models.js +0 -44
  167. package/src/observer.js +0 -83
  168. package/src/project-rules.js +0 -33
  169. package/src/publication/outbox-service.js +0 -46
  170. package/src/publication/publication-envelope-schema.js +0 -75
  171. package/src/publication/publication-envelope.js +0 -37
  172. package/src/publication/publication-policy.js +0 -82
  173. package/src/publication/publication-service.js +0 -48
  174. package/src/router.js +0 -58
  175. package/src/runtime-options.js +0 -138
  176. package/src/security/episode-visibility.js +0 -14
  177. package/src/security/fact-visibility.js +0 -15
  178. package/src/security/source-metadata-policy.js +0 -8
  179. package/src/storage/episode-evidence-preview.js +0 -100
  180. package/src/storage/fact-search-order.js +0 -18
  181. package/src/storage/file/episode-evidence.js +0 -37
  182. package/src/storage/file/episode-index.js +0 -59
  183. package/src/storage/file/fact-search.js +0 -60
  184. package/src/storage/file-store.js +0 -437
  185. package/src/storage/migrate.js +0 -128
  186. package/src/storage/migrations/001-initial.sql +0 -83
  187. package/src/storage/migrations/002-storage-integrity.sql +0 -113
  188. package/src/storage/record-validation.js +0 -46
  189. package/src/storage/snapshot-defaults.js +0 -54
  190. package/src/storage/sqlite/candidates-repository.js +0 -84
  191. package/src/storage/sqlite/episode-evidence-repository.js +0 -154
  192. package/src/storage/sqlite/episode-privacy-sql.js +0 -33
  193. package/src/storage/sqlite/episodes-repository.js +0 -52
  194. package/src/storage/sqlite/fact-search-repository.js +0 -162
  195. package/src/storage/sqlite/facts-repository.js +0 -146
  196. package/src/storage/sqlite/imports-repository.js +0 -39
  197. package/src/storage/sqlite/mapper.js +0 -84
  198. package/src/storage/sqlite/open-database.js +0 -15
  199. package/src/storage/sqlite/outbox-repository.js +0 -103
  200. package/src/storage/sqlite/snapshot-repository.js +0 -69
  201. package/src/storage/sqlite/spaces-repository.js +0 -52
  202. package/src/storage/sqlite/subscriptions-repository.js +0 -54
  203. package/src/storage/sqlite-store.js +0 -159
  204. package/src/storage/stable-json.js +0 -24
  205. package/src/storage/store-port.js +0 -20
  206. 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
- }