@gregiteen/ssss-cli 0.7.0 → 0.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 +63 -4
- package/README.md +29 -13
- package/VERSION +1 -1
- package/conformance/README.md +17 -11
- package/conformance/fixtures.json +68 -2
- package/conformance/reference-bundle.ucw.json +39 -5
- package/docs/help/bundle.md +6 -2
- package/docs/help/import.md +6 -2
- package/docs/help/leases.md +31 -0
- package/docs/help/localization.md +43 -0
- package/docs/help/overview.md +9 -5
- package/docs/help/portability.md +11 -3
- package/docs/help/runtime.md +3 -3
- package/docs/help/scaffold.md +2 -2
- package/docs/help/semantic.md +37 -0
- package/docs/ssss-spec.md +112 -7
- package/package.json +8 -3
- package/registry/core.json +43 -3
- package/scripts/audit-registry-field-usage.mjs +10 -1
- package/scripts/build-reference-bundle.mjs +25 -2
- package/scripts/cmd-export.mjs +3 -3
- package/scripts/cmd-import.mjs +5 -1
- package/scripts/cmd-localize.mjs +44 -0
- package/scripts/cmd-new.mjs +11 -11
- package/scripts/cmd-semantic.mjs +88 -0
- package/scripts/conformance.mjs +574 -2
- package/scripts/ssss.mjs +6 -2
- package/skills/ssss/SKILL.md +225 -0
- package/skills/ssss/evals/evals.json +37 -0
- package/skills/ssss/references/contract-reference.md +96 -0
- package/skills/ssss/scripts/validate-schema.mjs +258 -0
- package/skills/ssss/subagents/audit-ssss-contract.md +22 -0
- package/src/bundle.mjs +266 -41
- package/src/engine.mjs +78 -4
- package/src/frontmatter.mjs +141 -38
- package/src/registry.mjs +249 -7
- package/src/semantic.mjs +402 -0
package/docs/help/runtime.md
CHANGED
|
@@ -54,11 +54,11 @@ database canonical.
|
|
|
54
54
|
|
|
55
55
|
## Reference helpers
|
|
56
56
|
|
|
57
|
-
Use `@ssss
|
|
57
|
+
Use `@gregiteen/ssss-cli/runtime` when building a host daemon:
|
|
58
58
|
|
|
59
59
|
```js
|
|
60
|
-
import { createEngine } from '@ssss
|
|
61
|
-
import { planWorkflowTrigger } from '@ssss
|
|
60
|
+
import { createEngine } from '@gregiteen/ssss-cli/engine';
|
|
61
|
+
import { planWorkflowTrigger } from '@gregiteen/ssss-cli/runtime';
|
|
62
62
|
|
|
63
63
|
const plan = planWorkflowTrigger({
|
|
64
64
|
workflowPath: 'workflows/daily-digest/WORKFLOW.md',
|
package/docs/help/scaffold.md
CHANGED
|
@@ -13,7 +13,7 @@ ssss new my-app --with-total-recall --install
|
|
|
13
13
|
|
|
14
14
|
```
|
|
15
15
|
my-app/
|
|
16
|
-
package.json @ssss
|
|
16
|
+
package.json @gregiteen/ssss-cli pinned to this CLI's version tag; npm test = node --test
|
|
17
17
|
vault/ Starter SSSS documents:
|
|
18
18
|
rules/welcome.md (structural)
|
|
19
19
|
workflows/onboarding.md (structural, links [[welcome]])
|
|
@@ -38,7 +38,7 @@ provisions, and re-imports idempotently as a `sale` bundle (§16/§17) — with
|
|
|
38
38
|
| `--with-total-recall` | Add `total-recall-brain` + memory wiring to CLAUDE.md/README. |
|
|
39
39
|
| `--install` | Run `npm install`, Total Recall `init` (if requested), then `npm test`. |
|
|
40
40
|
| `--no-git` | Skip `git init`. |
|
|
41
|
-
| `--ref <git-ref>` | Pin `@ssss
|
|
41
|
+
| `--ref <git-ref>` | Pin `@gregiteen/ssss-cli` to a specific tag/branch/SHA (default: this CLI's version tag). |
|
|
42
42
|
| `--force` | Scaffold into a non-empty directory. |
|
|
43
43
|
|
|
44
44
|
Shelling out (git/npm/npx) uses `execFileSync` with fixed argument vectors — no shell,
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# Semantic projection (spec §11.9)
|
|
2
|
+
|
|
3
|
+
SSSS builds a deterministic search and graph projection directly from validated
|
|
4
|
+
Markdown. The projection is disposable: the vault remains the only source of truth.
|
|
5
|
+
|
|
6
|
+
```bash
|
|
7
|
+
ssss semantic ./vault
|
|
8
|
+
ssss semantic ./vault --query "refund policy" --limit 5
|
|
9
|
+
ssss semantic ./vault --locale es --query "política de reembolsos"
|
|
10
|
+
ssss semantic ./vault --locale es --out ./derived/semantic-es.json
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Records include stable identity, source path and hash, type, portability, surface
|
|
14
|
+
text, normalized Unicode tokens, and graph edges derived from `relations`, wiki
|
|
15
|
+
links, and Markdown links. Results use deterministic weighted lexical ranking; hosts
|
|
16
|
+
may fuse embeddings without replacing this interoperable baseline.
|
|
17
|
+
|
|
18
|
+
## Privacy and output safety
|
|
19
|
+
|
|
20
|
+
Only `structural` documents are indexed by default. `tenant_private` and
|
|
21
|
+
`resource_bound` sources require the explicit `--include-private` option and an
|
|
22
|
+
authorized caller. This option can expose customer or operational data; never enable
|
|
23
|
+
it for a public index.
|
|
24
|
+
|
|
25
|
+
`--out` must point to a regular file outside the source vault. Writes are atomic.
|
|
26
|
+
Symlinked vault entries and unsafe paths fail closed.
|
|
27
|
+
|
|
28
|
+
## Library API
|
|
29
|
+
|
|
30
|
+
```js
|
|
31
|
+
import { buildSemanticIndex, searchSemanticIndex } from '@gregiteen/ssss-cli/semantic';
|
|
32
|
+
|
|
33
|
+
const index = buildSemanticIndex('./vault', { locale: 'es' });
|
|
34
|
+
const results = searchSemanticIndex(index, 'reembolsos', { limit: 10 });
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
See also: `ssss help localization`.
|
package/docs/ssss-spec.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# SSSS — Structured Semantic Syntax System
|
|
2
2
|
|
|
3
|
-
**Specification v0.
|
|
3
|
+
**Specification v0.7 — Draft**
|
|
4
4
|
|
|
5
5
|
> This is the canonical, vendor-neutral specification for SSSS. It is the ground
|
|
6
6
|
> truth on which all SSSS implementations are built. It is intended to be vendored
|
|
@@ -31,6 +31,10 @@ SSSS additionally defines the **Operation Contract**: a single, validated, idemp
|
|
|
31
31
|
envelope through which all agent-generated mutations must flow. This makes
|
|
32
32
|
AI-generated state changes deterministic, replayable, conflict-safe, and auditable.
|
|
33
33
|
|
|
34
|
+
Its semantic projection contract turns the same canonical files into a deterministic
|
|
35
|
+
searchable graph, while translation overlays localize natural-language surfaces
|
|
36
|
+
without mutating symbolic control fields or private operational data.
|
|
37
|
+
|
|
34
38
|
Any tool, IDE, agent framework, daemon, or CLI that can read Markdown can
|
|
35
39
|
interoperate with an SSSS vault. The only thing that distinguishes a memory engine,
|
|
36
40
|
a chat runtime, and a workflow orchestrator is *which primitive types they read and
|
|
@@ -124,6 +128,17 @@ For OKF-compatible discovery, SSSS document primitives SHOULD also include:
|
|
|
124
128
|
| `tags` | array | Array of string tags for categorization and routing. |
|
|
125
129
|
| `aliases` | array | Array of alternative names for this concept, used for wiki autolinking. |
|
|
126
130
|
|
|
131
|
+
For stable semantic identity and graph projection, documents SHOULD also include:
|
|
132
|
+
|
|
133
|
+
| Field | Type | Description |
|
|
134
|
+
|-------|------|-------------|
|
|
135
|
+
| `semantic_id` | string | Stable concept identity that survives file moves and localized presentation. |
|
|
136
|
+
| `relations` | array | Explicit semantic edges to other vault-relative document paths or semantic ids. |
|
|
137
|
+
| `locale` | string | BCP-47-style locale of the authored natural-language surface, when known. |
|
|
138
|
+
|
|
139
|
+
`resource`, `tags`, and `aliases` serve both OKF discovery and the semantic layer.
|
|
140
|
+
These fields are recommendations, not new universal requirements.
|
|
141
|
+
|
|
127
142
|
Every primitive type defines its own additional REQUIRED and OPTIONAL fields
|
|
128
143
|
(§5.4). To maintain forward compatibility and allow agents scratchpad space, hosts MUST NOT reject documents containing unknown frontmatter keys. Unknown fields MUST be preserved.
|
|
129
144
|
|
|
@@ -180,6 +195,7 @@ primitive — it implements the subset its product requires — but any primitiv
|
|
|
180
195
|
| `page` | capability | structural | A VFS-native sandboxed custom workspace page. |
|
|
181
196
|
| `migration` | meta | structural | An SSSS schema migration state record. |
|
|
182
197
|
| `release` | meta | structural | An SSSS system schema version release record. |
|
|
198
|
+
| `translation` | localization | structural | A hash-bound, non-destructive localization overlay for a structural source document. |
|
|
183
199
|
|
|
184
200
|
The **Portability** column is the primitive's default portability class (§5.5); a host
|
|
185
201
|
resolves it from `registry/core.json`. Extension registries assign their own primitives a
|
|
@@ -201,7 +217,7 @@ Document primitives are either:
|
|
|
201
217
|
|
|
202
218
|
- **Replace-type** — the whole file represents current state; a write replaces it
|
|
203
219
|
entirely (`memory`, `skill`, `assistant`, `workflow`, `model`, `task`,
|
|
204
|
-
`conflict`).
|
|
220
|
+
`conflict`, `translation`).
|
|
205
221
|
- **Append-type** — the file is an ordered, append-only log; writes add records to
|
|
206
222
|
the body and MUST NOT rewrite prior records (`conversation`, `run`).
|
|
207
223
|
|
|
@@ -545,6 +561,49 @@ released_at: 2026-05-16T12:00:00Z
|
|
|
545
561
|
---
|
|
546
562
|
```
|
|
547
563
|
|
|
564
|
+
#### `translation`
|
|
565
|
+
|
|
566
|
+
A non-destructive localization overlay for one structural source document. A
|
|
567
|
+
translation is itself `structural`, but it does not replace or fork the source. The
|
|
568
|
+
source remains authoritative for identity, behavior, permissions, enums, links, and
|
|
569
|
+
all other symbolic control fields.
|
|
570
|
+
|
|
571
|
+
REQUIRED: `type`, `translation_id`, `source_path`, `source_hash`, `locale`, `status`
|
|
572
|
+
(`draft|reviewed|approved`), and `translated_fields` (a subset of
|
|
573
|
+
`title|description|body`). OPTIONAL: `translated_title`, `translated_description`,
|
|
574
|
+
`translator`, `reviewed_at`. The Markdown body is the translated body when
|
|
575
|
+
`translated_fields` includes `body`.
|
|
576
|
+
|
|
577
|
+
`translation_id`, `source_path`, and `locale` are immutable after creation.
|
|
578
|
+
`source_path` MUST be a safe, vault-relative path to an existing `structural`
|
|
579
|
+
document whose type is not `translation`. `source_hash` MUST equal the source's
|
|
580
|
+
current SHA-256 content hash, written as `sha256:<64 lowercase hex characters>`.
|
|
581
|
+
A stale, missing, private, resource-bound, recursive, traversing, or symlinked source
|
|
582
|
+
MUST be rejected.
|
|
583
|
+
|
|
584
|
+
```markdown
|
|
585
|
+
---
|
|
586
|
+
type: translation
|
|
587
|
+
title: "Política de reembolsos — español"
|
|
588
|
+
description: "Traducción al español de la política de reembolsos."
|
|
589
|
+
timestamp: 2026-07-10T00:00:00Z
|
|
590
|
+
translation_id: refund-policy-es
|
|
591
|
+
source_path: rules/refund-policy.md
|
|
592
|
+
source_hash: sha256:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
|
|
593
|
+
locale: es
|
|
594
|
+
status: approved
|
|
595
|
+
translated_fields: [title, description, body]
|
|
596
|
+
translated_title: "Política de reembolsos"
|
|
597
|
+
translated_description: "Reglas de reembolso para compradores."
|
|
598
|
+
---
|
|
599
|
+
|
|
600
|
+
Los reembolsos están disponibles dentro de los treinta días.
|
|
601
|
+
```
|
|
602
|
+
|
|
603
|
+
Draft and reviewed translations MAY be stored and previewed, but only approved,
|
|
604
|
+
hash-current overlays are applied by default to canonical localized projections
|
|
605
|
+
(§11.9).
|
|
606
|
+
|
|
548
607
|
### 5.5 Portability Classification
|
|
549
608
|
|
|
550
609
|
A workspace is not one undifferentiated blob. Some of it is the **reusable business
|
|
@@ -1042,11 +1101,50 @@ run, plus an event explaining the terminal failure.
|
|
|
1042
1101
|
|
|
1043
1102
|
#### Runtime Helpers
|
|
1044
1103
|
|
|
1045
|
-
The reference package exposes `@ssss
|
|
1104
|
+
The reference package exposes `@gregiteen/ssss-cli/runtime`, including deterministic helpers
|
|
1046
1105
|
for planning a workflow trigger into a `workflow_triggered` event envelope and a
|
|
1047
1106
|
task `operation` envelope. Hosts MAY implement their own daemon, but SHOULD pass the
|
|
1048
1107
|
runtime conformance checks to prove the same source-of-truth and idempotency rules.
|
|
1049
1108
|
|
|
1109
|
+
### 11.9 Semantic Projection & Localization Contract
|
|
1110
|
+
|
|
1111
|
+
The semantic layer is a **derived projection** over validated vault documents. It
|
|
1112
|
+
MUST be deterministic for the same vault bytes, registry set, locale, and projection
|
|
1113
|
+
options. It MUST NOT become a second source of truth.
|
|
1114
|
+
|
|
1115
|
+
Each projected record SHOULD expose a stable identity, source path and content hash,
|
|
1116
|
+
primitive type, portability class, surface text, normalized search tokens, and graph
|
|
1117
|
+
edges. Identity is resolved from `semantic_id`, then `resource`, then the source path.
|
|
1118
|
+
Edges are derived from explicit `relations`, wiki links, and Markdown links. Hosts MAY
|
|
1119
|
+
add embeddings or richer ranking, but the exact lexical/graph projection MUST remain
|
|
1120
|
+
available as a dependency-free interoperability baseline.
|
|
1121
|
+
|
|
1122
|
+
The safe default projection contains only `structural` documents. It MUST exclude
|
|
1123
|
+
`tenant_private` and `resource_bound` documents unless the caller explicitly enables
|
|
1124
|
+
private indexing in an authorized context. A localized export MUST use the same safe
|
|
1125
|
+
default, so requesting a locale can never implicitly disclose conversations, runs,
|
|
1126
|
+
tasks, credentials, customer data, or bound resource values.
|
|
1127
|
+
|
|
1128
|
+
When a locale is requested, the host MAY apply one eligible `translation` (§5.4) per
|
|
1129
|
+
source. Eligibility requires all of the following:
|
|
1130
|
+
|
|
1131
|
+
1. The overlay locale normalizes to the requested locale.
|
|
1132
|
+
2. Its status is `approved`, unless a caller explicitly opts into draft preview.
|
|
1133
|
+
3. The source is an existing, non-symlinked `structural` document.
|
|
1134
|
+
4. `source_hash` exactly matches the current source bytes.
|
|
1135
|
+
5. There is no second eligible overlay for the same source and locale.
|
|
1136
|
+
|
|
1137
|
+
An overlay may replace only `title`, `description`, and body. It MUST preserve `type`,
|
|
1138
|
+
paths, ids, enums, status, permissions, portability, relations, and every other
|
|
1139
|
+
symbolic field from the source. Stale hashes, duplicate overlays, traversal, symlink
|
|
1140
|
+
targets, recursive translations, and translations of non-structural sources MUST
|
|
1141
|
+
fail closed.
|
|
1142
|
+
|
|
1143
|
+
A materialized locale is a disposable projection, not a translated vault. It MUST be
|
|
1144
|
+
written outside the source vault to a new or empty non-symlinked directory, preserve
|
|
1145
|
+
source-relative paths, and include enough projection metadata to identify its locale
|
|
1146
|
+
and source hashes. It may be deleted and rebuilt at any time.
|
|
1147
|
+
|
|
1050
1148
|
---
|
|
1051
1149
|
|
|
1052
1150
|
## 12. Conformance
|
|
@@ -1061,6 +1159,11 @@ Fixtures are distributed as a JSON document carrying:
|
|
|
1061
1159
|
- `idempotency` — TTL and replay behavior.
|
|
1062
1160
|
- `validation_rules` — envelope and content rules.
|
|
1063
1161
|
- `runtime_contract` — trigger vocabulary and daemon idempotency rules (§11.8).
|
|
1162
|
+
- registry-extension checks — schema shape, regex validity, symlink rejection, and
|
|
1163
|
+
core/sibling collision rejection.
|
|
1164
|
+
- semantic/localization checks — deterministic indexing, privacy defaults, graph
|
|
1165
|
+
edges, exact source hashes, immutable overlay identity, and safe materialization
|
|
1166
|
+
(§11.9).
|
|
1064
1167
|
- `fixtures[]` — each with a `request`, an `expected_response`, and an
|
|
1065
1168
|
OPTIONAL `expected_http_status`.
|
|
1066
1169
|
- `error_codes` — the canonical code table.
|
|
@@ -1068,7 +1171,8 @@ Fixtures are distributed as a JSON document carrying:
|
|
|
1068
1171
|
The conformance fixture set is the shared test contract between all SSSS
|
|
1069
1172
|
implementations. A host MUST NOT claim SSSS conformance without passing the current
|
|
1070
1173
|
fixture set. Hosts implementing workflow daemons SHOULD also run the reference
|
|
1071
|
-
runtime checks exposed by `@ssss
|
|
1174
|
+
runtime checks exposed by `@gregiteen/ssss-cli/runtime`. Hosts exposing semantic
|
|
1175
|
+
search or localized projections MUST also pass the §11.9 checks.
|
|
1072
1176
|
|
|
1073
1177
|
---
|
|
1074
1178
|
|
|
@@ -1096,7 +1200,7 @@ opaque ID as the slug and keep the human-readable label in `title` / `name`.
|
|
|
1096
1200
|
This document is versioned independently of any host and of the conformance
|
|
1097
1201
|
fixture set.
|
|
1098
1202
|
|
|
1099
|
-
- The spec version is stated in the document header (currently **v0.
|
|
1203
|
+
- The spec version is stated in the document header (currently **v0.7 — Draft**).
|
|
1100
1204
|
- Breaking changes to the file format, the type registry, or the Operation
|
|
1101
1205
|
Contract increment the spec version.
|
|
1102
1206
|
- Until **v1.0**, any version MAY introduce breaking changes.
|
|
@@ -1208,7 +1312,7 @@ them without a spec change.
|
|
|
1208
1312
|
serialization of `files` (path-sorted, §16.1). An importer MUST recompute it and reject
|
|
1209
1313
|
a bundle whose files do not match. This is what makes a bundle tamper-evident and what a
|
|
1210
1314
|
marketplace lists against.
|
|
1211
|
-
- `exporter` — an identifier for the tool/host that produced the bundle (`"@ssss
|
|
1315
|
+
- `exporter` — an identifier for the tool/host that produced the bundle (`"@gregiteen/ssss-cli@0.8.0"`).
|
|
1212
1316
|
- `signature` — OPTIONAL detached signature over `content_hash` for a sold bundle, so a
|
|
1213
1317
|
buyer can verify authorship. Unsigned bundles are valid; signing is a marketplace concern.
|
|
1214
1318
|
|
|
@@ -1313,7 +1417,8 @@ cannot resolve a link MUST fail the provision rather than emit a dangling refere
|
|
|
1313
1417
|
|
|
1314
1418
|
The following frontmatter keys are reserved by this spec across all primitives and
|
|
1315
1419
|
MUST NOT be repurposed by hosts: `type`, `slug`, `schema_version`, `status`,
|
|
1316
|
-
`feedback`, `confidence
|
|
1420
|
+
`feedback`, `confidence`, `semantic_id`, `relations`, `locale`, `translation_id`,
|
|
1421
|
+
`source_path`, `source_hash`, and `translated_fields`.
|
|
1317
1422
|
|
|
1318
1423
|
Hosts adding their own frontmatter fields SHOULD prefix them `x_` to remain
|
|
1319
1424
|
forward-compatible with future spec revisions.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gregiteen/ssss-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0",
|
|
4
4
|
"description": "CLI tools and the reference engine for the Structured Semantic Syntax System",
|
|
5
5
|
"main": "src/engine.mjs",
|
|
6
6
|
"exports": {
|
|
@@ -10,13 +10,14 @@
|
|
|
10
10
|
"./registry": "./src/registry.mjs",
|
|
11
11
|
"./frontmatter": "./src/frontmatter.mjs",
|
|
12
12
|
"./bundle": "./src/bundle.mjs",
|
|
13
|
+
"./semantic": "./src/semantic.mjs",
|
|
13
14
|
"./conformance/fixtures.json": "./conformance/fixtures.json",
|
|
14
15
|
"./conformance/reference-bundle.ucw.json": "./conformance/reference-bundle.ucw.json",
|
|
15
16
|
"./registry/core.json": "./registry/core.json",
|
|
16
17
|
"./package.json": "./package.json"
|
|
17
18
|
},
|
|
18
19
|
"bin": {
|
|
19
|
-
"ssss": "
|
|
20
|
+
"ssss": "scripts/ssss.mjs"
|
|
20
21
|
},
|
|
21
22
|
"type": "module",
|
|
22
23
|
"engines": {
|
|
@@ -29,6 +30,7 @@
|
|
|
29
30
|
"conformance",
|
|
30
31
|
"docs/ssss-spec.md",
|
|
31
32
|
"docs/help",
|
|
33
|
+
"skills/ssss",
|
|
32
34
|
"VERSION",
|
|
33
35
|
"README.md",
|
|
34
36
|
"CHANGELOG.md",
|
|
@@ -46,7 +48,10 @@
|
|
|
46
48
|
"vault",
|
|
47
49
|
"operation-contract",
|
|
48
50
|
"ucw",
|
|
49
|
-
"provisioning"
|
|
51
|
+
"provisioning",
|
|
52
|
+
"semantic-search",
|
|
53
|
+
"localization",
|
|
54
|
+
"translation"
|
|
50
55
|
],
|
|
51
56
|
"author": "Greg Iteen",
|
|
52
57
|
"license": "ISC",
|
package/registry/core.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://ssss.dev/registry/v1",
|
|
3
3
|
"registry": "core",
|
|
4
|
-
"spec_version": "0.
|
|
5
|
-
"description": "The canonical SSSS core primitive registry. These
|
|
4
|
+
"spec_version": "0.7",
|
|
5
|
+
"description": "The canonical SSSS core primitive registry. These 15 document primitives and 5 contract primitives are defined by the SSSS specification (docs/ssss-spec.md §5) and are owned by this standard. Every document primitive declares a portability class (§5.5); the registry also defines the workflow runtime contract (§11.8), semantic/localization contract (§11.9), `.ucw` bundle format (§16), and provisioning contract (§17). A conformant host MUST implement any core primitive it uses according to this registry. Applications extend the core with their own primitives via an extension registry; extensions MUST NOT redefine a core or sibling-extension type.",
|
|
6
6
|
"conformance": "A host is core-conformant for a primitive if a file of that type validates exactly when all required_fields are present and non-empty, and (for append_only types) writes only append.",
|
|
7
7
|
|
|
8
8
|
"document_primitives": {
|
|
@@ -136,6 +136,34 @@
|
|
|
136
136
|
"portability": "structural",
|
|
137
137
|
"required_fields": ["type", "release_id", "version", "schema_version", "summary", "released_at"],
|
|
138
138
|
"spec_ref": "§5.4 release"
|
|
139
|
+
},
|
|
140
|
+
"translation": {
|
|
141
|
+
"family": "localization",
|
|
142
|
+
"canonical_path": "translations/<locale>/<source-path>.md",
|
|
143
|
+
"append_only": false,
|
|
144
|
+
"portability": "structural",
|
|
145
|
+
"required_fields": ["type", "translation_id", "source_path", "source_hash", "locale", "status", "translated_fields"],
|
|
146
|
+
"optional_fields": ["translated_title", "translated_description", "translator", "reviewed_at"],
|
|
147
|
+
"immutable_fields": ["translation_id", "source_path", "locale"],
|
|
148
|
+
"enums": {
|
|
149
|
+
"status": ["draft", "reviewed", "approved"],
|
|
150
|
+
"translated_fields": ["title", "description", "body"]
|
|
151
|
+
},
|
|
152
|
+
"patterns": {
|
|
153
|
+
"translation_id": "^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$",
|
|
154
|
+
"locale": "^[A-Za-z]{2,3}(?:-[A-Za-z0-9]{2,8})*$",
|
|
155
|
+
"source_hash": "^sha256:[a-f0-9]{64}$"
|
|
156
|
+
},
|
|
157
|
+
"references": {
|
|
158
|
+
"source_path": {
|
|
159
|
+
"must_exist": true,
|
|
160
|
+
"disallowed_types": ["translation"],
|
|
161
|
+
"allowed_portability": ["structural"],
|
|
162
|
+
"hash_field": "source_hash"
|
|
163
|
+
}
|
|
164
|
+
},
|
|
165
|
+
"notes": "A non-destructive presentation overlay. Only title, description, and body may be translated; symbolic control fields remain byte-for-byte sourced from the referenced structural document.",
|
|
166
|
+
"spec_ref": "§5.4 translation"
|
|
139
167
|
}
|
|
140
168
|
},
|
|
141
169
|
|
|
@@ -150,6 +178,7 @@
|
|
|
150
178
|
"universal_frontmatter": {
|
|
151
179
|
"required": ["type", "title", "description", "timestamp"],
|
|
152
180
|
"recommended_okf": ["resource", "tags", "aliases"],
|
|
181
|
+
"recommended_semantic": ["semantic_id", "resource", "tags", "aliases", "relations", "locale"],
|
|
153
182
|
"spec_ref": "§4.2"
|
|
154
183
|
},
|
|
155
184
|
|
|
@@ -219,7 +248,18 @@
|
|
|
219
248
|
"spec_ref": "§11.8"
|
|
220
249
|
},
|
|
221
250
|
|
|
222
|
-
"
|
|
251
|
+
"semantic": {
|
|
252
|
+
"version": 1,
|
|
253
|
+
"identity_fields": ["semantic_id", "resource", "type", "path"],
|
|
254
|
+
"surface_fields": ["title", "description", "name", "slug", "aliases", "tags"],
|
|
255
|
+
"relation_fields": ["relations", "wiki_links", "markdown_links"],
|
|
256
|
+
"translatable_fields": ["title", "description", "body"],
|
|
257
|
+
"locale_pattern": "^[A-Za-z]{2,3}(?:-[A-Za-z0-9]{2,8})*$",
|
|
258
|
+
"safe_default": "Semantic indexes exclude tenant_private and resource_bound documents unless include_private is explicitly enabled. Translation overlays may reference structural sources only.",
|
|
259
|
+
"spec_ref": "§11.9"
|
|
260
|
+
},
|
|
261
|
+
|
|
262
|
+
"reserved_keys": ["type", "slug", "schema_version", "status", "feedback", "confidence", "semantic_id", "locale", "translation_of", "translation_source_hash"],
|
|
223
263
|
"host_field_prefix": "x_",
|
|
224
264
|
"spec_ref_reserved": "Appendix A"
|
|
225
265
|
}
|
|
@@ -37,7 +37,15 @@ const ENGINE_FILES = [
|
|
|
37
37
|
// spec §6.3 + §9). If a primitive declares one, the engine source MUST
|
|
38
38
|
// reference it — otherwise the registry is making a promise the engine
|
|
39
39
|
// doesn't keep.
|
|
40
|
-
const ENGINE_ENFORCED_KEYS = [
|
|
40
|
+
const ENGINE_ENFORCED_KEYS = [
|
|
41
|
+
'required_fields',
|
|
42
|
+
'required_when',
|
|
43
|
+
'enums',
|
|
44
|
+
'patterns',
|
|
45
|
+
'immutable_fields',
|
|
46
|
+
'references',
|
|
47
|
+
'append_only',
|
|
48
|
+
];
|
|
41
49
|
|
|
42
50
|
// Keys that are real and load-bearing but are intentionally consumed
|
|
43
51
|
// elsewhere (export/bundle time, documentation, or the registry loader
|
|
@@ -75,6 +83,7 @@ function engineReferencesKey(engineSources, key) {
|
|
|
75
83
|
const patterns = [
|
|
76
84
|
new RegExp(`\\bdef\\.${key}\\b`),
|
|
77
85
|
new RegExp(`\\btypeDef\\.${key}\\b`),
|
|
86
|
+
new RegExp(`(?:\\.|\\?\\.)${key}\\b`),
|
|
78
87
|
new RegExp(`\\['${key}'\\]`),
|
|
79
88
|
new RegExp(`\\["${key}"\\]`),
|
|
80
89
|
];
|
|
@@ -15,10 +15,14 @@ import os from 'node:os';
|
|
|
15
15
|
import path from 'node:path';
|
|
16
16
|
import { fileURLToPath } from 'node:url';
|
|
17
17
|
import { exportBundle, validateBundle } from '../src/bundle.mjs';
|
|
18
|
+
import { documentHash } from '../src/registry.mjs';
|
|
18
19
|
import { generateIndexes } from './autolink.mjs';
|
|
19
20
|
|
|
20
21
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
21
22
|
const OUT = path.resolve(__dirname, '..', 'conformance', 'reference-bundle.ucw.json');
|
|
23
|
+
const PACKAGE = JSON.parse(
|
|
24
|
+
fs.readFileSync(path.resolve(__dirname, '..', 'package.json'), 'utf8')
|
|
25
|
+
);
|
|
22
26
|
|
|
23
27
|
// ─── The reference vault ────────────────────────────────────────────────────
|
|
24
28
|
const VAULT = {
|
|
@@ -104,11 +108,30 @@ description: Private support task for an attendee seat-change request.
|
|
|
104
108
|
timestamp: 2026-07-02T00:00:00Z
|
|
105
109
|
priority: high
|
|
106
110
|
category: support
|
|
107
|
-
status:
|
|
111
|
+
status: pending
|
|
108
112
|
---
|
|
109
113
|
Attendee jane@example.com requested a seat change.`,
|
|
110
114
|
};
|
|
111
115
|
|
|
116
|
+
// Structural translation overlay — hash-bound to the exact source document and
|
|
117
|
+
// applied only by the semantic/localization projection (§11.9).
|
|
118
|
+
VAULT['translations/es/rules/refund-policy.md'] =
|
|
119
|
+
`---
|
|
120
|
+
type: translation
|
|
121
|
+
title: Spanish Refund Policy Translation
|
|
122
|
+
description: Approved Spanish presentation overlay for the festival refund policy.
|
|
123
|
+
timestamp: 2026-07-10T00:00:00Z
|
|
124
|
+
translation_id: refund-policy-es
|
|
125
|
+
source_path: rules/refund-policy.md
|
|
126
|
+
source_hash: ${documentHash(VAULT['rules/refund-policy.md'])}
|
|
127
|
+
locale: es
|
|
128
|
+
status: approved
|
|
129
|
+
translated_fields: [title, description, body]
|
|
130
|
+
translated_title: Política de reembolsos
|
|
131
|
+
translated_description: Explica cuándo están disponibles los reembolsos para asistentes.
|
|
132
|
+
---
|
|
133
|
+
Los reembolsos están disponibles hasta catorce días antes del evento.`;
|
|
134
|
+
|
|
112
135
|
function buildVault() {
|
|
113
136
|
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'ssss-refvault-'));
|
|
114
137
|
const files = [];
|
|
@@ -134,7 +157,7 @@ try {
|
|
|
134
157
|
name: 'Festival in a Box',
|
|
135
158
|
description: 'A complete music-festival operation as a tradeable SSSS bundle.',
|
|
136
159
|
version: '1.0.0',
|
|
137
|
-
exporter:
|
|
160
|
+
exporter: `${PACKAGE.name}@${PACKAGE.version}`,
|
|
138
161
|
requiredExtensions: ['festech'],
|
|
139
162
|
parameters: [
|
|
140
163
|
{ key: 'business_name', label: 'Festival name', type: 'string', scope: 'workspace', source: 'user', required: true },
|
package/scripts/cmd-export.mjs
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
import fs from 'node:fs';
|
|
9
9
|
import path from 'node:path';
|
|
10
|
-
import { exportBundle } from '../src/bundle.mjs';
|
|
10
|
+
import { DEFAULT_EXPORTER, exportBundle } from '../src/bundle.mjs';
|
|
11
11
|
import { parseArgs, usage, die, wantsHelp } from './lib/cli.mjs';
|
|
12
12
|
|
|
13
13
|
const HELP = usage({
|
|
@@ -19,7 +19,7 @@ const HELP = usage({
|
|
|
19
19
|
['--name <s>', 'Bundle display name.'],
|
|
20
20
|
['--description <s>', 'Bundle description.'],
|
|
21
21
|
['--bundle-version <s>', 'Bundle version string (default: 0.1.0).'],
|
|
22
|
-
['--exporter <s>',
|
|
22
|
+
['--exporter <s>', `Exporter id recorded in provenance (default: ${DEFAULT_EXPORTER}).`],
|
|
23
23
|
['--ext <name>', 'Declare a required extension registry (repeatable).'],
|
|
24
24
|
['--exported-at <iso>', 'Override the export timestamp (default: epoch, for determinism).'],
|
|
25
25
|
['--registry <dir>', 'Registry directory (default: the package core registry).'],
|
|
@@ -50,7 +50,7 @@ export async function run(argv) {
|
|
|
50
50
|
name: flags.name || path.basename(path.resolve(vault)),
|
|
51
51
|
description: flags.description || '',
|
|
52
52
|
version: flags['bundle-version'] || '0.1.0',
|
|
53
|
-
exporter: flags.exporter ||
|
|
53
|
+
exporter: flags.exporter || DEFAULT_EXPORTER,
|
|
54
54
|
requiredExtensions: flags.ext || [],
|
|
55
55
|
...(flags['exported-at'] ? { exportedAt: flags['exported-at'] } : {}),
|
|
56
56
|
});
|
package/scripts/cmd-import.mjs
CHANGED
|
@@ -63,7 +63,11 @@ export async function run(argv) {
|
|
|
63
63
|
const engine = createEngine({ registryDir: flags.registry });
|
|
64
64
|
const result = importBundle(envelopes, vault, engine);
|
|
65
65
|
const failed = result.results.filter((r) => !r.success);
|
|
66
|
-
|
|
66
|
+
if (flags['dry-run']) {
|
|
67
|
+
console.log(`${result.ok ? '✓' : '✗'} import dry-run — ${result.wouldCommit || 0} would commit, ${envelopes.length - (result.wouldCommit || 0)} unchanged (idempotent), ${failed.length} failed → ${vault}`);
|
|
68
|
+
} else {
|
|
69
|
+
console.log(`${result.ok ? '✓' : '✗'} import — ${result.committed} committed, ${envelopes.length - result.committed} unchanged (idempotent), ${failed.length} failed → ${vault}`);
|
|
70
|
+
}
|
|
67
71
|
if (failed.length) {
|
|
68
72
|
for (const r of failed) console.error(` ✗ ${r.path}: ${(r.validation?.errors || []).join('; ')}`);
|
|
69
73
|
process.exit(1);
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/** `ssss localize` — materialize a non-destructive locale projection. */
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { materializeLocale } from '../src/semantic.mjs';
|
|
4
|
+
import { parseArgs, usage, die, wantsHelp } from './lib/cli.mjs';
|
|
5
|
+
|
|
6
|
+
const HELP = usage({
|
|
7
|
+
summary: 'Materialize approved translation overlays as a derived vault projection (spec §11.9).',
|
|
8
|
+
usage: 'ssss localize <vault-dir> --locale <tag> --out <empty-dir> [options]',
|
|
9
|
+
options: [
|
|
10
|
+
['--locale <tag>', 'Required BCP47-style target locale.'],
|
|
11
|
+
['--out <dir>', 'Required empty directory outside the source vault.'],
|
|
12
|
+
['--include-private', 'Explicitly include private/resource-bound source documents.'],
|
|
13
|
+
['--include-drafts', 'Allow non-approved translation overlays.'],
|
|
14
|
+
['--registry <dir>', 'Registry directory (default: package registry).'],
|
|
15
|
+
],
|
|
16
|
+
examples: [
|
|
17
|
+
'ssss localize ./vault --locale es --out ./derived/es',
|
|
18
|
+
],
|
|
19
|
+
seeAlso: ['ssss semantic', 'ssss help localization'],
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
export async function run(argv) {
|
|
23
|
+
if (wantsHelp(argv)) { console.log(HELP); return; }
|
|
24
|
+
const { positionals, flags } = parseArgs(argv, {
|
|
25
|
+
booleans: ['include-private', 'include-drafts'],
|
|
26
|
+
});
|
|
27
|
+
const vault = positionals[0];
|
|
28
|
+
if (!vault || !flags.locale || !flags.out) die('localize requires a vault, --locale, and --out.\n\n' + HELP);
|
|
29
|
+
try {
|
|
30
|
+
const manifest = materializeLocale(
|
|
31
|
+
path.resolve(vault),
|
|
32
|
+
flags.locale,
|
|
33
|
+
path.resolve(flags.out),
|
|
34
|
+
{
|
|
35
|
+
includePrivate: !!flags['include-private'],
|
|
36
|
+
includeDrafts: !!flags['include-drafts'],
|
|
37
|
+
registryDir: flags.registry,
|
|
38
|
+
}
|
|
39
|
+
);
|
|
40
|
+
process.stdout.write(JSON.stringify(manifest, null, 2) + '\n');
|
|
41
|
+
} catch (error) {
|
|
42
|
+
die(error.message);
|
|
43
|
+
}
|
|
44
|
+
}
|
package/scripts/cmd-new.mjs
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* `ssss new` — scaffold a fresh repo wired for SSSS (and, optionally, Total Recall).
|
|
3
3
|
*
|
|
4
4
|
* Produces a ready-to-run project: a starter `vault/` of core primitives, the
|
|
5
|
-
* `@ssss
|
|
5
|
+
* `@gregiteen/ssss-cli` dependency pinned to this CLI's own version tag, a dependency-free
|
|
6
6
|
* conformance test (`node --test`) that replays the canonical fixtures through the
|
|
7
7
|
* engine AND round-trips the vault as a `sale` bundle, plus a CLAUDE.md describing
|
|
8
8
|
* the conventions. With `--with-total-recall` it also wires the Total Recall
|
|
@@ -31,7 +31,7 @@ const HELP = usage({
|
|
|
31
31
|
['--with-total-recall', 'Also wire the Total Recall memory OS (total-recall-brain).'],
|
|
32
32
|
['--install', 'Run `npm install` after scaffolding (and Total Recall init if requested).'],
|
|
33
33
|
['--no-git', 'Do not run `git init`.'],
|
|
34
|
-
['--ref <git-ref>', `Pin @ssss
|
|
34
|
+
['--ref <git-ref>', `Pin @gregiteen/ssss-cli to this ref (default: v${VERSION}).`],
|
|
35
35
|
['--force', 'Allow scaffolding into a non-empty directory.'],
|
|
36
36
|
],
|
|
37
37
|
examples: [
|
|
@@ -81,7 +81,7 @@ export async function run(argv) {
|
|
|
81
81
|
export: 'ssss export vault --profile sale --out dist/bundle.ucw.json',
|
|
82
82
|
validate: 'ssss conformance --engine',
|
|
83
83
|
},
|
|
84
|
-
dependencies: { '@ssss
|
|
84
|
+
dependencies: { '@gregiteen/ssss-cli': `github:gregiteen/ssss#${ref}` },
|
|
85
85
|
...(withTR ? { devDependencies: { 'total-recall-brain': 'latest' } } : {}),
|
|
86
86
|
};
|
|
87
87
|
W(root, 'package.json', JSON.stringify(pkg, null, 2) + '\n');
|
|
@@ -94,7 +94,7 @@ export async function run(argv) {
|
|
|
94
94
|
W(root, 'vault/assistants/concierge.md',
|
|
95
95
|
'---\ntype: assistant\ntitle: Concierge\ndescription: Starter assistant definition for the project.\ntimestamp: 2026-07-02T00:00:00Z\nname: Concierge\n---\n\n# Concierge\n\nA starter assistant definition.\n');
|
|
96
96
|
W(root, 'vault/tasks/first-task.md',
|
|
97
|
-
'---\ntype: task\ntitle: First Task\ndescription: Starter private setup task that demonstrates tenant_private filtering.\ntimestamp: 2026-07-02T00:00:00Z\npriority: normal\ncategory: setup\nstatus:
|
|
97
|
+
'---\ntype: task\ntitle: First Task\ndescription: Starter private setup task that demonstrates tenant_private filtering.\ntimestamp: 2026-07-02T00:00:00Z\npriority: normal\ncategory: setup\nstatus: pending\n---\n\n# First task\n\nThis is `tenant_private` (§5.5) — it is **dropped** from `template`/`sale` exports.\n');
|
|
98
98
|
|
|
99
99
|
// ── conformance test (zero-dependency: node --test) ─────────────────────
|
|
100
100
|
W(root, 'test/ssss-conformance.test.mjs', CONFORMANCE_TEST);
|
|
@@ -107,7 +107,7 @@ export async function run(argv) {
|
|
|
107
107
|
// ── git + install (best-effort, flag-gated, no shell) ───────────────────
|
|
108
108
|
const log = (m) => console.error(m);
|
|
109
109
|
log(`Scaffolded SSSS project → ${root}`);
|
|
110
|
-
log(` @ssss
|
|
110
|
+
log(` @gregiteen/ssss-cli pinned to github:gregiteen/ssss#${ref}`);
|
|
111
111
|
if (withTR) log(' Total Recall wired (total-recall-brain).');
|
|
112
112
|
|
|
113
113
|
if (!flags['no-git'] && !fs.existsSync(path.join(root, '.git'))) {
|
|
@@ -153,11 +153,11 @@ import fs from 'node:fs';
|
|
|
153
153
|
import os from 'node:os';
|
|
154
154
|
import path from 'node:path';
|
|
155
155
|
import { fileURLToPath } from 'node:url';
|
|
156
|
-
import { createEngine } from '@ssss
|
|
157
|
-
import { exportBundle, validateBundle, provisionBundle, importBundle } from '@ssss
|
|
156
|
+
import { createEngine } from '@gregiteen/ssss-cli/engine';
|
|
157
|
+
import { exportBundle, validateBundle, provisionBundle, importBundle } from '@gregiteen/ssss-cli/bundle';
|
|
158
158
|
|
|
159
159
|
const require = createRequire(import.meta.url);
|
|
160
|
-
const { fixtures } = require('@ssss
|
|
160
|
+
const { fixtures } = require('@gregiteen/ssss-cli/conformance/fixtures.json');
|
|
161
161
|
const VAULT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..', 'vault');
|
|
162
162
|
|
|
163
163
|
test('engine implements the canonical Operation Contract (spec §6)', () => {
|
|
@@ -199,7 +199,7 @@ function readme(name, withTR) {
|
|
|
199
199
|
return `# ${name}
|
|
200
200
|
|
|
201
201
|
An [SSSS](https://github.com/gregiteen/ssss)-native project: a Markdown **vault** is
|
|
202
|
-
the source of truth, validated and packaged by the dependency-free \`@ssss
|
|
202
|
+
the source of truth, validated and packaged by the dependency-free \`@gregiteen/ssss-cli\`.
|
|
203
203
|
|
|
204
204
|
## Layout
|
|
205
205
|
|
|
@@ -240,9 +240,9 @@ This repo uses **SSSS** (Structured Semantic Syntax System) as its state contrac
|
|
|
240
240
|
|
|
241
241
|
## Source of truth
|
|
242
242
|
- \`vault/\` is the only source of truth — typed Markdown documents with YAML
|
|
243
|
-
frontmatter. Every file declares a \`type\` defined in the \`@ssss
|
|
243
|
+
frontmatter. Every file declares a \`type\` defined in the \`@gregiteen/ssss-cli\` core registry.
|
|
244
244
|
- Mutate the vault through the standard, not by hand-writing files in bulk:
|
|
245
|
-
\`npx ssss\` for bundle/tenant tooling, or the \`@ssss
|
|
245
|
+
\`npx ssss\` for bundle/tenant tooling, or the \`@gregiteen/ssss-cli/engine\` Operation Contract
|
|
246
246
|
in code.
|
|
247
247
|
|
|
248
248
|
## Portability (§5.5) — the rule that matters
|