@fenglimg/fabric-cli 2.0.0-rc.30 → 2.0.0-rc.34
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-PNRWNUFX.js → chunk-5N3KXIVI.js} +73 -4
- package/dist/{doctor-TTDTKOFJ.js → doctor-E26YO67D.js} +8 -2
- package/dist/index.js +4 -4
- package/dist/{install-OEBNSCS5.js → install-XCRX34CX.js} +4 -2
- package/dist/{uninstall-VLLJG7JT.js → uninstall-Q7V55BXH.js} +1 -1
- package/package.json +3 -3
- package/templates/hooks/cite-policy-evict.cjs +242 -0
- package/templates/hooks/configs/claude-code.json +11 -0
- package/templates/hooks/fabric-hint.cjs +11 -1
- package/templates/hooks/knowledge-hint-broad.cjs +276 -21
- package/templates/hooks/knowledge-hint-narrow.cjs +466 -14
- package/templates/skills/fabric-archive/SKILL.md +53 -864
- package/templates/skills/fabric-archive/ref/dry-run-scope.md +16 -0
- package/templates/skills/fabric-archive/ref/e5-cron-recap.md +5 -5
- package/templates/skills/fabric-archive/ref/i18n-policy.md +3 -3
- package/templates/skills/fabric-archive/ref/phase-0-range-resolution.md +156 -0
- package/templates/skills/fabric-archive/ref/{phase-0-4-onboard.md → phase-1-5-onboard.md} +21 -21
- package/templates/skills/fabric-archive/ref/phase-1-cross-session.md +60 -0
- package/templates/skills/fabric-archive/ref/phase-2-5-viability.md +54 -0
- package/templates/skills/fabric-archive/ref/phase-3-5-scope.md +80 -0
- package/templates/skills/fabric-archive/ref/phase-3-classify.md +63 -0
- package/templates/skills/fabric-archive/ref/phase-4-5-emit.md +78 -0
- package/templates/skills/fabric-archive/ref/phase-4-mcp-persist.md +89 -0
- package/templates/skills/fabric-archive/ref/rc-history.md +6 -6
- package/templates/skills/fabric-archive/ref/worked-examples.md +1 -1
- package/templates/skills/fabric-import/SKILL.md +29 -556
- package/templates/skills/fabric-import/ref/checkpoint-state.md +85 -0
- package/templates/skills/fabric-import/ref/output-contract.md +61 -0
- package/templates/skills/fabric-import/ref/phase-2-mining.md +213 -0
- package/templates/skills/fabric-import/ref/phase-3-dedup.md +75 -0
- package/templates/skills/fabric-import/ref/worked-examples.md +127 -0
- package/templates/skills/fabric-review/SKILL.md +56 -414
- package/templates/skills/fabric-review/ref/askuserquestion-policy.md +66 -0
- package/templates/skills/fabric-review/ref/modify-flow.md +95 -0
- package/templates/skills/fabric-review/ref/output-contract.md +58 -0
- package/templates/skills/fabric-review/ref/per-mode-flows.md +155 -0
- package/templates/skills/fabric-review/ref/semantic-check.md +26 -0
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# Phase 4.5 — Persist Archive Attempt (ref)
|
|
2
|
+
|
|
3
|
+
> **Loaded on demand.** SKILL.md hot path retains the MANDATORY-on-every-invocation rule, the dry-run cross-reference, and the outcome enum. This file holds the full event emission jsonc schema, outcome decision matrix, covered_through_ts watermark spec, multi-session emission rule, append-pattern reference, and the E5-cron-silent-skip worked example.
|
|
4
|
+
|
|
5
|
+
## What to emit
|
|
6
|
+
|
|
7
|
+
For EACH `session_id` in the run's scope (multi-session E4 runs emit MULTIPLE events — one per session_id; single-session E1/E2/E3/E5 runs emit ONE event), append ONE `session_archive_attempted` line to `.fabric/events.jsonl`:
|
|
8
|
+
|
|
9
|
+
```jsonc
|
|
10
|
+
{
|
|
11
|
+
"kind": "fabric-event",
|
|
12
|
+
"id": "<uuid or ts-derived>",
|
|
13
|
+
"ts": <epoch ms>,
|
|
14
|
+
"schema_version": 1,
|
|
15
|
+
"session_id": "<the session this event pertains to>",
|
|
16
|
+
"event_type": "session_archive_attempted",
|
|
17
|
+
"outcome": "proposed" | "viability_failed" | "user_dismissed" | "skipped_no_signal",
|
|
18
|
+
"covered_through_ts": <max event ts scanned for this session>,
|
|
19
|
+
"candidates_proposed": <integer, default 0>,
|
|
20
|
+
"knowledge_proposed_ids": ["<idempotency_key_1>", "..."] // default []
|
|
21
|
+
}
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Outcome decision matrix
|
|
25
|
+
|
|
26
|
+
| Skill terminal state | outcome | candidates_proposed | knowledge_proposed_ids |
|
|
27
|
+
|----------------------------------------------------------------------|----------------------|---------------------|-------------------------------------------------|
|
|
28
|
+
| Phase 4 wrote ≥ 1 pending entry | `proposed` | N (count written) | `[idempotency_key_1, idempotency_key_2, ...]` (from each fab_extract_knowledge response) |
|
|
29
|
+
| Phase 2.5 viability_failed AND entry_point ∈ {E2_explicit, E4_user_range} AND user saw + accepted the gate-FAIL message | `viability_failed` | 0 | `[]` |
|
|
30
|
+
| Phase 3 batch review — user dismissed ALL presented candidates | `user_dismissed` | 0 | `[]` |
|
|
31
|
+
| Phase 1 filter dropped every session in scope OR Phase 2.5 silent-skip path (E1_hook / E3_ai_self_trigger / E5_cron) | `skipped_no_signal` | 0 | `[]` |
|
|
32
|
+
|
|
33
|
+
Rationale highlights:
|
|
34
|
+
- `user_dismissed` is the ONLY outcome that suppresses future auto-rescan (respects user decision per Q3.4).
|
|
35
|
+
- `proposed` populates `knowledge_proposed_ids` so the cross-session digest in Phase 1 can dedupe future runs against already-proposed entries.
|
|
36
|
+
- `viability_failed` vs `skipped_no_signal` distinguishes "user was prompted but the gate stopped us" from "we never bothered the user" — both allow rescan but the doctor history report differentiates them.
|
|
37
|
+
|
|
38
|
+
## covered_through_ts watermark
|
|
39
|
+
|
|
40
|
+
```
|
|
41
|
+
covered_through_ts = max(events_in_scope[*].ts)
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
where `events_in_scope` is the set of events the skill actually examined for THAT session_id (Phase 2 + Phase 1 digest input). On rescan, Phase 1 compares the current `max(ts)` against this stored watermark — only sessions with new events past the watermark are eligible candidates.
|
|
45
|
+
|
|
46
|
+
## Multi-session emission rule
|
|
47
|
+
|
|
48
|
+
When the run scope spans multiple session_ids (E4 user-range with `--since` / topic-keyword matching multiple sessions), emit ONE `session_archive_attempted` event PER session_id. Each event's `covered_through_ts` is computed against that session's own event subset. The `knowledge_proposed_ids` for a multi-session `proposed` run lists ALL idempotency_keys produced by the run; ledger consumers that want per-session breakdown should join against `source_sessions` on each pending entry.
|
|
49
|
+
|
|
50
|
+
## Append pattern (Bash echo, 4KB-safe, fail-tolerant)
|
|
51
|
+
|
|
52
|
+
Reuse the Phase 2.5 `events.jsonl Constraint Note` pattern: single-line JSON ≤ 4KB, no embedded newlines. Best-effort write — if the append fails (disk full, permission denied, race), the skill MUST still exit successfully. Log the failure to stderr only; do NOT surface it to the user. Rationale: a missing `session_archive_attempted` event degrades gracefully — the next Phase 1 digest treats the session as "never archived" and re-evaluates it, which is the safe-default behavior.
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
# Pseudo — actual implementation uses the same pattern as the legacy
|
|
56
|
+
# knowledge_archive_aborted emit at the end of Phase 2.5.
|
|
57
|
+
echo '{"kind":"fabric-event","id":"...","ts":..., "schema_version":1, "session_id":"...", "event_type":"session_archive_attempted","outcome":"...","covered_through_ts":...,"candidates_proposed":0,"knowledge_proposed_ids":[]}' >> .fabric/events.jsonl
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
The per-field caps from Phase 2.5's constraint note carry over: `knowledge_proposed_ids` capped at 20 entries (drop tail with `...` marker in `id` field if truncated); other fields are bounded by schema.
|
|
61
|
+
|
|
62
|
+
## Worked example: E5 cron silent-skip
|
|
63
|
+
|
|
64
|
+
Setup: An OS cron job runs `fabric-archive` at 03:00 daily for the "today" range (E5 entry_point). Today's session was routine config edits — no archive signals fire.
|
|
65
|
+
|
|
66
|
+
Trace:
|
|
67
|
+
1. Phase 0 resolves `entry_point=E5_cron`, range = "today" → 1 session_id in scope.
|
|
68
|
+
2. Phase 1 digest collects events for that session_id; nothing dropped.
|
|
69
|
+
3. Phase 1.5 onboard is skipped (E5 is not E2).
|
|
70
|
+
4. Phase 2.5 viability gate runs — `archive_signals_hit=0` → `gate=FAIL (reason=no_signal)`.
|
|
71
|
+
5. `entry_point=E5_cron` ∈ {E1, E3, E5} → SILENT-SKIP branch. No message rendered.
|
|
72
|
+
6. Phase 4.5 (mandatory) appends ONE event:
|
|
73
|
+
```
|
|
74
|
+
{"kind":"fabric-event","id":"...","ts":<now>,"schema_version":1,"session_id":"<today-session-id>","event_type":"session_archive_attempted","outcome":"skipped_no_signal","covered_through_ts":<max ts of today's events>,"candidates_proposed":0,"knowledge_proposed_ids":[]}
|
|
75
|
+
```
|
|
76
|
+
7. Skill exits silently. Cron output is empty.
|
|
77
|
+
|
|
78
|
+
Next day's cron rescan: Phase 1 sees `covered_through_ts < max(ts of session's new events)` → session is rescan-eligible → loop continues without `user_dismissed` block.
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
# Phase 4 — Persist via MCP (ref)
|
|
2
|
+
|
|
3
|
+
> **Loaded on demand.** SKILL.md hot path retains the per-candidate one-call rule + brief mention of `proposed_reason` enum + session_context format. This file holds the full MCP call shape (with all rc.7/rc.23 optional fields), the C1 triage-field inference table, the proposed_reason mapping table, and the T5 array-form idempotency notes.
|
|
4
|
+
|
|
5
|
+
## Full MCP tool call shape
|
|
6
|
+
|
|
7
|
+
```ts
|
|
8
|
+
mcp__fabric__fab_extract_knowledge({
|
|
9
|
+
source_sessions: ["<session id1>", "<session id2>", ...], // T5: array form (Phase 1)
|
|
10
|
+
recent_paths: ["<path1>", "<path2>", ...], // capped at archive_max_recent_paths (config-resolved, default 20)
|
|
11
|
+
user_messages_summary: "<compact prose ≤500 chars>",
|
|
12
|
+
type: "decisions" | "pitfalls" | "guidelines" | "models" | "processes",
|
|
13
|
+
slug: "<kebab-case-2-to-5-words>",
|
|
14
|
+
layer: "team" | "personal",
|
|
15
|
+
relevance_scope: "narrow" | "broad", // from Phase 3.5
|
|
16
|
+
relevance_paths: ["<glob1>", "<literal2>", ...], // narrow ⇒ derived; broad ⇒ []
|
|
17
|
+
// v2.0.0-rc.7 T6: required fields for future-self reviewability.
|
|
18
|
+
proposed_reason:
|
|
19
|
+
"explicit-user-mark" // user said "always / never / 下次注意" etc.
|
|
20
|
+
| "diagnostic-then-fix" // long debug loop surfaced a new pattern/pitfall
|
|
21
|
+
| "decision-confirmation" // ≥2 options weighed AND rationale stated → decision/model
|
|
22
|
+
| "wrong-turn-revert" // tried path X, reverted → pitfall
|
|
23
|
+
| "new-dependency-or-pattern" // new dep/lib/abstraction introduced
|
|
24
|
+
| "dismissal-with-reason", // user rejected approach AND said why
|
|
25
|
+
session_context: "<3-5 line markdown: session goal + key turning point>",
|
|
26
|
+
// v2.0.0-rc.23 TASK-006 (a-C1): four OPTIONAL structured triage fields.
|
|
27
|
+
// Lift implicit signals out of `## Session context` prose so future-self
|
|
28
|
+
// reviewers / plan-context retrievers can triage relevance from
|
|
29
|
+
// frontmatter alone, without re-reading the body. Omit any field the
|
|
30
|
+
// skill cannot infer cleanly — guessing is worse than omitting.
|
|
31
|
+
intent_clues: ["<short trigger>", "<negative trigger e.g. 'NOT for X'>"], // when this rule applies / when NOT
|
|
32
|
+
tech_stack: ["<lang/framework>", "..."], // inferred from recent_paths (see table below)
|
|
33
|
+
impact: ["<consequence of ignoring>"], // why future-self should care
|
|
34
|
+
must_read_if: "<one-line strong trigger>" // single condition; if it holds, the entry is required reading
|
|
35
|
+
// tags? — NOT in current schema; reserved for future
|
|
36
|
+
})
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## C1 triage-field inference table
|
|
40
|
+
|
|
41
|
+
| Field | Inference source | Skip when |
|
|
42
|
+
|----------------|----------------------------------------------------------------------------------|------------------------------------|
|
|
43
|
+
| `intent_clues` | Pull from `session_context` turning point + negative phrasing in the transcript ("not for", "don't do X when") | No clear trigger phrasing surfaced |
|
|
44
|
+
| `tech_stack` | Map `recent_paths` extensions: `.ts`→`typescript`, `.tsx`→`typescript`+`react`, `.go`→`go`, `package.json`→`nodejs`, `pyproject.toml`→`python`, `Cargo.toml`→`rust`. Add framework markers from path heuristics (`cocos`→`cocos-creator`, `next.config`→`nextjs`) | Rule is stack-agnostic |
|
|
45
|
+
| `impact` | Pull from the diagnostic-loop body — "wasted 30 min", "production outage", "silent data loss" | No observable consequence stated |
|
|
46
|
+
| `must_read_if` | Strongest single trigger from the worth-archive signal: a file path, a routine, a recurring condition; ≤160 chars | No single dominant trigger fits |
|
|
47
|
+
|
|
48
|
+
All four fields are STRICTLY OPTIONAL. The schema accepts the call without any of them — omit rather than guess. None of the four participate in the idempotency_key hash (server formula at `extract-knowledge.ts:100-106` is frozen to `{source_session, type, slug}`), so partial-vs-full fill of these fields on the same triple is safe.
|
|
49
|
+
|
|
50
|
+
## proposed_reason → classification mapping
|
|
51
|
+
|
|
52
|
+
The skill infers `proposed_reason` from the classification + viability-gate signal that fired:
|
|
53
|
+
|
|
54
|
+
| Signal fired (Phase 2.5) | Classification | Default proposed_reason |
|
|
55
|
+
|--------------------------------|----------------|-----------------------------|
|
|
56
|
+
| Explicit normative language | guideline | `explicit-user-mark` |
|
|
57
|
+
| Wrong-turn-and-revert | pitfall | `wrong-turn-revert` |
|
|
58
|
+
| Long diagnostic loop | pitfall/model | `diagnostic-then-fix` |
|
|
59
|
+
| New dependency adoption | decision/model | `new-dependency-or-pattern` |
|
|
60
|
+
| New pattern emergence | model | `new-dependency-or-pattern` |
|
|
61
|
+
| Decision confirmation | decision | `decision-confirmation` |
|
|
62
|
+
| Explicit dismissal-with-reason | decision | `dismissal-with-reason` |
|
|
63
|
+
| Process formalization | process | `new-dependency-or-pattern` |
|
|
64
|
+
|
|
65
|
+
## session_context format
|
|
66
|
+
|
|
67
|
+
```
|
|
68
|
+
Session goal: <one-line of what the user was trying to accomplish>
|
|
69
|
+
Turning point: <one-line of the key moment that produced the worth-archive observation>
|
|
70
|
+
[optional 1-3 more lines of supporting context]
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Future-self reviewing the pending entry MUST be able to understand WHY this entry was proposed without conversation transcript access — `proposed_reason` is the structured why; `session_context` is the narrative why.
|
|
74
|
+
|
|
75
|
+
Note on type plurality: the MCP enum uses plural directory-form (decisions / pitfalls / guidelines / models / processes), while the conceptual classification uses singular nouns (decision / pitfall / guideline / model / process). They map 1:1.
|
|
76
|
+
|
|
77
|
+
The server returns `{ pending_path, idempotency_key }`. Display `pending_path` to the user so they can `Read` the persisted entry if they wish.
|
|
78
|
+
|
|
79
|
+
## Idempotency Notes (T5 array-form, rc.7+)
|
|
80
|
+
|
|
81
|
+
The MCP tool derives `idempotency_key = sha256({source_session, type, slug})`. Calling `fab_extract_knowledge` twice with the same `(source_session, type, slug)` triple is SAFE: the server appends new evidence to the existing pending file rather than overwriting or producing duplicates. The skill MAY be re-invoked on the same session without producing junk.
|
|
82
|
+
|
|
83
|
+
If the skill needs to record a genuinely separate observation in the same session+type, the slug MUST differ.
|
|
84
|
+
|
|
85
|
+
**T5 array-form**: when `source_sessions` is passed as an array (rc.7 T5 contract), only `source_sessions[0]` participates in the server-side idempotency hash. Server formula at `packages/server/src/services/extract-knowledge.ts:78` is `sha256(JSON.stringify({source_session: sourceSessions[0], type, slug}))`. Implications:
|
|
86
|
+
|
|
87
|
+
- Same `(type, slug)` but a different **first** session → distinct idempotency key → produces two pending files.
|
|
88
|
+
- Same first session but different tail sessions → evidence-merge into the SAME pending file; tail `session_id`s are NOT recorded as independent evidence keys.
|
|
89
|
+
- The formula is intentionally stable across the rc.5 → rc.7 migration; adding or removing tail entries does NOT change the idempotency key, preserving rc.5 single-session compat.
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
## v2.0.0-rc.7 (T5)
|
|
6
6
|
|
|
7
|
-
Cross-session digest mechanism introduced. Stop hook writes per-session digest to `.fabric/.cache/session-digests/<session_id>.md`. fabric-archive Phase
|
|
7
|
+
Cross-session digest mechanism introduced. Stop hook writes per-session digest to `.fabric/.cache/session-digests/<session_id>.md`. fabric-archive Phase 1 reads these to stitch context across sessions since the last `knowledge_proposed` event.
|
|
8
8
|
|
|
9
9
|
## v2.0.0-rc.20 (TASK-02 / TASK-03)
|
|
10
10
|
|
|
@@ -12,7 +12,7 @@ Cross-session digest mechanism introduced. Stop hook writes per-session digest t
|
|
|
12
12
|
|
|
13
13
|
## v2.0.0-rc.23 (F8c / a-C2)
|
|
14
14
|
|
|
15
|
-
- **F8c**: Phase
|
|
15
|
+
- **F8c**: Phase 1.5 first-run onboard phase added. S5 slots (`tech-stack-decision`, `architecture-pattern`, `code-style-tone`, `build-system-idiom`, `domain-vocabulary`) baseline the workspace tone for plan_context retrieval.
|
|
16
16
|
- **a-C2**: knowledge_enriched event for description-grade frontmatter back-fill.
|
|
17
17
|
|
|
18
18
|
## v2.0.0-rc.24 (TASK-01 / TASK-04)
|
|
@@ -23,16 +23,16 @@ Cross-session digest mechanism introduced. Stop hook writes per-session digest t
|
|
|
23
23
|
|
|
24
24
|
Major fabric-archive overhaul:
|
|
25
25
|
|
|
26
|
-
- **TASK-01**: `session_archive_attempted` event — drives Phase
|
|
27
|
-
- **TASK-05**: 5-entry model (E1 hook / E2 explicit / E3 AI-self / E4 user-range / E5 cron). Phase
|
|
26
|
+
- **TASK-01**: `session_archive_attempted` event — drives Phase 1 cross-session digest rescan filter (outcome state machine: proposed / viability_failed / user_dismissed / skipped_no_signal).
|
|
27
|
+
- **TASK-05**: 5-entry model (E1 hook / E2 explicit / E3 AI-self / E4 user-range / E5 cron). Phase 0 Range Resolution parses time-window + topic-keyword hints into a `session_id[]` scope filter. Anti-loop constants (12h cooldown, normative-keyword scan) landed here.
|
|
28
28
|
- **Q3.4**: outcome-based rescan suppression — `user_dismissed` permanently skips a session.
|
|
29
29
|
|
|
30
30
|
## v2.0.0-rc.27 (TASK-007 / TASK-011 / TASK-012)
|
|
31
31
|
|
|
32
|
-
- **TASK-007**: Phase
|
|
32
|
+
- **TASK-007**: Phase 4.5 dry-run override path (Codex audit §2.25).
|
|
33
33
|
- **TASK-011** (Codex review fix): cite_commitments index-aligned with cite_ids on multi-id parses (audit §2.18 follow-up).
|
|
34
34
|
- **TASK-012** (Codex review fix): dropped stale "no dry-run mode" prose that conflicted with TASK-007.
|
|
35
35
|
|
|
36
36
|
## v2.0.0-rc.28 (this release)
|
|
37
37
|
|
|
38
|
-
SKILL.md split into entry (hot path) + `ref/` (this file + i18n-policy + phase-
|
|
38
|
+
SKILL.md split into entry (hot path) + `ref/` (this file + i18n-policy + phase-1-5-onboard + worked-examples + e5-cron-recap). 1343 → ~950 lines for the hot path (~29% reduction). Active flow logic unchanged; reference-only content (almost-never-loaded i18n class taxonomy, Phase 1.5 onboard, end-to-end examples, E5 cron setup) moved out.
|
|
@@ -74,5 +74,5 @@ mcp__fabric__fab_extract_knowledge({
|
|
|
74
74
|
})
|
|
75
75
|
```
|
|
76
76
|
|
|
77
|
-
Layer = personal (跨项目通用 + 工具/编辑器偏好 signals dominate; no 强 team signal applies). Scope = broad with `relevance_paths=[]` (personal layer ALWAYS forces broad — paths don't generalize across projects per Phase
|
|
77
|
+
Layer = personal (跨项目通用 + 工具/编辑器偏好 signals dominate; no 强 team signal applies). Scope = broad with `relevance_paths=[]` (personal layer ALWAYS forces broad — paths don't generalize across projects per Phase 3.5 special case).
|
|
78
78
|
|