stillmade-sdk 0.1.0 → 0.1.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.
- package/AGENTS.md +4 -0
- package/MODULES.md +5 -3
- package/NATIVE_MCP.md +22 -3
- package/PASTE_TO_LLM.md +4 -0
- package/SDK.md +15 -5
- package/package.json +1 -1
- package/packages/block-platform/project-type-recommendations.js +14 -2
- package/packages/block-sdk/builder-contract.js +4 -1
- package/packages/block-sdk/runtime.js +1 -1
- package/packages/block-sdk/triggers.js +3 -3
package/AGENTS.md
CHANGED
|
@@ -8,6 +8,10 @@ Contract `stillmade.block-builder@1.0.0`. Humans, coding agents, imported source
|
|
|
8
8
|
|
|
9
9
|
Treat the current SDK (`stillmade.block.json` manifest, `packages/block-sdk` contracts, validators, examples and published docs) as the source of truth. Before writing code, read the manifest contract, at least two working first-party Blocks closest to the request, the runtime you will use, the typed port and resolver contracts, and the shared-interface contract when you need a custom view. Do not invent runtimes, operations, permissions, ports, host services or bridge calls. If the documentation and the validator disagree, the validator wins and the mismatch should be reported.
|
|
10
10
|
|
|
11
|
+
## Reuse first
|
|
12
|
+
|
|
13
|
+
Before building, check what already exists (`find_existing_blocks` over MCP, or the Marketplace and your library) by the inputs, results and operations the goal needs. Use an installed or reviewed Block that already does it; remix a close one so its license, notices and creator credit stay attached; chain existing Blocks and build only the missing step. Never republish another creator's source without remix lineage: public copies are refused. Build a new Block when nothing fits or the person asks for their own version, and say which similar Blocks you considered.
|
|
14
|
+
|
|
11
15
|
## Define the capability first
|
|
12
16
|
|
|
13
17
|
Translate the request into an explicit capability contract before implementation: what the Block does; each input with its type, meaning and whether it is required (prefer optional settings with safe defaults over extra required questions); each output with its type and meaning; persistent state; project context it reads; permissions; UI; long-running behavior; expected failures; cancellation; determinism; and whether it needs hosted models, media, desktop tools or shared editing. Keep the public interface as small and general as possible and keep implementation details out of it.
|
package/MODULES.md
CHANGED
|
@@ -135,9 +135,11 @@ WebAssembly codec. Images arrive as saved references: read the bytes with
|
|
|
135
135
|
- Generating code at run time (`new Function`, used by Emscripten bindings) is
|
|
136
136
|
allowed inside the sandbox.
|
|
137
137
|
|
|
138
|
-
Module Blocks run in StillMade in the browser
|
|
139
|
-
|
|
140
|
-
|
|
138
|
+
Module Blocks run in StillMade in the person's browser, only while StillMade is
|
|
139
|
+
open. They cannot run on a schedule, from an event or on new media: StillMade has
|
|
140
|
+
no server sandbox for them. A workflow's background run stops before a module Step
|
|
141
|
+
and the person runs it in the project. Marketplace listings show module Blocks as
|
|
142
|
+
**Browser only**. For work that must run unattended, use a JavaScript Block.
|
|
141
143
|
|
|
142
144
|
## Test, pack and import
|
|
143
145
|
|
package/NATIVE_MCP.md
CHANGED
|
@@ -105,10 +105,10 @@ Use the backend origin, without a path. HTTP is accepted only for localhost. Red
|
|
|
105
105
|
|
|
106
106
|
## Available user actions
|
|
107
107
|
|
|
108
|
-
- `list_catalog`, `search_marketplace`
|
|
108
|
+
- `list_catalog`, `search_marketplace`, `find_existing_blocks`
|
|
109
109
|
- `search_github_candidates`, `inspect_github_repository`, `read_github_source`, `inspect_github_sdk_package`
|
|
110
110
|
- `get_block_authoring_guide`, `search_documentation`, `validate_block_source`, `test_block_source`
|
|
111
|
-
- `list_creations`, `get_creation`, `save_creation`
|
|
111
|
+
- `list_creations`, `get_creation`, `save_creation`, `begin_block_remix`
|
|
112
112
|
- `list_projects`, `get_project_context`
|
|
113
113
|
- `get_run`, `list_recent_runs`
|
|
114
114
|
- With `analytics:read`: `get_creator_analytics`, `get_creator_retention`, `get_creator_dotplot`, `get_my_listing_reviews`
|
|
@@ -119,11 +119,30 @@ Live-tab inspection and control are no longer exposed in the app connection UI.
|
|
|
119
119
|
External MCP clients continue to use the saved catalog, creation, project-context,
|
|
120
120
|
and run-inspection tools listed above.
|
|
121
121
|
|
|
122
|
+
## Reuse first
|
|
123
|
+
|
|
124
|
+
Before authoring, the client calls `find_existing_blocks` with the goal and, when
|
|
125
|
+
known, the inputs it starts from and the results it must produce. It searches
|
|
126
|
+
reviewed Marketplace listings, tested Community Blocks, built-ins and the
|
|
127
|
+
person's own Blocks by function and name, with no model, provider or credit
|
|
128
|
+
cost, and returns one outcome:
|
|
129
|
+
|
|
130
|
+
- `use` or `use-own`: an existing Block already does it; offer it instead of building.
|
|
131
|
+
- `remix`: a close Block allows an attributed remix. `begin_block_remix` creates a
|
|
132
|
+
private draft from that exact version, with its license, notices and creator
|
|
133
|
+
credit; retrying the same `requestId` returns the same draft.
|
|
134
|
+
- `compose` or `build-gap`: existing Blocks chain together; build only the missing step.
|
|
135
|
+
- `build`: nothing close exists, or the person wants their own version.
|
|
136
|
+
|
|
137
|
+
`validate_block_source` and `save_creation` also list up to three similar existing
|
|
138
|
+
Blocks (`similarExisting`). Publishing an exact copy of another creator's public
|
|
139
|
+
Block without remix lineage is refused.
|
|
140
|
+
|
|
122
141
|
## Block authoring uses the connected model
|
|
123
142
|
|
|
124
143
|
When a user asks Claude, GPT, or another MCP client to create or refine a Block,
|
|
125
144
|
the connected client model writes the complete SDK package itself. The default
|
|
126
|
-
sequence is `get_block_authoring_guide`, targeted `search_documentation` calls,
|
|
145
|
+
sequence is `find_existing_blocks`, `get_block_authoring_guide`, targeted `search_documentation` calls,
|
|
127
146
|
local source composition by that model, `validate_block_source`, repair of every
|
|
128
147
|
reported failure, optional offline `test_block_source` for an eligible package,
|
|
129
148
|
and `save_creation` with `kind: "block"` and the observed
|
package/PASTE_TO_LLM.md
CHANGED
|
@@ -10,6 +10,10 @@ Contract `stillmade.block-builder@1.0.0`. Humans, coding agents, imported source
|
|
|
10
10
|
|
|
11
11
|
Treat the current SDK (`stillmade.block.json` manifest, `packages/block-sdk` contracts, validators, examples and published docs) as the source of truth. Before writing code, read the manifest contract, at least two working first-party Blocks closest to the request, the runtime you will use, the typed port and resolver contracts, and the shared-interface contract when you need a custom view. Do not invent runtimes, operations, permissions, ports, host services or bridge calls. If the documentation and the validator disagree, the validator wins and the mismatch should be reported.
|
|
12
12
|
|
|
13
|
+
### Reuse first
|
|
14
|
+
|
|
15
|
+
Before building, check what already exists (`find_existing_blocks` over MCP, or the Marketplace and your library) by the inputs, results and operations the goal needs. Use an installed or reviewed Block that already does it; remix a close one so its license, notices and creator credit stay attached; chain existing Blocks and build only the missing step. Never republish another creator's source without remix lineage: public copies are refused. Build a new Block when nothing fits or the person asks for their own version, and say which similar Blocks you considered.
|
|
16
|
+
|
|
13
17
|
### Define the capability first
|
|
14
18
|
|
|
15
19
|
Translate the request into an explicit capability contract before implementation: what the Block does; each input with its type, meaning and whether it is required (prefer optional settings with safe defaults over extra required questions); each output with its type and meaning; persistent state; project context it reads; permissions; UI; long-running behavior; expected failures; cancellation; determinism; and whether it needs hosted models, media, desktop tools or shared editing. Keep the public interface as small and general as possible and keep implementation details out of it.
|
package/SDK.md
CHANGED
|
@@ -160,6 +160,10 @@ Contract `stillmade.block-builder@1.0.0`. Humans, coding agents, imported source
|
|
|
160
160
|
|
|
161
161
|
Treat the current SDK (`stillmade.block.json` manifest, `packages/block-sdk` contracts, validators, examples and published docs) as the source of truth. Before writing code, read the manifest contract, at least two working first-party Blocks closest to the request, the runtime you will use, the typed port and resolver contracts, and the shared-interface contract when you need a custom view. Do not invent runtimes, operations, permissions, ports, host services or bridge calls. If the documentation and the validator disagree, the validator wins and the mismatch should be reported.
|
|
162
162
|
|
|
163
|
+
### Reuse first
|
|
164
|
+
|
|
165
|
+
Before building, check what already exists (`find_existing_blocks` over MCP, or the Marketplace and your library) by the inputs, results and operations the goal needs. Use an installed or reviewed Block that already does it; remix a close one so its license, notices and creator credit stay attached; chain existing Blocks and build only the missing step. Never republish another creator's source without remix lineage: public copies are refused. Build a new Block when nothing fits or the person asks for their own version, and say which similar Blocks you considered.
|
|
166
|
+
|
|
163
167
|
### Define the capability first
|
|
164
168
|
|
|
165
169
|
Translate the request into an explicit capability contract before implementation: what the Block does; each input with its type, meaning and whether it is required (prefer optional settings with safe defaults over extra required questions); each output with its type and meaning; persistent state; project context it reads; permissions; UI; long-running behavior; expected failures; cancellation; determinism; and whether it needs hosted models, media, desktop tools or shared editing. Keep the public interface as small and general as possible and keep implementation details out of it.
|
|
@@ -1888,8 +1892,8 @@ event through an input with `"semantic": "workflow_event"` and
|
|
|
1888
1892
|
`"sources": ["project"]`.
|
|
1889
1893
|
|
|
1890
1894
|
Triggers work for recipe, JavaScript and hosted (`runtime: "capability"`)
|
|
1891
|
-
Blocks. Module Blocks run in
|
|
1892
|
-
|
|
1895
|
+
Blocks. Module Blocks run only in the person's browser, so they cannot declare
|
|
1896
|
+
triggers or run unattended. Sandboxed code has 25 seconds per run.
|
|
1893
1897
|
|
|
1894
1898
|
### Hosted Blocks run inside an approved budget
|
|
1895
1899
|
|
|
@@ -2136,9 +2140,11 @@ WebAssembly codec. Images arrive as saved references: read the bytes with
|
|
|
2136
2140
|
- Generating code at run time (`new Function`, used by Emscripten bindings) is
|
|
2137
2141
|
allowed inside the sandbox.
|
|
2138
2142
|
|
|
2139
|
-
Module Blocks run in StillMade in the browser
|
|
2140
|
-
|
|
2141
|
-
|
|
2143
|
+
Module Blocks run in StillMade in the person's browser, only while StillMade is
|
|
2144
|
+
open. They cannot run on a schedule, from an event or on new media: StillMade has
|
|
2145
|
+
no server sandbox for them. A workflow's background run stops before a module Step
|
|
2146
|
+
and the person runs it in the project. Marketplace listings show module Blocks as
|
|
2147
|
+
**Browser only**. For work that must run unattended, use a JavaScript Block.
|
|
2142
2148
|
|
|
2143
2149
|
### Test, pack and import
|
|
2144
2150
|
|
|
@@ -7050,6 +7056,10 @@ Contract `stillmade.block-builder@1.0.0`. Humans, coding agents, imported source
|
|
|
7050
7056
|
|
|
7051
7057
|
Treat the current SDK (`stillmade.block.json` manifest, `packages/block-sdk` contracts, validators, examples and published docs) as the source of truth. Before writing code, read the manifest contract, at least two working first-party Blocks closest to the request, the runtime you will use, the typed port and resolver contracts, and the shared-interface contract when you need a custom view. Do not invent runtimes, operations, permissions, ports, host services or bridge calls. If the documentation and the validator disagree, the validator wins and the mismatch should be reported.
|
|
7052
7058
|
|
|
7059
|
+
### Reuse first
|
|
7060
|
+
|
|
7061
|
+
Before building, check what already exists (`find_existing_blocks` over MCP, or the Marketplace and your library) by the inputs, results and operations the goal needs. Use an installed or reviewed Block that already does it; remix a close one so its license, notices and creator credit stay attached; chain existing Blocks and build only the missing step. Never republish another creator's source without remix lineage: public copies are refused. Build a new Block when nothing fits or the person asks for their own version, and say which similar Blocks you considered.
|
|
7062
|
+
|
|
7053
7063
|
### Define the capability first
|
|
7054
7064
|
|
|
7055
7065
|
Translate the request into an explicit capability contract before implementation: what the Block does; each input with its type, meaning and whether it is required (prefer optional settings with safe defaults over extra required questions); each output with its type and meaning; persistent state; project context it reads; permissions; UI; long-running behavior; expected failures; cancellation; determinism; and whether it needs hosted models, media, desktop tools or shared editing. Keep the public interface as small and general as possible and keep implementation details out of it.
|
package/package.json
CHANGED
|
@@ -39,6 +39,12 @@ function bestRequirementMatch(manifest,requirement,semantics) {
|
|
|
39
39
|
return matches.find(match=>match.exact) || matches[0] || null;
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
+
/** The best result slot (an output, or a planned terminal action) that meets
|
|
43
|
+
* a required {type, semantic}: {compatible, exact, reason}, or null. */
|
|
44
|
+
export function requirementMatch(manifest,requirement,semantics) {
|
|
45
|
+
return bestRequirementMatch(manifest,requirement,semantics);
|
|
46
|
+
}
|
|
47
|
+
|
|
42
48
|
export function blockProvidesRequirement(manifest,requirement,semantics) {
|
|
43
49
|
return !!bestRequirementMatch(manifest,requirement,semantics);
|
|
44
50
|
}
|
|
@@ -70,7 +76,7 @@ export function missingCapabilityPlacements(requirements,combination,candidates)
|
|
|
70
76
|
});
|
|
71
77
|
}
|
|
72
78
|
|
|
73
|
-
export function recommendProjectTypeCombinations({goal,requirements,handoffRequirements=[],sourceMaterials, resultPins={},candidates,semantics,trustedUsage=[],trustedExecution=[],trustedCosts=[],trustedCreators=[],executionPreference='any',executionDevices=[],maxSteps=8,beamWidth=12,maxEvaluations=1200}) {
|
|
79
|
+
export function recommendProjectTypeCombinations({goal,requirements,handoffRequirements=[],sourceMaterials, resultPins={},candidates,semantics,trustedUsage=[],trustedExecution=[],trustedCosts=[],trustedCreators=[],trustedQuality=[],executionPreference='any',executionDevices=[],maxSteps=8,beamWidth=12,maxEvaluations=1200}) {
|
|
74
80
|
assert(RECOMMENDATION_EXECUTION_PREFERENCES.includes(executionPreference),'RECOMMENDATION','Choose an available execution preference.');
|
|
75
81
|
assert(Array.isArray(executionDevices)&&executionDevices.length<=3&&new Set(executionDevices).size===executionDevices.length&&executionDevices.every(device=>RECOMMENDATION_EXECUTION_DEVICES.includes(device)),'RECOMMENDATION','Choose only phone, browser, or desktop execution devices.');
|
|
76
82
|
assert(typeof goal==='string' && goal.trim() && goal.length<=4000,'RECOMMENDATION','Describe what the software should do.');
|
|
@@ -103,6 +109,9 @@ export function recommendProjectTypeCombinations({goal,requirements,handoffRequi
|
|
|
103
109
|
const available=[...catalog.values()];
|
|
104
110
|
const usage=new Map(trustedUsage.filter(row=>Number.isSafeInteger(row.completedProjects) && row.completedProjects>=0 && Number.isSafeInteger(row.repeatUsers) && row.repeatUsers>=0).map(row=>[`${row.entityId}@${row.version}:${row.digest}`,row]));
|
|
105
111
|
const usageFor=candidate=>candidate.release?usage.get(`${candidate.release.entityId}@${candidate.release.version}:${candidate.release.digest}`):undefined;
|
|
112
|
+
// Distinct people other than the creator who installed each Block. A tie-break only.
|
|
113
|
+
const installs=new Map(trustedQuality.filter(row=>typeof row?.entityId==='string'&&Number.isSafeInteger(row.installs)&&row.installs>=0).map(row=>[row.entityId,row.installs]));
|
|
114
|
+
const installsFor=candidate=>candidate.release?installs.get(candidate.release.entityId):undefined;
|
|
106
115
|
const execution=new Map(trustedExecution.filter(row=>Number.isSafeInteger(row.terminalRuns) && row.terminalRuns>=5 && Number.isSafeInteger(row.completedRuns) && row.completedRuns>=0 && row.completedRuns<=row.terminalRuns && Number.isSafeInteger(row.observedUsers) && row.observedUsers>=3 && row.observedUsers<=row.terminalRuns).map(row=>[`${row.entityId}@${row.version}:${row.digest}`,row]));
|
|
107
116
|
const executionFor=candidate=>candidate.release?execution.get(`${candidate.release.entityId}@${candidate.release.version}:${candidate.release.digest}`):undefined;
|
|
108
117
|
const costs=new Map(trustedCosts.filter(row=>Number.isSafeInteger(row.costRuns) && row.costRuns>=5 && Number.isSafeInteger(row.costUsers) && row.costUsers>=3 && row.costUsers<=row.costRuns && Number.isFinite(row.medianNetCredits) && row.medianNetCredits>=0 && row.medianNetCredits<=Number.MAX_SAFE_INTEGER).map(row=>[`${row.entityId}@${row.version}:${row.digest}`,row]));
|
|
@@ -226,7 +235,10 @@ export function recommendProjectTypeCombinations({goal,requirements,handoffRequi
|
|
|
226
235
|
const exactResults=resultMatches.filter(result=>result?.match.exact).length,semanticFitBonus=exactResults*2;
|
|
227
236
|
const creatorHistory=selected.map(creatorFor).filter(Boolean);
|
|
228
237
|
const creatorBonus=selected.length?creatorHistory.reduce((total,row)=>total+(row.completedRuns+1)/(row.terminalRuns+2)-0.5,0)/selected.length:0;
|
|
229
|
-
|
|
238
|
+
// Reviewed Blocks win ties over Community ones; widely installed Blocks win ties over new ones.
|
|
239
|
+
const installBonus=selected.length?selected.reduce((total,candidate)=>total+Math.min(1,Math.log1p(installsFor(candidate)||0)/Math.log1p(50)),0)/selected.length:0;
|
|
240
|
+
const communityPenalty=selected.filter(candidate=>candidate.origin==='community').length*0.5;
|
|
241
|
+
const score=(coverage+handoffs.length-missingHandoffs.length)*1000-broken*300-missingSourceInputs.length*600-deviceIssues.length*300-audit.counts.questions*30-keys.length*10-approvals+usageBonus+preferenceBonus+semanticFitBonus+completionBonus+latencyBonus+costBonus+creatorBonus+installBonus-communityPenalty;
|
|
230
242
|
const resultAllocations=resultMatches.map((result,index)=>result?{requirement:wanted[index].key,stageId:connected.stages[result.candidateIndex].id,port:result.port,exact:result.match.exact,...(result.viaAction?{viaAction:result.viaAction,requestType:result.requestType}:{})}:null);
|
|
231
243
|
return {keys,pinnedConnections,definition:connected,audit,missing,missingHandoffs,sourceInputs,missingSourceInputs,handoffPlan,resultAllocations,deviceSupport,deviceIssues,score,coverage,assemblyReady:broken===0&&missing.length===0&&missingHandoffs.length===0&&unavailableSourceInputs.length===0&&deviceIssues.length===0,compatible:broken===0 && missing.length===0 && missingHandoffs.length===0 && missingSourceInputs.length===0 && deviceIssues.length===0,explanation:{requiredResults:wanted.length,coveredResults:coverage,requiredHandoffs:handoffs.length,connectedHandoffs:handoffs.length-missingHandoffs.length,missingSourceInputs:missingSourceInputs.length,plannedActionResults:resultAllocations.filter(item=>item?.viaAction).length,exactResults,compatibleResults:coverage-exactResults,semanticFitBonus,connectionIssues:broken,questions:audit.counts.questions,permissionDeclarations:approvals,blockCount:keys.length,requestedExecutionDevices:executionDevices,declaredSupportedDeviceChecks:deviceSupport.length-deviceIssues.length,unknownDeviceChecks:deviceIssues.filter(item=>item.status==='undeclared').length,unsupportedDeviceChecks:deviceIssues.filter(item=>item.status==='declared-unsupported').length,observedUsageBlocks:observed.length,usageBonus,observedExecutionBlocks:measured.length,completionBonus,observedLatencyBlocks:timed.length,latencyBonus,latencyMetric:'hosted-created-to-completed-median',observedCostBlocks:priced.length,costBonus,costMetric:'verified-single-call-net-credits-median',observedCreatorBlocks:creatorHistory.length,creatorBonus,creatorMetric:'other-block-hosted-completion-history',localBlocks,executionPreference,preferenceBonus}};
|
|
232
244
|
}
|
|
@@ -29,6 +29,9 @@ const SECTIONS=Object.freeze([
|
|
|
29
29
|
rule('source-of-truth','both',
|
|
30
30
|
'Use only documented SDK runtimes, types, operations, permissions and host APIs; never invent one.',
|
|
31
31
|
'Treat the current SDK (`stillmade.block.json` manifest, `packages/block-sdk` contracts, validators, examples and published docs) as the source of truth. Before writing code, read the manifest contract, at least two working first-party Blocks closest to the request, the runtime you will use, the typed port and resolver contracts, and the shared-interface contract when you need a custom view. Do not invent runtimes, operations, permissions, ports, host services or bridge calls. If the documentation and the validator disagree, the validator wins and the mismatch should be reported.'),
|
|
32
|
+
rule('reuse-first','both',
|
|
33
|
+
'Reuse before building: use, remix or chain an existing Block when one fits; build only what is missing.',
|
|
34
|
+
'Before building, check what already exists (`find_existing_blocks` over MCP, or the Marketplace and your library) by the inputs, results and operations the goal needs. Use an installed or reviewed Block that already does it; remix a close one so its license, notices and creator credit stay attached; chain existing Blocks and build only the missing step. Never republish another creator\'s source without remix lineage: public copies are refused. Build a new Block when nothing fits or the person asks for their own version, and say which similar Blocks you considered.'),
|
|
32
35
|
rule('capability-contract','block',
|
|
33
36
|
'Define the contract first: typed inputs (optional with safe defaults where possible), outputs, state, permissions, UI, failures and cancellation. Keep it small.',
|
|
34
37
|
'Translate the request into an explicit capability contract before implementation: what the Block does; each input with its type, meaning and whether it is required (prefer optional settings with safe defaults over extra required questions); each output with its type and meaning; persistent state; project context it reads; permissions; UI; long-running behavior; expected failures; cancellation; determinism; and whether it needs hosted models, media, desktop tools or shared editing. Keep the public interface as small and general as possible and keep implementation details out of it.'),
|
|
@@ -113,7 +116,7 @@ export const BUILDER_CONTRACT=Object.freeze({
|
|
|
113
116
|
gapClasses:GAP_CLASSES,
|
|
114
117
|
});
|
|
115
118
|
|
|
116
|
-
const SECTION_TITLES=Object.freeze({'source-of-truth':'Source of truth','capability-contract':'Define the capability first','compose':'Blocks compose','platform-primitives':'Use platform primitives','no-workarounds':'No hidden workarounds','ui':'Interface','multiplayer':'Shared editing','external-services':'External services','dependencies':'Dependencies','security':'Security','lifecycle':'Execution lifecycle','errors':'Useful failures','adapt-to-platform':'Adapt to the platform','verification':'What StillMade verifies','project-types':'Project Types','readiness-report':'Readiness report'});
|
|
119
|
+
const SECTION_TITLES=Object.freeze({'source-of-truth':'Source of truth','reuse-first':'Reuse first','capability-contract':'Define the capability first','compose':'Blocks compose','platform-primitives':'Use platform primitives','no-workarounds':'No hidden workarounds','ui':'Interface','multiplayer':'Shared editing','external-services':'External services','dependencies':'Dependencies','security':'Security','lifecycle':'Execution lifecycle','errors':'Useful failures','adapt-to-platform':'Adapt to the platform','verification':'What StillMade verifies','project-types':'Project Types','readiness-report':'Readiness report'});
|
|
117
120
|
const inScope=(scope,wanted)=>wanted==='all'||scope==='both'||scope===wanted;
|
|
118
121
|
|
|
119
122
|
/** Render the contract for a model prompt ('compact'), a guide ('full') or an SDK folder ('agents-md'). */
|
|
@@ -55,7 +55,7 @@ export async function runPackageAsync(pkg, values, options = {}) {
|
|
|
55
55
|
// A module runs only through an injected executor: StillMade's sandboxed
|
|
56
56
|
// browser Worker, or the CLI's local Node worker for the creator's own tests.
|
|
57
57
|
const pinned=structuredClone(pkg),input=validateValues(pinned.manifest.inputs,values);
|
|
58
|
-
assert(typeof options.module==='function','RUNTIME_UNAVAILABLE','Module Blocks run in StillMade in the browser, or locally with the SDK CLI.
|
|
58
|
+
assert(typeof options.module==='function','RUNTIME_UNAVAILABLE','Module Blocks run in StillMade in the browser, or locally with the SDK CLI. They cannot run unattended: StillMade has no server sandbox for module Blocks.');
|
|
59
59
|
const result=await executeHostCall(structuredClone(pinned),input,{signal:options.signal,execute:options.module});
|
|
60
60
|
assert(!options.signal?.aborted,'CANCELLED','Run cancelled');
|
|
61
61
|
assert(result&&typeof result==='object'&&Object.keys(result).every(key=>['outputs','logs'].includes(key)),'MODULE_RESULT','The module host returned an unexpected result');
|
|
@@ -6,8 +6,8 @@
|
|
|
6
6
|
|
|
7
7
|
export const BLOCK_TRIGGER_EVENTS=Object.freeze(['media.saved','schedule','webhook','project.completed','provider']);
|
|
8
8
|
export const BLOCK_TRIGGER_LIMITS=Object.freeze({triggers:4,labelLength:120,minEverySeconds:60,maxEverySeconds:31536000});
|
|
9
|
-
// Runtimes StillMade can run without anyone present. Module Blocks
|
|
10
|
-
//
|
|
9
|
+
// Runtimes StillMade can run without anyone present. Module Blocks run only in
|
|
10
|
+
// the person's browser (StillMade has no server sandbox for them).
|
|
11
11
|
export const UNATTENDED_RUNTIMES=Object.freeze(['recipe','javascript','capability']);
|
|
12
12
|
const MEDIA_TYPES=['image','video','audio','asset'];
|
|
13
13
|
const MEDIA_KINDS=['image','video','audio'];
|
|
@@ -27,7 +27,7 @@ export function triggerProblems(manifest){
|
|
|
27
27
|
const triggers=manifest?.triggers,problems=[],add=(path,message)=>problems.push({path,message});
|
|
28
28
|
if(triggers===undefined)return problems;
|
|
29
29
|
if(!Array.isArray(triggers)||!triggers.length||triggers.length>BLOCK_TRIGGER_LIMITS.triggers){add('triggers',`Declare 1–${BLOCK_TRIGGER_LIMITS.triggers} triggers`);return problems;}
|
|
30
|
-
if(!UNATTENDED_RUNTIMES.includes(manifest.runtime))add('triggers',manifest.runtime==='module'?'Module Blocks run in
|
|
30
|
+
if(!UNATTENDED_RUNTIMES.includes(manifest.runtime))add('triggers',manifest.runtime==='module'?'Module Blocks run only in the person\'s browser, so they cannot have triggers. Use a recipe, JavaScript or hosted (capability) Block for triggers':'Triggers need a recipe, JavaScript or hosted (capability) Block');
|
|
31
31
|
const seen=new Set();
|
|
32
32
|
triggers.forEach((trigger,index)=>{
|
|
33
33
|
const path=`triggers.${index}`;
|