stillmade-sdk 0.1.21 → 0.1.23
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/AGENTS.md +5 -1
- package/PASTE_TO_LLM.md +11 -3
- package/SDK.md +30 -5
- package/package.json +1 -1
- package/packages/block-cli/cli.js +4 -1
- package/packages/block-cli/dev-host/assets/host.js +18 -9
- package/packages/block-cli/dev-host/assets/index.css +1 -1
- package/packages/block-cli/ready-gate.js +7 -1
- package/packages/block-sdk/builder-contract.js +5 -2
- package/packages/block-sdk/contracts.js +3 -1
- package/packages/block-sdk/feature-map.js +58 -0
- package/packages/block-sdk/index.d.ts +9 -0
- package/packages/block-sdk/index.js +1 -0
package/AGENTS.md
CHANGED
|
@@ -6,7 +6,7 @@ This folder is the StillMade Block SDK. Read this file before writing code; it i
|
|
|
6
6
|
|
|
7
7
|
Do not tell the user a Block is ready, done or working until `node packages/block-cli/cli.js gate .` passes after your last edit, and report the exact status it prints. In this folder Claude Code (`.claude/settings.json`) and Cursor (`.cursor/hooks.json`) run the gate when you finish a turn and send any failures back to you, but only in a session started in this folder: if you downloaded the SDK during the current session, run the gate yourself. Other agents must also run it themselves. If you cannot fix a failure, say plainly that the Block is not ready and list the failing checks.
|
|
8
8
|
|
|
9
|
-
Contract `stillmade.block-builder@1.
|
|
9
|
+
Contract `stillmade.block-builder@1.6.1`. Humans, coding agents, imported source, GitHub repositories and generated code all adapt to the Block platform; anything that becomes a StillMade Block obeys this contract.
|
|
10
10
|
|
|
11
11
|
## Source of truth
|
|
12
12
|
|
|
@@ -40,6 +40,10 @@ Translate the request into an explicit capability contract before implementation
|
|
|
40
40
|
|
|
41
41
|
A Block is one job: not a mini-app of many jobs and not a fragment of one. Its outputs become other Blocks' inputs and its inputs come from other Blocks, project context or the user. Use the typed port system: shared StillMade types (`image`, `video`, `audio`, `asset`, `script`, `shot[]`, ...), a `semantic` meaning on every port, `required` and a short `description`. Mark exactly one primary input and one primary output so Project Type Steps connect automatically, and use `kind: "task"`: a `workspace` Block owns a project document and is never connected automatically. Inputs marked `context` read the project and cannot receive a connection from another Step. Output reusable StillMade values: media references (`{kind,assetId,versionId,url}`) and structured production values with `schemaVersion: 1`, preserving provenance, versions and relationships downstream Blocks need. Never make ordinary users wire JSON, copy IDs, understand internal paths or translate one Block's output into another: `createUniversalResolver()` (the same engine as the Project Type composer) resolves inputs from compatible upstream outputs, permitted project context and, for optional non-context inputs, `StillMade.requestFromUser`.
|
|
42
42
|
|
|
43
|
+
## Feature map
|
|
44
|
+
|
|
45
|
+
Every Block carries a feature map in `manifest.features`, written by whoever builds it while they build, so the person never writes it. Add one entry for each separate thing a person could ask for: a tool, a mode, a preset family or a kind of result (an editor's reaction GIFs, its motion presets, a recorder's screen recording), not one entry covering several tools. Each entry has a lowercase `id`, a `label` of 40 characters or fewer, `does` (what it does, 160 characters or fewer) and `asks`: 1–8 short requests in a customer's own words that this feature answers ("add a fire gif over my car"). `operation` names an id in the Block's own `manifest.operations` (omit it when there are none); `inputs`/`outputs` name declared ports. The gate fails a Block without one. Add or update the entry in the same change that adds or alters a tool, and remove it when the tool goes. List only what the code really does; listings are generated from this map, nobody can edit them, and StillMade matches requests to features. Features are not tested at publish: each shows as new until real use proves it.
|
|
46
|
+
|
|
43
47
|
## Use platform primitives
|
|
44
48
|
|
|
45
49
|
Prefer, in order: an SDK capability; a documented host capability (the hosted operations are text.generate, audio.speech, audio.transcribe, audio.music, audio.sfx, image.generate, video.generate, image.describe, media.analyze, web.fetch, web.research, timeline.propose, workspace.propose, connection.execute; connected third-party apps go through `connection.execute`); an approved dependency the SDK already bundles; small Block-local code. Do not duplicate what StillMade provides. A Block never contains its own asset system, file picker, authentication, project-context system, input resolver, Block connection system, credit system, secrets store, permission system, progress system, multiplayer system, persistence system, model-provider abstraction or execution protocol.
|
package/PASTE_TO_LLM.md
CHANGED
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
<!-- builder-contract:start (generated by npm run build:sdk; do not edit) -->
|
|
4
4
|
|
|
5
|
-
## Block builder contract (stillmade.block-builder@1.
|
|
5
|
+
## Block builder contract (stillmade.block-builder@1.6.1)
|
|
6
6
|
|
|
7
|
-
Contract `stillmade.block-builder@1.
|
|
7
|
+
Contract `stillmade.block-builder@1.6.1`. Humans, coding agents, imported source, GitHub repositories and generated code all adapt to the Block platform; anything that becomes a StillMade Block obeys this contract.
|
|
8
8
|
|
|
9
9
|
### Source of truth
|
|
10
10
|
|
|
@@ -38,6 +38,10 @@ Translate the request into an explicit capability contract before implementation
|
|
|
38
38
|
|
|
39
39
|
A Block is one job: not a mini-app of many jobs and not a fragment of one. Its outputs become other Blocks' inputs and its inputs come from other Blocks, project context or the user. Use the typed port system: shared StillMade types (`image`, `video`, `audio`, `asset`, `script`, `shot[]`, ...), a `semantic` meaning on every port, `required` and a short `description`. Mark exactly one primary input and one primary output so Project Type Steps connect automatically, and use `kind: "task"`: a `workspace` Block owns a project document and is never connected automatically. Inputs marked `context` read the project and cannot receive a connection from another Step. Output reusable StillMade values: media references (`{kind,assetId,versionId,url}`) and structured production values with `schemaVersion: 1`, preserving provenance, versions and relationships downstream Blocks need. Never make ordinary users wire JSON, copy IDs, understand internal paths or translate one Block's output into another: `createUniversalResolver()` (the same engine as the Project Type composer) resolves inputs from compatible upstream outputs, permitted project context and, for optional non-context inputs, `StillMade.requestFromUser`.
|
|
40
40
|
|
|
41
|
+
### Feature map
|
|
42
|
+
|
|
43
|
+
Every Block carries a feature map in `manifest.features`, written by whoever builds it while they build, so the person never writes it. Add one entry for each separate thing a person could ask for: a tool, a mode, a preset family or a kind of result (an editor's reaction GIFs, its motion presets, a recorder's screen recording), not one entry covering several tools. Each entry has a lowercase `id`, a `label` of 40 characters or fewer, `does` (what it does, 160 characters or fewer) and `asks`: 1–8 short requests in a customer's own words that this feature answers ("add a fire gif over my car"). `operation` names an id in the Block's own `manifest.operations` (omit it when there are none); `inputs`/`outputs` name declared ports. The gate fails a Block without one. Add or update the entry in the same change that adds or alters a tool, and remove it when the tool goes. List only what the code really does; listings are generated from this map, nobody can edit them, and StillMade matches requests to features. Features are not tested at publish: each shows as new until real use proves it.
|
|
44
|
+
|
|
41
45
|
### Use platform primitives
|
|
42
46
|
|
|
43
47
|
Prefer, in order: an SDK capability; a documented host capability (the hosted operations are text.generate, audio.speech, audio.transcribe, audio.music, audio.sfx, image.generate, video.generate, image.describe, media.analyze, web.fetch, web.research, timeline.propose, workspace.propose, connection.execute; connected third-party apps go through `connection.execute`); an approved dependency the SDK already bundles; small Block-local code. Do not duplicate what StillMade provides. A Block never contains its own asset system, file picker, authentication, project-context system, input resolver, Block connection system, credit system, secrets store, permission system, progress system, multiplayer system, persistence system, model-provider abstraction or execution protocol.
|
|
@@ -148,6 +152,10 @@ Every finished Block must support automatic remixing through the standard SDK co
|
|
|
148
152
|
|
|
149
153
|
A Block package is StillMade SDK 0.1.0 JSON. Prefer {manifest,recipe,tests} for supported operations. Otherwise use {manifest,code,tests} with runtime:"javascript": code is a synchronous function body receiving input and returning declared output bindings, e.g. return {text:input.text.toUpperCase()}. JavaScript runs in isolated QuickJS: no fetch, DOM, Node APIs, modules, dependencies, timers, or host services; no promises, imports, require, eval or Function. Limits: 500 ms execution, 16 MiB heap, 256 KiB code, 4 MiB JSON I/O. Include concrete passing fixtures that reflect the requested behavior, including an edge case; never approximate a hosted model call with fabricated deterministic output. Manifest fields: schemaVersion:1,sdkVersion:"0.1.0",id:"creator.name",version:"1.0.0",name,description,kind:"task",runtime:"recipe", "javascript", "comfyui", or "capability",inputs/outputs as named {type,default?,min?,max?,role?,primary?}. Usually mark one primary input and output with primary:true. Semantic roles such as source_image and character_reference are distinct and must never be guessed,permissions:{project:[],network:[],filesystem:[],secrets:[]},ui:[{control,port}]. Recipe: {schemaVersion:1,steps:[{id,op,args}],outputs}. References: {"$input":"port"}, {"$step":"step-id"}. Supported operations: {"value.copy":{"description":"Copy a JSON value without changing it.","args":["value"]},"text.trim":{"description":"Remove leading and trailing whitespace.","args":["text"]},"text.replace":{"description":"Replace literal text; no regular expressions.","args":["text","find","replacement"]},"text.join":{"description":"Join an array of text values.","args":["items","separator"]},"image.thicken-lines":{"description":"Expand dark outlines while preserving other colors.","args":["image","thickness","threshold"]}}. Types include text,number,integer,boolean,json,image,audio,video,script,text[]. Include test {name,input,expected} where expected is output bindings.
|
|
150
154
|
|
|
155
|
+
### Feature map
|
|
156
|
+
|
|
157
|
+
Every Block lists its separate tools in manifest.features, one entry per tool or mode a person could ask for: {"id":"reaction-gifs","label":"Reaction GIFs","does":"Search GIFs and drop one over a clip.","asks":["add a fire gif over my car","reaction gif when he laughs"]}. Use 1–24 entries; id is lowercase with hyphens, label at most 40 characters, does at most 160, asks 1–8 short requests in a customer's words. A Block that really does one job has one entry. Rewrite the starting entry create writes (it copies the description), or the gate fails. When refining or remixing, add, change or remove entries in the same change as the tool, and keep the ids of tools that stay.
|
|
158
|
+
|
|
151
159
|
### Port meanings
|
|
152
160
|
|
|
153
161
|
For each newly created Block, declare the meaning of every input and output in its manifest contract, not just a physical type. Each input needs semantic, required:boolean and a short plain-language description. Each output needs semantic and a short description. Use lowercase snake_case or dotted semantic names, such as company_profile or email_subject; different meanings are not interchangeable merely because both are text. If an existing role is present, semantic must equal that role. Reuse an exact existing meaning only when the information actually has that meaning. Describe structured fields with schema when their shape matters: for example {name:"string",website:"string",industry:"string?"}. Supported schema fields are string/text, number, integer, boolean, object, json, arrays of those types, and optional fields with ?. Declare sources only when a requirement restricts where its answer may come from: upstream, project, adapter, chat, default, user or external. Do not mark a credential as ordinary text or put secrets in defaults. Contracts describe information; they never authorize network access, model calls, project edits, credit spending or new runtime APIs. Keep existing imported, installed and base Block contracts unchanged; do not silently relabel old published contracts to make a connection appear compatible. New contracts must match actual code and fixtures.
|
|
@@ -208,7 +216,7 @@ Every Block interface, generated or custom, follows StillMade's compact rules: C
|
|
|
208
216
|
|
|
209
217
|
*When:* StillMade's builder adds this section when the person did not ask for a custom interface.
|
|
210
218
|
|
|
211
|
-
Optional custom view interfaces are supported, but generated manifest.ui controls are sufficient unless the user asks for a custom interface.
|
|
219
|
+
Optional custom view interfaces are supported, but generated manifest.ui controls are sufficient unless the user asks for a custom interface. Shape the manifest so the generated controls stay compact: choices use control:"select" with a few short string options (shown as one row of tiles); bounded numbers use control:"slider" with min and max; on/off is a boolean; one-line text says "up to N characters" (160 or fewer) in its description so it sits beside its label, and multi-line text is kept for prompts and briefs. Inputs beyond the few that matter go in a uiLayout group with collapsed:true; they move there, never get deleted.
|
|
212
220
|
|
|
213
221
|
### Custom interfaces
|
|
214
222
|
|
package/SDK.md
CHANGED
|
@@ -182,7 +182,7 @@ The archive needs Node.js 22 or later and nothing else; its runtime is bundled,
|
|
|
182
182
|
|
|
183
183
|
## Block builder contract
|
|
184
184
|
|
|
185
|
-
Contract `stillmade.block-builder@1.
|
|
185
|
+
Contract `stillmade.block-builder@1.6.1`. Humans, coding agents, imported source, GitHub repositories and generated code all adapt to the Block platform; anything that becomes a StillMade Block obeys this contract.
|
|
186
186
|
|
|
187
187
|
### Source of truth
|
|
188
188
|
|
|
@@ -216,6 +216,10 @@ Translate the request into an explicit capability contract before implementation
|
|
|
216
216
|
|
|
217
217
|
A Block is one job: not a mini-app of many jobs and not a fragment of one. Its outputs become other Blocks' inputs and its inputs come from other Blocks, project context or the user. Use the typed port system: shared StillMade types (`image`, `video`, `audio`, `asset`, `script`, `shot[]`, ...), a `semantic` meaning on every port, `required` and a short `description`. Mark exactly one primary input and one primary output so Project Type Steps connect automatically, and use `kind: "task"`: a `workspace` Block owns a project document and is never connected automatically. Inputs marked `context` read the project and cannot receive a connection from another Step. Output reusable StillMade values: media references (`{kind,assetId,versionId,url}`) and structured production values with `schemaVersion: 1`, preserving provenance, versions and relationships downstream Blocks need. Never make ordinary users wire JSON, copy IDs, understand internal paths or translate one Block's output into another: `createUniversalResolver()` (the same engine as the Project Type composer) resolves inputs from compatible upstream outputs, permitted project context and, for optional non-context inputs, `StillMade.requestFromUser`.
|
|
218
218
|
|
|
219
|
+
### Feature map
|
|
220
|
+
|
|
221
|
+
Every Block carries a feature map in `manifest.features`, written by whoever builds it while they build, so the person never writes it. Add one entry for each separate thing a person could ask for: a tool, a mode, a preset family or a kind of result (an editor's reaction GIFs, its motion presets, a recorder's screen recording), not one entry covering several tools. Each entry has a lowercase `id`, a `label` of 40 characters or fewer, `does` (what it does, 160 characters or fewer) and `asks`: 1–8 short requests in a customer's own words that this feature answers ("add a fire gif over my car"). `operation` names an id in the Block's own `manifest.operations` (omit it when there are none); `inputs`/`outputs` name declared ports. The gate fails a Block without one. Add or update the entry in the same change that adds or alters a tool, and remove it when the tool goes. List only what the code really does; listings are generated from this map, nobody can edit them, and StillMade matches requests to features. Features are not tested at publish: each shows as new until real use proves it.
|
|
222
|
+
|
|
219
223
|
### Use platform primitives
|
|
220
224
|
|
|
221
225
|
Prefer, in order: an SDK capability; a documented host capability (the hosted operations are text.generate, audio.speech, audio.transcribe, audio.music, audio.sfx, image.generate, video.generate, image.describe, media.analyze, web.fetch, web.research, timeline.propose, workspace.propose, connection.execute; connected third-party apps go through `connection.execute`); an approved dependency the SDK already bundles; small Block-local code. Do not duplicate what StillMade provides. A Block never contains its own asset system, file picker, authentication, project-context system, input resolver, Block connection system, credit system, secrets store, permission system, progress system, multiplayer system, persistence system, model-provider abstraction or execution protocol.
|
|
@@ -5914,8 +5918,17 @@ export interface FrameView { runtime: 'frame'; html: string; css?: string; theme
|
|
|
5914
5918
|
export interface BlockPackage { portable?: PortableMetadata; manifest: Manifest; view?: BlockView|FrameView; code?: string; module?: ModuleDescriptor; comfyui?: ComfyWorkflow; capability?: ConnectedCapability|TextGenerationCapability|SpeechCapability|TranscriptionCapability|ImageGenerationCapability|VideoGenerationCapability|ImageDescriptionCapability|TimelineProposalCapability; recipe?: { schemaVersion: 1; steps: { id: string; op: string; args: Record<string, unknown> }[]; outputs: Record<string, unknown> }; tests: { name: string; input: Record<string, unknown>; expected?: Record<string, unknown>; state?: BlockState; expectedState?: BlockState; expectations?: Record<string, ConnectedResultExpectation|ComfyImageExpectation|CapabilityTextExpectation|CapabilityAudioExpectation|CapabilityTranscriptExpectation|CapabilityImageExpectation|CapabilityVideoExpectation|CapabilityTimelineExpectation> }[]; }
|
|
5915
5919
|
/** Named sandbox action with fixed declared input settings and produced ports. */
|
|
5916
5920
|
export interface BlockOperation {id:string;label:string;description:string;inputs:Record<string,string|number|boolean>;outputs:string[]}
|
|
5921
|
+
/** One entry of a Block's feature map: a separate thing the Block can do and the requests it answers. */
|
|
5922
|
+
export interface BlockFeature {id:string;label:string;does:string;asks:string[];operation?:string;inputs?:string[];outputs?:string[]}
|
|
5923
|
+
export const FEATURE_MAP_LIMITS: Readonly<{features:24;id:48;label:40;does:160;asks:8;ask:80}>;
|
|
5924
|
+
/** Validation messages for `manifest.features`; [] when valid or absent. */
|
|
5925
|
+
export function featureMapErrors(manifest:unknown):string[];
|
|
5926
|
+
/** The declared feature map, or one derived from operations or the Block itself. */
|
|
5927
|
+
export function blockFeatures(manifest:unknown):(BlockFeature&{source:'declared'|'derived'})[];
|
|
5917
5928
|
export interface Manifest {
|
|
5918
5929
|
operations?: BlockOperation[];
|
|
5930
|
+
/** Feature map: what the Block can do, tool by tool. Written by the builder; listings are generated from it. */
|
|
5931
|
+
features?: BlockFeature[];
|
|
5919
5932
|
storage?: import('./block-storage.js').BlockStorageDeclaration;
|
|
5920
5933
|
/** Events the Block can run on by itself, once the project owner turns them on. */
|
|
5921
5934
|
triggers?: import('./triggers.js').BlockTrigger[];
|
|
@@ -7224,9 +7237,9 @@ Ask the assistant to return source files or one `.stillmade.json` package. Run t
|
|
|
7224
7237
|
|
|
7225
7238
|
<!-- builder-contract:start (generated by npm run build:sdk; do not edit) -->
|
|
7226
7239
|
|
|
7227
|
-
### Block builder contract (stillmade.block-builder@1.
|
|
7240
|
+
### Block builder contract (stillmade.block-builder@1.6.1)
|
|
7228
7241
|
|
|
7229
|
-
Contract `stillmade.block-builder@1.
|
|
7242
|
+
Contract `stillmade.block-builder@1.6.1`. Humans, coding agents, imported source, GitHub repositories and generated code all adapt to the Block platform; anything that becomes a StillMade Block obeys this contract.
|
|
7230
7243
|
|
|
7231
7244
|
### Source of truth
|
|
7232
7245
|
|
|
@@ -7260,6 +7273,10 @@ Translate the request into an explicit capability contract before implementation
|
|
|
7260
7273
|
|
|
7261
7274
|
A Block is one job: not a mini-app of many jobs and not a fragment of one. Its outputs become other Blocks' inputs and its inputs come from other Blocks, project context or the user. Use the typed port system: shared StillMade types (`image`, `video`, `audio`, `asset`, `script`, `shot[]`, ...), a `semantic` meaning on every port, `required` and a short `description`. Mark exactly one primary input and one primary output so Project Type Steps connect automatically, and use `kind: "task"`: a `workspace` Block owns a project document and is never connected automatically. Inputs marked `context` read the project and cannot receive a connection from another Step. Output reusable StillMade values: media references (`{kind,assetId,versionId,url}`) and structured production values with `schemaVersion: 1`, preserving provenance, versions and relationships downstream Blocks need. Never make ordinary users wire JSON, copy IDs, understand internal paths or translate one Block's output into another: `createUniversalResolver()` (the same engine as the Project Type composer) resolves inputs from compatible upstream outputs, permitted project context and, for optional non-context inputs, `StillMade.requestFromUser`.
|
|
7262
7275
|
|
|
7276
|
+
### Feature map
|
|
7277
|
+
|
|
7278
|
+
Every Block carries a feature map in `manifest.features`, written by whoever builds it while they build, so the person never writes it. Add one entry for each separate thing a person could ask for: a tool, a mode, a preset family or a kind of result (an editor's reaction GIFs, its motion presets, a recorder's screen recording), not one entry covering several tools. Each entry has a lowercase `id`, a `label` of 40 characters or fewer, `does` (what it does, 160 characters or fewer) and `asks`: 1–8 short requests in a customer's own words that this feature answers ("add a fire gif over my car"). `operation` names an id in the Block's own `manifest.operations` (omit it when there are none); `inputs`/`outputs` name declared ports. The gate fails a Block without one. Add or update the entry in the same change that adds or alters a tool, and remove it when the tool goes. List only what the code really does; listings are generated from this map, nobody can edit them, and StillMade matches requests to features. Features are not tested at publish: each shows as new until real use proves it.
|
|
7279
|
+
|
|
7263
7280
|
### Use platform primitives
|
|
7264
7281
|
|
|
7265
7282
|
Prefer, in order: an SDK capability; a documented host capability (the hosted operations are text.generate, audio.speech, audio.transcribe, audio.music, audio.sfx, image.generate, video.generate, image.describe, media.analyze, web.fetch, web.research, timeline.propose, workspace.propose, connection.execute; connected third-party apps go through `connection.execute`); an approved dependency the SDK already bundles; small Block-local code. Do not duplicate what StillMade provides. A Block never contains its own asset system, file picker, authentication, project-context system, input resolver, Block connection system, credit system, secrets store, permission system, progress system, multiplayer system, persistence system, model-provider abstraction or execution protocol.
|
|
@@ -7370,6 +7387,10 @@ Every finished Block must support automatic remixing through the standard SDK co
|
|
|
7370
7387
|
|
|
7371
7388
|
A Block package is StillMade SDK 0.1.0 JSON. Prefer {manifest,recipe,tests} for supported operations. Otherwise use {manifest,code,tests} with runtime:"javascript": code is a synchronous function body receiving input and returning declared output bindings, e.g. return {text:input.text.toUpperCase()}. JavaScript runs in isolated QuickJS: no fetch, DOM, Node APIs, modules, dependencies, timers, or host services; no promises, imports, require, eval or Function. Limits: 500 ms execution, 16 MiB heap, 256 KiB code, 4 MiB JSON I/O. Include concrete passing fixtures that reflect the requested behavior, including an edge case; never approximate a hosted model call with fabricated deterministic output. Manifest fields: schemaVersion:1,sdkVersion:"0.1.0",id:"creator.name",version:"1.0.0",name,description,kind:"task",runtime:"recipe", "javascript", "comfyui", or "capability",inputs/outputs as named {type,default?,min?,max?,role?,primary?}. Usually mark one primary input and output with primary:true. Semantic roles such as source_image and character_reference are distinct and must never be guessed,permissions:{project:[],network:[],filesystem:[],secrets:[]},ui:[{control,port}]. Recipe: {schemaVersion:1,steps:[{id,op,args}],outputs}. References: {"$input":"port"}, {"$step":"step-id"}. Supported operations: {"value.copy":{"description":"Copy a JSON value without changing it.","args":["value"]},"text.trim":{"description":"Remove leading and trailing whitespace.","args":["text"]},"text.replace":{"description":"Replace literal text; no regular expressions.","args":["text","find","replacement"]},"text.join":{"description":"Join an array of text values.","args":["items","separator"]},"image.thicken-lines":{"description":"Expand dark outlines while preserving other colors.","args":["image","thickness","threshold"]}}. Types include text,number,integer,boolean,json,image,audio,video,script,text[]. Include test {name,input,expected} where expected is output bindings.
|
|
7372
7389
|
|
|
7390
|
+
### Feature map
|
|
7391
|
+
|
|
7392
|
+
Every Block lists its separate tools in manifest.features, one entry per tool or mode a person could ask for: {"id":"reaction-gifs","label":"Reaction GIFs","does":"Search GIFs and drop one over a clip.","asks":["add a fire gif over my car","reaction gif when he laughs"]}. Use 1–24 entries; id is lowercase with hyphens, label at most 40 characters, does at most 160, asks 1–8 short requests in a customer's words. A Block that really does one job has one entry. Rewrite the starting entry create writes (it copies the description), or the gate fails. When refining or remixing, add, change or remove entries in the same change as the tool, and keep the ids of tools that stay.
|
|
7393
|
+
|
|
7373
7394
|
### Port meanings
|
|
7374
7395
|
|
|
7375
7396
|
For each newly created Block, declare the meaning of every input and output in its manifest contract, not just a physical type. Each input needs semantic, required:boolean and a short plain-language description. Each output needs semantic and a short description. Use lowercase snake_case or dotted semantic names, such as company_profile or email_subject; different meanings are not interchangeable merely because both are text. If an existing role is present, semantic must equal that role. Reuse an exact existing meaning only when the information actually has that meaning. Describe structured fields with schema when their shape matters: for example {name:"string",website:"string",industry:"string?"}. Supported schema fields are string/text, number, integer, boolean, object, json, arrays of those types, and optional fields with ?. Declare sources only when a requirement restricts where its answer may come from: upstream, project, adapter, chat, default, user or external. Do not mark a credential as ordinary text or put secrets in defaults. Contracts describe information; they never authorize network access, model calls, project edits, credit spending or new runtime APIs. Keep existing imported, installed and base Block contracts unchanged; do not silently relabel old published contracts to make a connection appear compatible. New contracts must match actual code and fixtures.
|
|
@@ -7430,7 +7451,7 @@ Every Block interface, generated or custom, follows StillMade's compact rules: C
|
|
|
7430
7451
|
|
|
7431
7452
|
*When:* StillMade's builder adds this section when the person did not ask for a custom interface.
|
|
7432
7453
|
|
|
7433
|
-
Optional custom view interfaces are supported, but generated manifest.ui controls are sufficient unless the user asks for a custom interface.
|
|
7454
|
+
Optional custom view interfaces are supported, but generated manifest.ui controls are sufficient unless the user asks for a custom interface. Shape the manifest so the generated controls stay compact: choices use control:"select" with a few short string options (shown as one row of tiles); bounded numbers use control:"slider" with min and max; on/off is a boolean; one-line text says "up to N characters" (160 or fewer) in its description so it sits beside its label, and multi-line text is kept for prompts and briefs. Inputs beyond the few that matter go in a uiLayout group with collapsed:true; they move there, never get deleted.
|
|
7434
7455
|
|
|
7435
7456
|
### Custom interfaces
|
|
7436
7457
|
|
|
@@ -12288,6 +12309,10 @@ Every finished Block must support automatic remixing through the standard SDK co
|
|
|
12288
12309
|
|
|
12289
12310
|
A Block package is StillMade SDK 0.1.0 JSON. Prefer {manifest,recipe,tests} for supported operations. Otherwise use {manifest,code,tests} with runtime:"javascript": code is a synchronous function body receiving input and returning declared output bindings, e.g. return {text:input.text.toUpperCase()}. JavaScript runs in isolated QuickJS: no fetch, DOM, Node APIs, modules, dependencies, timers, or host services; no promises, imports, require, eval or Function. Limits: 500 ms execution, 16 MiB heap, 256 KiB code, 4 MiB JSON I/O. Include concrete passing fixtures that reflect the requested behavior, including an edge case; never approximate a hosted model call with fabricated deterministic output. Manifest fields: schemaVersion:1,sdkVersion:"0.1.0",id:"creator.name",version:"1.0.0",name,description,kind:"task",runtime:"recipe", "javascript", "comfyui", or "capability",inputs/outputs as named {type,default?,min?,max?,role?,primary?}. Usually mark one primary input and output with primary:true. Semantic roles such as source_image and character_reference are distinct and must never be guessed,permissions:{project:[],network:[],filesystem:[],secrets:[]},ui:[{control,port}]. Recipe: {schemaVersion:1,steps:[{id,op,args}],outputs}. References: {"$input":"port"}, {"$step":"step-id"}. Supported operations: {"value.copy":{"description":"Copy a JSON value without changing it.","args":["value"]},"text.trim":{"description":"Remove leading and trailing whitespace.","args":["text"]},"text.replace":{"description":"Replace literal text; no regular expressions.","args":["text","find","replacement"]},"text.join":{"description":"Join an array of text values.","args":["items","separator"]},"image.thicken-lines":{"description":"Expand dark outlines while preserving other colors.","args":["image","thickness","threshold"]}}. Types include text,number,integer,boolean,json,image,audio,video,script,text[]. Include test {name,input,expected} where expected is output bindings.
|
|
12290
12311
|
|
|
12312
|
+
### Feature map
|
|
12313
|
+
|
|
12314
|
+
Every Block lists its separate tools in manifest.features, one entry per tool or mode a person could ask for: {"id":"reaction-gifs","label":"Reaction GIFs","does":"Search GIFs and drop one over a clip.","asks":["add a fire gif over my car","reaction gif when he laughs"]}. Use 1–24 entries; id is lowercase with hyphens, label at most 40 characters, does at most 160, asks 1–8 short requests in a customer's words. A Block that really does one job has one entry. Rewrite the starting entry create writes (it copies the description), or the gate fails. When refining or remixing, add, change or remove entries in the same change as the tool, and keep the ids of tools that stay.
|
|
12315
|
+
|
|
12291
12316
|
### Port meanings
|
|
12292
12317
|
|
|
12293
12318
|
For each newly created Block, declare the meaning of every input and output in its manifest contract, not just a physical type. Each input needs semantic, required:boolean and a short plain-language description. Each output needs semantic and a short description. Use lowercase snake_case or dotted semantic names, such as company_profile or email_subject; different meanings are not interchangeable merely because both are text. If an existing role is present, semantic must equal that role. Reuse an exact existing meaning only when the information actually has that meaning. Describe structured fields with schema when their shape matters: for example {name:"string",website:"string",industry:"string?"}. Supported schema fields are string/text, number, integer, boolean, object, json, arrays of those types, and optional fields with ?. Declare sources only when a requirement restricts where its answer may come from: upstream, project, adapter, chat, default, user or external. Do not mark a credential as ordinary text or put secrets in defaults. Contracts describe information; they never authorize network access, model calls, project edits, credit spending or new runtime APIs. Keep existing imported, installed and base Block contracts unchanged; do not silently relabel old published contracts to make a connection appear compatible. New contracts must match actual code and fixtures.
|
|
@@ -12348,7 +12373,7 @@ Every Block interface, generated or custom, follows StillMade's compact rules: C
|
|
|
12348
12373
|
|
|
12349
12374
|
*When:* StillMade's builder adds this section when the person did not ask for a custom interface.
|
|
12350
12375
|
|
|
12351
|
-
Optional custom view interfaces are supported, but generated manifest.ui controls are sufficient unless the user asks for a custom interface.
|
|
12376
|
+
Optional custom view interfaces are supported, but generated manifest.ui controls are sufficient unless the user asks for a custom interface. Shape the manifest so the generated controls stay compact: choices use control:"select" with a few short string options (shown as one row of tiles); bounded numbers use control:"slider" with min and max; on/off is a boolean; one-line text says "up to N characters" (160 or fewer) in its description so it sits beside its label, and multi-line text is kept for prompts and briefs. Inputs beyond the few that matter go in a uiLayout group with collapsed:true; they move there, never get deleted.
|
|
12352
12377
|
|
|
12353
12378
|
### Custom interfaces
|
|
12354
12379
|
|
package/package.json
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import {blockFeatures} from '../block-sdk/feature-map.js';
|
|
2
3
|
import {assertRemixReady} from '../block-sdk/remix-policy.js';
|
|
3
4
|
import {remixBlock,bundledRemixSource,assertRemixAttribution} from '../block-platform/block-remix.js';
|
|
4
5
|
import {verifyPortableSources} from '../block-sdk/portable-github.js';
|
|
@@ -200,6 +201,8 @@ export async function main(rawArgs) {
|
|
|
200
201
|
if (command === 'create') {
|
|
201
202
|
if(args.length<2)throw Object.assign(new Error('Name the folder to create: stillmade-block create my-block [template]'),{code:'USAGE'});
|
|
202
203
|
const template=templateNamed(extra),files=await template.files();
|
|
204
|
+
// Every new Block starts with a feature map (one entry from its name and description) for the builder to rewrite as it grows.
|
|
205
|
+
{const created=JSON.parse(files['stillmade.block.json']);if(!created.features&&!created.stages){created.features=blockFeatures(created).map(({source,...feature})=>feature);files['stillmade.block.json']=`${JSON.stringify(created,null,2)}\n`;}}
|
|
203
206
|
// Editors pick up the generated types for the view, src/run.js and module code.
|
|
204
207
|
files['stillmade-env.d.ts']=blockTypeDeclarations(JSON.parse(files['stillmade.block.json']));
|
|
205
208
|
files['jsconfig.json']=`${JSON.stringify({compilerOptions:{target:'ES2022',module:'ESNext',moduleResolution:'Bundler',lib:['ES2022','DOM'],jsx:'react-jsx',checkJs:false},include:['src','module','stillmade-env.d.ts']},null,2)}\n`;
|
|
@@ -208,7 +211,7 @@ export async function main(rawArgs) {
|
|
|
208
211
|
const names=['stillmade.block.json',...Object.keys(files).filter(name=>name!=='stillmade.block.json')];
|
|
209
212
|
for(const name of names){await mkdir(dirname(join(path,name)),{recursive:true});await writeFile(join(path,name),files[name],{flag:'wx'});}
|
|
210
213
|
// Coding agents read command output: restate the readiness rule where they will see it.
|
|
211
|
-
return { created: path, sdkVersion: '0.1.0', template:template.name, runtime:template.runtime, files:names, next: 'Build the Block, then run `stillmade-block gate .`. Do not call the Block ready until the gate passes; report the status it prints.' };
|
|
214
|
+
return { created: path, sdkVersion: '0.1.0', template:template.name, runtime:template.runtime, files:names, next: 'Build the Block and write its feature map (`manifest.features`: one entry per thing it can do), then run `stillmade-block gate .`. Do not call the Block ready until the gate passes; report the status it prints.' };
|
|
212
215
|
}
|
|
213
216
|
if (command === 'gate') {
|
|
214
217
|
// Every new or edited Block in a folder must pass readiness before anyone calls it ready.
|