@davidorex/pi-context 0.26.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 +23 -0
- package/README.md +195 -0
- package/dist/block-api.d.ts +328 -0
- package/dist/block-api.d.ts.map +1 -0
- package/dist/block-api.js +1167 -0
- package/dist/block-api.js.map +1 -0
- package/dist/block-validation.d.ts +33 -0
- package/dist/block-validation.d.ts.map +1 -0
- package/dist/block-validation.js +213 -0
- package/dist/block-validation.js.map +1 -0
- package/dist/context-dir.d.ts +93 -0
- package/dist/context-dir.d.ts.map +1 -0
- package/dist/context-dir.js +224 -0
- package/dist/context-dir.js.map +1 -0
- package/dist/context-sdk.d.ts +428 -0
- package/dist/context-sdk.d.ts.map +1 -0
- package/dist/context-sdk.js +1327 -0
- package/dist/context-sdk.js.map +1 -0
- package/dist/context.d.ts +497 -0
- package/dist/context.d.ts.map +1 -0
- package/dist/context.js +1060 -0
- package/dist/context.js.map +1 -0
- package/dist/dispatch-context.d.ts +112 -0
- package/dist/dispatch-context.d.ts.map +1 -0
- package/dist/dispatch-context.js +119 -0
- package/dist/dispatch-context.js.map +1 -0
- package/dist/execution-context.d.ts +138 -0
- package/dist/execution-context.d.ts.map +1 -0
- package/dist/execution-context.js +151 -0
- package/dist/execution-context.js.map +1 -0
- package/dist/index.d.ts +34 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1655 -0
- package/dist/index.js.map +1 -0
- package/dist/lens-validator.d.ts +50 -0
- package/dist/lens-validator.d.ts.map +1 -0
- package/dist/lens-validator.js +46 -0
- package/dist/lens-validator.js.map +1 -0
- package/dist/lens-view.d.ts +75 -0
- package/dist/lens-view.d.ts.map +1 -0
- package/dist/lens-view.js +253 -0
- package/dist/lens-view.js.map +1 -0
- package/dist/rename-canonical-id.d.ts +64 -0
- package/dist/rename-canonical-id.d.ts.map +1 -0
- package/dist/rename-canonical-id.js +378 -0
- package/dist/rename-canonical-id.js.map +1 -0
- package/dist/roadmap-plan.d.ts +186 -0
- package/dist/roadmap-plan.d.ts.map +1 -0
- package/dist/roadmap-plan.js +534 -0
- package/dist/roadmap-plan.js.map +1 -0
- package/dist/samples-catalog.d.ts +48 -0
- package/dist/samples-catalog.d.ts.map +1 -0
- package/dist/samples-catalog.js +128 -0
- package/dist/samples-catalog.js.map +1 -0
- package/dist/schema-migrations.d.ts +82 -0
- package/dist/schema-migrations.d.ts.map +1 -0
- package/dist/schema-migrations.js +106 -0
- package/dist/schema-migrations.js.map +1 -0
- package/dist/schema-validator.d.ts +76 -0
- package/dist/schema-validator.d.ts.map +1 -0
- package/dist/schema-validator.js +219 -0
- package/dist/schema-validator.js.map +1 -0
- package/dist/schema-write.d.ts +122 -0
- package/dist/schema-write.d.ts.map +1 -0
- package/dist/schema-write.js +210 -0
- package/dist/schema-write.js.map +1 -0
- package/dist/status-vocab.d.ts +60 -0
- package/dist/status-vocab.d.ts.map +1 -0
- package/dist/status-vocab.js +109 -0
- package/dist/status-vocab.js.map +1 -0
- package/dist/test-helpers.d.ts +12 -0
- package/dist/test-helpers.d.ts.map +1 -0
- package/dist/test-helpers.js +28 -0
- package/dist/test-helpers.js.map +1 -0
- package/dist/topo.d.ts +19 -0
- package/dist/topo.d.ts.map +1 -0
- package/dist/topo.js +99 -0
- package/dist/topo.js.map +1 -0
- package/dist/update-check.d.ts +6 -0
- package/dist/update-check.d.ts.map +1 -0
- package/dist/update-check.js +82 -0
- package/dist/update-check.js.map +1 -0
- package/package.json +115 -0
- package/samples/blocks/context-contracts.json +3 -0
- package/samples/blocks/conventions.json +3 -0
- package/samples/blocks/decisions.json +3 -0
- package/samples/blocks/features.json +3 -0
- package/samples/blocks/framework-gaps.json +3 -0
- package/samples/blocks/issues.json +3 -0
- package/samples/blocks/layer-plans.json +3 -0
- package/samples/blocks/phase.json +3 -0
- package/samples/blocks/rationale.json +3 -0
- package/samples/blocks/requirements.json +3 -0
- package/samples/blocks/research.json +3 -0
- package/samples/blocks/spec-reviews.json +3 -0
- package/samples/blocks/story.json +3 -0
- package/samples/blocks/tasks.json +3 -0
- package/samples/blocks/verification.json +3 -0
- package/samples/conception.json +467 -0
- package/samples/schemas/context-contracts.schema.json +89 -0
- package/samples/schemas/conventions.schema.json +34 -0
- package/samples/schemas/decisions.schema.json +87 -0
- package/samples/schemas/features.schema.json +53 -0
- package/samples/schemas/framework-gaps.schema.json +64 -0
- package/samples/schemas/issues.schema.json +39 -0
- package/samples/schemas/layer-plans.schema.json +92 -0
- package/samples/schemas/phase.schema.json +118 -0
- package/samples/schemas/rationale.schema.json +24 -0
- package/samples/schemas/requirements.schema.json +34 -0
- package/samples/schemas/research.schema.json +134 -0
- package/samples/schemas/spec-reviews.schema.json +62 -0
- package/samples/schemas/story.schema.json +73 -0
- package/samples/schemas/tasks.schema.json +34 -0
- package/samples/schemas/verification.schema.json +37 -0
- package/schemas/bootstrap.schema.json +24 -0
- package/schemas/config.schema.json +193 -0
- package/schemas/layer.schema.json +9 -0
- package/schemas/priority.schema.json +9 -0
- package/schemas/relations.schema.json +31 -0
- package/schemas/severity.schema.json +9 -0
- package/schemas/source.schema.json +9 -0
- package/schemas/status.schema.json +9 -0
- package/schemas/verification-method.schema.json +9 -0
- package/skill-narrative.md +130 -0
- package/skills/pi-context/SKILL.md +684 -0
- package/skills/pi-context/references/bundled-resources.md +47 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## [0.3.0] - 2026-03-18
|
|
4
|
+
|
|
5
|
+
## [0.2.0] - 2026-03-17
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
- `/project init` command to scaffold `.project/` directory with default schemas and empty block files
|
|
9
|
+
- Update check on session start for `@davidorex/pi-project-workflows` meta-package
|
|
10
|
+
- Monorepo integration as workspace package
|
|
11
|
+
|
|
12
|
+
## [0.1.0] - 2026-03-14
|
|
13
|
+
|
|
14
|
+
### Added
|
|
15
|
+
- Block CRUD: `readBlock`, `writeBlock`, `appendToBlock`, `updateItemInBlock` with atomic writes (tmp + rename)
|
|
16
|
+
- Write-time schema validation via AJV against `.project/schemas/*.schema.json`
|
|
17
|
+
- `ValidationError` class with structured error reporting
|
|
18
|
+
- Post-step block validation: `snapshotBlockFiles`, `validateChangedBlocks`, `rollbackBlockFiles`
|
|
19
|
+
- Derived project state: `projectState(cwd)` computes all metrics dynamically (source files, tests, phases, block summaries, agents, workflows, schemas, templates, recent commits)
|
|
20
|
+
- Block discovery: `availableBlocks(cwd)`, `availableSchemas(cwd)`, `findAppendableBlocks(cwd)`
|
|
21
|
+
- Generic block tools: `append-block-item` and `update-block-item` (work with any user-defined block type)
|
|
22
|
+
- `/project` command with `status` and `add-work` subcommands
|
|
23
|
+
- `PROJECT_DIR` and `SCHEMAS_DIR` constants as single source of truth for `.project/` path
|
package/README.md
ADDED
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
# pi-context
|
|
2
|
+
|
|
3
|
+
Schema-driven project state management for [Pi](https://github.com/badlogic/pi-mono).
|
|
4
|
+
|
|
5
|
+
Schemas are the design language. You define what your project tracks by writing JSON Schemas, and the entire system — tools, validation, derived state, workflow integration — adapts automatically. Drop a new `.schema.json` file into `.project/schemas/` and it instantly becomes an addressable block type with write-time validation, discovery, and generic CRUD tooling. No code changes.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
pi install npm:@davidorex/pi-context
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Getting Started
|
|
14
|
+
|
|
15
|
+
```
|
|
16
|
+
/context init # create the empty substrate skeleton
|
|
17
|
+
/context install # reconcile .project/ against installed_* lists in config.json
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
`init` is intentionally minimal: it writes the bootstrap pointer + substrate/schemas dirs only — no config, no schemas, no starter blocks (DEC-0011 ship-no-defaults). Adopt the packaged conception with `/context accept-all` (writes `config.json` from `samples/conception.json`), or hand-declare `config.json`'s `installed_schemas` / `installed_blocks`, then run `/context install` (opt-in install ceremony, idempotent, `--update` overwrites). The package-shipped samples catalog (`samples/blocks/` and `samples/schemas/`, per DEC-0037) is the source.
|
|
21
|
+
|
|
22
|
+
## How It Works
|
|
23
|
+
|
|
24
|
+
Project data lives under the substrate root (the dir chosen at init and recorded in `config.json`'s `root` field by accept-all; no default is shipped — DEC-0015) as typed JSON block files. Each block has a corresponding JSON Schema that defines its shape. All writes — whether from tools, workflows, or agents — are validated against the schema before data hits disk. Invalid data is never persisted.
|
|
25
|
+
|
|
26
|
+
After `/context init` the substrate skeleton is just the dirs (no config, no schemas, no blocks):
|
|
27
|
+
|
|
28
|
+
```
|
|
29
|
+
.project/
|
|
30
|
+
schemas/ — empty until accept-all + install
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
After `/context accept-all` (writes `config.json` from the packaged conception) + `/context install` (with declared entries) and any user authoring, the directory typically grows:
|
|
34
|
+
|
|
35
|
+
```
|
|
36
|
+
.project/
|
|
37
|
+
config.json — substrate bootstrap (always at .project/, exempt from root redirection)
|
|
38
|
+
relations.json — closure-table edges (always at .project/, exempt from root redirection)
|
|
39
|
+
schemas/<name>.schema.json — installed from samples/schemas/, plus any user-authored schemas
|
|
40
|
+
<name>.json — installed from samples/blocks/, plus any user-authored blocks
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
The schema is the contract. When pi-workflows agents produce output that writes to project blocks, the schema enforces the shape. When `/context add-work` extracts items from conversation, the schema constrains what gets written. When `contextState()` derives block summaries, it reads the typed data the schemas guarantee.
|
|
44
|
+
|
|
45
|
+
**Tools registered:** the tool surface grows with the package — read the generated `skills/pi-context/SKILL.md` for the current set, or call the `list-tools` tool at runtime (in-pi) / `grep pi.registerTool packages/pi-context/src/index.ts` (source). Families: block CRUD (read/write/append/update/remove, top-level + nested), item-level read (`read-block-item`, `read-block-page`), query (`filter-block-items`, `resolve-item(s)-by-id`, `find-references`, `walk-ancestors`, `context-walk-descendants`), substrate write (`append-relation`, `amend-config`, `write-schema`, `rename-canonical-id`), discovery/introspection (`read-config`, `read-schema`, `read-samples-catalog`, `list-tools`, `context-current-state`), lifecycle (`context-init`, `context-accept-all`, `context-status`, `context-validate`, `context-validate-relations`, `complete-task`).
|
|
46
|
+
|
|
47
|
+
**Commands registered:**
|
|
48
|
+
- `/context init <dir>` — bootstrap pointer + substrate/schemas dirs only (no config, no defaults)
|
|
49
|
+
- `/context accept-all` — adopt `samples/conception.json` as `config.json` (idempotent; never overwrites an existing config)
|
|
50
|
+
- `/context install [--update]` — reconcile the substrate against `installed_schemas` / `installed_blocks` in `config.json` by copying assets from the samples catalog (skip-if-exists by default; `--update` overwrites)
|
|
51
|
+
- `/context view <lensId>` — render a configured lens (groupByLens projection) into the conversation as markdown
|
|
52
|
+
- `/context lens-curate <lensId>` — surface bin-assignment suggestions for uncategorized items as a follow-up turn; the LLM persists chosen edges via `append-block-item` against `relations.json`
|
|
53
|
+
- `/context status` — derived project state (source metrics, test counts, block summaries, git state)
|
|
54
|
+
- `/context add-work` — extract structured items from conversation into typed blocks
|
|
55
|
+
- `/context validate` — cross-block referential integrity checks
|
|
56
|
+
|
|
57
|
+
## Source Files
|
|
58
|
+
|
|
59
|
+
| File | Purpose |
|
|
60
|
+
|------|---------|
|
|
61
|
+
| `src/index.ts` | Extension entry point — tool and command registration |
|
|
62
|
+
| `src/block-api.ts` | Block CRUD: `readBlock`, `writeBlock`, `appendToBlock`, `updateItemInBlock`, `appendToNestedArray`, `updateNestedArrayItem`, `removeFromBlock`, `removeFromNestedArray`, `readBlockDir` |
|
|
63
|
+
| `src/schema-validator.ts` | AJV wrapper: `validate`, `validateFromFile`, `ValidationError` |
|
|
64
|
+
| `src/block-validation.ts` | Post-step validation: `snapshotBlockFiles`, `validateChangedBlocks`, `rollbackBlockFiles` |
|
|
65
|
+
| `src/context-sdk.ts` | Derived state + cross-block resolver: `contextState`, `availableBlocks`, `availableSchemas`, `findAppendableBlocks`, `validateContext`, `buildIdIndex`, `resolveItemById`, `completeTask`. Re-exports the substrate API from `context.ts` (config/relations loaders, lens algorithms, validators, `resolveContextDir`) so existing consumers get one import surface. |
|
|
66
|
+
| `src/context.ts` | Substrate bootstrap: `loadConfig`, `loadRelations`, `loadContext` (mtime-keyed cache), `resolveContextDir(cwd)` (the `config.root` resolver every path helper routes through), the lens algorithms (`edgesForLens`, `synthesizeFromField`, `walkDescendants`, `groupByLens`, `listUncategorized`, `displayName`), `validateRelations`. Type exports: `ConfigBlock`, `HierarchyDecl`, `LensSpec`, `Edge`, `ItemRecord`, `ContextData`, `SubstrateValidationIssue`, `SubstrateValidationResult`, `CurationSuggestion`. |
|
|
67
|
+
| `src/lens-view.ts` | Lens-view consumption surface — pure functions for `/context view` + `/context lens-curate`: `loadLensView`, `renderLensView`, `buildCurationSuggestions`, `validateContextRelations`, `edgesForLensByName`, `walkLensDescendants`. |
|
|
68
|
+
| `src/context-dir.ts` | Path-builders that route through `resolveContextDir(cwd)`: `schemasDir`, `schemaPath`, `agentsDir`, `contextTemplatesDir`. |
|
|
69
|
+
| `src/update-check.ts` | Checks for updates to `@davidorex/pi-project-workflows` on session start |
|
|
70
|
+
|
|
71
|
+
## API
|
|
72
|
+
|
|
73
|
+
### Block I/O (`src/block-api.ts`)
|
|
74
|
+
|
|
75
|
+
```typescript
|
|
76
|
+
readBlock(cwd: string, blockName: string): unknown
|
|
77
|
+
readBlockDir(cwd: string, subdir: string): unknown[]
|
|
78
|
+
writeBlock(cwd: string, blockName: string, data: unknown): void
|
|
79
|
+
appendToBlock(cwd: string, blockName: string, arrayKey: string, item: unknown): void
|
|
80
|
+
updateItemInBlock(cwd: string, blockName: string, arrayKey: string, predicate, updates): void
|
|
81
|
+
appendToNestedArray(cwd, blockName, parentArrayKey, parentPredicate, nestedArrayKey, item): void
|
|
82
|
+
updateNestedArrayItem(cwd, blockName, parentArrayKey, parentPredicate, nestedArrayKey, nestedPredicate, updates): void
|
|
83
|
+
removeFromBlock(cwd, blockName, arrayKey, predicate): { removed: number }
|
|
84
|
+
removeFromNestedArray(cwd, blockName, parentArrayKey, parentPredicate, nestedArrayKey, nestedPredicate): { removed: number }
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
All writes are atomic (tmp file + rename) and serialised per block via `withBlockLock`. If a schema exists for the block, validation runs before the write — invalid data is never persisted. `update*` operations throw on no-match; `remove*` operations are idempotent (`{ removed: 0 }` on no-match).
|
|
88
|
+
|
|
89
|
+
### Schema Validation (`src/schema-validator.ts`)
|
|
90
|
+
|
|
91
|
+
```typescript
|
|
92
|
+
validate(schema: Record<string, unknown>, data: unknown, label: string): unknown
|
|
93
|
+
validateFromFile(schemaPath: string, data: unknown, label: string): unknown
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
Throws `ValidationError` with structured AJV error details on failure.
|
|
97
|
+
|
|
98
|
+
### Derived State + Cross-Block Resolver (`src/context-sdk.ts`)
|
|
99
|
+
|
|
100
|
+
```typescript
|
|
101
|
+
contextState(cwd: string): ContextState
|
|
102
|
+
availableBlocks(cwd: string): BlockInfo[]
|
|
103
|
+
availableSchemas(cwd: string): string[]
|
|
104
|
+
findAppendableBlocks(cwd: string): Array<{ block, arrayKey, schemaPath }>
|
|
105
|
+
validateContext(cwd: string): { status: "clean" | "warnings" | "invalid"; issues: ValidationIssue[] }
|
|
106
|
+
buildIdIndex(cwd: string): Map<string, ItemLocation>
|
|
107
|
+
resolveItemById(cwd: string, id: string): ItemLocation | null
|
|
108
|
+
completeTask(cwd, taskId, verificationId): CompleteTaskResult
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
`contextState()` computes everything fresh on each call — no cache, no stale data. `buildIdIndex` / `resolveItemById` enforce kind-prefix consistency (a `DEC-` id found in a non-decisions block throws), so the cross-block-reference plumbing in pi-jit-agents and pi-workflows can rely on the prefix invariant.
|
|
112
|
+
|
|
113
|
+
### Substrate API (`src/context.ts`, re-exported from `src/context-sdk.ts`)
|
|
114
|
+
|
|
115
|
+
```typescript
|
|
116
|
+
// Bootstrap loaders
|
|
117
|
+
loadConfig(cwd: string): ConfigBlock | null
|
|
118
|
+
loadRelations(cwd: string): Edge[]
|
|
119
|
+
loadContext(cwd: string): ContextData // mtime-keyed cached snapshot
|
|
120
|
+
resolveContextDir(cwd: string): string // resolves config.root, falls back to the bootstrap pointer
|
|
121
|
+
|
|
122
|
+
// Lens algorithms (pure, callable directly with loaded inputs)
|
|
123
|
+
synthesizeFromField(lens: LensSpec, items: ItemRecord[]): Edge[]
|
|
124
|
+
edgesForLens(lens: LensSpec, items: ItemRecord[], authoredEdges: Edge[]): Edge[]
|
|
125
|
+
walkDescendants(parentId: string, relationType: string, edges: Edge[]): string[]
|
|
126
|
+
groupByLens(items: ItemRecord[], lens: LensSpec, lensEdges: Edge[]): Map<string, ItemRecord[]>
|
|
127
|
+
listUncategorized(lens, grouped): { uncategorized: ItemRecord[]; suggestionTemplate: ... }
|
|
128
|
+
|
|
129
|
+
// Validation + display
|
|
130
|
+
validateRelations(cwd, options?): SubstrateValidationResult
|
|
131
|
+
displayName(canonicalId: string, naming: Record<string, string> | undefined): string
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
`config.root` is the substrate's "where do I live" answer — block-api, schemas-discovery, phase-discovery, and every other path consumer route through `resolveContextDir(cwd)` so a relocated root reaches the runtime instead of being trapped in the SDK. `config.json` and `relations.json` themselves are exempt — they always live at `.project/` because they are the substrate that defines `root`.
|
|
135
|
+
|
|
136
|
+
### Lens View Consumption (`src/lens-view.ts`)
|
|
137
|
+
|
|
138
|
+
```typescript
|
|
139
|
+
loadLensView(cwd: string, lensId: string): LoadedLensView | { error: string }
|
|
140
|
+
renderLensView(view: LoadedLensView, naming: Record<string, string> | undefined): string
|
|
141
|
+
buildCurationSuggestions(view: LoadedLensView): string
|
|
142
|
+
validateContextRelations(cwd: string): SubstrateValidationResult
|
|
143
|
+
edgesForLensByName(cwd: string, lensId: string): Edge[] | { error: string }
|
|
144
|
+
walkLensDescendants(cwd: string, parentId: string, relationType: string): string[]
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
Pure functions consumed by the `/context view`, `/context lens-curate`, `context-edges-for-lens`, `context-walk-descendants`, and `context-validate-relations` shells in `index.ts`. Tests call them directly without an `ExtensionCommandContext`.
|
|
148
|
+
|
|
149
|
+
### Substrate Path Surface (`src/context-dir.ts`)
|
|
150
|
+
|
|
151
|
+
```typescript
|
|
152
|
+
resolveContextDir(cwd): string // resolves config.root; falls back to the bootstrap pointer
|
|
153
|
+
schemasDir(cwd): string // <cwd>/<resolveContextDir>/schemas
|
|
154
|
+
schemaPath(cwd, blockName): string // <cwd>/<resolveContextDir>/schemas/<name>.schema.json
|
|
155
|
+
agentsDir(cwd): string // <cwd>/<resolveContextDir>/agents
|
|
156
|
+
contextTemplatesDir(cwd): string // <cwd>/<resolveContextDir>/templates
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
Canonical builders consumed across pi-jit-agents and pi-workflows for any substrate-root path construction. All path-builders route through `resolveContextDir(cwd)` so a relocated root reaches every consumer. Replace inline `path.join(cwd, ".project", ...)` with these.
|
|
160
|
+
|
|
161
|
+
### Block Validation (`src/block-validation.ts`)
|
|
162
|
+
|
|
163
|
+
Used by workflow executors for post-step integrity checks:
|
|
164
|
+
|
|
165
|
+
```typescript
|
|
166
|
+
snapshotBlockFiles(cwd: string): BlockSnapshot // Map<string, BlockFileSnapshot>
|
|
167
|
+
validateChangedBlocks(cwd: string, snapshot: BlockSnapshot): void
|
|
168
|
+
rollbackBlockFiles(cwd: string, snapshot: BlockSnapshot): string[]
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
## For LLMs
|
|
172
|
+
|
|
173
|
+
When working with this extension:
|
|
174
|
+
|
|
175
|
+
- **Read `src/context-sdk.ts`** to understand what project state is available and how it's computed
|
|
176
|
+
- **Read `src/block-api.ts`** to understand the CRUD operations and validation behavior
|
|
177
|
+
- **Read `src/index.ts`** to see tool parameter schemas and command handler logic
|
|
178
|
+
- Use the `append-block-item` tool to add items — it handles schema validation, duplicate checking, and atomic writes
|
|
179
|
+
- Use the `update-block-item` tool with a `match` predicate (e.g., `{ id: "gap-123" }`) and `updates` object
|
|
180
|
+
- Block schemas define the contract — consult `.project/schemas/*.schema.json` to understand what fields are required
|
|
181
|
+
- `contextState(cwd)` is the single source of truth for project metrics — prefer it over manual filesystem inspection
|
|
182
|
+
|
|
183
|
+
## Tests
|
|
184
|
+
|
|
185
|
+
```bash
|
|
186
|
+
npm test
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
Runs `tsx --test src/*.test.ts`. Test files: `block-api.test.ts`, `block-tools.test.ts`, `schema-validator.test.ts`, `context-sdk.test.ts`.
|
|
190
|
+
|
|
191
|
+
## Development
|
|
192
|
+
|
|
193
|
+
Part of the [`pi-project-workflows`](../../README.md) monorepo. All four packages (pi-context, pi-jit-agents, pi-workflows, pi-behavior-monitors) plus the pi-project-workflows meta-package are versioned in lockstep (current version in each `package.json`).
|
|
194
|
+
|
|
195
|
+
`npm run build` compiles TypeScript to `dist/` via `tsc`. The package ships `dist/`, not `src/` — the `pi.extensions` entry point is `./dist/index.js`.
|
|
@@ -0,0 +1,328 @@
|
|
|
1
|
+
import type { DispatchContext } from "./dispatch-context.js";
|
|
2
|
+
/**
|
|
3
|
+
* Read and parse a .project/{blockName}.json file.
|
|
4
|
+
* Throws if the file does not exist or contains invalid JSON.
|
|
5
|
+
*
|
|
6
|
+
* Optional filter: when provided, returns a shallow copy of the block with only
|
|
7
|
+
* matching items in the specified array key. Non-array or missing keys return the
|
|
8
|
+
* block unchanged. The filter is applied after parsing, before returning.
|
|
9
|
+
*/
|
|
10
|
+
export declare function readBlock(cwd: string, blockName: string, filter?: {
|
|
11
|
+
arrayKey: string;
|
|
12
|
+
predicate: (item: Record<string, unknown>) => boolean;
|
|
13
|
+
}): unknown;
|
|
14
|
+
/**
|
|
15
|
+
* Validated whole-file write to an arbitrary `(filePath, schemaPath)` pair.
|
|
16
|
+
* The `.project/`-targeting `writeBlock` becomes a thin wrapper over this.
|
|
17
|
+
* `schemaPath = null` skips AJV validation entirely (matches `writeBlock`'s
|
|
18
|
+
* "no schema file present" semantic).
|
|
19
|
+
*
|
|
20
|
+
* `ctx` (FGAP-004): when provided AND the schema declares author fields at
|
|
21
|
+
* the top-level envelope (and `data` is object-shaped, NOT array-shaped),
|
|
22
|
+
* the envelope is stamped before AJV runs. Top-level array files (e.g.
|
|
23
|
+
* monitor pattern lists) skip envelope-stamping silently — the envelope
|
|
24
|
+
* lookup returns an empty set for array schemas because their top-level
|
|
25
|
+
* `properties` is undefined.
|
|
26
|
+
*
|
|
27
|
+
* Atomic write via tmp + rename. Does NOT itself acquire a `withBlockLock`
|
|
28
|
+
* — whole-file overwrite has no read-modify-write race that locking would
|
|
29
|
+
* protect against. Callers performing read-modify-write (e.g.
|
|
30
|
+
* `appendToTypedFile`, `appendToBlock`, …) wrap the surrounding critical
|
|
31
|
+
* section in `withBlockLock` themselves; `writeTypedFile` is then called
|
|
32
|
+
* from inside that section. This matches the prior `writeBlock` /
|
|
33
|
+
* `appendToBlock` split exactly — preserves byte-identical lock semantics
|
|
34
|
+
* for existing callers.
|
|
35
|
+
*/
|
|
36
|
+
export declare function writeTypedFile(filePath: string, schemaPath: string | null, data: unknown, ctx?: DispatchContext, errorLabel?: string): void;
|
|
37
|
+
/**
|
|
38
|
+
* Validated atomic append to an array within a `(filePath, schemaPath)` pair.
|
|
39
|
+
* `arrayPath = null` means "the file IS the array" (top-level array shape,
|
|
40
|
+
* e.g. monitor patterns / instructions); `arrayPath = string` means
|
|
41
|
+
* "data[arrayPath] is the target array" (object-with-array-field shape, the
|
|
42
|
+
* `.project/` block convention).
|
|
43
|
+
*
|
|
44
|
+
* `ctx` (FGAP-004): when provided AND the schema declares author fields on
|
|
45
|
+
* the items reached by `arrayPath` (or, for the flat-array case, on the
|
|
46
|
+
* array's `items.properties.*`), the appended item is stamped via
|
|
47
|
+
* `stampItem` in create-mode before AJV validation. For the flat-array
|
|
48
|
+
* case the array key passed to the per-array-key cache lookup is the
|
|
49
|
+
* arbitrary token `__top__` — `collectArrayItemAuthorDecisions` only
|
|
50
|
+
* traverses `properties.*` paths and never visits a top-level array
|
|
51
|
+
* schema, so the lookup will always miss; flat-array stamping is
|
|
52
|
+
* intentionally a no-op until a schema actually declares author fields
|
|
53
|
+
* on a top-level array shape (no current consumer does so).
|
|
54
|
+
*/
|
|
55
|
+
export declare function appendToTypedFile(filePath: string, schemaPath: string | null, arrayPath: string | null, item: unknown, ctx?: DispatchContext, errorLabel?: string): void;
|
|
56
|
+
/**
|
|
57
|
+
* Validated atomic bulk append-if-absent to an array within a
|
|
58
|
+
* `(filePath, schemaPath)` pair. Each candidate in `items` is appended only
|
|
59
|
+
* when no element already present (on-disk OR earlier in this same batch)
|
|
60
|
+
* shares its `matchKey`. Dedup is keyed solely on `matchKey(item)` — the
|
|
61
|
+
* write surface does no semantic validation beyond the whole-array AJV check
|
|
62
|
+
* and this exact-duplicate-no-op; richer integrity (referential, etc.) is
|
|
63
|
+
* deferred to callers / downstream validators.
|
|
64
|
+
*
|
|
65
|
+
* `arrayPath` mirrors `appendToTypedFile`: `null` ⇒ the file content IS the
|
|
66
|
+
* array (flat top-level array shape); `string` ⇒ `data[arrayPath]` is the
|
|
67
|
+
* target array (object-with-array-field shape, the `.project/` convention).
|
|
68
|
+
* The branching is identical to `appendToTypedFile`'s.
|
|
69
|
+
*
|
|
70
|
+
* The whole read-find-write critical section runs inside `withBlockLock`, so
|
|
71
|
+
* concurrent batches against the same file serialise. When `appended === 0`
|
|
72
|
+
* nothing is written (the file is left byte-identical). The first write
|
|
73
|
+
* against an absent file works: `withBlockLock` skips locking when the file is
|
|
74
|
+
* absent (no contention possible), and the absent file is treated as an empty
|
|
75
|
+
* array for the flat-array shape — only that shape is creatable from absence;
|
|
76
|
+
* the object-with-array-field shape requires an existing envelope and so still
|
|
77
|
+
* throws via `readTypedFile`.
|
|
78
|
+
*
|
|
79
|
+
* `ctx` is threaded to `writeTypedFile` for attestation parity; per the
|
|
80
|
+
* top-level-array stamping semantics documented above, flat-array shapes with
|
|
81
|
+
* no declared envelope author fields treat it as a structural no-op.
|
|
82
|
+
*/
|
|
83
|
+
export declare function appendManyToTypedFileIfAbsent(filePath: string, schemaPath: string | null, arrayPath: string | null, items: unknown[], matchKey: (item: unknown) => string, ctx?: DispatchContext, errorLabel?: string): {
|
|
84
|
+
appended: number;
|
|
85
|
+
skipped: number;
|
|
86
|
+
};
|
|
87
|
+
/**
|
|
88
|
+
* Validated atomic find-by-predicate update of one item inside an array
|
|
89
|
+
* reachable from `(filePath, schemaPath, arrayPath)`. Generalises
|
|
90
|
+
* `updateItemInBlock` to arbitrary file paths and supports both top-level
|
|
91
|
+
* array files (`arrayPath === null`) and object-with-array-field files
|
|
92
|
+
* (`arrayPath === string`). Throws on predicate miss; AJV validates the
|
|
93
|
+
* whole file after mutation.
|
|
94
|
+
*
|
|
95
|
+
* Multi-match warning emits on stderr with the established `[block-api]`
|
|
96
|
+
* prefix (grep-discoverable across legacy log lines).
|
|
97
|
+
*
|
|
98
|
+
* `ctx`: when supplied AND the schema declares author fields on the items
|
|
99
|
+
* reachable by `arrayPath`, the merged item is stamped in update-mode
|
|
100
|
+
* before AJV runs. Flat-array stamping is a no-op (see
|
|
101
|
+
* `maybeStampTypedItem`).
|
|
102
|
+
*/
|
|
103
|
+
export declare function updateItemInTypedFile(filePath: string, schemaPath: string | null, arrayPath: string | null, predicate: (item: Record<string, unknown>) => boolean, updates: Record<string, unknown>, ctx?: DispatchContext, errorLabel?: string): void;
|
|
104
|
+
/**
|
|
105
|
+
* Validated atomic find-or-append. Generalises `upsertItemInBlock` to
|
|
106
|
+
* arbitrary `(filePath, schemaPath, arrayPath)` triples, including
|
|
107
|
+
* top-level array files via `arrayPath === null`.
|
|
108
|
+
*
|
|
109
|
+
* FGAP-018 fix lives here (was in `upsertItemInBlock` prior to Step 6.3):
|
|
110
|
+
* on the update branch, declared create-time attestation fields are
|
|
111
|
+
* pre-merged from the existing on-disk item onto the supplied item if
|
|
112
|
+
* absent, so attestation integrity (FGAP-004) holds across replacement.
|
|
113
|
+
* The wrapper `upsertItemInBlock` inherits the fix structurally.
|
|
114
|
+
*
|
|
115
|
+
* For the flat-array case the pre-merge is a structural no-op — the
|
|
116
|
+
* `declaredAuthorFieldsForArray` lookup keyed by `__top__` returns the
|
|
117
|
+
* empty set (top-level array schemas are never visited by
|
|
118
|
+
* `collectArrayItemAuthorDecisions`), so no fields are carried. This is
|
|
119
|
+
* intentional: no current consumer declares author fields on a top-level
|
|
120
|
+
* array shape, and the unconditional pre-merge code path simply finds
|
|
121
|
+
* nothing to merge. If a future consumer lands such a schema, the
|
|
122
|
+
* stamping cataloguer needs an extension (filed-or-future work) — this
|
|
123
|
+
* primitive will then start preserving attestation on flat-array upserts
|
|
124
|
+
* automatically.
|
|
125
|
+
*/
|
|
126
|
+
export declare function upsertItemInTypedFile(filePath: string, schemaPath: string | null, arrayPath: string | null, item: Record<string, unknown>, idField: string, ctx?: DispatchContext, errorLabel?: string): {
|
|
127
|
+
mode: "appended" | "updated";
|
|
128
|
+
};
|
|
129
|
+
/**
|
|
130
|
+
* Validated atomic predicate-based remove. Generalises `removeFromBlock`
|
|
131
|
+
* to arbitrary `(filePath, schemaPath, arrayPath)` triples including
|
|
132
|
+
* top-level array files. Idempotent on miss (returns `{ removed: 0 }`
|
|
133
|
+
* without throwing or writing). AJV validates whole file after mutation
|
|
134
|
+
* (so e.g. a `minItems` violation surfaces).
|
|
135
|
+
*/
|
|
136
|
+
export declare function removeFromTypedFile(filePath: string, schemaPath: string | null, arrayPath: string | null, predicate: (item: Record<string, unknown>) => boolean, ctx?: DispatchContext, errorLabel?: string): {
|
|
137
|
+
removed: number;
|
|
138
|
+
};
|
|
139
|
+
/**
|
|
140
|
+
* Validated atomic append to a nested array inside a parent-array item.
|
|
141
|
+
* Generalises `appendToNestedArray` to arbitrary `(filePath, schemaPath,
|
|
142
|
+
* parentArrayKey, nestedArrayKey)`. Nesting requires object-with-array-field
|
|
143
|
+
* shape — a top-level array file cannot host nested arrays at the same
|
|
144
|
+
* structural level — so `parentArrayKey` is `string` (no `null` form).
|
|
145
|
+
*
|
|
146
|
+
* Throws on missing parent key, no parent match, missing nested key, or
|
|
147
|
+
* AJV failure. Multi-match warning emits at parent level via stderr with
|
|
148
|
+
* the established `[block-api]` prefix.
|
|
149
|
+
*/
|
|
150
|
+
export declare function appendToNestedTypedFile(filePath: string, schemaPath: string | null, parentArrayKey: string, predicate: (item: Record<string, unknown>) => boolean, nestedArrayKey: string, item: unknown, ctx?: DispatchContext, errorLabel?: string): void;
|
|
151
|
+
/**
|
|
152
|
+
* Validated atomic update of a single item inside a nested array on a
|
|
153
|
+
* parent-array item. Generalises `updateNestedArrayItem` to arbitrary
|
|
154
|
+
* `(filePath, schemaPath, parentArrayKey, nestedArrayKey)`. Object-shape
|
|
155
|
+
* file required (see `appendToNestedTypedFile` doc).
|
|
156
|
+
*
|
|
157
|
+
* Throws on missing parent key, no parent/nested match, missing nested
|
|
158
|
+
* key, or AJV failure. Multi-match warnings emit at both parent and
|
|
159
|
+
* nested levels via stderr with the `[block-api]` prefix.
|
|
160
|
+
*/
|
|
161
|
+
export declare function updateNestedItemInTypedFile(filePath: string, schemaPath: string | null, parentArrayKey: string, parentPredicate: (item: Record<string, unknown>) => boolean, nestedArrayKey: string, nestedPredicate: (item: Record<string, unknown>) => boolean, updates: Record<string, unknown>, ctx?: DispatchContext, errorLabel?: string): void;
|
|
162
|
+
/**
|
|
163
|
+
* Validated atomic remove from a nested array. Generalises
|
|
164
|
+
* `removeFromNestedArray` to arbitrary `(filePath, schemaPath,
|
|
165
|
+
* parentArrayKey, nestedArrayKey)`. Object-shape file required (see
|
|
166
|
+
* `appendToNestedTypedFile` doc). Idempotent on nested-miss (returns
|
|
167
|
+
* `{ removed: 0 }`); throws on parent-miss to surface a malformed
|
|
168
|
+
* caller, mirroring the wrapper's prior semantics.
|
|
169
|
+
*/
|
|
170
|
+
export declare function removeFromNestedTypedFile(filePath: string, schemaPath: string | null, parentArrayKey: string, parentPredicate: (item: Record<string, unknown>) => boolean, nestedArrayKey: string, nestedPredicate: (item: Record<string, unknown>) => boolean, ctx?: DispatchContext, errorLabel?: string): {
|
|
171
|
+
removed: number;
|
|
172
|
+
};
|
|
173
|
+
/**
|
|
174
|
+
* Validate `data` against its schema (if one exists) and write atomically
|
|
175
|
+
* to `.project/{blockName}.json`. Throws `ValidationError` on schema failure.
|
|
176
|
+
* Files without a corresponding schema are written without validation.
|
|
177
|
+
*
|
|
178
|
+
* Thin wrapper over `writeTypedFile` — see that function for full semantics.
|
|
179
|
+
* `ctx` (FGAP-004): whole-block writes are treated as create-mode envelope
|
|
180
|
+
* stamping; callers wanting per-item attribution should prefer the
|
|
181
|
+
* array-grained writers.
|
|
182
|
+
*/
|
|
183
|
+
export declare function writeBlock(cwd: string, blockName: string, data: unknown, ctx?: DispatchContext): void;
|
|
184
|
+
/**
|
|
185
|
+
* Read current file, push item onto data[arrayKey], validate whole file
|
|
186
|
+
* against schema, write atomically. Throws if file doesn't exist, if
|
|
187
|
+
* arrayKey is missing or not an array, or if validation fails.
|
|
188
|
+
*
|
|
189
|
+
* `ctx` (FGAP-004): when provided AND the schema declares author fields on
|
|
190
|
+
* `properties.<arrayKey>.items.properties.*`, the appended item is stamped
|
|
191
|
+
* via `stampItem` in create-mode before AJV validation. Schemas that don't
|
|
192
|
+
* declare author fields fall through unstamped — guards against
|
|
193
|
+
* `additionalProperties: false` AJV failures on blocks whose item shape
|
|
194
|
+
* doesn't carry author markers yet.
|
|
195
|
+
*/
|
|
196
|
+
export declare function appendToBlock(cwd: string, blockName: string, arrayKey: string, item: unknown, ctx?: DispatchContext): void;
|
|
197
|
+
/**
|
|
198
|
+
* Find an item in data[arrayKey] by predicate, shallow-merge updates onto it,
|
|
199
|
+
* validate whole file against schema, write atomically. Throws if no item
|
|
200
|
+
* matches, if arrayKey is missing or not an array, or if validation fails.
|
|
201
|
+
*
|
|
202
|
+
* `ctx` (FGAP-004): when provided AND the schema declares author fields on
|
|
203
|
+
* the array's items, the merged item is run through `stampItem` in
|
|
204
|
+
* update-mode after the shallow merge — `created_by` / `created_at` are
|
|
205
|
+
* preserved, `modified_by` / `modified_at` refresh.
|
|
206
|
+
*/
|
|
207
|
+
export declare function updateItemInBlock(cwd: string, blockName: string, arrayKey: string, predicate: (item: Record<string, unknown>) => boolean, updates: Record<string, unknown>, ctx?: DispatchContext): void;
|
|
208
|
+
/**
|
|
209
|
+
* Atomically find-or-append a single item in `data[arrayKey]` keyed by
|
|
210
|
+
* `idField`. Acquires the block lock; reads the array; locates the first
|
|
211
|
+
* existing item where `existingItem[idField] === item[idField]`; if found
|
|
212
|
+
* the item at that index is REPLACED (not shallow-merged) by the supplied
|
|
213
|
+
* `item` and stamping runs in `"update"` mode; otherwise `item` is pushed
|
|
214
|
+
* onto the array and stamping runs in `"create"` mode. AJV validates the
|
|
215
|
+
* whole file against the schema after mutation, before write.
|
|
216
|
+
*
|
|
217
|
+
* Composing existing `updateItemInBlock` + `appendToBlock` from a caller
|
|
218
|
+
* would release the block lock between the read-check and the mutating
|
|
219
|
+
* write, which is race-prone for concurrent monitor/LLM writes against the
|
|
220
|
+
* same block — this primitive holds the lock for both halves of the
|
|
221
|
+
* find-or-append decision in one atomic critical section.
|
|
222
|
+
*
|
|
223
|
+
* Throws when `item[idField]` is missing or empty (defensive — surfaces a
|
|
224
|
+
* malformed call site early instead of silently appending a duplicate
|
|
225
|
+
* that would never match on a subsequent upsert). Throws on the usual
|
|
226
|
+
* block / arrayKey / not-array invariants and on AJV validation failure.
|
|
227
|
+
*
|
|
228
|
+
* Replacement semantics (vs. updateItemInBlock's shallow-merge): upsert is
|
|
229
|
+
* the call surface for monitor write-actions where the template produces
|
|
230
|
+
* the FULL item shape per classification — there is no prior partial state
|
|
231
|
+
* to merge against. Callers that need merge-on-update should continue to
|
|
232
|
+
* use `updateItemInBlock`.
|
|
233
|
+
*/
|
|
234
|
+
export declare function upsertItemInBlock(cwd: string, blockName: string, arrayKey: string, item: Record<string, unknown>, idField: string, ctx?: DispatchContext): {
|
|
235
|
+
mode: "appended" | "updated";
|
|
236
|
+
};
|
|
237
|
+
/**
|
|
238
|
+
* Atomically append an item to a nested array inside a parent-array item.
|
|
239
|
+
*
|
|
240
|
+
* Read current file, locate parent-array item by predicate, push `item` onto
|
|
241
|
+
* `data[parentArrayKey][matchedIndex][nestedArrayKey]`, validate whole file
|
|
242
|
+
* against schema, write atomically. Throws if file doesn't exist; if
|
|
243
|
+
* parentArrayKey is missing or not an array; if no parent item matches the
|
|
244
|
+
* predicate; if the matched parent item has no `nestedArrayKey` or it is not
|
|
245
|
+
* an array; or if validation fails. Mirrors updateItemInBlock's structure:
|
|
246
|
+
* file lock, predicate findIndex, multi-match warning, clone-before-write so
|
|
247
|
+
* the original array remains unmodified if writeBlock throws.
|
|
248
|
+
*/
|
|
249
|
+
export declare function appendToNestedArray(cwd: string, blockName: string, parentArrayKey: string, predicate: (item: Record<string, unknown>) => boolean, nestedArrayKey: string, item: unknown, ctx?: DispatchContext): void;
|
|
250
|
+
/**
|
|
251
|
+
* Atomically update a single item inside a nested array on a parent-array
|
|
252
|
+
* item: locate parent by parentPredicate, locate nested by nestedPredicate,
|
|
253
|
+
* shallow-merge `updates` onto the matched nested item, validate the whole
|
|
254
|
+
* file against schema, write atomically. Throws on missing block / missing
|
|
255
|
+
* parent key / parent key not array / no parent match / matched parent
|
|
256
|
+
* missing nestedKey / nested key not array / no nested match / validation
|
|
257
|
+
* failure. Multi-match warnings emit at both parent and nested levels via
|
|
258
|
+
* console.error (mirrors the established appendToNestedArray /
|
|
259
|
+
* updateItemInBlock convention). Clone-then-write keeps the original arrays
|
|
260
|
+
* unmodified if writeBlock throws.
|
|
261
|
+
*/
|
|
262
|
+
export declare function updateNestedArrayItem(cwd: string, blockName: string, parentArrayKey: string, parentPredicate: (item: Record<string, unknown>) => boolean, nestedArrayKey: string, nestedPredicate: (item: Record<string, unknown>) => boolean, updates: Record<string, unknown>, ctx?: DispatchContext): void;
|
|
263
|
+
/**
|
|
264
|
+
* Atomically remove all items matching `predicate` from a top-level array
|
|
265
|
+
* inside `data[arrayKey]`, validate the whole file against schema, write
|
|
266
|
+
* atomically. Returns `{ removed: <count> }`. Throws on missing block /
|
|
267
|
+
* missing key / key not array / validation failure (e.g., schema requires
|
|
268
|
+
* minItems and removal violates it). Returns `{ removed: 0 }` on no match
|
|
269
|
+
* without throwing — removal of a non-existent item is treated as an
|
|
270
|
+
* idempotent successful no-op, distinct from update which throws on miss.
|
|
271
|
+
*/
|
|
272
|
+
export declare function removeFromBlock(cwd: string, blockName: string, arrayKey: string, predicate: (item: Record<string, unknown>) => boolean, ctx?: DispatchContext): {
|
|
273
|
+
removed: number;
|
|
274
|
+
};
|
|
275
|
+
/**
|
|
276
|
+
* Atomically remove all items matching `nestedPredicate` from a nested array
|
|
277
|
+
* inside the parent-array item matched by `parentPredicate`. Validates and
|
|
278
|
+
* writes atomically. Returns `{ removed: <count> }`. Throws on missing block
|
|
279
|
+
* / missing parent key / parent key not array / no parent match / matched
|
|
280
|
+
* parent missing nestedKey / nested key not array / validation failure.
|
|
281
|
+
* Returns `{ removed: 0 }` on no nested match without throwing (idempotent,
|
|
282
|
+
* mirrors removeFromBlock semantics). Multi-match warning at parent level
|
|
283
|
+
* via console.error.
|
|
284
|
+
*/
|
|
285
|
+
export declare function removeFromNestedArray(cwd: string, blockName: string, parentArrayKey: string, parentPredicate: (item: Record<string, unknown>) => boolean, nestedArrayKey: string, nestedPredicate: (item: Record<string, unknown>) => boolean, ctx?: DispatchContext): {
|
|
286
|
+
removed: number;
|
|
287
|
+
};
|
|
288
|
+
/**
|
|
289
|
+
* Read all `.json` files in a `.project/<subdir>/` directory and return the
|
|
290
|
+
* parsed contents as a sorted array. Sort order is filesystem-name ascending
|
|
291
|
+
* (matches Array.sort default on the basename strings). Missing directories
|
|
292
|
+
* return `[]` — on-demand `.project/` subdirectories are valid and represent
|
|
293
|
+
* "no items yet". Throws on filesystem read failure of a present file or on
|
|
294
|
+
* invalid JSON, with file-relative path in the error message. Behavior must
|
|
295
|
+
* match the previous private `executeReadDir` in pi-workflows step-block.ts
|
|
296
|
+
* byte-identically; both pi-workflows and the `read-block-dir` registered
|
|
297
|
+
* tool consume this single export.
|
|
298
|
+
*/
|
|
299
|
+
export declare function readBlockDir(cwd: string, subdir: string): unknown[];
|
|
300
|
+
/**
|
|
301
|
+
* Resolve the item subschema for a block schema: find the first array property
|
|
302
|
+
* carrying `items`, dereferencing a single-level `$ref` to `#/definitions/<x>`
|
|
303
|
+
* or `#/$defs/<x>` (the shape FK-stripped block schemas use, e.g. features /
|
|
304
|
+
* spec-reviews). Returns the array key + the resolved item schema object (with
|
|
305
|
+
* its `properties` / `required` / `id`). Throws when no array property is found
|
|
306
|
+
* or the `$ref` cannot be resolved.
|
|
307
|
+
*
|
|
308
|
+
* FGAP-083: callers that read `items.properties.id.pattern` / `items.required`
|
|
309
|
+
* straight off `props[arrayKey].items` get `undefined` for `$ref` items; this
|
|
310
|
+
* one dereference is the fix shared by auto-id, author-field auto-stamp, and
|
|
311
|
+
* whole-file validation.
|
|
312
|
+
*/
|
|
313
|
+
export declare function resolveBlockItemSchema(schema: Record<string, unknown>): {
|
|
314
|
+
arrayKey: string;
|
|
315
|
+
itemSchema: Record<string, unknown>;
|
|
316
|
+
};
|
|
317
|
+
/**
|
|
318
|
+
* Allocate the next id for a block from its schema's id pattern — canonical and
|
|
319
|
+
* `$ref`-aware (FGAP-084 / FGAP-083). Reads the block schema, resolves the item
|
|
320
|
+
* subschema, parses the `id` pattern's prefix + minimum digit width
|
|
321
|
+
* (`^FGAP-\d{3}$` → `FGAP-`/3; `^TASK-\d{3,}$` → `TASK-`/3), scans existing item
|
|
322
|
+
* ids for the max numeric suffix, and returns `prefix` + zero-padded (maxN+1).
|
|
323
|
+
* Throws when the schema is missing or the id pattern is absent / not
|
|
324
|
+
* prefix+width parseable. Orchestrator CLIs + the in-pi append tool route
|
|
325
|
+
* through this instead of re-implementing allocation.
|
|
326
|
+
*/
|
|
327
|
+
export declare function nextId(cwd: string, blockName: string): string;
|
|
328
|
+
//# sourceMappingURL=block-api.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"block-api.d.ts","sourceRoot":"","sources":["../src/block-api.ts"],"names":[],"mappings":"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"}
|