@gregiteen/ssss-cli 0.10.3 → 0.11.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -7,6 +7,39 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.11.1] - 2026-10-19
11
+ ### Fixed
12
+ - The frontmatter parser (`@gregiteen/ssss-cli/frontmatter`) now reads the YAML
13
+ that Total Recall and other tools actually write. It previously dropped
14
+ hyphenated keys (`allowed-tools`), truncated wrapped values, split quoted
15
+ commas inside inline arrays, left JSON flow maps and arrays of JSON objects
16
+ as strings, turned tags like `context:universal` into maps, and kept
17
+ trailing `# comments`; `patch` then wrote those mis-parsed values back to
18
+ disk. Verified against 27,536 vault files across 55 Total Recall brains: the
19
+ only differences from a js-yaml reading are leading-zero codes and ISO
20
+ timestamps, which SSSS keeps as strings on purpose (spec §4.5).
21
+ - The serializer quotes strings containing commas or a leading indicator and
22
+ writes nested objects inside inline arrays as JSON, so values round-trip.
23
+
24
+ ### Added
25
+ - `scripts/check-frontmatter.mjs`, run by `npm test`.
26
+ - Documents a broken writer flattened onto one line with literal `\n` text
27
+ (23 such vault files exist) are repaired automatically on read, and
28
+ `repairEscapedNewlines` is exported from `@gregiteen/ssss-cli/frontmatter`.
29
+ `scripts/autolink.mjs` now uses the shared frontmatter parser.
30
+
31
+ ## [0.11.0] - 2026-10-13
32
+ ### Added
33
+ - `trigger` gains `event_subject` and `event_match`, and `assistant` gains `owns`.
34
+ `@gregiteen/ssss-cli/runtime` exports `triggerMatchesEvent`, `subjectMatches`
35
+ and `resolveSubjectOwner`; the spec (§11.8) defines event matching and subject
36
+ ownership, which `source: event` previously left undefined.
37
+
38
+ ### Fixed
39
+ - Work caused by an event is now keyed by `event_id` (and carries it as
40
+ `causation_id`), not by the event's timestamp. Two events in the same
41
+ millisecond no longer collapse into one task path and key.
42
+
10
43
  ## [0.10.3] - 2026-10-01
11
44
  ### Fixed
12
45
  - Read event logs in 64 KiB chunks when building duplicate-ID indexes or
package/VERSION CHANGED
@@ -1 +1 @@
1
- 0.10.3
1
+ 0.11.1
@@ -106,7 +106,7 @@
106
106
  "file_count": 14,
107
107
  "provenance": {
108
108
  "content_hash": "sha256:7febd673938a3dc04c068e0bf08097a9783c09e612606d2df9a4db8dcb8907f5",
109
- "exporter": "@gregiteen/ssss-cli@0.10.3"
109
+ "exporter": "@gregiteen/ssss-cli@0.11.1"
110
110
  }
111
111
  },
112
112
  "files": [
package/docs/ssss-spec.md CHANGED
@@ -210,9 +210,21 @@ exactly this subset.
210
210
  under the first. A map entry may itself hold an inline array.
211
211
  - **Folded strings**: `>` and `>-` block scalars.
212
212
 
213
- Anchors, aliases, tags, multi-document streams, and flow maps (`{a: 1}`) are
214
- outside the subset. A host MAY accept them but MUST NOT require them, and
215
- authors SHOULD NOT use them in documents that leave the host.
213
+ Anchors, aliases, tags, and multi-document streams are outside the subset.
214
+ Flow maps (`{a: 1}`) and JSON-style inline values (`[{"a": 1}]`) are also
215
+ outside it, but the reference parser reads them because other tools write them
216
+ (for example Total Recall's JSON-shaped metadata). A host MAY accept any of
217
+ these but MUST NOT require them, and authors SHOULD NOT use them in documents
218
+ that leave the host.
219
+
220
+ Where the reference parser reads a form YAML 1.2 also defines, it follows YAML:
221
+ keys may contain `-`, `.` and `@`; a `:` only splits a key when whitespace or
222
+ end of line follows, so `context:universal` is a value; plain and quoted
223
+ scalars may wrap onto indented continuation lines; a trailing ` # comment` on
224
+ an unquoted value is dropped; and a block list may sit at its key's indent.
225
+ Two deliberate deviations keep values lossless: an integer with a leading zero
226
+ (`07885`) stays a **string**, since it is a code and not a number, and
227
+ timestamps stay strings, as above.
216
228
 
217
229
  ---
218
230
 
@@ -1487,6 +1499,24 @@ Core trigger types are:
1487
1499
  | `file_change` | A matching vault path is created, patched, or deleted. |
1488
1500
  | `condition` | A host-defined predicate over vault/projection state becomes true. |
1489
1501
 
1502
+ An `event` trigger selects canonical events (§8) with two optional fields on the
1503
+ `trigger` primitive, evaluated as a pure function of the trigger and the event:
1504
+
1505
+ - `event_subject` is a glob over the event `subject`. `*` matches within one `/`
1506
+ segment and `**` matches across segments.
1507
+ - `event_match` maps dotted event paths (for example `principal.kind`) to a literal
1508
+ or an array of allowed literals. Every entry MUST hold.
1509
+
1510
+ A trigger with neither field matches nothing. An event nobody matches is only
1511
+ recorded. Work an event causes MUST carry the event's `event_id` as `causation_id`,
1512
+ and its idempotency basis uses `event_id` in place of `scheduled_for`, so a replayed
1513
+ event creates no second task and two events at the same instant create two.
1514
+
1515
+ An `assistant` MAY declare `owns`, a list of subject globs it is responsible for.
1516
+ The owner of a subject is the assistant whose claim has the longest literal prefix.
1517
+ Equal best claims are a conflict that a host MUST surface rather than resolve
1518
+ silently. Ownership says who is responsible; a lease (§7) says who is acting now.
1519
+
1490
1520
  Trigger entries SHOULD use the fields documented in §5.4 `workflow`. Hosts MAY add
1491
1521
  type-specific `x_` fields, but MUST preserve unknown fields when rewriting the
1492
1522
  workflow document (§4.2).
@@ -1497,6 +1527,7 @@ The idempotency basis for runtime-created work is:
1497
1527
 
1498
1528
  ```text
1499
1529
  workspace_id + workflow_id + trigger_id + scheduled_for
1530
+ workspace_id + workflow_id + trigger_id + event_id (event-driven work)
1500
1531
  ```
1501
1532
 
1502
1533
  Two daemon ticks evaluating the same trigger for the same scheduled instant MUST
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gregiteen/ssss-cli",
3
- "version": "0.10.3",
3
+ "version": "0.11.1",
4
4
  "description": "CLI tools and the reference engine for the Structured Semantic Syntax System",
5
5
  "main": "src/engine.mjs",
6
6
  "exports": {
@@ -56,7 +56,7 @@
56
56
  ],
57
57
  "scripts": {
58
58
  "conformance": "node ./scripts/conformance.mjs conformance",
59
- "test": "node ./scripts/conformance.mjs conformance --engine && node ./scripts/check-events-streaming.mjs"
59
+ "test": "node ./scripts/conformance.mjs conformance --engine && node ./scripts/check-events-streaming.mjs && node ./scripts/check-frontmatter.mjs"
60
60
  },
61
61
  "keywords": [
62
62
  "ssss",
@@ -115,6 +115,7 @@
115
115
  "append_only": false,
116
116
  "portability": "structural",
117
117
  "required_fields": ["type", "name"],
118
+ "optional_fields": ["owns"],
118
119
  "spec_ref": "§5.4 assistant"
119
120
  },
120
121
  "workflow": {
@@ -132,7 +133,7 @@
132
133
  "append_only": false,
133
134
  "portability": "structural",
134
135
  "required_fields": ["type", "name", "source", "status"],
135
- "optional_fields": ["slug", "description", "cron", "interval", "timezone", "target_workflow", "target_params", "concurrency", "misfire_policy"],
136
+ "optional_fields": ["slug", "description", "cron", "interval", "timezone", "target_workflow", "target_params", "concurrency", "misfire_policy", "event_subject", "event_match"],
136
137
  "enums": {
137
138
  "source": ["cron", "interval", "webhook", "event", "file_change", "condition", "manual"],
138
139
  "status": ["active", "paused", "disabled"],
@@ -0,0 +1,5 @@
1
+ {
2
+ "$schema": "https://ssss.dev/registry/v1",
3
+ "description": "Extensions composed when a caller does not scope a registry load. Extensions NOT listed here are product-specific: a host loads one only when it is operating on that product's vault, passing the extension name explicitly (`ssss export --ext <name>`). This keeps two unrelated products from colliding on a shared primitive name, which §5.6 makes a load-time error.",
4
+ "default_extensions": ["festech"]
5
+ }