@gi4nks/ph 1.6.0 → 1.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +22 -1
- package/LICENSE +1 -1
- package/README.md +79 -19
- package/dist/cli.js +3593 -3677
- package/dist/cli.js.map +1 -1
- package/docs/evals/context-retrieval-golden.json +17 -1
- package/docs/ph-architecture-review.html +179 -0
- package/docs/ph-manual.md +129 -73
- package/docs/ph-operational-memory-analysis.html +104 -0
- package/docs/plans/2026-10-10-operational-memory.md +192 -0
- package/docs/specs/SPEC-001-architecture-cli.md +100 -72
- package/docs/specs/SPEC-002-database-layer.md +22 -3
- package/docs/specs/SPEC-003-capture-modes.md +22 -9
- package/docs/specs/SPEC-005-search.md +46 -11
- package/docs/specs/SPEC-006-analysis-pipeline.md +8 -6
- package/docs/specs/SPEC-007-memory-summaries.md +19 -19
- package/docs/specs/SPEC-008-embeddings.md +8 -2
- package/docs/specs/SPEC-009-retention-archive.md +2 -2
- package/docs/specs/SPEC-010-remote-sync.md +77 -103
- package/docs/specs/SPEC-011-mcp-server.md +7 -4
- package/docs/specs/SPEC-012-tui-browser.md +30 -96
- package/docs/specs/SPEC-015-config-env.md +4 -0
- package/docs/specs/SPEC-016-operational-memory.md +48 -0
- package/docs/specs/SPEC-017-architecture-consolidation.md +63 -0
- package/docs/specs/SPEC-018-interaction-inspection-and-recall-integrity.md +164 -0
- package/docs/specs/SPEC-019-network-capture-and-ranking-integrity.md +36 -0
- package/docs/specs/SPEC-INDEX.md +12 -7
- package/docs/specs/SPEC-ISSUES.md +104 -18
- package/hooks/claude/README.md +1 -1
- package/hooks/codex/README.md +1 -1
- package/hooks/codex/ph-hook.sh +2 -1
- package/hooks/gemini/README.md +1 -1
- package/package.json +6 -7
|
@@ -19,6 +19,7 @@ get/set`, and environment overrides (`PH_DB`, `PH_REMOTE_URL`, `GEMINI_API_KEY`)
|
|
|
19
19
|
- `PhConfig` (src/config/index.ts:5-22): geminiApiKey, dbPath, analyzeProvider,
|
|
20
20
|
ollamaUrl, ollamaModel, ollamaEmbedModel, filterMinLength, filterMinRelevance,
|
|
21
21
|
backgroundAnalysis, remoteUrl, remoteApiKey, remoteLastPush, remoteLastPull,
|
|
22
|
+
remotePushCursor {target, databaseId, id}, remotePullCursor {target, databaseId, id},
|
|
22
23
|
retentionDays, retentionMinStarred, retentionMinAnalyzed, retentionMinRelevance.
|
|
23
24
|
- Env: `PH_DB` (dbPath, cli.ts:157), `PH_REMOTE_URL` (remote.ts:6-8),
|
|
24
25
|
`GEMINI_API_KEY` (cli.ts:153-155).
|
|
@@ -75,6 +76,9 @@ file.
|
|
|
75
76
|
- `save()` writes the whole object — concurrent `ph` processes (e.g. a hook
|
|
76
77
|
logging while the user sets config) can clobber each other's writes (no
|
|
77
78
|
locking).
|
|
79
|
+
- `remoteLastPush` and `remoteLastPull` are global timestamps rather than
|
|
80
|
+
target-scoped values, so status can display another remote's last success.
|
|
81
|
+
Cursor identity also omits the remote database generation (SPEC-ISSUES-025).
|
|
78
82
|
- Config comments in AGENTS.md describe defaults that live in code
|
|
79
83
|
(load-time defaults in cli.ts/commands) — the doc is authoritative for intent,
|
|
80
84
|
code for truth.
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# SPEC-016 — Operational memory workflow
|
|
2
|
+
|
|
3
|
+
**Status:** Implemented (2026-10-10)
|
|
4
|
+
|
|
5
|
+
## Purpose
|
|
6
|
+
|
|
7
|
+
Support a deliberate `prepare → work → close → promote` loop. Task retrieval is shared by CLI context, chat, and MCP knowledge checks. General context without a task remains non-semantic. Captured work only becomes curated knowledge after explicit user approval, and promoted memories keep verifiable prompt sources.
|
|
8
|
+
|
|
9
|
+
## Behavior
|
|
10
|
+
|
|
11
|
+
### `ph prepare`
|
|
12
|
+
|
|
13
|
+
- Accepts a task description and a project inferred from CWD or specified with `--project`.
|
|
14
|
+
- Uses shared `getProjectContext` retrieval with the task as a semantic query.
|
|
15
|
+
- If embeddings fail, labels the failure and falls back to recent project context.
|
|
16
|
+
- Renders source IDs and bounds the retrieved content using `--budget`; source references are preserved even if they exceed that target.
|
|
17
|
+
- Does not generate text or write to the database.
|
|
18
|
+
|
|
19
|
+
### `ph close`
|
|
20
|
+
|
|
21
|
+
- Requires exactly one explicit selection: `--since <duration>` or inclusive `--from <id> --to <id>`; selects only prompts tagged with the chosen project.
|
|
22
|
+
- Prints source prompt/response excerpts before generating proposals. `--dry-run` performs no generation and no database writes.
|
|
23
|
+
- Uses the configured analysis provider to propose zero or more knowledge entries. Every proposal must cite one or more selected prompt IDs.
|
|
24
|
+
- Requires an interactive TTY to approve or edit proposals. Proposals are staged until the user completes the review; quitting or interrupting before completion writes nothing.
|
|
25
|
+
- Checks for an interactive TTY before calling the analysis provider.
|
|
26
|
+
- On completed review, approved proposals append memories with cited `prompt_ids` and update `project_summaries` in one SQLite transaction. A failed write rolls back the whole approved batch.
|
|
27
|
+
|
|
28
|
+
### MCP
|
|
29
|
+
|
|
30
|
+
- `check_project_knowledge` uses the shared retrieval and formatter; embedding failure is labeled and falls back to recent context.
|
|
31
|
+
- `save_decision` accepts optional `promptIds`, validates existence and project ownership before writing, and stores them on the memory.
|
|
32
|
+
|
|
33
|
+
## GWT Acceptance
|
|
34
|
+
|
|
35
|
+
1. **Given** a task in a project with semantic embeddings, **when** `ph prepare` runs, **then** it returns scoped evidence and source IDs without changing prompt, memory, or summary data.
|
|
36
|
+
2. **Given** unavailable Ollama embeddings, **when** `ph prepare` runs, **then** it labels the fallback and renders recent context for the selected project.
|
|
37
|
+
3. **Given** selected prompt history, **when** `ph close --dry-run` runs, **then** it displays the selected excerpts without calling a model or writing memory/summary data.
|
|
38
|
+
4. **Given** generated proposals, **when** a cited ID is not in the selected prompt set, **then** the response is rejected before review or persistence.
|
|
39
|
+
5. **Given** a user approves proposals and finishes review, **when** review commits, **then** each approved memory stores the proposal's cited prompt IDs and updates the matching project summary.
|
|
40
|
+
6. **Given** `save_decision` receives a missing or other-project prompt ID, **when** called through MCP, **then** it returns an error and creates no memory.
|
|
41
|
+
7. **Given** MCP or CLI task retrieval for a project, **when** embeddings fail, **then** shared recent-context fallback is used and the degradation is visible.
|
|
42
|
+
8. **Given** a batch contains an invalid memory write, **when** promotion fails, **then** none of the batch's memories or summary updates persist.
|
|
43
|
+
9. **Given** `ph close` runs without an interactive TTY, **when** it is not a dry run, **then** it exits before calling the analysis provider.
|
|
44
|
+
|
|
45
|
+
## Verification
|
|
46
|
+
|
|
47
|
+
- Deterministic golden retrieval contract spans at least 12 judged queries across five projects; fixed-vector ranking test reports Recall@2/MRR without generation calls.
|
|
48
|
+
- Full local verification on 2026-10-10: 93 Vitest tests, ESLint, TypeScript, and tsup build passed.
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# SPEC-017 — Internal architecture consolidation
|
|
2
|
+
|
|
3
|
+
- **ID**: SPEC-017
|
|
4
|
+
- **Cluster**: Core, DB, MCP
|
|
5
|
+
- **Status**: Implemented
|
|
6
|
+
- **Date**: 2026-10-22
|
|
7
|
+
|
|
8
|
+
## Purpose
|
|
9
|
+
|
|
10
|
+
Reduce internal coupling and constrain product-surface growth without changing
|
|
11
|
+
the public behavior of existing PH commands, MCP tools, or the SQLite schema.
|
|
12
|
+
|
|
13
|
+
**Spec impact: none.** This is an internal-only change. Existing CLI syntax,
|
|
14
|
+
MCP tool names and payloads, database schema, persisted data, and retrieval
|
|
15
|
+
results remain compatible.
|
|
16
|
+
|
|
17
|
+
## Decisions
|
|
18
|
+
|
|
19
|
+
1. Do not add, remove, rename, or deprecate user-facing commands in this work.
|
|
20
|
+
Clarify the existing jobs of `context`, `prepare`, agent-facing MCP, and
|
|
21
|
+
`chat`; hold new feature proposals until the operational workflow is used on
|
|
22
|
+
three real tasks across different projects.
|
|
23
|
+
2. Keep `src/mcp/server.ts` as the protocol composition root. Move tool
|
|
24
|
+
declarations, domain handlers, and response formatting into cohesive
|
|
25
|
+
modules. It remains responsible for MCP SDK registration and error/content
|
|
26
|
+
envelope translation.
|
|
27
|
+
3. Keep `PhDB` as the public facade and keep its constructor, method names, and
|
|
28
|
+
return values stable. Keep prompt CRUD, FTS, schema, and migrations in the
|
|
29
|
+
prompt core. Move memory/summary operations and archive operations behind
|
|
30
|
+
internal repositories sharing the same SQLite connection. Semantic vectors
|
|
31
|
+
remain in the existing `SemanticIndex`. Preserve the single connection and
|
|
32
|
+
transaction boundary.
|
|
33
|
+
4. Reuse shared project-context and memory-promotion operations from CLI and
|
|
34
|
+
MCP. Adapters must not own business validation or multi-write consistency.
|
|
35
|
+
|
|
36
|
+
## Acceptance
|
|
37
|
+
|
|
38
|
+
- Existing commands and all registered MCP tools retain their current names,
|
|
39
|
+
schemas, behavior, and text response contracts.
|
|
40
|
+
- Existing databases open without migration or data rewrite.
|
|
41
|
+
- `PhDB` remains source-compatible for current callers.
|
|
42
|
+
- MCP server composition contains no per-tool business logic or response
|
|
43
|
+
formatting.
|
|
44
|
+
- Memory/summary and archive SQL operations are owned by cohesive internal
|
|
45
|
+
persistence modules; prompt CRUD and FTS remain together in the prompt core.
|
|
46
|
+
Transaction behavior stays on the shared connection.
|
|
47
|
+
- New user-facing capabilities are not introduced in this change.
|
|
48
|
+
- Existing test suite, lint, TypeScript check, and build pass.
|
|
49
|
+
|
|
50
|
+
## Verification
|
|
51
|
+
|
|
52
|
+
- `npm test`: 17 files, 94 tests passed.
|
|
53
|
+
- `npm run lint`: passed.
|
|
54
|
+
- `npx tsc --noEmit`: passed.
|
|
55
|
+
- `npm run build`: passed.
|
|
56
|
+
|
|
57
|
+
## Non-goals
|
|
58
|
+
|
|
59
|
+
- Removing or renaming existing commands or MCP tools.
|
|
60
|
+
- Reworking retrieval ranking, metadata storage, or the SQLite schema.
|
|
61
|
+
- Splitting files solely to reduce line counts.
|
|
62
|
+
- Adding agent feedback, automatic memory promotion, or project-state
|
|
63
|
+
fingerprinting.
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
# SPEC-018 — Interaction inspection and recall integrity
|
|
2
|
+
|
|
3
|
+
- **ID**: SPEC-018
|
|
4
|
+
- **Cluster**: Core, Capture, Search, Memory, MCP
|
|
5
|
+
- **Status**: Implemented
|
|
6
|
+
- **Date**: 2026-10-24
|
|
7
|
+
- **Source**: Implemented interaction retrieval in `src/commands/search.ts`, `src/commands/show.ts`, and `src/interaction/detail.ts`, with behavior covered in `src/commands/__tests__/`.
|
|
8
|
+
|
|
9
|
+
## Purpose
|
|
10
|
+
|
|
11
|
+
Make the stored unit of PH useful and verifiable: a person can find one
|
|
12
|
+
interaction, inspect its complete prompt, response, capture metadata, and
|
|
13
|
+
derived analysis, and tell whether capture enrichment or configured remote
|
|
14
|
+
delivery succeeded. Keep the daily workflow small while making retrieval and
|
|
15
|
+
durable project knowledge consistent across adapters.
|
|
16
|
+
|
|
17
|
+
## Scope
|
|
18
|
+
|
|
19
|
+
- Add one CLI detail operation and make export formats preserve the complete
|
|
20
|
+
interaction record.
|
|
21
|
+
- Make full-text search cover analyzed summary/insight text as well as the raw
|
|
22
|
+
prompt and response.
|
|
23
|
+
- Make task-aware context retrieval share one project-scoped policy across CLI,
|
|
24
|
+
chat, and MCP knowledge checks.
|
|
25
|
+
- Keep per-interaction analysis in prompt metadata. Only explicit `close` and
|
|
26
|
+
MCP `save_decision` promotion write active project memories and summaries.
|
|
27
|
+
- Persist bounded lifecycle outcomes for optional background analysis and
|
|
28
|
+
configured per-capture remote push; expose recent capture state through an
|
|
29
|
+
advanced CLI diagnostic.
|
|
30
|
+
- Keep everyday help focused on setup, search, detail, and optional context.
|
|
31
|
+
Existing maintenance and integration commands stay available through
|
|
32
|
+
`ph help --all`.
|
|
33
|
+
|
|
34
|
+
## Decisions
|
|
35
|
+
|
|
36
|
+
1. `ph show <id>` is the canonical single-interaction view. It prints complete
|
|
37
|
+
stored prompt and response, source/capture fields, all supported analysis
|
|
38
|
+
metadata, and an explicit analysis state. Missing response and missing
|
|
39
|
+
analysis are rendered as such, not silently omitted. `--json` emits the
|
|
40
|
+
complete record and decoded metadata. `--archive` resolves an archived row
|
|
41
|
+
using the ID printed by archived search.
|
|
42
|
+
2. `ph search` remains a compact discovery list and prints an actionable
|
|
43
|
+
`ph show <id>` hint. `--full` means full prompt and response. Text queries
|
|
44
|
+
also match analyzed summary, key insights, and technical decisions. Search
|
|
45
|
+
ranking and current project/global scope rules remain stable.
|
|
46
|
+
3. `ph export <id>` formats all preserve prompt and response. Markdown and JSON
|
|
47
|
+
also preserve complete capture and analysis metadata; plain text includes
|
|
48
|
+
clear Prompt and Response headings. `--archive` exports an archived row.
|
|
49
|
+
4. `analyzeAll` and background analysis update only per-interaction metadata;
|
|
50
|
+
they do not write `memories` or `project_summaries`. Existing saved memories
|
|
51
|
+
are retained. Only `promoteProjectKnowledge`, reached through CLI `close`
|
|
52
|
+
and MCP `save_decision`, creates active curated project knowledge.
|
|
53
|
+
5. `retrieveTaskContext` owns task embedding, project scope, shared sources, and
|
|
54
|
+
explicit recent-context fallback. CLI task `context`, `chat`, and MCP
|
|
55
|
+
`check_project_knowledge` use this policy. `chat` embeds the user's actual
|
|
56
|
+
task prompt. General project-context retrieval without a task remains a
|
|
57
|
+
separate non-semantic operation.
|
|
58
|
+
6. Capture records use backward-compatible optional metadata fields for
|
|
59
|
+
analysis and remote-push lifecycle states. States are bounded enums and
|
|
60
|
+
failure text is a safe category, never raw provider output or credentials.
|
|
61
|
+
`ph status` shows the latest captures and their available state; it does not
|
|
62
|
+
claim that a configured hook delivered an interaction that is absent.
|
|
63
|
+
7. SPEC-018 supersedes SPEC-017's “no new user-facing capability” acceptance
|
|
64
|
+
only for `ph show`, complete `ph export`/`--full`, and advanced `ph status`.
|
|
65
|
+
It does not remove or rename existing commands, MCP tools, or configuration.
|
|
66
|
+
The only new table column is rebuildable search text derived from existing
|
|
67
|
+
metadata; the migration must preserve all prompt/response records and be
|
|
68
|
+
idempotent.
|
|
69
|
+
|
|
70
|
+
## Data contract
|
|
71
|
+
|
|
72
|
+
`PromptMetadata` may contain:
|
|
73
|
+
|
|
74
|
+
- `analysis_status`: `pending`, `complete`, or `failed` when analysis was
|
|
75
|
+
requested; absent on legacy records is inferred as `complete` when analysis
|
|
76
|
+
fields exist and otherwise `not requested`.
|
|
77
|
+
- `analysis_error`: one safe category (`worker_launch_failed`,
|
|
78
|
+
`provider_unavailable`, `analysis_failed`, or `analysis_persistence_failed`).
|
|
79
|
+
- `remote_sync_status`: `pending`, `complete`, or `failed` for configured
|
|
80
|
+
per-capture pushes; absent on old records is `unknown` when a remote is
|
|
81
|
+
configured and `not configured` otherwise.
|
|
82
|
+
- `remote_sync_error`: `push_failed` only; raw response bodies are not stored.
|
|
83
|
+
- `technical_decisions`: per-interaction analyzed decisions, alongside
|
|
84
|
+
`summary`, `key_insights`, `quality`, and `relevance`.
|
|
85
|
+
|
|
86
|
+
The FTS index receives a derived text field built from analysis summary, key
|
|
87
|
+
insights, and technical decisions. The existing prompt, response, and tool
|
|
88
|
+
fields remain indexed/scoped as before. Rebuilding FTS from existing rows must
|
|
89
|
+
be safe and idempotent.
|
|
90
|
+
|
|
91
|
+
## Acceptance criteria
|
|
92
|
+
|
|
93
|
+
- **G1 — Full detail**: Given a stored interaction with prompt, response,
|
|
94
|
+
metadata, and analysis fields, when `ph show <id>` runs, then all are printed
|
|
95
|
+
without truncation. Given missing response or analysis, then the output names
|
|
96
|
+
the missing state and returns successfully.
|
|
97
|
+
- **G1a — Archived detail**: Given an archived search result ID, when
|
|
98
|
+
`ph show <id> --archive` or `ph export <id> --archive` runs, then the original
|
|
99
|
+
prompt, response, and metadata are shown without changing the archive.
|
|
100
|
+
- **G2 — Complete export**: Given a stored interaction, when each supported
|
|
101
|
+
export format runs, then prompt and response are present; JSON includes the
|
|
102
|
+
full entry and decoded metadata. Unknown IDs and formats fail with a useful
|
|
103
|
+
message.
|
|
104
|
+
- **G3 — Search to detail**: Given a matching result, when `ph search` prints
|
|
105
|
+
it, then the ID and `ph show <id>` instruction are visible. `--full` prints
|
|
106
|
+
complete prompt and response. Search still honors current-project default,
|
|
107
|
+
`--all`, explicit project, filters, and the requested result limit.
|
|
108
|
+
- **G4 — Search derived analysis**: Given only a summary, insight, or technical
|
|
109
|
+
decision contains a query term, when search runs, then the source interaction
|
|
110
|
+
is returned. Existing prompt/response matches and BM25 ordering continue to
|
|
111
|
+
work. Updating metadata updates indexed analysis text; rebuilding old DBs
|
|
112
|
+
indexes existing metadata without losing prompt history.
|
|
113
|
+
- **G5 — One active knowledge writer**: Given manual or background analysis,
|
|
114
|
+
when it succeeds, then the interaction metadata is updated and no active
|
|
115
|
+
memory or project summary is created. Given `close` approval or MCP
|
|
116
|
+
`save_decision`, then the existing provenance validation and transactional
|
|
117
|
+
promotion write the curated memory and summary. Existing memories remain
|
|
118
|
+
readable.
|
|
119
|
+
- **G6 — Shared task retrieval**: Given a task prompt in a project, when CLI
|
|
120
|
+
`context`, `chat`, or MCP `check_project_knowledge` retrieves context, then
|
|
121
|
+
they use the same task embedding prefix, project scope, sources, and labeled
|
|
122
|
+
fallback behavior. `chat` includes the user's task in the semantic query.
|
|
123
|
+
Retrieval remains read-only.
|
|
124
|
+
- **G7 — Lifecycle status**: Given background analysis is requested, when a
|
|
125
|
+
capture is stored, then its state becomes pending and transitions to complete
|
|
126
|
+
or a safe failed category. Spawn failure, missing provider, empty analysis,
|
|
127
|
+
provider error, and persistence error are observable. Given configured remote
|
|
128
|
+
push, then its state transitions from pending to complete/failed. State writes
|
|
129
|
+
do not overwrite unrelated metadata.
|
|
130
|
+
- **G8 — Diagnostic**: Given captured records exist, when `ph status` runs, then
|
|
131
|
+
it shows a bounded recent list with timestamp, tool, project, response
|
|
132
|
+
presence, analysis state, and remote state. It does not print prompt or
|
|
133
|
+
response content. `status` is listed in advanced help, not the short default
|
|
134
|
+
guide.
|
|
135
|
+
- **G9 — Small product surface**: The short guide documents setup, search,
|
|
136
|
+
inspecting a result with `show`, and optional task context. Existing advanced
|
|
137
|
+
commands remain available behind `ph help --all`.
|
|
138
|
+
- **G10 — Compatibility**: Existing DB files open without destructive rewrite;
|
|
139
|
+
existing IDs, prompt/response text, config, commands, and MCP tool names stay
|
|
140
|
+
intact. Analysis-derived FTS data is rebuilt transactionally or through an
|
|
141
|
+
idempotent migration.
|
|
142
|
+
|
|
143
|
+
## Implementation map
|
|
144
|
+
|
|
145
|
+
| Concern | Files |
|
|
146
|
+
|---|---|
|
|
147
|
+
| Detail command, compact search, export/help | `src/cli.ts`, `src/commands/{show,search,export,status}.ts`, `src/display/print.ts` |
|
|
148
|
+
| Record and search index | `src/types.ts`, `src/db/index.ts`, `src/db/__tests__/phdb.test.ts` |
|
|
149
|
+
| Analysis lifecycle and trust | `src/analyzer/index.ts`, `src/commands/{analyze,background-analyze,log}.ts`, `src/background/analyzer.ts` |
|
|
150
|
+
| Task retrieval | `src/knowledge/task-context.ts`, `src/commands/{context,chat}.ts`, `src/mcp/tools/projects.ts` |
|
|
151
|
+
| MCP detail projection | `src/mcp/tools/prompts.ts`, `src/mcp/tools/format.ts` |
|
|
152
|
+
| Contracts and user docs | `docs/specs/SPEC-001-architecture-cli.md`, `SPEC-003-capture-modes.md`, `SPEC-005-search.md`, `SPEC-016-operational-memory.md`, `docs/ph-manual.md`, `README.md` |
|
|
153
|
+
|
|
154
|
+
## Verification
|
|
155
|
+
|
|
156
|
+
Focused GWT tests cover detail/export fidelity, FTS metadata indexing and
|
|
157
|
+
migration, memory ownership, retrieval parity/fallback, lifecycle transitions,
|
|
158
|
+
and status output. Completion requires `npm test`, `npm run lint`,
|
|
159
|
+
`npx tsc --noEmit`, and `npm run build`.
|
|
160
|
+
|
|
161
|
+
## Related
|
|
162
|
+
|
|
163
|
+
SPEC-001, SPEC-002, SPEC-003, SPEC-005, SPEC-006, SPEC-007, SPEC-011,
|
|
164
|
+
SPEC-016, and SPEC-017.
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# SPEC-019 — Network, capture, and retrieval integrity
|
|
2
|
+
|
|
3
|
+
- **ID**: SPEC-019
|
|
4
|
+
- **Cluster**: Capture, Sync, Search, CLI
|
|
5
|
+
- **Status**: Implemented
|
|
6
|
+
- **Date**: 2026-10-24
|
|
7
|
+
- **Source**: Implemented network, sync, capture, and ranking contracts in `src/server/`, `src/sync/`, `src/capture/lifecycle.ts`, and related tests.
|
|
8
|
+
|
|
9
|
+
## Purpose
|
|
10
|
+
|
|
11
|
+
Close the remaining correctness and exposure gaps at PH's network and live-capture seams. The everyday local workflow stays simple; optional HTTP and sync paths must fail safely and preserve every acknowledged interaction.
|
|
12
|
+
|
|
13
|
+
## Scope and decisions
|
|
14
|
+
|
|
15
|
+
1. **HTTP exposure**: `ph server` listens on loopback by default and requires a configured API key before opening the listener. Every endpoint except `/health` requires that key. Health never returns the database path. Request bodies have a documented byte limit; malformed/oversized requests return bounded client errors without leaking internal exception text. A non-loopback deployment still requires explicit `--host` and the same authentication; cross-machine deployments require a trusted network or TLS termination.
|
|
16
|
+
2. **Push pagination**: local prompts are selected by monotonically increasing local row ID, not timestamp. The remote push cursor is scoped to both the normalized target URL and the persistent source database ID. Pages are split into HTTP bodies no larger than the server byte limit; the outer cursor advances only after every subpage and record is acknowledged or deduplicated. A failed subpage leaves the outer page retryable. Retrying is safe because `sync_hash` is idempotent.
|
|
17
|
+
3. **Pull pagination**: the server returns prompts in ascending remote row-ID order, a continuation cursor, and `hasMore`. The client persists an opaque target-and-local-database-scoped ID cursor only after a page is fully inserted or deduplicated. Switching either target or local database starts at row zero. Missing cursor fields are a compatibility error, not permission to silently fall back to a capped timestamp pull. Legacy timestamp cursors trigger a full idempotent scan from row zero.
|
|
18
|
+
4. **Capture completion**: hooks/direct `ph log`, inline wrapper, and interactive PTY wrapper share lifecycle initialization and configured analysis/remote-push effects. Invalid remote URLs mark the optional push failed without blocking local persistence or tool execution. Wrapper records identify a live capture owner; bulk sync stops before a live record so it cannot publish a partial response or advance past it. Markers from exited processes are cleared and the locally captured partial record remains eligible. Inline wrapper stdout is forwarded unchanged and persisted as the response; exit code is preserved. Live pushes have a five-second timeout. Empty responses are still captured and lifecycle work is dispatched.
|
|
19
|
+
5. **Search ranking**: raw prompt/response FTS and derived-metadata FTS retain separate indexes. Results use Reciprocal Rank Fusion (RRF, fixed `k=60`) across the two ranked lists, then timestamp descending and ID descending for deterministic ties. The raw-only relative BM25 order remains unchanged. Project-scoped CLI semantic search loads project embeddings through one metadata join instead of issuing one prompt query per embedding.
|
|
20
|
+
6. **Everyday help and docs**: short help lists optional `ph context "task"`; SPEC-010, SPEC-003, SPEC-005, SPEC-018, SPEC-ISSUES, README, manual, and AGENTS describe the implemented security, cursor, lifecycle, and ranking contracts.
|
|
21
|
+
|
|
22
|
+
## Acceptance criteria
|
|
23
|
+
|
|
24
|
+
- **G1 — Fail-closed HTTP**: Without `remoteApiKey`, `ph server` fails before listening. Default host is loopback. With a key, health returns status only; all data endpoints require the Bearer key. Invalid JSON returns 400, an oversized body returns 413, and internal errors do not expose exception details.
|
|
25
|
+
- **G2 — Lossless push**: Given more than one row-ID page, same-timestamp rows, late-imported lower-timestamp rows, bodies that exceed the byte limit, and a server response with per-record errors, every local row remains eligible until acknowledged. Live captures are held until completion; completed subpages checkpoint only after all subrequests are acknowledged. A database switch resets its cursor to zero. Retries do not duplicate acknowledged records.
|
|
26
|
+
- **G3 — Lossless pull**: Given over 10,000 remote rows, pagination imports all rows. Equal timestamps do not skip records. Legacy timestamp-only or database-unscoped config starts an idempotent full scan. A target or local database change starts at row zero. A server without continuation support fails clearly.
|
|
27
|
+
- **G4 — Shared live capture effects**: Given configured analysis and remote sync, direct log, inline wrapper, and PTY wrapper mark pending and dispatch the same effects. A malformed optional remote URL does not block local persistence or launching the wrapped CLI. A concurrent bulk push stops before active captures and resumes after completion; abandoned owner markers are reclaimed. Inline stdout is both displayed and stored as response. Exit status is preserved. Empty output is explicitly stored and still gets lifecycle completion.
|
|
28
|
+
- **G5 — Search ranking**: Raw-only queries preserve BM25 order; analysis-only queries find the correct source record; mixed-source queries follow RRF with deterministic tie breaks. Updating analysis metadata keeps the derived index fresh.
|
|
29
|
+
- **G6 — Product help**: Default help documents setup, search, show, and optional task context; status and maintenance remain advanced.
|
|
30
|
+
- **G7 — Migration and compatibility**: Existing prompt/response rows and sync dedup hashes remain intact. Legacy sync config replays idempotently instead of advancing a lossy timestamp cursor. HTTP/API clients receive an actionable upgrade error when pagination support is missing.
|
|
31
|
+
- **G8 — Bounded startup work**: Given a database whose search-text migration is complete, When another `PhDB` instance opens, Then it does not scan and parse all rows with empty derived metadata again. The database identity remains stable across reopen and differs across database files.
|
|
32
|
+
- **G9 — Scoped semantic loading**: Given embeddings across multiple projects, When CLI semantic search selects one project, Then only that project's vectors are loaded by a joined query and no per-vector `getById` lookup is issued.
|
|
33
|
+
|
|
34
|
+
## Verification
|
|
35
|
+
|
|
36
|
+
Verification completed: `npm test`, `npm run lint`, `npx tsc --noEmit`, and `npm run build` pass. Focused tests cover server startup/auth/body bounds, pull pagination over 10,000 records, partial push retry and late old-timestamp records, database-scoped push/pull cursors, active-capture deferral and stale-marker recovery, byte-sized push subpages, invalid-URL local capture and real inline child execution, legacy metadata backfill with blank rows and no repeated scan, project-scoped embedding loads, inline response/exit forwarding, and mixed-index ranking. HTML link validation and `git diff --check` pass.
|
package/docs/specs/SPEC-INDEX.md
CHANGED
|
@@ -7,27 +7,32 @@ semantic-release + OIDC provenance).
|
|
|
7
7
|
|
|
8
8
|
Cluster map: Core (CLI/architecture) · Capture (wrapper/hooks/log) · DB (PhDB)
|
|
9
9
|
· Search (FTS/semantic) · AI (analysis/embeddings) · Memory (memories/summaries)
|
|
10
|
-
· Sync (server/remote) · MCP ·
|
|
10
|
+
· Sync (server/remote) · MCP · Import · Analytics · Config. The history TUI was
|
|
11
|
+
retired on 2026-10-22; SPEC-012 is retained as a decision record.
|
|
11
12
|
|
|
12
13
|
## Registry
|
|
13
14
|
|
|
14
15
|
| ID | Feature | Cluster | Status | Tests |
|
|
15
16
|
|----|---------|---------|--------|-------|
|
|
16
|
-
| SPEC-001 | Architecture & CLI dispatch | Core | **Implemented (
|
|
17
|
-
| SPEC-002 | Database layer (PhDB) | DB | **Implemented (
|
|
18
|
-
| SPEC-003 | Capture modes (pty/inline/hooks/log) | Capture | **Implemented (
|
|
17
|
+
| SPEC-001 | Architecture & CLI dispatch | Core | **Implemented (plain-text daily workflow)** | `src/commands/__tests__/operational-memory.test.ts` |
|
|
18
|
+
| SPEC-002 | Database layer (PhDB) | DB | **Implemented; stable DB identity and one-time metadata migration (SPEC-019)** | `src/db/__tests__/phdb.test.ts` |
|
|
19
|
+
| SPEC-003 | Capture modes (pty/inline/hooks/log) | Capture | **Implemented; shared live lifecycle (SPEC-019)** | `src/runner/inline.test.ts`, `src/capture/lifecycle.ts` |
|
|
19
20
|
| SPEC-004 | Filter pipeline & metadata | Core | **Implemented (baseline)** | — |
|
|
20
|
-
| SPEC-005 | Search (FTS + filters + semantic) | Search | **Implemented (
|
|
21
|
+
| SPEC-005 | Search (FTS + filters + semantic) | Search | **Implemented; cross-index RRF and scoped CLI vector loading (SPEC-019)** | `src/db/__tests__/phdb.test.ts`, `src/commands/__tests__/search.test.ts` |
|
|
21
22
|
| SPEC-006 | Analysis pipeline (LLM) | AI | **Implemented (baseline)** | — |
|
|
22
23
|
| SPEC-007 | Memory & project summaries | Memory | **Implemented (baseline)** | — |
|
|
23
24
|
| SPEC-008 | Embeddings (sqlite-vec) | AI | **Implemented (baseline)** | — |
|
|
24
25
|
| SPEC-009 | Retention & archive | DB | **Implemented (baseline)** | — |
|
|
25
|
-
| SPEC-010 | Remote sync (server + push/pull) | Sync | **Implemented (
|
|
26
|
+
| SPEC-010 | Remote sync (server + push/pull) | Sync | **Implemented; database-scoped cursors, active-capture barrier, byte-bounded pages (SPEC-019)** | `src/server/__tests__/server.test.ts`, `src/commands/__tests__/remote.test.ts`, `src/sync/__tests__/client.test.ts` |
|
|
26
27
|
| SPEC-011 | MCP server | MCP | **Implemented (baseline)** | — |
|
|
27
|
-
| SPEC-012 |
|
|
28
|
+
| SPEC-012 | Interactive history browser | Retired UI | **Retired 2026-10-22** | — |
|
|
28
29
|
| SPEC-013 | Importers (claude/gemini/opencode/codex) | Import | **Implemented** | import fixtures |
|
|
29
30
|
| SPEC-014 | Analytics commands (sessions/stats/cluster/timeline) | Analytics | **Implemented (baseline)** | — |
|
|
30
31
|
| SPEC-015 | Config & env overrides | Config | **Implemented (baseline)** | — |
|
|
32
|
+
| SPEC-016 | Operational memory workflow (context/close/MCP provenance) | Memory, CLI, MCP | **Implemented** | `src/commands/__tests__/operational-memory.test.ts`, `src/mcp/__tests__/server.test.ts` |
|
|
33
|
+
| SPEC-017 | Internal architecture consolidation (CLI surface gate, MCP modules, DB repositories) | Core, DB, MCP | **Implemented** | `src/knowledge/`, `src/mcp/tools/`, `src/db/{memory,archive}-repository.ts` |
|
|
34
|
+
| SPEC-018 | Interaction inspection and recall integrity | Core, Capture, Search, Memory, MCP | **Implemented** | `src/commands/__tests__/`, `src/db/__tests__/phdb.test.ts`, `src/context/__tests__/context.test.ts`, `src/mcp/__tests__/server.test.ts` |
|
|
35
|
+
| SPEC-019 | Network, capture, and retrieval integrity | Capture, Sync, Search, CLI | **Implemented; follow-up edge cases closed** | `src/server/__tests__/server.test.ts`, `src/capture/__tests__/lifecycle.test.ts`, `src/commands/__tests__/remote.test.ts`, `src/sync/__tests__/client.test.ts`, `src/commands/__tests__/search.test.ts`, `src/db/__tests__/phdb.test.ts` |
|
|
31
36
|
|
|
32
37
|
## Cross-cutting findings (SPEC-ISSUES.md)
|
|
33
38
|
|
|
@@ -37,12 +37,10 @@ Status: Open → assigned SPEC / fixed.
|
|
|
37
37
|
never in package.json → lint was completely broken). Fixed (downgrade).
|
|
38
38
|
- **ISSUE-007 — ZERO test files (FIXED 2026-10-09)** — baseline had no test
|
|
39
39
|
files. Tests now cover database, search, memory, archive, sync, config,
|
|
40
|
-
analysis, sessions, context, capture,
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
ANSI-clean response persistence. Broader screen flows remain covered by
|
|
45
|
-
component/module tests rather than end-to-end navigation.
|
|
40
|
+
analysis, sessions, context, capture, importer formats, PTY response cleanup,
|
|
41
|
+
HTTP endpoints, and MCP tool calls over an in-memory protocol transport. The
|
|
42
|
+
retired Ink browser coverage is historical; current product tests target the
|
|
43
|
+
plain-text CLI, capture adapters, and command modules.
|
|
46
44
|
- **ISSUE-016 — NON_PRINTABLE pattern matched plain words (FIXED 2026-08-08)** —
|
|
47
45
|
the filter's non-printable regex `^[\x00-\x1f\x7f\x1b\[\]()#;\d;A-Za-z]*$`
|
|
48
46
|
matched ANY all-alphanumeric string (e.g. "yes") because of `[A-Za-z\d]` in
|
|
@@ -73,23 +71,21 @@ Status: Open → assigned SPEC / fixed.
|
|
|
73
71
|
- **ISSUE-010 — cli.ts TUI bootstrap duplicated 3× (FIXED 2026-08-08)** —
|
|
74
72
|
extracted `openBrowser(db, props)` and `runRerun()` in `src/cli.ts`; default,
|
|
75
73
|
`search -i`, and `browse` now share the alt-screen cleanup path. Fixed.
|
|
76
|
-
- **ISSUE-011 — BrowseApp remains a large module** —
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
rendering in `src/ui/FilterPanel.tsx`; filter transitions are directly tested
|
|
80
|
-
and the keyboard path to open/close the rendered filter panel has a PTY smoke
|
|
81
|
-
test. Detail/edit/rerun and other screen interactions remain in BrowseApp.
|
|
74
|
+
- **ISSUE-011 — BrowseApp remains a large module (RETIRED 2026-10-22)** — the
|
|
75
|
+
history TUI and its Ink/React screens were removed when PH moved to the
|
|
76
|
+
plain-text daily workflow. This finding no longer applies to the product.
|
|
82
77
|
- **ISSUE-012 — sync_hash excludes args/workdir (FIXED 2026-08-08)** — dedup
|
|
83
78
|
hash was `sha256(tool|prompt|response)` duplicated inline in server
|
|
84
79
|
(src/server/index.ts:104) and remote (remote.ts:116) — drift risk. Now a
|
|
85
80
|
shared `syncHash` helper (src/utils/syncHash.ts) that includes `args` ONLY
|
|
86
81
|
when present — backward compatible: entries without args keep the legacy
|
|
87
82
|
hash (no mass re-push), entries with different args no longer collapse. Fixed.
|
|
88
|
-
- **ISSUE-013 — server auth
|
|
83
|
+
- **ISSUE-013 — server auth was conditional and fail-open (FIXED 2026-10-24)** —
|
|
89
84
|
`remoteApiKey` was sent by the client but the HTTP server never checked it.
|
|
90
85
|
Now `createRequestHandler` (exported for tests) gates every endpoint except
|
|
91
|
-
`/health` with `Authorization: Bearer <key>` (timingSafeEqual)
|
|
92
|
-
|
|
86
|
+
`/health` with `Authorization: Bearer <key>` (timingSafeEqual). Since
|
|
87
|
+
SPEC-019, startup refuses to run without a key; default bind is loopback and
|
|
88
|
+
`/health` returns status only (src/server/index.ts). Fixed.
|
|
93
89
|
- **ISSUE-014 — memories prompt_ids unused after summaries** — `prompt_ids` in
|
|
94
90
|
`memories` (src/db/index.ts:109) is written but the summary merge path
|
|
95
91
|
(project_summaries) tracks prompt_count instead; the timeline joins via
|
|
@@ -98,6 +94,87 @@ Status: Open → assigned SPEC / fixed.
|
|
|
98
94
|
duplicates formatting logic that the TUI ListEntry also renders; two code paths
|
|
99
95
|
for entry display can drift (e.g. badges, truncation rules).
|
|
100
96
|
|
|
97
|
+
## Follow-up findings (2026-10-24)
|
|
98
|
+
|
|
99
|
+
- **ISSUE-019 — sync cursors were shared across local databases (FIXED 2026-10-24)** —
|
|
100
|
+
global configuration stored push/pull cursors keyed only by remote target, so
|
|
101
|
+
switching `PH_DB` or `db-path` could skip records. Each SQLite file now has a
|
|
102
|
+
persistent UUID included in both cursor comparisons; older cursor shapes replay
|
|
103
|
+
idempotently from row zero (`src/db/index.ts:69-79,129`,
|
|
104
|
+
`src/commands/remote.ts:44-49,118-126`). Regression coverage:
|
|
105
|
+
`src/commands/__tests__/remote.test.ts` switches local database files and
|
|
106
|
+
verifies both push and pull restart at row zero.
|
|
107
|
+
- **ISSUE-020 — invalid optional remote URL interrupted local capture (FIXED 2026-10-24)** —
|
|
108
|
+
`syncTarget()` could throw before the local row was inserted or the wrapped
|
|
109
|
+
CLI started. Remote URLs are validated when configured; environment overrides
|
|
110
|
+
are handled as a failed remote effect while local capture continues
|
|
111
|
+
(`src/sync/protocol.ts:25-40`, `src/capture/lifecycle.ts:24-40,63-68`,
|
|
112
|
+
`src/commands/config.ts:174-175`). Regression coverage:
|
|
113
|
+
`src/config/__tests__/config.test.ts`, `src/capture/__tests__/lifecycle.test.ts`,
|
|
114
|
+
and `src/runner/inline.test.ts` verify validation, local persistence, and that
|
|
115
|
+
the wrapped child still runs and its response is saved.
|
|
116
|
+
- **ISSUE-021 — bulk sync could publish a live partial response (FIXED 2026-10-24)** —
|
|
117
|
+
wrappers persist prompts before their response is complete. Captures now carry
|
|
118
|
+
a local owner PID; bulk push stops before a live capture and clears markers
|
|
119
|
+
left by exited owners, preventing the partial and final versions from being
|
|
120
|
+
imported as separate interactions (`src/commands/wrap.ts:53-63`,
|
|
121
|
+
`src/runner/inline.ts:50-58`, `src/capture/lifecycle.ts:24-40,49-55`,
|
|
122
|
+
`src/commands/remote.ts:68-104,205-212`). Regression coverage:
|
|
123
|
+
`src/commands/__tests__/remote.test.ts` verifies a live partial response is
|
|
124
|
+
withheld and only the completed response is pushed.
|
|
125
|
+
- **ISSUE-022 — fixed record-count pages could exceed the request-body cap (FIXED 2026-10-24)** —
|
|
126
|
+
a 500-row request could exceed the server's 32 MiB limit and repeat unchanged.
|
|
127
|
+
The client now splits outer pages by serialized byte size before sending and
|
|
128
|
+
aggregates acknowledgements; an individually oversized record gets an
|
|
129
|
+
explicit ID and size error (`src/sync/client.ts:9-29,32-50`,
|
|
130
|
+
`src/sync/protocol.ts:4-5`). Regression coverage in
|
|
131
|
+
`src/sync/__tests__/client.test.ts` verifies byte limits, record order,
|
|
132
|
+
acknowledgement aggregation, and a clear error for a single oversized row.
|
|
133
|
+
- **ISSUE-023 — search metadata backfill scanned the prompt table on every open (FIXED 2026-10-24)** —
|
|
134
|
+
rows with legitimately empty derived text were selected and parsed on each
|
|
135
|
+
command. The backfill now runs once under an immediate transaction and records
|
|
136
|
+
its completion in `ph_meta` (`src/db/index.ts:185-205`).
|
|
137
|
+
`src/db/__tests__/phdb.test.ts` upgrades a legacy database with analyzed and
|
|
138
|
+
blank rows, verifies searchable derived text, and ensures a later open does
|
|
139
|
+
not query the blank rows again.
|
|
140
|
+
- **ISSUE-024 — project semantic search issued one query per vector (FIXED 2026-10-24)** —
|
|
141
|
+
CLI search loaded all legacy embeddings and called `getById` for each vector
|
|
142
|
+
to filter the current project. `SemanticIndex.loadProject()` now filters via
|
|
143
|
+
one join, and the CLI loads only scoped vectors (`src/db/semantic-index.ts:43-50`,
|
|
144
|
+
`src/db/index.ts:518-524`, `src/commands/search.ts:107-110`). Regression
|
|
145
|
+
coverage in `src/db/__tests__/phdb.test.ts` checks project membership through
|
|
146
|
+
the joined query; `src/commands/__tests__/search.test.ts` verifies the CLI
|
|
147
|
+
chooses the scoped loader and never loads all vectors for a project search.
|
|
148
|
+
- **ISSUE-025 — remote database replacement is invisible to sync cursors (OPEN 2026-10-24)** —
|
|
149
|
+
Push/pull cursors are keyed by normalized URL and local database UUID, but
|
|
150
|
+
`/api/sync/pull` returns only row IDs and continuation state. If the remote
|
|
151
|
+
SQLite database is replaced behind the same URL, a stored high cursor treats
|
|
152
|
+
its new low IDs as already read; push likewise does not replay old local rows.
|
|
153
|
+
Config also stores only one push and one pull cursor, so switching A→B→A
|
|
154
|
+
replays A from row zero (idempotently, but with a full network scan).
|
|
155
|
+
The global `remoteLastPush` and `remoteLastPull` fields can also report another
|
|
156
|
+
target's time (`src/commands/remote.ts:111-119, 127-170, 183-199`,
|
|
157
|
+
`src/server/index.ts:161-170`, `src/config/index.ts:23-26`). Add remote
|
|
158
|
+
database identity to the protocol and scope all checkpoint/status state to it.
|
|
159
|
+
- **ISSUE-026 — semantic retrieval paths can disagree and vectors lack provenance (OPEN 2026-10-24)** —
|
|
160
|
+
The CLI loads the legacy BLOB table, computes cosine similarity, and applies
|
|
161
|
+
a fixed `0.3` cutoff, while context, HTTP, and MCP use `sqlite-vec`. The same
|
|
162
|
+
query can return a different set and order by consumer. Stored vectors do not
|
|
163
|
+
identify the configured embedding model; changing `ollama-embed-model` changes
|
|
164
|
+
query vectors, and `ph embed-all` leaves existing vectors untouched
|
|
165
|
+
(`src/commands/search.ts:95-120`, `src/db/semantic-index.ts:8-50`,
|
|
166
|
+
`src/commands/embed-all.ts:6-32`, `src/config/index.ts:20`). Unify the search
|
|
167
|
+
contract and make vector profile changes explicit.
|
|
168
|
+
- **ISSUE-027 — database migration work scales with history (OPEN 2026-10-24)** —
|
|
169
|
+
Every `PhDB` constructor calls `migrate()`. Routine opens still select prompts
|
|
170
|
+
missing `$schema_version` by parsing the JSON field and retry legacy column
|
|
171
|
+
migrations. On the first open after the derived-search migration, the marker
|
|
172
|
+
prevents repeats, but every blank `search_metadata` row is loaded and updated
|
|
173
|
+
individually inside one immediate transaction. Large databases can pay O(n)
|
|
174
|
+
startup work and hold a write lock during that first backfill
|
|
175
|
+
(`src/db/index.ts:72-80, 164-205, 209-217`). Version and bound the migration
|
|
176
|
+
steps, and avoid rewriting rows with no searchable analysis text.
|
|
177
|
+
|
|
101
178
|
## Issue-to-spec map
|
|
102
179
|
|
|
103
180
|
| Issue | Spec (fix target) | Status |
|
|
@@ -108,15 +185,24 @@ Status: Open → assigned SPEC / fixed.
|
|
|
108
185
|
| 004 | SPEC-003 | Fixed 2026-08-08 |
|
|
109
186
|
| 005 | SPEC-002 | Fixed 2026-08-08 |
|
|
110
187
|
| 006 | — (tooling) | Fixed 2026-08-08 (eslint 9 + @eslint/js) |
|
|
111
|
-
| 007 | SPEC-002/003/005/009/010/011/012/013/014 | Fixed 2026-10-09
|
|
188
|
+
| 007 | SPEC-002/003/005/009/010/011/012/013/014 | Fixed 2026-10-09; test scope updated after TUI retirement |
|
|
112
189
|
| 008 | — (docs) | Open |
|
|
113
190
|
| 009 | — (chore) | Open |
|
|
114
191
|
| 010 | SPEC-001 | Fixed 2026-08-08 |
|
|
115
|
-
| 011 | SPEC-012 |
|
|
192
|
+
| 011 | SPEC-012 | Retired 2026-10-22 |
|
|
116
193
|
| 012 | SPEC-010 | Fixed 2026-08-08 (shared syncHash, args-aware, backward compatible) |
|
|
117
|
-
| 013 | SPEC-010 | Fixed 2026-
|
|
194
|
+
| 013 | SPEC-010/019 | Fixed 2026-10-24 (mandatory key, loopback default, health redaction) |
|
|
118
195
|
| 014 | SPEC-007 | Open |
|
|
119
196
|
| 015 | SPEC-012 | Open |
|
|
120
197
|
| 016 | SPEC-004 | Fixed 2026-08-08 |
|
|
121
198
|
| 017 | SPEC-004 | Fixed 2026-08-08 |
|
|
122
199
|
| 018 | SPEC-005/014 | Fixed 2026-10-09 |
|
|
200
|
+
| 019 | SPEC-010/019 | Fixed 2026-10-24 (persistent local database UUID scopes push/pull cursors) |
|
|
201
|
+
| 020 | SPEC-003/019 | Fixed 2026-10-24 (invalid optional remote URL cannot block local capture) |
|
|
202
|
+
| 021 | SPEC-003/010/019 | Fixed 2026-10-24 (active and abandoned capture markers handled before bulk push) |
|
|
203
|
+
| 022 | SPEC-010/019 | Fixed 2026-10-24 (push subpages bounded by serialized request bytes) |
|
|
204
|
+
| 023 | SPEC-002/019 | Fixed 2026-10-24 (one-time transactional search metadata backfill) |
|
|
205
|
+
| 024 | SPEC-005/019 | Fixed 2026-10-24 (project embedding load uses one metadata join) |
|
|
206
|
+
| 025 | SPEC-010/019 | Open (remote database replacement is not detected; timestamps are global) |
|
|
207
|
+
| 026 | SPEC-005/008 | Open (semantic search engines diverge; vectors lack model profile) |
|
|
208
|
+
| 027 | SPEC-002 | Open (routine database initialization repeats history scans) |
|
package/hooks/claude/README.md
CHANGED
package/hooks/codex/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Codex CLI hook for ph
|
|
2
2
|
|
|
3
|
-
The hook imports the active Codex rollout after each completed turn. Codex supplies the transcript path to the `Stop` hook; `ph` pairs user messages with the assistant response and deduplicates turns already captured.
|
|
3
|
+
The hook imports the active Codex rollout after each completed turn. Codex supplies the transcript path to the `Stop` hook; `ph` pairs user messages with the assistant response and deduplicates turns already captured. The hook supplies the active CLI working directory to the importer so captures are associated with the project where Codex was launched, even when the transcript records a synthetic directory.
|
|
4
4
|
|
|
5
5
|
## Install
|
|
6
6
|
|
package/hooks/codex/ph-hook.sh
CHANGED
|
@@ -4,11 +4,12 @@ set -u
|
|
|
4
4
|
|
|
5
5
|
INPUT=$(cat)
|
|
6
6
|
TRANSCRIPT_PATH=$(printf '%s' "$INPUT" | node -e 'let s="";process.stdin.on("data",d=>s+=d);process.stdin.on("end",()=>{try{process.stdout.write(JSON.parse(s).transcript_path||"")}catch{}})' 2>/dev/null)
|
|
7
|
+
WORKDIR="$PWD"
|
|
7
8
|
if [ -z "$TRANSCRIPT_PATH" ] || [ ! -f "$TRANSCRIPT_PATH" ]; then
|
|
8
9
|
printf '{}\n'
|
|
9
10
|
exit 0
|
|
10
11
|
fi
|
|
11
12
|
|
|
12
|
-
ph import codex --file "$TRANSCRIPT_PATH" >/dev/null 2>&1 || true
|
|
13
|
+
ph import codex --file "$TRANSCRIPT_PATH" --workdir "$WORKDIR" >/dev/null 2>&1 || true
|
|
13
14
|
printf '{}\n'
|
|
14
15
|
exit 0
|
package/hooks/gemini/README.md
CHANGED
package/package.json
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gi4nks/ph",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.8.0",
|
|
4
4
|
"description": "Transparent CLI wrapper that captures and indexes AI prompts",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
7
|
+
"engines": {
|
|
8
|
+
"node": ">=22"
|
|
9
|
+
},
|
|
7
10
|
"bin": {
|
|
8
11
|
"ph": "dist/cli.js"
|
|
9
12
|
},
|
|
@@ -55,12 +58,11 @@
|
|
|
55
58
|
"eval:retrieval": "tsx scripts/eval-context-retrieval.ts"
|
|
56
59
|
},
|
|
57
60
|
"dependencies": {
|
|
58
|
-
"@gi4nks/
|
|
61
|
+
"@gi4nks/wise": "^2.1.0",
|
|
59
62
|
"@lydell/node-pty": "^1.2.0-beta.3",
|
|
60
63
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
64
|
+
"ai": "^7.0.136",
|
|
61
65
|
"better-sqlite3": "^12.8.0",
|
|
62
|
-
"ink": "^7.0.5",
|
|
63
|
-
"react": "^19.2.7",
|
|
64
66
|
"sqlite-vec": "^0.1.9",
|
|
65
67
|
"zod": "^4.3.6"
|
|
66
68
|
},
|
|
@@ -72,12 +74,9 @@
|
|
|
72
74
|
"@semantic-release/npm": "^13.1.5",
|
|
73
75
|
"@types/better-sqlite3": "^7.6.13",
|
|
74
76
|
"@types/node": "^25.9.3",
|
|
75
|
-
"@types/react": "^19.2.7",
|
|
76
77
|
"@typescript-eslint/eslint-plugin": "^8.58.2",
|
|
77
78
|
"@typescript-eslint/parser": "^8.58.2",
|
|
78
79
|
"eslint": "^9.39.5",
|
|
79
|
-
"eslint-plugin-react": "^7.37.5",
|
|
80
|
-
"eslint-plugin-react-hooks": "^7.0.1",
|
|
81
80
|
"semantic-release": "^25.0.3",
|
|
82
81
|
"tsup": "^8.5.1",
|
|
83
82
|
"tsx": "^4.21.0",
|