fuli-context 0.7.2 → 0.7.4-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (113) hide show
  1. package/README.md +173 -21
  2. package/README.zh-CN.md +146 -12
  3. package/compose.graphiti.yml +2 -0
  4. package/dist/web/assets/{AboutPage-DfnZo7Lo.js → AboutPage-CftRexSY.js} +1 -1
  5. package/dist/web/assets/{ConnectionsPage-BloaSKmt.js → ConnectionsPage-D5J91x6d.js} +1 -1
  6. package/dist/web/assets/{useMinimumLoadingDisplay-BpCyBeko.css → KnowledgeEditDialog-DWUV_NPp.css} +1 -1
  7. package/dist/web/assets/KnowledgeEditDialog-wotVahvr.js +1 -0
  8. package/dist/web/assets/{KnowledgeInspector-Bjhdu2mf.css → KnowledgeInspector--1NujtXW.css} +1 -1
  9. package/dist/web/assets/KnowledgeInspector-BzkW0mVs.js +1 -0
  10. package/dist/web/assets/KnowledgeOrganizerPage-BebUDiHt.js +1 -0
  11. package/dist/web/assets/KnowledgePage-OUT07aKH.js +1 -0
  12. package/dist/web/assets/KnowledgeWorkspace-1pHJ0MNZ.js +4 -0
  13. package/dist/web/assets/OverviewPage-CHE6XhdS.js +1 -0
  14. package/dist/web/assets/PersonalProfilePage-B7T09bow.css +1 -0
  15. package/dist/web/assets/PersonalProfilePage-CXXiabUy.js +1 -0
  16. package/dist/web/assets/PersonalProjectsPage-d2wYGW8n.js +1 -0
  17. package/dist/web/assets/PublicProjectsPage-hxLShtnZ.js +1 -0
  18. package/dist/web/assets/{ReviewPage-B7EN817i.js → ReviewPage-DUeyu7E8.js} +1 -1
  19. package/dist/web/assets/{SearchableSelect-ClLN0rIb.js → SearchableSelect-C5RiB5F8.js} +1 -1
  20. package/dist/web/assets/SettingsPage-BMuASSzQ.js +1 -0
  21. package/dist/web/assets/SettingsPage-CAfz4qiV.css +1 -0
  22. package/dist/web/assets/WritingTastePage-B9BCYIwQ.js +1 -0
  23. package/dist/web/assets/WritingTastePage-DSgvTH6x.css +1 -0
  24. package/dist/web/assets/{console-CbDsKrsO.js → console-DMvHxKf9.js} +1 -1
  25. package/dist/web/assets/conversation-launcher-settings-Dnlcw7Rj.js +1 -0
  26. package/dist/web/assets/{i18n-BQcns1PH.js → i18n-CWfd8Dtt.js} +1 -1
  27. package/dist/web/assets/{identity-B8K4VYg6.js → identity-C9mLdR8L.js} +1 -1
  28. package/dist/web/assets/index-F5e2sQ7p.js +2 -0
  29. package/dist/web/assets/index-X2j29j8i.css +1 -0
  30. package/dist/web/assets/{model-eF52GgPF.js → model-CsYAR8O3.js} +1 -1
  31. package/dist/web/assets/paths-CDREouhi.js +1 -0
  32. package/dist/web/assets/useApi-CROJJdhE-BLQiPVw0.js +1 -0
  33. package/dist/web/assets/vue-router-DN8x6iY1.js +1 -0
  34. package/dist/web/index.html +7 -6
  35. package/graph-provider/fuli_graph/app.py +238 -2
  36. package/graph-provider/fuli_graph/auth.py +18 -0
  37. package/graph-provider/fuli_graph/collaboration_context.py +253 -17
  38. package/graph-provider/fuli_graph/common_knowledge.py +6 -2
  39. package/graph-provider/fuli_graph/config.py +5 -0
  40. package/graph-provider/fuli_graph/graph_models.py +6 -0
  41. package/graph-provider/fuli_graph/graph_projection.py +14 -0
  42. package/graph-provider/fuli_graph/graph_query.py +27 -3
  43. package/graph-provider/fuli_graph/knowledge_management.py +19 -1
  44. package/graph-provider/fuli_graph/knowledge_review.py +49 -4
  45. package/graph-provider/fuli_graph/knowledge_review_models.py +11 -5
  46. package/graph-provider/fuli_graph/knowledge_search.py +11 -0
  47. package/graph-provider/fuli_graph/models.py +15 -2
  48. package/graph-provider/fuli_graph/personal_global_preference_models.py +234 -0
  49. package/graph-provider/fuli_graph/personal_global_preferences.py +1247 -0
  50. package/graph-provider/fuli_graph/project_action_models.py +22 -0
  51. package/graph-provider/fuli_graph/project_knowledge.py +121 -2
  52. package/graph-provider/fuli_graph/provider_values.py +24 -0
  53. package/graph-provider/fuli_graph/runtime.py +78 -0
  54. package/graph-provider/fuli_graph/search_projection.py +14 -1
  55. package/graph-provider/fuli_graph/store_knowledge.py +116 -2
  56. package/graph-provider/fuli_graph/workflow_candidate_models.py +168 -0
  57. package/graph-provider/fuli_graph/workflow_candidates.py +996 -0
  58. package/graph-provider/fuli_graph/workflow_observation_models.py +30 -0
  59. package/graph-provider/fuli_graph/workflow_observations.py +84 -0
  60. package/graph-provider/pyproject.toml +1 -1
  61. package/npm-shrinkwrap.json +18 -18
  62. package/package.json +4 -4
  63. package/skills/capturing-session-knowledge/SKILL.md +32 -5
  64. package/skills/flreview/SKILL.md +68 -40
  65. package/skills/flreview/agents/openai.yaml +2 -2
  66. package/src/agent-tools/graph-definitions.js +140 -24
  67. package/src/agent-tools/graph-handlers.js +10 -4
  68. package/src/cli/command-registry.js +1 -1
  69. package/src/cli/local-runtime-command.js +69 -2
  70. package/src/graphiti/agent-knowledge-workflows.js +497 -16
  71. package/src/graphiti/collaboration-preference-projection.js +162 -0
  72. package/src/graphiti/federated-application.js +157 -162
  73. package/src/graphiti/federated-search-support.js +102 -0
  74. package/src/graphiti/knowledge-provider-mapping.js +15 -0
  75. package/src/graphiti/provider-client.js +162 -10
  76. package/src/graphiti/related-project-suggestions.js +109 -0
  77. package/src/graphiti/runtime-config.js +14 -0
  78. package/src/graphiti/source-marker.js +2 -2
  79. package/src/graphiti/user-taste-skill.js +241 -0
  80. package/src/graphiti/workflow-candidate-mapping.js +87 -0
  81. package/src/graphiti/workflow-observation.js +82 -0
  82. package/src/graphiti/writing-taste-profile-workflow.js +25 -0
  83. package/src/graphiti/writing-taste-profile.js +490 -0
  84. package/src/http/graph-api-router.js +15 -2
  85. package/src/mcp/context-resources.js +158 -0
  86. package/src/mcp/create-mcp-server.js +41 -5
  87. package/src/mcp/instructions.js +5 -7
  88. package/src/mcp/session-id.js +60 -0
  89. package/src/mcp/task-context-registry.js +15 -3
  90. package/src/mcp/tool-annotations.js +8 -1
  91. package/src/mcp/tool-result.js +28 -4
  92. package/src/server.js +0 -1
  93. package/src/setup/claude-code-config.js +17 -6
  94. package/src/setup/graph-runtime.js +20 -2
  95. package/src/system/runtime-settings.js +121 -2
  96. package/src/system/system-service.js +5 -1
  97. package/README.en.md +0 -5
  98. package/dist/web/assets/KnowledgeInspector-QvNpv0_k.js +0 -1
  99. package/dist/web/assets/KnowledgeOrganizerPage-DKq1jVD5.js +0 -1
  100. package/dist/web/assets/KnowledgePage-BWL0jT01.js +0 -1
  101. package/dist/web/assets/KnowledgeWorkspace-Czq6aZ7b.js +0 -4
  102. package/dist/web/assets/OverviewPage-5sJoO1Gh.js +0 -1
  103. package/dist/web/assets/PersonalProfilePage-CdmEzyvZ.css +0 -1
  104. package/dist/web/assets/PersonalProfilePage-tVChM9ik.js +0 -1
  105. package/dist/web/assets/PersonalProjectsPage-BPFrup4V.js +0 -1
  106. package/dist/web/assets/PublicProjectsPage-BPJSeREN.js +0 -1
  107. package/dist/web/assets/SettingsPage-C6ouU0sR.css +0 -1
  108. package/dist/web/assets/SettingsPage-Chd_B3eH.js +0 -1
  109. package/dist/web/assets/index-CB8Xmsc2.js +0 -2
  110. package/dist/web/assets/index-CZeuPh-U.css +0 -1
  111. package/dist/web/assets/paths-hwz-Ac1g.js +0 -1
  112. package/dist/web/assets/useMinimumLoadingDisplay-wCgGDmHg.js +0 -1
  113. package/dist/web/assets/vue-router-BsEp_XwI.js +0 -1
package/README.md CHANGED
@@ -14,14 +14,15 @@
14
14
  <a href="LICENSE"><img src="https://img.shields.io/npm/l/fuli-context?style=flat" alt="license" /></a>
15
15
  </p>
16
16
 
17
- Fuli is a local-first collaboration context graph for AI agents. It turns reusable knowledge,
18
- experience, decision rationale, and preferences from human–AI project work into assets with
19
- provenance, scope, authority, and temporal history. Codex, Claude Code, and Cursor can then reuse
20
- those assets in later tasks instead of relearning the same context.
17
+ Fuli is a local-first collaboration relationship graph for AI agents. Continued human–Agent
18
+ dialogue gradually connects projects, people, decisions, preferences, workflow steps, and evidence.
19
+ Those nodes may point to Fuli-local content, an external knowledge base, or another data source.
20
+ Codex, Claude Code, and Cursor can then reuse the taste, personality, judgment preferences, and
21
+ working methods formed through that collaboration.
21
22
 
22
- Fuli is not a transcript archive, and it is not an attempt to build a personality model that
23
- replaces human judgment. AI retrieves, summarizes, warns, and executes; humans retain final
24
- authority.
23
+ Fuli is not a transcript archive or a knowledge base whose goal is to collect more documents, and
24
+ it is not an attempt to build a personality model that replaces human judgment. AI retrieves,
25
+ summarizes, warns, and executes; humans retain final authority.
25
26
 
26
27
  ## npm packages
27
28
 
@@ -69,10 +70,11 @@ preview followed by an explicit, one-time, atomic action.
69
70
  ### 4. Assemble context, then retrieve evidence on demand
70
71
 
71
72
  Fuli does not inject the complete history at session start. The entry step always loads effective
72
- personal-global preferences and preferences from one exactly matched project. When the current task
73
- signals that a stable prior fact, method, URL, decision, release, deployment, or authentication
74
- runbook may matter, the same step also performs a small bounded recall from that project and its
75
- authorized knowledge sources. The agent uses focused on-demand search when more evidence is needed.
73
+ personal-global preferences, preferences from one exactly matched project, and explicitly
74
+ propagating preferences from authorized parent projects. When the current task signals that a
75
+ stable prior fact, method, URL, decision, release, deployment, or authentication runbook may matter,
76
+ the same step also performs a small bounded recall from that project and its authorized knowledge
77
+ sources. The agent uses focused on-demand search when more evidence is needed.
76
78
  Retrieval alone is not usage; a usage event is recorded only when an item materially affects an
77
79
  answer, implementation, or decision.
78
80
 
@@ -96,12 +98,18 @@ Activity platform (parent: shared runbooks)
96
98
 
97
99
  When an agent works in the hotel project, it searches hotel-local knowledge first, then follows
98
100
  explicit outgoing `PART_OF` or `USES_KNOWLEDGE_FROM` relationships to authorized sources, up to two
99
- hops. A child item with the same stable key overrides an inherited item. Generic `RELATED_TO`
100
- relationships do not expand scope, and project-scoped personal preferences are not inherited.
101
-
102
- Similar items from multiple children create only a common-knowledge candidate. Current clustering
103
- is a lexical heuristic, not proof of semantic equivalence. A human must select the canonical item,
104
- duplicates, parent project, and rationale before an atomic promotion can occur.
101
+ hops. A child item with the same stable key overrides an inherited item. Project-scoped personal
102
+ preferences remain exact by default; only preferences explicitly marked `descendants` or
103
+ `selected_projects` may propagate over the same authorized relationships, with origin project,
104
+ path, and distance preserved. Equally near parent conflicts require human judgment and are never
105
+ resolved by weight. Generic `RELATED_TO` relationships do not expand scope automatically; search
106
+ returns only a one-time read-only expansion suggestion that the Agent must ask the user to approve.
107
+
108
+ Similar items from multiple children create only a common-knowledge candidate. A shared preference
109
+ across projects without one common parent likewise creates only a personal-global candidate while
110
+ preserving each source text, qualifier, and provenance. Current clustering is a lexical heuristic,
111
+ not proof of semantic equivalence. A human must choose the content, scope, and rationale before it
112
+ can apply.
105
113
 
106
114
  ### 7. Local first; no personal model in the shared layer
107
115
 
@@ -110,6 +118,136 @@ transcripts, credentials, temporary logs, or command output. The team-shared lay
110
118
  confirmed project or domain knowledge with context and provenance—not personal taste, personality,
111
119
  or judgment preferences.
112
120
 
121
+ ## Practical use: classification, scope, project resolution, and retrieval
122
+
123
+ ### Decide what to store before deciding where to store it
124
+
125
+ Content type and effective scope are independent dimensions. The first three rows are personal
126
+ collaboration preferences and carry a `profileAspect`. Project facts have no `profileAspect` and do
127
+ not appear on the Personal preferences page.
128
+
129
+ | Type | What belongs here | Example |
130
+ | --- | --- | --- |
131
+ | Taste (`taste`) | Outcomes, styles, and quality directions the user explicitly likes or rejects across UI, writing, product, architecture, or engineering work | “Use fewer large gradients and avoid cards nested inside cards.” |
132
+ | Personality (`personality`) | A stable working or collaboration trait explicitly described by the user | “I communicate directly and want the Agent to move work forward proactively.” |
133
+ | Judgment preference (`judgment_preference`) | Decision conditions, priorities, risk posture, and operational boundaries used when making trade-offs | “Discuss directional ambiguity first; never `git push` without explicit authorization.” |
134
+ | Project knowledge | Reusable objective facts, terminology, requirements, routes, APIs, architecture, rationale, and runbooks | “A GitHub Release triggers Fuli's npm publication.” |
135
+
136
+ Four questions provide a quick classifier: “What outcome do I want?” is taste; “How do I work over
137
+ the long term?” is personality; “How do I decide under a trade-off?” is judgment preference; and
138
+ “How does this system objectively work?” is project knowledge. One-off commands, temporary output,
139
+ unverified guesses, raw chat, and credentials are not retained.
140
+
141
+ Personality is not a catch-all category for everything learned about a person. Only an explicit,
142
+ stable self-description can be confirmed with a human basis. A personality inferred by an Agent
143
+ from one behavior must remain `pending`; it cannot masquerade as human-confirmed. An empty
144
+ Personality filter on `/preferences` therefore usually means there is no qualifying item in the
145
+ selected scope, not that capture failed. “Keep copy concise” is more likely taste, while “do not
146
+ push without authorization” is more likely a judgment preference. To make the intent explicit,
147
+ say: `This is a long-term collaboration trait; save it as a personal-global personality preference: I communicate directly.` An Agent-inferred candidate can be confirmed, corrected, or invalidated
148
+ by the user from `/preferences` or `/flreview`.
149
+
150
+ ### Personal-global, project-scoped, and shared
151
+
152
+ | Scope | When to use it | Key write fields | Retrieval rule |
153
+ | --- | --- | --- | --- |
154
+ | Personal-global preference | The behavior should remain the same in unrelated projects | `targetKind: "personal"`; omit `personalProjectId`; set `profileAspect` | Loaded for every task |
155
+ | Project-scoped personal preference | The collaboration behavior belongs to one project or project family | Same fields plus the exact `personalProjectId`; default to `local_only` and never inherited by child projects; explicitly use `descendants` or `selected_projects` when propagation is intended | Exact project wins; propagation follows only the explicit inheritance mode and authorized relationships, and score never resolves a conflict automatically |
156
+ | Project knowledge | A fact belongs to one project or to a designated parent/source project | `targetKind: "personal"`; set `personalProjectId`; omit `profileAspect` | Search the current project first, then authorized `PART_OF` / `USES_KNOWLEDGE_FROM` sources up to two hops |
157
+ | Team-shared knowledge | Human-confirmed project or domain knowledge genuinely needed by a team | `targetKind: "project"` after preview/review | Visible only from explicitly selected or subscribed public projects; personal preferences never enter this layer |
158
+
159
+ To choose a preference scope, ask: **Should this change the Agent's behavior in a completely
160
+ unrelated project?** If yes, use personal-global. If it applies only to Fuli, use a project-scoped
161
+ preference. If it applies to a project family, keep it project-scoped and explicitly choose whether
162
+ it may propagate to descendants. Do not turn an objective project fact into a personal-global item
163
+ merely because more than one project may reuse it. Put it in an explicit parent or knowledge-source
164
+ project and add a directional authorization relation. When global and project-scoped variants have
165
+ the same stable `attributes.preferenceKey`, human/source confirmation authority is resolved first;
166
+ at equal authority, the exact project variant overrides the global one.
167
+
168
+ ### How Fuli identifies the current project
169
+
170
+ Fuli matches only stable `project_id` values already registered under Personal projects; it does
171
+ not guess from fuzzy directory similarity. Normally the `project_id` matches the repository
172
+ directory name, so `/workspace/fuli` maps to `fuli`. Standard calls pass only the current working
173
+ directory, and resolution follows this order:
174
+
175
+ 1. Find the nearest Git repository root and match its directory name exactly to a registered
176
+ `project_id`.
177
+ 2. For a Codex worktree, recover the original repository ID from its `.git` pointer.
178
+ 3. Match the current directory name exactly to a registered project ID.
179
+ 4. At a workspace root, match one registered direct child only when exactly one child contains
180
+ `.git`, `package.json`, `pyproject.toml`, `Cargo.toml`, or `go.mod`.
181
+ 5. Multiple candidates return `ambiguous`; no candidate returns `unmatched`. Neither state applies
182
+ project preferences or guesses a project.
183
+
184
+ For an unregistered repository with an unambiguous identity, the installed capture skill may call
185
+ `upsert_personal_project` before the first project-scoped write to create a minimal local private
186
+ project. It never creates or subscribes to a public project automatically. If a workspace has
187
+ multiple candidates, run the Agent from the exact project directory or explicitly register and
188
+ select the project first.
189
+
190
+ ### Which tool the Agent calls and when
191
+
192
+ Normal use does not require manual MCP calls: submit a task to the Agent from the project directory.
193
+ The Claude Code hook calls `begin_task_context`; Codex and Cursor prompt fallback call the following
194
+ once at the start of each task:
195
+
196
+ ```json
197
+ {
198
+ "tool": "get_collaboration_preferences",
199
+ "arguments": {
200
+ "projectPath": "/workspace/fuli",
201
+ "taskPrompt": "Fix npm publishing and reuse this project's existing release conventions."
202
+ }
203
+ }
204
+ ```
205
+
206
+ The important part of a matched response resembles:
207
+
208
+ ```json
209
+ {
210
+ "context": {
211
+ "personal_project_id": "fuli",
212
+ "project_resolution": {
213
+ "status": "matched",
214
+ "basis": "repository_root",
215
+ "personal_project_id": "fuli"
216
+ }
217
+ },
218
+ "effective_preferences": ["personal-global preferences + exact fuli preferences"]
219
+ }
220
+ ```
221
+
222
+ If entry-time `task_knowledge_recall` did not answer a stable project fact, search with one to four
223
+ short queries centered on an action, artifact, target system, or identifier. Do not use the full
224
+ user request verbatim as the only query:
225
+
226
+ ```json
227
+ {
228
+ "tool": "search_current_project_knowledge",
229
+ "arguments": {
230
+ "projectPath": "/workspace/fuli",
231
+ "queries": ["npm publication runbook", "GitHub Release trigger"],
232
+ "includePending": false
233
+ }
234
+ }
235
+ ```
236
+
237
+ At task end, hook mode calls `checkpoint_task_knowledge`: use `capture_candidates` only for a small,
238
+ durable, evidence-backed batch; otherwise use `retain_nothing`. A prompt-fallback Agent applies the
239
+ same rule and writes through `capture_session_knowledge`. Personal preferences set the correct
240
+ `profileAspect` and stable `attributes.preferenceKey`; project facts omit `profileAspect`. If
241
+ automatic capture is disabled under Settings, writes return `capture_disabled` and no category is
242
+ created.
243
+
244
+ Run these local contract tests to check that the README and project-path behavior still match the
245
+ implementation:
246
+
247
+ ```bash
248
+ npm run test:node -- test/acceptance-docs.test.js test/project-path-context.test.js
249
+ ```
250
+
113
251
  ## Agent interaction sequence
114
252
 
115
253
  This is the simplified lifecycle for a normal task. The Chinese
@@ -321,7 +459,7 @@ system locale. User data such as paths and space names is displayed unchanged.
321
459
  | `fuli --help` / `fuli -h` | List every public command and its available options |
322
460
  | `fuli --version` / `fuli -v` | Print the installed Fuli CLI version |
323
461
  | `fuli setup [options]` | Initialize the Provider, UI, agent integrations, and Skills; safe to rerun |
324
- | `fuli start [options]` | Start the Provider and UI, optionally opening a browser, rebuilding containers, or enabling LAN access |
462
+ | `fuli start [options]` | Check Agent integrations, then start the Provider and UI; optionally open a browser, rebuild containers, or enable LAN access |
325
463
  | `fuli stop [--data-dir DIR]` | Stop services without deleting data |
326
464
  | `fuli restart [options]` | Restart local services using the same runtime options as `start` |
327
465
  | `fuli status [--json] [--data-dir DIR] [--port PORT]` | Show UI, personal graph, and shared-service status; `--json` emits machine-readable output |
@@ -345,6 +483,9 @@ are used. LAN mode listens on private IPv4 addresses and prints the reachable UR
345
483
  `fuli` username, and a temporary access code generated for that start. The default remains
346
484
  loopback-only; internal Providers and Neo4j ports are never exposed by `--lan`. LAN mode uses
347
485
  HTTP Basic Auth and is intended only for trusted home or office Wi-Fi, not public deployment.
486
+ Before starting, `fuli start` performs a read-only check of detected Agent MCP, Skill, Codex bootstrap,
487
+ and Claude lifecycle integrations. If any are missing or outdated, it still starts the local services
488
+ and tells you to run `fuli setup`; it never applies setup changes implicitly.
348
489
 
349
490
  `setup` and `update` accept:
350
491
 
@@ -383,17 +524,28 @@ reuse the same data.
383
524
  ## Agent integrations and primary tools
384
525
 
385
526
  Fuli installs the `capturing-session-knowledge`, `grilling-project`, and `flreview` Skills for
386
- supported agents. `/flreview` offers all knowledge, personal preferences, or personal-project
387
- scope. If the user has no patience, it skips mood, time, and token questions and reviews only a
388
- small number of highest-priority items.
527
+ supported agents. `/flreview` asks FULI for ranked candidates, then the invoking Agent generates a
528
+ fresh interactive review artifact. FULI remains the durable source of truth and write surface; no
529
+ permanent review tab or one-question-at-a-time chat flow is required.
389
530
  Claude Code uses `UserPromptSubmit` and `Stop` hooks for the task lifecycle. Codex's user-level
390
531
  `AGENTS.md` and Cursor instructions use prompt fallback. Preference content remains in local Fuli as
391
532
  the single source of truth and is not copied into agent configuration.
392
533
 
534
+ FULI also exposes read-only `fuli://` resources for each local personal project and for global taste.
535
+ Agents with MCP mention support can select them from the `@` picker; a project resource selects one
536
+ exact project and never expands the search to other projects or `RELATED_TO` projects.
537
+
538
+ When a task needs a taste or judgment recommendation, `get_user_taste_skill` generates a bounded,
539
+ read-only `user-taste` Skill projection from the effective personal profile and prior task data.
540
+ The projection labels evidence status and scope, returns task-matched recommendations, and is
541
+ regenerated as preferences are added or revised. It never overwrites a user-authored taste Skill;
542
+ the durable graph remains the source of truth.
543
+
393
544
  | Tool | Purpose |
394
545
  | --- | --- |
395
546
  | `begin_task_context` | Hook entry: resolve the task, run bounded recall when signaled, and create a task token |
396
547
  | `get_collaboration_preferences` | Fallback entry: read effective preferences and bounded task recall |
548
+ | `get_user_taste_skill` | Generate the current evidence-labeled taste Skill projection and task recommendations |
397
549
  | `search_current_project_knowledge` | Search the child first, then authorized knowledge sources |
398
550
  | `search_knowledge_graph` | Run a general query within an explicit bounded scope |
399
551
  | `search_connected_knowledge` | Search the graph, project-bound read-only sources, and selected public projects without merging provenance |
package/README.zh-CN.md CHANGED
@@ -14,12 +14,13 @@
14
14
  <a href="LICENSE"><img src="https://img.shields.io/npm/l/fuli-context?style=flat" alt="许可证" /></a>
15
15
  </p>
16
16
 
17
- 复利是一个面向 AI Agent 的本地优先协作上下文图谱。它把人与 AI 在项目中产生的、经得起
18
- 复用的知识、经验、决策理由和偏好组织成有来源、有作用域、有时间关系的资产,让 Codex、
19
- Claude Code 和 Cursor 在后续任务中少重复学习一次。
17
+ 复利是一个面向 AI Agent 的本地优先协作关系图谱。人与 Agent 的持续对话会逐步形成项目、
18
+ 人物、决定、偏好、行为步骤和证据之间的关系;关系节点可以指向 Fuli 本地内容,也可以连接
19
+ 外部知识库或其他数据源。Codex、Claude Code 和 Cursor 因而能在后续任务中复用已经形成的
20
+ 品味、个性、判断偏好与协作方法。
20
21
 
21
- 复利不是聊天记录仓库,也不试图建立一个替代人的“人格模型”。AI 负责检索、提醒、归纳和
22
- 执行;人始终保留最终判断权。
22
+ 复利不是聊天记录仓库,也不是以“收集更多文档”为目标的知识库,更不试图建立一个替代人的
23
+ “人格模型”。AI 负责检索、提醒、归纳和执行;人始终保留最终判断权。
23
24
 
24
25
  ## npm 包
25
26
 
@@ -61,9 +62,10 @@ AI 可以发现候选、指出冲突、建议公共化,也可以在得到授
61
62
 
62
63
  ### 4. 先组装上下文,再按需取证
63
64
 
64
- Fuli 不会在会话开始时把全部历史塞给模型。入口阶段始终加载当前任务实际生效的个人全局偏好
65
- 和精确项目偏好;当任务信号表明可能需要稳定的历史事实、方法、网址、决策、发布、部署或认证
66
- Runbook 时,同一步骤还会在精确项目及其获授权知识来源中执行一次小规模、有界的自动召回。
65
+ Fuli 不会在会话开始时把全部历史塞给模型。入口阶段始终加载当前任务实际生效的个人全局偏好、
66
+ 精确项目偏好和显式允许传播的上级项目偏好;当任务信号表明可能需要稳定的历史事实、方法、
67
+ 网址、决策、发布、部署或认证 Runbook 时,同一步骤还会在精确项目及其获授权知识来源中执行
68
+ 一次小规模、有界的自动召回。
67
69
  需要更多证据时,Agent 再使用聚焦查询按需检索。只有真正影响回答、实现或决策的知识才记录为
68
70
  一次使用,单纯检索不会增加权重。
69
71
 
@@ -86,10 +88,14 @@ Runbook 时,同一步骤还会在精确项目及其获授权知识来源中执
86
88
 
87
89
  Agent 在酒店项目工作时先搜索酒店本地知识,再沿显式的 `PART_OF` 或
88
90
  `USES_KNOWLEDGE_FROM` 关系向上搜索允许继承的知识,最多两跳。同稳定键的子项目内容覆盖
89
- 父项目内容;普通 `RELATED_TO` 关系不会扩大作用域,项目级个人偏好也不会向下继承。
91
+ 父项目内容。项目级个人偏好默认只在精确项目生效;只有显式设置为 `descendants` 或
92
+ `selected_projects` 的偏好才可沿同样的授权关系传播,并返回来源项目、路径和距离。多个同层
93
+ 父项目冲突时必须交给人判断,不能靠权重选胜者。普通 `RELATED_TO` 不会自动扩大作用域;
94
+ 搜索结果只返回一次性只读扩展建议,由 Agent 先询问用户。
90
95
 
91
- 多个子项目中相似的内容只会形成公共化候选。当前聚类是词法启发式信号,不是语义等价证明;
92
- 必须由人选择规范项、重复项、上级项目和理由后,才能原子提升。
96
+ 多个子项目中相似的内容只会形成公共化候选。跨无共同父级项目出现的共同偏好也只能形成个人
97
+ 全局候选,并完整保留每个项目的原文、限定词和来源。当前聚类是词法启发式信号,不是语义
98
+ 等价证明;必须由人选择内容、作用域和理由后,才能生效。
93
99
 
94
100
  ### 7. 本地优先,公开层不包含个人模型
95
101
 
@@ -97,6 +103,121 @@ Agent 在酒店项目工作时先搜索酒店本地知识,再沿显式的 `PAR
97
103
  原始命令输出。团队共享层只承载经过确认、具有上下文和来源的项目或领域知识,不包含个人的
98
104
  品味、个性和判断偏好。
99
105
 
106
+ ## 实际怎么用:分类、作用域、项目识别与取回
107
+
108
+ ### 先判断存什么,再判断存在哪里
109
+
110
+ “内容类型”和“生效范围”是两个独立维度。前三类是个人协作偏好,会带有
111
+ `profileAspect`;项目事实不带 `profileAspect`,也不会出现在“个人偏好”页中。
112
+
113
+ | 类型 | 应该存什么 | 例子 |
114
+ | --- | --- | --- |
115
+ | 品味 `taste` | 用户明确喜欢或排斥的结果、风格与质量方向,适用于界面、文案、产品、架构和工程结果 | “页面少用大渐变,不要卡片套卡片” |
116
+ | 个性 `personality` | 用户明确自我描述、并且预计长期稳定的工作或协作特点 | “我习惯直接沟通,希望 Agent 主动推进” |
117
+ | 判断偏好 `judgment_preference` | 面对取舍时的决策条件、优先级、风险倾向和操作边界 | “方向性歧义先讨论;未明确时禁止 `git push`” |
118
+ | 项目知识 | 可复用的客观项目事实、术语、需求、路由、API、架构、决策理由和 Runbook | “Fuli 的 npm 发布由 GitHub Release 触发” |
119
+
120
+ 可以用四个问题快速分类:它描述的是“想要什么结果”时存品味;描述“我是怎样长期协作的”时
121
+ 存个性;描述“遇到取舍时怎么决定”时存判断偏好;描述“这个系统客观上如何工作”时存项目
122
+ 知识。一次性命令、临时输出、未经验证的猜测、原始聊天和凭据都不沉淀。
123
+
124
+ “个性”不是所有个人信息的兜底分类。只有用户明确给出的稳定自我描述可以直接带着人工依据
125
+ 确认;Agent 仅从一次行为推断出的个性必须先保持 `pending`,不能伪装成人工确认。因此
126
+ `/preferences` 的“个性”为空,通常表示当前范围内还没有符合这个标准的条目,而不是沉淀
127
+ 失败。像“文案简洁”更可能是品味,“未授权不推送”更可能是判断偏好。需要明确沉淀时,可以
128
+ 直接说:`这是我的长期协作个性,请作为个人全局偏好保存:我习惯直接沟通。` Agent 推断的
129
+ 候选可在 `/preferences` 或 `/flreview` 中由用户确认、纠正或失效。
130
+
131
+ ### 全局、项目级和公共层
132
+
133
+ | 范围 | 何时使用 | 写入关键字段 | 取回规则 |
134
+ | --- | --- | --- | --- |
135
+ | 个人全局偏好 | 在无关项目中也应该保持不变 | `targetKind: "personal"`,不传 `personalProjectId`,设置 `profileAspect` | 每个任务都加载 |
136
+ | 项目级个人偏好 | 协作方式属于一个项目或项目族 | 同上,同时传精确的 `personalProjectId`;默认 `local_only`,不向子项目继承;需传播时显式使用 `descendants` 或 `selected_projects` | 精确项目优先;仅按显式继承模式沿获授权关系传播,冲突不按分数自动裁决 |
137
+ | 项目知识 | 事实只属于一个项目,或应由某个上级项目统一维护 | `targetKind: "personal"`,传 `personalProjectId`,不设置 `profileAspect` | 先查当前项目,再沿获授权的 `PART_OF` / `USES_KNOWLEDGE_FROM` 最多向上两跳 |
138
+ | 团队公共知识 | 经人工确认、确实需要共享的项目或领域知识 | `targetKind: "project"`,并经过预览/审核 | 只有明确订阅或选择的公共项目可见;个人偏好永不进入这一层 |
139
+
140
+ 判断作用域时问一句:**换到完全无关的项目,这条协作偏好还应该改变 Agent 的行为吗?**
141
+ “是”就存个人全局;“否,只在 Fuli 项目或项目族”就存项目级偏好,并明确是否允许向子项目
142
+ 传播。客观项目事实不要因为多个项目都可能用到就改存个人全局;应放在明确的上级或知识源
143
+ 项目,再建立有方向的授权关系。全局和项目级存在同一 `attributes.preferenceKey` 时,
144
+ 确认权威必须先裁决;权威相同时才由精确项目版本覆盖全局版本。
145
+
146
+ ### Fuli 怎么识别当前项目
147
+
148
+ Fuli 只匹配已经登记在“个人项目”中的稳定 `project_id`,不根据目录内容做模糊猜测。通常让
149
+ `project_id` 与仓库目录名一致,例如仓库 `/workspace/fuli` 对应项目 `fuli`。标准调用只传
150
+ 当前工作目录,解析顺序如下:
151
+
152
+ 1. 向上找到最近的 Git 仓库根;仓库目录名与已登记 `project_id` 完全相同时命中。
153
+ 2. 如果当前目录是 Codex worktree,从 `.git` 指向的原始仓库恢复项目 ID。
154
+ 3. 当前目录名与已登记项目 ID 完全相同时命中。
155
+ 4. 如果当前目录是工作区根,并且正好只有一个已登记的直接子目录带 `.git`、`package.json`、
156
+ `pyproject.toml`、`Cargo.toml` 或 `go.mod`,命中这个唯一子项目。
157
+ 5. 多个候选返回 `ambiguous`,没有候选返回 `unmatched`;两种情况都不会应用项目级偏好,也
158
+ 不会猜一个项目。
159
+
160
+ 第一次进入尚未登记、但身份明确的仓库时,已安装的沉淀 Skill 可以在首次项目级写入前通过
161
+ `upsert_personal_project` 创建最小的本机私有项目;它不会自动创建或订阅公共项目。若工作区
162
+ 有多个候选,应进入精确项目目录运行 Agent,或先在“个人项目”中明确选择和登记。
163
+
164
+ ### Agent 什么时候调用什么
165
+
166
+ 正常使用时,不需要手工调用 MCP 工具:在项目目录中向 Agent 提任务即可。Claude Code Hook
167
+ 调用 `begin_task_context`;Codex 和 Cursor 的 Prompt fallback 在每个任务开始调用一次:
168
+
169
+ ```json
170
+ {
171
+ "tool": "get_collaboration_preferences",
172
+ "arguments": {
173
+ "projectPath": "/workspace/fuli",
174
+ "taskPrompt": "修复 npm 发布流程,并沿用这个项目已有的发布约定"
175
+ }
176
+ }
177
+ ```
178
+
179
+ 命中后,返回值中的关键部分类似:
180
+
181
+ ```json
182
+ {
183
+ "context": {
184
+ "personal_project_id": "fuli",
185
+ "project_resolution": {
186
+ "status": "matched",
187
+ "basis": "repository_root",
188
+ "personal_project_id": "fuli"
189
+ }
190
+ },
191
+ "effective_preferences": ["个人全局偏好 + fuli 的精确项目偏好"]
192
+ }
193
+ ```
194
+
195
+ 入口返回的 `task_knowledge_recall` 没有回答稳定项目事实时,再用 1 至 4 条面向动作、产物、目标
196
+ 系统或标识符的短查询检索;不要把整段用户请求原样当成唯一查询:
197
+
198
+ ```json
199
+ {
200
+ "tool": "search_current_project_knowledge",
201
+ "arguments": {
202
+ "projectPath": "/workspace/fuli",
203
+ "queries": ["npm 发布 Runbook", "GitHub Release 触发条件"],
204
+ "includePending": false
205
+ }
206
+ }
207
+ ```
208
+
209
+ 任务结束时,Hook 模式调用 `checkpoint_task_knowledge`:只有少量、可复用且有证据的内容才用
210
+ `capture_candidates`;否则使用 `retain_nothing`。Prompt fallback Agent 遵守相同判断标准,并
211
+ 通过 `capture_session_knowledge` 写入。写个人偏好时设置正确的 `profileAspect` 和稳定的
212
+ `attributes.preferenceKey`;写项目事实时不设置 `profileAspect`。如果“设置”中的自动沉淀已
213
+ 关闭,写入会返回 `capture_disabled`,不会产生任何类别的条目。
214
+
215
+ 本地可先运行下面两个契约测试,验证 README 说明和项目路径解析仍与实现一致:
216
+
217
+ ```bash
218
+ npm run test:node -- test/acceptance-docs.test.js test/project-path-context.test.js
219
+ ```
220
+
100
221
  ## Agent 交互时序
101
222
 
102
223
  下面是日常任务的简化时序。更完整的项目继承、使用计数、写入预览和来源标记流程见
@@ -289,7 +410,7 @@ CLI 的帮助、交互提示、状态和错误信息固定使用英文,不跟
289
410
  | `fuli --help` / `fuli -h` | 显示所有公开命令及其可用参数 |
290
411
  | `fuli --version` / `fuli -v` | 显示当前安装的 Fuli CLI 版本 |
291
412
  | `fuli setup [选项]` | 初始化 Provider、管理界面、Agent 接入和 Skills;可重复执行 |
292
- | `fuli start [选项]` | 启动 Provider 和管理界面;可选择启动后打开浏览器、重建容器或启用 LAN 访问 |
413
+ | `fuli start [选项]` | 检查 Agent 接入后启动 Provider 和管理界面;可选择启动后打开浏览器、重建容器或启用 LAN 访问 |
293
414
  | `fuli stop [--data-dir DIR]` | 停止服务并保留数据 |
294
415
  | `fuli restart [选项]` | 使用与 `start` 相同的运行参数重启本机服务 |
295
416
  | `fuli status [--json] [--data-dir DIR] [--port PORT]` | 查看管理界面、个人图谱和公共服务状态;`--json` 输出机器可读结果 |
@@ -314,6 +435,9 @@ fuli stop
314
435
  口令。默认启动仍只监听 `127.0.0.1`;内部 Provider、Neo4j Browser 和 Bolt 不会随
315
436
  `--lan` 开放。局域网模式使用 HTTP Basic Auth,只适合可信家庭或办公 Wi-Fi,不等同于
316
437
  HTTPS 公网部署。
438
+ `fuli start` 启动前会只读检查已检测到的 Agent 的 MCP、Skill、Codex bootstrap 和 Claude
439
+ 生命周期接入。如果有缺失或过期,它仍会启动本机服务,但会提示执行 `fuli setup`;不会在
440
+ 后台隐式修改接入配置。
317
441
 
318
442
  `setup` 和 `update` 支持:
319
443
 
@@ -357,10 +481,20 @@ Code 使用 `UserPromptSubmit` 和 `Stop` Hook 接入任务生命周期;Codex
357
481
  `AGENTS.md` 与 Cursor 指令使用 Prompt fallback。偏好正文始终以本机 Fuli 为唯一来源,
358
482
  不会复制到 Agent 配置中。
359
483
 
484
+ FULI MCP 还提供只读的 `fuli://` resources:每个本地个人项目和“全局品味”各有一个可选条目。
485
+ 支持 MCP mention 的 Agent 可以在 `@` 选择器里选中它们;项目条目只代表一个精确项目,
486
+ 不会因为选择而自动扩大到其他项目或 `RELATED_TO` 项目。
487
+
488
+ 当任务需要品味或判断建议时,`get_user_taste_skill` 会根据当前生效的个人档案和历史任务
489
+ 数据生成一份有界、只读的 `user-taste` Skill 结论。它会标注证据状态与作用域,返回与当前
490
+ 任务匹配的推荐,并在偏好新增或修订后重新生成;不会覆盖用户自己编写的 taste Skill,持久
491
+ 图谱仍是唯一来源。
492
+
360
493
  | 工具 | 用途 |
361
494
  | --- | --- |
362
495
  | `begin_task_context` | Hook 入口:解析任务、在命中信号时执行有界召回并创建任务令牌 |
363
496
  | `get_collaboration_preferences` | Fallback 入口:读取生效偏好和有界任务召回 |
497
+ | `get_user_taste_skill` | 生成当前带证据状态的 taste Skill 结论和任务推荐 |
364
498
  | `search_current_project_knowledge` | 子项目优先、按授权关系向上检索 |
365
499
  | `search_knowledge_graph` | 在明确的有界范围内执行更通用的查询 |
366
500
  | `search_connected_knowledge` | 分开检索图谱、项目绑定的只读来源和选定公共项目,保留来源边界 |
@@ -47,6 +47,8 @@ services:
47
47
  FULI_PROVIDER_ID: local-personal
48
48
  FULI_PROVIDER_NAME: Fuli Personal Provider
49
49
  FULI_BOOTSTRAP_TOKEN: ${FULI_PERSONAL_BOOTSTRAP_TOKEN}
50
+ FULI_HUMAN_REVIEW_TOKEN: ${FULI_PERSONAL_HUMAN_REVIEW_TOKEN}
51
+ FULI_WORKFLOW_OBSERVATION_TOKEN: ${FULI_PERSONAL_WORKFLOW_OBSERVATION_TOKEN}
50
52
  FULI_NEO4J_URI: bolt://personal-neo4j:7687
51
53
  FULI_NEO4J_USER: neo4j
52
54
  FULI_NEO4J_PASSWORD: ${FULI_PERSONAL_NEO4J_PASSWORD}
@@ -1 +1 @@
1
- import{Q as e,_ as t,a as n,b as r,f as i,j as a,k as o,m as s,p as c,tt as l,x as u}from"./i18n-BQcns1PH.js";import{t as d}from"./fuli-logo-Bu9WBuQe.js";import{t as f}from"./_plugin-vue_export-helper-BDNMzG2s.js";var p=[`aria-label`],m={class:`label-dimension-strip`},h=[`data-dimension`],g={class:`label-guide-sheet`},_={class:`label-guide-section profile-guide`},v={class:`label-definition-list`},y=[`data-kind`],b={class:`label-guide-section quadrant-guide`},x={class:`quadrant-explainer`},S={class:`quadrant-y-axis`,"aria-hidden":`true`},C={class:`quadrant-grid`},w=[`data-quadrant`],T={class:`quadrant-x-axis`,"aria-hidden":`true`},E={class:`quadrant-notes`},D={class:`label-guide-section confirmation-guide`},O={class:`status-definition-list`},k=[`data-status`],A={class:`status-boundaries`},j={class:`label-example`},M={class:`label-example-tags`,"aria-hidden":`true`},N={class:`label-token profile-token`,"data-kind":`taste`},P={class:`label-token origin-token`},ee={class:`label-token status-token`,"data-status":`confirmed`},F={class:`label-all-note`},I=f(u({__name:`LabelGuide`,setup(r){let u=c(()=>[{key:`profile`,title:n(`about.dimensions.profile.title`),question:n(`about.dimensions.profile.question`),timing:n(`about.dimensions.profile.timing`)},{key:`origin`,title:n(`about.dimensions.origin.title`),question:n(`about.dimensions.origin.question`),timing:n(`about.dimensions.origin.timing`)},{key:`confirmation`,title:n(`about.dimensions.confirmation.title`),question:n(`about.dimensions.confirmation.question`),timing:n(`about.dimensions.confirmation.timing`)}]),d=c(()=>[{key:`taste`,label:n(`about.profiles.taste.label`),short:n(`about.profiles.taste.short`),description:n(`about.profiles.taste.description`)},{key:`personality`,label:n(`about.profiles.personality.label`),short:n(`about.profiles.personality.short`),description:n(`about.profiles.personality.description`)},{key:`judgment`,label:n(`about.profiles.judgment.label`),short:n(`about.profiles.judgment.short`),description:n(`about.profiles.judgment.description`)}]),f=c(()=>[{key:`known-unknown`,label:n(`about.quadrants.knownUnknown.label`),coordinate:n(`about.quadrants.knownUnknown.coordinate`),description:n(`about.quadrants.knownUnknown.description`)},{key:`known-known`,label:n(`about.quadrants.knownKnown.label`),coordinate:n(`about.quadrants.knownKnown.coordinate`),description:n(`about.quadrants.knownKnown.description`)},{key:`unknown-unknown`,label:n(`about.quadrants.unknownUnknown.label`),coordinate:n(`about.quadrants.unknownUnknown.coordinate`),description:n(`about.quadrants.unknownUnknown.description`)},{key:`unknown-known`,label:n(`about.quadrants.unknownKnown.label`),coordinate:n(`about.quadrants.unknownKnown.coordinate`),description:n(`about.quadrants.unknownKnown.description`)}]),I=c(()=>[{key:`pending`,label:n(`about.statuses.pending.label`),description:n(`about.statuses.pending.description`),rule:n(`about.statuses.pending.rule`)},{key:`agent-confirmed`,label:n(`about.statuses.agentConfirmed.label`),description:n(`about.statuses.agentConfirmed.description`),rule:n(`about.statuses.agentConfirmed.rule`)},{key:`confirmed`,label:n(`about.statuses.confirmed.label`),description:n(`about.statuses.confirmed.description`),rule:n(`about.statuses.confirmed.rule`)}]);return(r,c)=>(o(),t(`section`,{class:`label-guide`,"aria-label":e(n)(`about.labelsAria`)},[s(`div`,m,[(o(!0),t(i,null,a(u.value,e=>(o(),t(`article`,{key:e.key,"data-dimension":e.key},[c[0]||=s(`i`,{"aria-hidden":`true`},null,-1),s(`div`,null,[s(`strong`,null,l(e.title),1),s(`p`,null,l(e.question),1),s(`small`,null,l(e.timing),1)])],8,h))),128))]),s(`div`,g,[s(`section`,_,[s(`header`,null,[s(`span`,null,l(e(n)(`about.sections.profile.index`)),1),s(`div`,null,[s(`h3`,null,l(e(n)(`about.sections.profile.title`)),1),s(`p`,null,l(e(n)(`about.sections.profile.meta`)),1)])]),s(`div`,v,[(o(!0),t(i,null,a(d.value,e=>(o(),t(`article`,{key:e.key,class:`label-definition-row`},[s(`span`,{class:`label-token profile-token`,"data-kind":e.key},l(e.label),9,y),s(`div`,null,[s(`strong`,null,l(e.short),1),s(`p`,null,l(e.description),1)])]))),128))])]),s(`section`,b,[s(`header`,null,[s(`span`,null,l(e(n)(`about.sections.origin.index`)),1),s(`div`,null,[s(`h3`,null,l(e(n)(`about.sections.origin.title`)),1),s(`p`,null,l(e(n)(`about.sections.origin.meta`)),1)])]),s(`div`,x,[s(`div`,S,[s(`span`,null,l(e(n)(`about.quadrants.aware`)),1),s(`strong`,null,l(e(n)(`about.quadrants.awareness`)),1),s(`span`,null,l(e(n)(`about.quadrants.unaware`)),1)]),s(`div`,C,[(o(!0),t(i,null,a(f.value,e=>(o(),t(`article`,{key:e.key,"data-quadrant":e.key},[s(`span`,null,l(e.coordinate),1),s(`strong`,null,l(e.label),1),s(`p`,null,l(e.description),1)],8,w))),128))]),s(`div`,T,[s(`span`,null,l(e(n)(`about.quadrants.unmastered`)),1),s(`strong`,null,l(e(n)(`about.quadrants.mastery`)),1),s(`span`,null,l(e(n)(`about.quadrants.mastered`)),1)]),s(`div`,E,[s(`p`,null,l(e(n)(`about.quadrants.immutable`)),1),s(`p`,null,l(e(n)(`about.quadrants.unclassified`)),1)])])]),s(`section`,D,[s(`header`,null,[s(`span`,null,l(e(n)(`about.sections.confirmation.index`)),1),s(`div`,null,[s(`h3`,null,l(e(n)(`about.sections.confirmation.title`)),1),s(`p`,null,l(e(n)(`about.sections.confirmation.meta`)),1)])]),s(`div`,null,[s(`div`,O,[(o(!0),t(i,null,a(I.value,r=>(o(),t(`article`,{key:r.key,class:`status-definition-row`},[s(`span`,{class:`label-token status-token`,"data-status":r.key},l(r.label),9,k),s(`p`,null,l(r.description),1),s(`div`,null,[s(`span`,null,l(e(n)(`about.statuses.entryCondition`)),1),s(`strong`,null,l(r.rule),1)])]))),128))]),s(`div`,A,[s(`p`,null,l(e(n)(`about.statuses.usageBoundary`)),1),s(`p`,null,l(e(n)(`about.statuses.resetBoundary`)),1)])])]),s(`section`,j,[s(`div`,null,[s(`span`,null,l(e(n)(`about.example.title`)),1),s(`strong`,null,l(e(n)(`about.example.item`)),1)]),s(`div`,M,[s(`span`,N,l(e(n)(`about.example.profile`)),1),s(`span`,P,l(e(n)(`about.example.origin`)),1),s(`span`,ee,l(e(n)(`about.example.status`)),1)]),s(`p`,null,l(e(n)(`about.example.description`)),1)]),s(`p`,F,l(e(n)(`about.allFilter`)),1)])],8,p))}}),[[`__scopeId`,`data-v-b79b7e68`]]),L={class:`open-source-credits`},R={class:`credits-roll`},z={class:`credit-grid`},B=[`href`],V={class:`credit-mark`},H=[`src`,`alt`],U={class:`credit-copy`},W={class:`credit-source-note`},G={class:`fuli-finale`},K={class:`finale-brand`},q=[`src`],J=f(u({__name:`OpenSourceCredits`,setup(r){let u=c(()=>[{name:`Vue.js`,role:n(`about.credits.roles.vue`),logo:`https://raw.githubusercontent.com/vuejs/docs/main/src/public/logo.svg`,url:`https://vuejs.org/`},{name:`Vite`,role:n(`about.credits.roles.vite`),logo:`https://raw.githubusercontent.com/vitejs/vite/main/docs/public/logo-without-border.svg`,url:`https://vite.dev/`},{name:`Pinia`,role:n(`about.credits.roles.pinia`),logo:`https://raw.githubusercontent.com/vuejs/pinia/v4/packages/docs/public/logo.svg`,url:`https://pinia.vuejs.org/`},{name:`D3.js`,role:n(`about.credits.roles.d3`),logo:`https://raw.githubusercontent.com/d3/d3-logo/master/d3.svg`,url:`https://d3js.org/`},{name:`Vitest`,role:n(`about.credits.roles.vitest`),logo:`https://raw.githubusercontent.com/vitest-dev/vitest/main/docs/public/logo-without-border.svg`,url:`https://vitest.dev/`},{name:`Hono`,role:n(`about.credits.roles.hono`),logo:`https://raw.githubusercontent.com/honojs/website/main/public/images/logo.svg`,url:`https://hono.dev/`},{name:`Neo4j`,role:n(`about.credits.roles.neo4j`),logo:`https://avatars.githubusercontent.com/u/201120?v=4`,url:`https://neo4j.com/`},{name:`Zod`,role:n(`about.credits.roles.zod`),logo:`https://raw.githubusercontent.com/colinhacks/zod/main/packages/docs/public/logo/logo_square.png`,url:`https://zod.dev/`},{name:`FastAPI`,role:n(`about.credits.roles.fastapi`),logo:`https://raw.githubusercontent.com/fastapi/fastapi/master/docs/en/docs/img/favicon.png`,url:`https://fastapi.tiangolo.com/`},{name:`Graphiti`,role:n(`about.credits.roles.graphiti`),logo:`https://avatars.githubusercontent.com/u/132832125?s=128&v=4`,url:`https://github.com/getzep/graphiti`},{name:`Model Context Protocol`,role:n(`about.credits.roles.mcp`),logo:`https://raw.githubusercontent.com/modelcontextprotocol/docs/main/favicon.svg`,url:`https://modelcontextprotocol.io/`}]);return(r,c)=>(o(),t(`section`,L,[s(`div`,R,[s(`header`,null,[s(`h3`,null,l(e(n)(`about.credits.title`)),1),s(`p`,null,l(e(n)(`about.credits.description`)),1)]),s(`div`,z,[(o(!0),t(i,null,a(u.value,e=>(o(),t(`a`,{key:e.name,href:e.url,target:`_blank`,rel:`noreferrer`},[s(`span`,V,[s(`img`,{src:e.logo,alt:e.name},null,8,H)]),s(`span`,U,[s(`strong`,null,l(e.name),1),s(`small`,null,l(e.role),1)])],8,B))),128))]),s(`p`,W,l(e(n)(`about.credits.sourceNote`)),1)]),s(`footer`,G,[s(`div`,K,[s(`img`,{src:e(d),alt:``,"aria-hidden":`true`},null,8,q),s(`div`,null,[s(`strong`,null,l(e(n)(`common.brand`)),1),c[0]||=s(`span`,null,`Context Graph`,-1)])]),s(`p`,null,l(e(n)(`about.credits.finale`)),1)])]))}}),[[`__scopeId`,`data-v-8676884b`]]),Y={class:`product-principles`},X={class:`principles-lede`},Z={class:`principle-sequence`},Q={class:`principle-boundaries`},$=[`data-boundary`],te=f(u({__name:`ProductPrinciples`,setup(r){let u=c(()=>[{key:`capture`,index:n(`about.philosophy.capture.index`),title:n(`about.philosophy.capture.title`),description:n(`about.philosophy.capture.description`)},{key:`project`,index:n(`about.philosophy.project.index`),title:n(`about.philosophy.project.title`),description:n(`about.philosophy.project.description`)},{key:`review`,index:n(`about.philosophy.review.index`),title:n(`about.philosophy.review.title`),description:n(`about.philosophy.review.description`)},{key:`reuse`,index:n(`about.philosophy.reuse.index`),title:n(`about.philosophy.reuse.title`),description:n(`about.philosophy.reuse.description`)}]),d=c(()=>[{key:`local`,title:n(`about.philosophy.local.title`),description:n(`about.philosophy.local.description`)},{key:`authority`,title:n(`about.philosophy.authority.title`),description:n(`about.philosophy.authority.description`)},{key:`scope`,title:n(`about.philosophy.scope.title`),description:n(`about.philosophy.scope.description`)}]);return(r,c)=>(o(),t(`section`,Y,[s(`header`,X,[s(`h3`,null,l(e(n)(`about.philosophy.title`)),1),s(`p`,null,l(e(n)(`about.philosophy.intro`)),1),s(`p`,null,l(e(n)(`about.philosophy.support`)),1)]),s(`div`,Z,[(o(!0),t(i,null,a(u.value,e=>(o(),t(`article`,{key:e.key},[s(`span`,null,l(e.index),1),s(`div`,null,[s(`h4`,null,l(e.title),1),s(`p`,null,l(e.description),1)])]))),128))]),s(`div`,Q,[s(`strong`,null,l(e(n)(`about.philosophy.boundariesTitle`)),1),s(`div`,null,[(o(!0),t(i,null,a(d.value,e=>(o(),t(`article`,{key:e.key},[s(`i`,{"data-boundary":e.key,"aria-hidden":`true`},null,8,$),s(`h4`,null,l(e.title),1),s(`p`,null,l(e.description),1)]))),128))])])]))}}),[[`__scopeId`,`data-v-d823b02d`]]),ne=[`aria-label`],re={class:`about-content`},ie={class:`about-labels-section`},ae=f(u({__name:`AboutPage`,setup(i){return(i,a)=>(o(),t(`section`,{class:`view about-view`,"aria-label":e(n)(`about.aria`)},[s(`div`,re,[r(te),s(`section`,ie,[s(`header`,null,[s(`h3`,null,l(e(n)(`about.labelsIntro.title`)),1),s(`p`,null,l(e(n)(`about.labelsIntro.description`)),1)]),r(I)]),r(J)])],8,ne))}}),[[`__scopeId`,`data-v-6bd30c79`]]);export{ae as default};
1
+ import{Q as e,_ as t,a as n,b as r,f as i,j as a,k as o,m as s,p as c,tt as l,x as u}from"./i18n-CWfd8Dtt.js";import{t as d}from"./fuli-logo-Bu9WBuQe.js";import{t as f}from"./_plugin-vue_export-helper-BDNMzG2s.js";var p=[`aria-label`],m={class:`label-dimension-strip`},h=[`data-dimension`],g={class:`label-guide-sheet`},_={class:`label-guide-section profile-guide`},v={class:`label-definition-list`},y=[`data-kind`],b={class:`label-guide-section quadrant-guide`},x={class:`quadrant-explainer`},S={class:`quadrant-y-axis`,"aria-hidden":`true`},C={class:`quadrant-grid`},w=[`data-quadrant`],T={class:`quadrant-x-axis`,"aria-hidden":`true`},E={class:`quadrant-notes`},D={class:`label-guide-section confirmation-guide`},O={class:`status-definition-list`},k=[`data-status`],A={class:`status-boundaries`},j={class:`label-example`},M={class:`label-example-tags`,"aria-hidden":`true`},N={class:`label-token profile-token`,"data-kind":`taste`},P={class:`label-token origin-token`},ee={class:`label-token status-token`,"data-status":`confirmed`},F={class:`label-all-note`},I=f(u({__name:`LabelGuide`,setup(r){let u=c(()=>[{key:`profile`,title:n(`about.dimensions.profile.title`),question:n(`about.dimensions.profile.question`),timing:n(`about.dimensions.profile.timing`)},{key:`origin`,title:n(`about.dimensions.origin.title`),question:n(`about.dimensions.origin.question`),timing:n(`about.dimensions.origin.timing`)},{key:`confirmation`,title:n(`about.dimensions.confirmation.title`),question:n(`about.dimensions.confirmation.question`),timing:n(`about.dimensions.confirmation.timing`)}]),d=c(()=>[{key:`taste`,label:n(`about.profiles.taste.label`),short:n(`about.profiles.taste.short`),description:n(`about.profiles.taste.description`)},{key:`personality`,label:n(`about.profiles.personality.label`),short:n(`about.profiles.personality.short`),description:n(`about.profiles.personality.description`)},{key:`judgment`,label:n(`about.profiles.judgment.label`),short:n(`about.profiles.judgment.short`),description:n(`about.profiles.judgment.description`)}]),f=c(()=>[{key:`known-unknown`,label:n(`about.quadrants.knownUnknown.label`),coordinate:n(`about.quadrants.knownUnknown.coordinate`),description:n(`about.quadrants.knownUnknown.description`)},{key:`known-known`,label:n(`about.quadrants.knownKnown.label`),coordinate:n(`about.quadrants.knownKnown.coordinate`),description:n(`about.quadrants.knownKnown.description`)},{key:`unknown-unknown`,label:n(`about.quadrants.unknownUnknown.label`),coordinate:n(`about.quadrants.unknownUnknown.coordinate`),description:n(`about.quadrants.unknownUnknown.description`)},{key:`unknown-known`,label:n(`about.quadrants.unknownKnown.label`),coordinate:n(`about.quadrants.unknownKnown.coordinate`),description:n(`about.quadrants.unknownKnown.description`)}]),I=c(()=>[{key:`pending`,label:n(`about.statuses.pending.label`),description:n(`about.statuses.pending.description`),rule:n(`about.statuses.pending.rule`)},{key:`agent-confirmed`,label:n(`about.statuses.agentConfirmed.label`),description:n(`about.statuses.agentConfirmed.description`),rule:n(`about.statuses.agentConfirmed.rule`)},{key:`confirmed`,label:n(`about.statuses.confirmed.label`),description:n(`about.statuses.confirmed.description`),rule:n(`about.statuses.confirmed.rule`)}]);return(r,c)=>(o(),t(`section`,{class:`label-guide`,"aria-label":e(n)(`about.labelsAria`)},[s(`div`,m,[(o(!0),t(i,null,a(u.value,e=>(o(),t(`article`,{key:e.key,"data-dimension":e.key},[c[0]||=s(`i`,{"aria-hidden":`true`},null,-1),s(`div`,null,[s(`strong`,null,l(e.title),1),s(`p`,null,l(e.question),1),s(`small`,null,l(e.timing),1)])],8,h))),128))]),s(`div`,g,[s(`section`,_,[s(`header`,null,[s(`span`,null,l(e(n)(`about.sections.profile.index`)),1),s(`div`,null,[s(`h3`,null,l(e(n)(`about.sections.profile.title`)),1),s(`p`,null,l(e(n)(`about.sections.profile.meta`)),1)])]),s(`div`,v,[(o(!0),t(i,null,a(d.value,e=>(o(),t(`article`,{key:e.key,class:`label-definition-row`},[s(`span`,{class:`label-token profile-token`,"data-kind":e.key},l(e.label),9,y),s(`div`,null,[s(`strong`,null,l(e.short),1),s(`p`,null,l(e.description),1)])]))),128))])]),s(`section`,b,[s(`header`,null,[s(`span`,null,l(e(n)(`about.sections.origin.index`)),1),s(`div`,null,[s(`h3`,null,l(e(n)(`about.sections.origin.title`)),1),s(`p`,null,l(e(n)(`about.sections.origin.meta`)),1)])]),s(`div`,x,[s(`div`,S,[s(`span`,null,l(e(n)(`about.quadrants.aware`)),1),s(`strong`,null,l(e(n)(`about.quadrants.awareness`)),1),s(`span`,null,l(e(n)(`about.quadrants.unaware`)),1)]),s(`div`,C,[(o(!0),t(i,null,a(f.value,e=>(o(),t(`article`,{key:e.key,"data-quadrant":e.key},[s(`span`,null,l(e.coordinate),1),s(`strong`,null,l(e.label),1),s(`p`,null,l(e.description),1)],8,w))),128))]),s(`div`,T,[s(`span`,null,l(e(n)(`about.quadrants.unmastered`)),1),s(`strong`,null,l(e(n)(`about.quadrants.mastery`)),1),s(`span`,null,l(e(n)(`about.quadrants.mastered`)),1)]),s(`div`,E,[s(`p`,null,l(e(n)(`about.quadrants.immutable`)),1),s(`p`,null,l(e(n)(`about.quadrants.unclassified`)),1)])])]),s(`section`,D,[s(`header`,null,[s(`span`,null,l(e(n)(`about.sections.confirmation.index`)),1),s(`div`,null,[s(`h3`,null,l(e(n)(`about.sections.confirmation.title`)),1),s(`p`,null,l(e(n)(`about.sections.confirmation.meta`)),1)])]),s(`div`,null,[s(`div`,O,[(o(!0),t(i,null,a(I.value,r=>(o(),t(`article`,{key:r.key,class:`status-definition-row`},[s(`span`,{class:`label-token status-token`,"data-status":r.key},l(r.label),9,k),s(`p`,null,l(r.description),1),s(`div`,null,[s(`span`,null,l(e(n)(`about.statuses.entryCondition`)),1),s(`strong`,null,l(r.rule),1)])]))),128))]),s(`div`,A,[s(`p`,null,l(e(n)(`about.statuses.usageBoundary`)),1),s(`p`,null,l(e(n)(`about.statuses.resetBoundary`)),1)])])]),s(`section`,j,[s(`div`,null,[s(`span`,null,l(e(n)(`about.example.title`)),1),s(`strong`,null,l(e(n)(`about.example.item`)),1)]),s(`div`,M,[s(`span`,N,l(e(n)(`about.example.profile`)),1),s(`span`,P,l(e(n)(`about.example.origin`)),1),s(`span`,ee,l(e(n)(`about.example.status`)),1)]),s(`p`,null,l(e(n)(`about.example.description`)),1)]),s(`p`,F,l(e(n)(`about.allFilter`)),1)])],8,p))}}),[[`__scopeId`,`data-v-b79b7e68`]]),L={class:`open-source-credits`},R={class:`credits-roll`},z={class:`credit-grid`},B=[`href`],V={class:`credit-mark`},H=[`src`,`alt`],U={class:`credit-copy`},W={class:`credit-source-note`},G={class:`fuli-finale`},K={class:`finale-brand`},q=[`src`],J=f(u({__name:`OpenSourceCredits`,setup(r){let u=c(()=>[{name:`Vue.js`,role:n(`about.credits.roles.vue`),logo:`https://raw.githubusercontent.com/vuejs/docs/main/src/public/logo.svg`,url:`https://vuejs.org/`},{name:`Vite`,role:n(`about.credits.roles.vite`),logo:`https://raw.githubusercontent.com/vitejs/vite/main/docs/public/logo-without-border.svg`,url:`https://vite.dev/`},{name:`Pinia`,role:n(`about.credits.roles.pinia`),logo:`https://raw.githubusercontent.com/vuejs/pinia/v4/packages/docs/public/logo.svg`,url:`https://pinia.vuejs.org/`},{name:`D3.js`,role:n(`about.credits.roles.d3`),logo:`https://raw.githubusercontent.com/d3/d3-logo/master/d3.svg`,url:`https://d3js.org/`},{name:`Vitest`,role:n(`about.credits.roles.vitest`),logo:`https://raw.githubusercontent.com/vitest-dev/vitest/main/docs/public/logo-without-border.svg`,url:`https://vitest.dev/`},{name:`Hono`,role:n(`about.credits.roles.hono`),logo:`https://raw.githubusercontent.com/honojs/website/main/public/images/logo.svg`,url:`https://hono.dev/`},{name:`Neo4j`,role:n(`about.credits.roles.neo4j`),logo:`https://avatars.githubusercontent.com/u/201120?v=4`,url:`https://neo4j.com/`},{name:`Zod`,role:n(`about.credits.roles.zod`),logo:`https://raw.githubusercontent.com/colinhacks/zod/main/packages/docs/public/logo/logo_square.png`,url:`https://zod.dev/`},{name:`FastAPI`,role:n(`about.credits.roles.fastapi`),logo:`https://raw.githubusercontent.com/fastapi/fastapi/master/docs/en/docs/img/favicon.png`,url:`https://fastapi.tiangolo.com/`},{name:`Graphiti`,role:n(`about.credits.roles.graphiti`),logo:`https://avatars.githubusercontent.com/u/132832125?s=128&v=4`,url:`https://github.com/getzep/graphiti`},{name:`Model Context Protocol`,role:n(`about.credits.roles.mcp`),logo:`https://raw.githubusercontent.com/modelcontextprotocol/docs/main/favicon.svg`,url:`https://modelcontextprotocol.io/`}]);return(r,c)=>(o(),t(`section`,L,[s(`div`,R,[s(`header`,null,[s(`h3`,null,l(e(n)(`about.credits.title`)),1),s(`p`,null,l(e(n)(`about.credits.description`)),1)]),s(`div`,z,[(o(!0),t(i,null,a(u.value,e=>(o(),t(`a`,{key:e.name,href:e.url,target:`_blank`,rel:`noreferrer`},[s(`span`,V,[s(`img`,{src:e.logo,alt:e.name},null,8,H)]),s(`span`,U,[s(`strong`,null,l(e.name),1),s(`small`,null,l(e.role),1)])],8,B))),128))]),s(`p`,W,l(e(n)(`about.credits.sourceNote`)),1)]),s(`footer`,G,[s(`div`,K,[s(`img`,{src:e(d),alt:``,"aria-hidden":`true`},null,8,q),s(`div`,null,[s(`strong`,null,l(e(n)(`common.brand`)),1),c[0]||=s(`span`,null,`Context Graph`,-1)])]),s(`p`,null,l(e(n)(`about.credits.finale`)),1)])]))}}),[[`__scopeId`,`data-v-8676884b`]]),Y={class:`product-principles`},X={class:`principles-lede`},Z={class:`principle-sequence`},Q={class:`principle-boundaries`},$=[`data-boundary`],te=f(u({__name:`ProductPrinciples`,setup(r){let u=c(()=>[{key:`capture`,index:n(`about.philosophy.capture.index`),title:n(`about.philosophy.capture.title`),description:n(`about.philosophy.capture.description`)},{key:`project`,index:n(`about.philosophy.project.index`),title:n(`about.philosophy.project.title`),description:n(`about.philosophy.project.description`)},{key:`review`,index:n(`about.philosophy.review.index`),title:n(`about.philosophy.review.title`),description:n(`about.philosophy.review.description`)},{key:`reuse`,index:n(`about.philosophy.reuse.index`),title:n(`about.philosophy.reuse.title`),description:n(`about.philosophy.reuse.description`)}]),d=c(()=>[{key:`local`,title:n(`about.philosophy.local.title`),description:n(`about.philosophy.local.description`)},{key:`authority`,title:n(`about.philosophy.authority.title`),description:n(`about.philosophy.authority.description`)},{key:`scope`,title:n(`about.philosophy.scope.title`),description:n(`about.philosophy.scope.description`)}]);return(r,c)=>(o(),t(`section`,Y,[s(`header`,X,[s(`h3`,null,l(e(n)(`about.philosophy.title`)),1),s(`p`,null,l(e(n)(`about.philosophy.intro`)),1),s(`p`,null,l(e(n)(`about.philosophy.support`)),1)]),s(`div`,Z,[(o(!0),t(i,null,a(u.value,e=>(o(),t(`article`,{key:e.key},[s(`span`,null,l(e.index),1),s(`div`,null,[s(`h4`,null,l(e.title),1),s(`p`,null,l(e.description),1)])]))),128))]),s(`div`,Q,[s(`strong`,null,l(e(n)(`about.philosophy.boundariesTitle`)),1),s(`div`,null,[(o(!0),t(i,null,a(d.value,e=>(o(),t(`article`,{key:e.key},[s(`i`,{"data-boundary":e.key,"aria-hidden":`true`},null,8,$),s(`h4`,null,l(e.title),1),s(`p`,null,l(e.description),1)]))),128))])])]))}}),[[`__scopeId`,`data-v-d823b02d`]]),ne=[`aria-label`],re={class:`about-content`},ie={class:`about-labels-section`},ae=f(u({__name:`AboutPage`,setup(i){return(i,a)=>(o(),t(`section`,{class:`view about-view`,"aria-label":e(n)(`about.aria`)},[s(`div`,re,[r(te),s(`section`,ie,[s(`header`,null,[s(`h3`,null,l(e(n)(`about.labelsIntro.title`)),1),s(`p`,null,l(e(n)(`about.labelsIntro.description`)),1)]),r(I)]),r(J)])],8,ne))}}),[[`__scopeId`,`data-v-6bd30c79`]]);export{ae as default};