skillscript-runtime 0.27.0 → 0.27.2

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.
Files changed (26) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/README.md +5 -1
  3. package/dist/cli.js +6 -2
  4. package/dist/cli.js.map +1 -1
  5. package/dist/errors.js +2 -2
  6. package/dist/errors.js.map +1 -1
  7. package/dist/help-content.js +5 -5
  8. package/docs/adopter-playbook.md +4 -6
  9. package/docs/configuration.md +1 -0
  10. package/docs/language-reference.md +127 -156
  11. package/examples/connectors/DataStoreTemplate/DataStoreTemplate.ts +14 -0
  12. package/examples/onboarding-scaffold/file-data-store.ts +13 -2
  13. package/examples/onboarding-scaffold/openai-local-model.ts +3 -1
  14. package/examples/onboarding-scaffold/tmux-shell-agent-connector.ts +41 -5
  15. package/examples/skillscripts/classify-support-ticket.skill.provenance.json +10 -0
  16. package/examples/skillscripts/data-store-roundtrip.skill.provenance.json +10 -0
  17. package/examples/skillscripts/doc-qa-with-citations.skill.provenance.json +10 -0
  18. package/examples/skillscripts/feedback-sentiment-scan.skill.provenance.json +10 -0
  19. package/examples/skillscripts/hello-world.skill.provenance.json +1 -1
  20. package/examples/skillscripts/morning-brief.skill.md +5 -6
  21. package/examples/skillscripts/morning-brief.skill.provenance.json +10 -0
  22. package/examples/skillscripts/queue-length-monitor.skill.provenance.json +10 -0
  23. package/examples/skillscripts/service-health-watch.skill.provenance.json +10 -0
  24. package/examples/skillscripts/skill-store-roundtrip.skill.provenance.json +10 -0
  25. package/examples/skillscripts/youtrack-morning-sweep.skill.provenance.json +10 -0
  26. package/package.json +1 -1
@@ -165,4 +165,18 @@ export class DataStoreTemplate implements DataStore {
165
165
  // - Return { id, created_at }
166
166
  throw new Error("TODO: write() — persist record; return { id, created_at }.");
167
167
  }
168
+
169
+ /**
170
+ * Direct lookup by substrate-assigned id (v0.13.8 — lets `data_read`
171
+ * inspect a record without a query roundtrip). Return `null` when the id
172
+ * isn't found — do NOT throw; null-on-miss is the DataStore convention
173
+ * (contrast SkillStore, which throws `SkillNotFoundError`). Substrates
174
+ * without a native by-id lookup can implement via a filtered query, but
175
+ * the null semantics must hold.
176
+ */
177
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
178
+ async get(_id: string): Promise<PortableData | null> {
179
+ // TODO — fetch one record by id from your substrate; null when missing.
180
+ throw new Error("TODO: get() — return the record for this id, or null.");
181
+ }
168
182
  }
@@ -5,7 +5,7 @@
5
5
  // their concrete substrate (e.g., swap the JSON file for a Postgres
6
6
  // table, the substring match for actual full-text search, etc.).
7
7
  //
8
- // **Scope.** Implements `query()` + `write()` per the DataStore contract.
8
+ // **Scope.** Implements `query()` + `write()` + `get()` per the DataStore contract.
9
9
 
10
10
  import { readFileSync, existsSync, writeFileSync } from "node:fs";
11
11
  import { randomUUID } from "node:crypto";
@@ -35,7 +35,9 @@ export class FileDataStore implements DataStore {
35
35
  implementation: "FileDataStore",
36
36
  contract_version: "1.0.0",
37
37
  features: {
38
- supports_fts: true,
38
+ // FTS is the baseline query mode — declared via `manifest().supported_modes`,
39
+ // not a feature flag. Flags are the closed `DataStoreFeature` set.
40
+ supports_writes: true,
39
41
  supports_semantic: false,
40
42
  supports_rerank: false,
41
43
  },
@@ -96,11 +98,20 @@ export class FileDataStore implements DataStore {
96
98
  return { id, created_at };
97
99
  }
98
100
 
101
+ /**
102
+ * Direct lookup by id (v0.13.8 DataStore contract). Null-on-miss —
103
+ * never throws for an unknown id.
104
+ */
105
+ async get(id: string): Promise<PortableData | null> {
106
+ return this.loadFile().find((r) => r.id === id) ?? null;
107
+ }
108
+
99
109
  async manifest(): Promise<ManifestInfo> {
100
110
  return {
101
111
  capabilities_version: "1",
102
112
  manifest: {
103
113
  kind: "file-data-store",
114
+ supported_modes: ["fts"],
104
115
  file_path: this.config.filePath,
105
116
  record_count: this.loadFile().length,
106
117
  supports_write: true,
@@ -43,8 +43,10 @@ export class OpenAILocalModel implements LocalModel {
43
43
  implementation: "OpenAILocalModel",
44
44
  contract_version: "1.0.0",
45
45
  features: {
46
+ supports_max_tokens: true,
47
+ supports_timeout: false,
46
48
  supports_streaming: false,
47
- supports_token_count: false,
49
+ supports_embedding: false,
48
50
  },
49
51
  };
50
52
  }
@@ -5,9 +5,11 @@
5
5
  // with agents running in tmux sessions can wire `# Output: agent: <agent>`
6
6
  // end-to-end against this impl.
7
7
  //
8
- // **Scope.** Implements `deliver()` + `list_agents()` + `wake()` +
9
- // `manifest()` per the AgentConnector contract. `wake()` is a no-op
10
- // here (tmux panes are always live; wake is for harnesses with sleep modes).
8
+ // **Scope.** Implements the full AgentConnector contract: `deliver()` +
9
+ // `list_agents()` + `wake()` + `agent_status()` + `health_check()` +
10
+ // `request_response()` + `manifest()`. `wake()` degrades to a no-op (tmux
11
+ // panes are always live; wake is for harnesses with sleep modes) and
12
+ // `request_response()` throws not-implemented (send-keys is fire-and-forget).
11
13
 
12
14
  import { spawn } from "node:child_process";
13
15
  import type {
@@ -16,6 +18,8 @@ import type {
16
18
  AgentStatus,
17
19
  DeliveryPayload,
18
20
  DeliveryReceipt,
21
+ RequestResponseOpts,
22
+ Response,
19
23
  WakeOpts,
20
24
  WakeReceipt,
21
25
  } from "skillscript-runtime/connectors";
@@ -36,7 +40,10 @@ export class TmuxShellAgentConnector implements AgentConnector {
36
40
  connector_type: "agent_connector",
37
41
  implementation: "TmuxShellAgentConnector",
38
42
  contract_version: "1.0.0",
39
- features: { supports_deliver: true, supports_wake: false },
43
+ // AgentConnector flags are method-presence shape (one per contract
44
+ // method). `wake` is present but degrades to a no-op — see wake()'s
45
+ // `woken: false` receipt.
46
+ features: { deliver: true, wake: true, list_agents: true, agent_status: true },
40
47
  };
41
48
  }
42
49
 
@@ -75,10 +82,13 @@ export class TmuxShellAgentConnector implements AgentConnector {
75
82
  }
76
83
 
77
84
  async wake(agent_id: string, _opts?: WakeOpts): Promise<WakeReceipt> {
78
- // tmux panes are always live; no-op wake returns immediately.
85
+ // tmux panes are always live there is nothing to wake. `woken: false`
86
+ // is the honest receipt: the substrate performed no wake action (the
87
+ // contract reads false as "degraded to deliver-only").
79
88
  const session = this.config.sessionMap[agent_id];
80
89
  return {
81
90
  woken_at: Date.now(),
91
+ woken: false,
82
92
  ...(session !== undefined ? { session_id: session } : {}),
83
93
  };
84
94
  }
@@ -87,6 +97,32 @@ export class TmuxShellAgentConnector implements AgentConnector {
87
97
  return this.config.sessionMap[agent_id] !== undefined ? "active" : "unknown";
88
98
  }
89
99
 
100
+ /**
101
+ * Substrate liveness: is the `tmux` binary reachable? Invoked at
102
+ * `Registry.registerAgentConnector()` — a false return refuses the wiring
103
+ * early instead of failing on the first deliver.
104
+ */
105
+ async health_check(): Promise<boolean> {
106
+ try {
107
+ await this.tmux(["-V"]);
108
+ return true;
109
+ } catch {
110
+ return false;
111
+ }
112
+ }
113
+
114
+ /**
115
+ * tmux send-keys is fire-and-forget — there is no reply channel to
116
+ * correlate a response on. Throw not-implemented per the contract's
117
+ * documented pattern (see NoOpAgentConnector) rather than fake a reply.
118
+ */
119
+ async request_response(agent_id: string, _payload: DeliveryPayload, _opts: RequestResponseOpts): Promise<Response> {
120
+ throw new Error(
121
+ `TmuxShellAgentConnector: request_response(${agent_id}) not implemented — ` +
122
+ `tmux send-keys has no reply channel. Use deliver() for one-way output.`,
123
+ );
124
+ }
125
+
90
126
  async manifest(): Promise<ManifestInfo> {
91
127
  return {
92
128
  capabilities_version: "1",
@@ -0,0 +1,10 @@
1
+ {
2
+ "provenance_version": "1.0",
3
+ "language_version": "1.0",
4
+ "compiler_version": "0.1.0-dev",
5
+ "compiled_at": "2026-07-09T22:36:21.217Z",
6
+ "source_skill": {
7
+ "name": "classify-support-ticket"
8
+ },
9
+ "data_skills_inlined": []
10
+ }
@@ -0,0 +1,10 @@
1
+ {
2
+ "provenance_version": "1.0",
3
+ "language_version": "1.0",
4
+ "compiler_version": "0.1.0-dev",
5
+ "compiled_at": "2026-07-09T22:36:21.422Z",
6
+ "source_skill": {
7
+ "name": "data-store-roundtrip"
8
+ },
9
+ "data_skills_inlined": []
10
+ }
@@ -0,0 +1,10 @@
1
+ {
2
+ "provenance_version": "1.0",
3
+ "language_version": "1.0",
4
+ "compiler_version": "0.1.0-dev",
5
+ "compiled_at": "2026-07-09T22:36:21.590Z",
6
+ "source_skill": {
7
+ "name": "doc-qa-with-citations"
8
+ },
9
+ "data_skills_inlined": []
10
+ }
@@ -0,0 +1,10 @@
1
+ {
2
+ "provenance_version": "1.0",
3
+ "language_version": "1.0",
4
+ "compiler_version": "0.1.0-dev",
5
+ "compiled_at": "2026-07-09T22:36:21.766Z",
6
+ "source_skill": {
7
+ "name": "feedback-sentiment-scan"
8
+ },
9
+ "data_skills_inlined": []
10
+ }
@@ -2,7 +2,7 @@
2
2
  "provenance_version": "1.0",
3
3
  "language_version": "1.0",
4
4
  "compiler_version": "0.1.0-dev",
5
- "compiled_at": "2026-07-06T17:54:43.615Z",
5
+ "compiled_at": "2026-07-09T22:36:21.957Z",
6
6
  "source_skill": {
7
7
  "name": "hello-world"
8
8
  },
@@ -1,23 +1,22 @@
1
1
  # Skill: morning-brief
2
2
  # Status: Draft
3
- # Description: Compose a daily morning brief from calendar, mailbox, and overnight notes when the cron trigger fires at 7am. Delivers via the agent: lifecycle hook to the receiving agent, who decides whether to surface to Slack / Discord / etc. Requires a `calendar` connector configured in connectors.json (the dotted `$ calendar.*` form). `model=qwen` is a representative LocalModel alias — adopters register one under whatever name fits (the bundled bootstrap registers `default`).
3
+ # Description: Compose a daily morning brief from calendar, mailbox, and overnight notes when the cron trigger fires at 7am. Delivers via the agent: lifecycle hook to the receiving agent, who decides whether to surface to Slack / Discord / etc. Requires a `calendar` connector configured in connectors.json (the dotted `$ calendar.*` form). `model=qwen` is a representative LocalModel alias — adopters register one under whatever name fits (the bundled bootstrap registers `default`). Every leg carries a per-leg `(fallback:)` so one failed source degrades loudly instead of sinking the whole gather; BRIEF itself is fallback-bound so the output template always renders.
4
4
  # Vars: AGENT, BRIEF_HORIZON_HOURS=24
5
5
  # Triggers: cron: 0 7 * * *
6
- # OnError: morning-brief-degraded
7
6
  # Output: agent: ${AGENT}
8
7
 
9
8
  ${BRIEF}
10
9
 
11
10
  calendar:
12
- $ calendar.list_events horizon_hours=${BRIEF_HORIZON_HOURS} -> EVENTS
11
+ $ calendar.list_events horizon_hours=${BRIEF_HORIZON_HOURS} -> EVENTS (fallback: "(calendar unavailable)")
13
12
 
14
13
  mailbox:
15
- $ data_read mode=fts query="messages for ${AGENT}" limit=10 -> MAIL
14
+ $ data_read mode=fts query="messages for ${AGENT}" limit=10 -> MAIL (fallback: "(mailbox unavailable)")
16
15
 
17
16
  overnight:
18
- $ data_read mode=rerank query="overnight notes and writes" limit=15 -> NOTES
17
+ $ data_read mode=rerank query="overnight notes and writes" limit=15 -> NOTES (fallback: "(overnight notes unavailable)")
19
18
 
20
19
  compose: needs: calendar, mailbox, overnight
21
- $ llm prompt="Compose a concise morning brief. Calendar: ${EVENTS|json}. Mailbox: ${MAIL|json}. Overnight notes: ${NOTES|json}. Three sections, six bullets max each." model=qwen maxTokens=1200 -> BRIEF
20
+ $ llm prompt="Compose a concise morning brief. Calendar: ${EVENTS|json}. Mailbox: ${MAIL|json}. Overnight notes: ${NOTES|json}. Three sections, six bullets max each. A source marked unavailable should be reported as such, not invented." model=qwen maxTokens=1200 -> BRIEF (fallback: "(morning brief unavailable — compose failed; check the llm connector)")
22
21
 
23
22
  default: compose
@@ -0,0 +1,10 @@
1
+ {
2
+ "provenance_version": "1.0",
3
+ "language_version": "1.0",
4
+ "compiler_version": "0.1.0-dev",
5
+ "compiled_at": "2026-07-09T22:36:22.134Z",
6
+ "source_skill": {
7
+ "name": "morning-brief"
8
+ },
9
+ "data_skills_inlined": []
10
+ }
@@ -0,0 +1,10 @@
1
+ {
2
+ "provenance_version": "1.0",
3
+ "language_version": "1.0",
4
+ "compiler_version": "0.1.0-dev",
5
+ "compiled_at": "2026-07-09T22:36:22.313Z",
6
+ "source_skill": {
7
+ "name": "queue-length-monitor"
8
+ },
9
+ "data_skills_inlined": []
10
+ }
@@ -0,0 +1,10 @@
1
+ {
2
+ "provenance_version": "1.0",
3
+ "language_version": "1.0",
4
+ "compiler_version": "0.1.0-dev",
5
+ "compiled_at": "2026-07-09T22:36:22.486Z",
6
+ "source_skill": {
7
+ "name": "service-health-watch"
8
+ },
9
+ "data_skills_inlined": []
10
+ }
@@ -0,0 +1,10 @@
1
+ {
2
+ "provenance_version": "1.0",
3
+ "language_version": "1.0",
4
+ "compiler_version": "0.1.0-dev",
5
+ "compiled_at": "2026-07-09T22:36:22.672Z",
6
+ "source_skill": {
7
+ "name": "skill-store-roundtrip"
8
+ },
9
+ "data_skills_inlined": []
10
+ }
@@ -0,0 +1,10 @@
1
+ {
2
+ "provenance_version": "1.0",
3
+ "language_version": "1.0",
4
+ "compiler_version": "0.1.0-dev",
5
+ "compiled_at": "2026-07-09T22:36:22.850Z",
6
+ "source_skill": {
7
+ "name": "youtrack-morning-sweep"
8
+ },
9
+ "data_skills_inlined": []
10
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "skillscript-runtime",
3
- "version": "0.27.0",
3
+ "version": "0.27.2",
4
4
  "description": "Runtime, compiler, lint, CLI, and dashboard for Skillscript — a small declarative language for authoring agent workflows.",
5
5
  "license": "MIT",
6
6
  "author": "Scott Shwarts <scotts@pobox.com>",