The agent knew 23 of the editor's commands. It could not point a Variables node at a variable, group nodes, edit ports, transitions, containers, colliders or the project settings. Stage 5a brings the catalog to 85 commands in five areas and keeps every answer short. - The catalog lists names and descriptions only. With a query (an area or command names) it adds the arguments. All schemas at once would pass the 60 000 character limit of one answer. - add_port points a Variables node at a variable. The port takes the variable's kind, and an unknown name is refused with the list of the ones that exist. - add_group and add_comment take nodes instead of coordinates. They follow the nodes after the arrange step, in the same undo step. - The rule for which list a port picks from moved into portChoices.ts. Inspector and agent now share it. - The frame of a group around nodes moved into annotationDrag.ts, so the button and the agent get the same frame. - list_assets returns the project settings. get_asset shows the content of placed containers with the ids overrides need. get_graph shows declared ports and frame colors. - A new node is placed at the height of its port, in the free spot whose links cross the fewest others. A source goes left of the node it feeds. Before, new nodes always went right of the rest. - Arrange breaks a tie in crossings by putting the flow on top, and exec links pull harder when a column is sorted. - A comment over a group keeps clear of the group's title bar. - The agent's instructions and lint_graph ask to look at crossings too and to call arrange_graph when there are more than needed. Left out on purpose: file assets (no upload), paste from the clipboard, internal wrapper commands and switching plugins on. Found on the way: - Variable commands on a Struct asset did not run through WithStructTypes. New fields did not reach variables of that type. - A query "variables" also matched set_variables_scope. A word that names an area now means only that area. Tests: - agent-catalog (new, 10), agent-edit, graph-arrange (3 new) and relay green. 11 bends of the code, all red. - e2e 71 on atx: 22/22, the new check sees port speed and a group around all 4 drawn nodes. - Live on a test project: a speed variable of 300 moved the player to x 150.03 in 0.5 s. A re-placed Variables node landed below Axis input with 4 crossings instead of 7. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
173 lines
6.2 KiB
TypeScript
173 lines
6.2 KiB
TypeScript
import {
|
|
CreateAssetCommand,
|
|
DeleteAssetCommand,
|
|
DuplicateAssetCommand,
|
|
MakeProjectAssetCommand,
|
|
RenameAssetCommand,
|
|
ResetAssetPropertyCommand,
|
|
SetAssetPropertyCommand,
|
|
SetMachineScopeCommand,
|
|
SetMachineStartCommand,
|
|
SetStartSceneCommand,
|
|
SetVariablesPersistentCommand,
|
|
SetVariablesScopeCommand,
|
|
} from '../../../core/commands/assetCommands';
|
|
import { ASSET_TYPES, type AssetType } from '../../../core/model/AssetTypes';
|
|
import type { PropertyBag, PropertyValue } from '../../../core/model/Properties';
|
|
import type { Scope, SharedScope } from '../../../core/model/Scope';
|
|
import {
|
|
ASSET,
|
|
anyValue,
|
|
type CatalogCommand,
|
|
flag,
|
|
id,
|
|
madeAsset,
|
|
object,
|
|
oneOf,
|
|
text,
|
|
theAsset,
|
|
} from './shared';
|
|
|
|
/** Assets the agent cannot make: each needs a file, and there is no upload for agents. */
|
|
const FILE_TYPES: readonly AssetType[] = ['texture', 'font', 'sound', 'video'];
|
|
|
|
export const ASSET_COMMANDS: readonly CatalogCommand[] = [
|
|
{
|
|
name: 'create_asset',
|
|
description:
|
|
'Makes a new asset. A scene is where objects are placed; a sprite, text or camera is placed into one; ' +
|
|
"a behavior is a graph of nodes that runs on the object it is placed under. Textures, fonts, sounds and videos need a file and can't be made here.",
|
|
args: object(
|
|
{
|
|
type: {
|
|
type: 'string',
|
|
enum: ASSET_TYPES.filter((type) => !FILE_TYPES.includes(type)),
|
|
description: 'The kind of asset.',
|
|
},
|
|
name: { type: 'string', minLength: 1, description: 'Its name in the asset list.' },
|
|
props: {
|
|
type: 'object',
|
|
description: "Starting values of its properties by key (see catalog topic 'asset_types').",
|
|
},
|
|
},
|
|
['type', 'name'],
|
|
),
|
|
build: (args) => {
|
|
const command = new CreateAssetCommand(
|
|
text(args, 'type') as AssetType,
|
|
text(args, 'name'),
|
|
(args.props ?? {}) as PropertyBag,
|
|
);
|
|
return { command, made: { id: command.asset.id } };
|
|
},
|
|
shows: madeAsset,
|
|
},
|
|
{
|
|
name: 'rename_asset',
|
|
description: 'Renames an asset.',
|
|
args: object({ asset: ASSET, name: { type: 'string', minLength: 1 } }, ['asset', 'name']),
|
|
build: (args) => ({ command: new RenameAssetCommand(text(args, 'asset'), text(args, 'name')) }),
|
|
shows: theAsset,
|
|
},
|
|
{
|
|
name: 'duplicate_asset',
|
|
description: 'Copies an asset; the copy comes right behind it in the list.',
|
|
args: object({ asset: ASSET }, ['asset']),
|
|
build: (args) => {
|
|
const command = new DuplicateAssetCommand(text(args, 'asset'));
|
|
return { command, made: { id: command.copyId } };
|
|
},
|
|
shows: madeAsset,
|
|
},
|
|
{
|
|
name: 'delete_asset',
|
|
description:
|
|
'Deletes an asset and what depends on it (placed copies of it, for one). The user is asked first and may say no.',
|
|
args: object({ asset: ASSET }, ['asset']),
|
|
confirms: true,
|
|
build: (args) => ({ command: new DeleteAssetCommand(text(args, 'asset')) }),
|
|
},
|
|
{
|
|
name: 'set_asset_property',
|
|
description: "Sets a property of an asset by its key (see get_asset, or catalog topic 'asset_types').",
|
|
args: object({ asset: ASSET, key: id('Key of the property.'), value: anyValue }, [
|
|
'asset',
|
|
'key',
|
|
'value',
|
|
]),
|
|
build: (args) => ({
|
|
command: new SetAssetPropertyCommand(
|
|
text(args, 'asset'),
|
|
text(args, 'key'),
|
|
args.value as PropertyValue,
|
|
),
|
|
}),
|
|
shows: theAsset,
|
|
},
|
|
{
|
|
name: 'reset_asset_property',
|
|
description: 'Puts a property of an asset back to what a new asset starts with.',
|
|
args: object({ asset: ASSET, key: id('Key of the property.') }, ['asset', 'key']),
|
|
build: (args) => ({ command: new ResetAssetPropertyCommand(text(args, 'asset'), text(args, 'key')) }),
|
|
shows: theAsset,
|
|
},
|
|
{
|
|
name: 'set_start_scene',
|
|
description: 'Makes a scene the one the game starts in; an empty scene id takes that back.',
|
|
args: object({ scene: { type: 'string', description: 'Id of the scene, or "".' } }, ['scene']),
|
|
build: (args) => ({ command: new SetStartSceneCommand(text(args, 'scene')) }),
|
|
},
|
|
{
|
|
name: 'set_machine_scope',
|
|
description:
|
|
'How many current states a state machine keeps: local, one per behavior running it; global, one for the ' +
|
|
'whole run; scene, one that starts over with every scene.',
|
|
args: object({ asset: ASSET, scope: oneOf(['local', 'global', 'scene'], 'The scope.') }, [
|
|
'asset',
|
|
'scope',
|
|
]),
|
|
build: (args) => ({
|
|
command: new SetMachineScopeCommand(text(args, 'asset'), text(args, 'scope') as Scope),
|
|
}),
|
|
shows: theAsset,
|
|
},
|
|
{
|
|
name: 'set_machine_start',
|
|
description: 'Makes a state node the state a machine starts in; an empty node id takes the mark off.',
|
|
args: object({ asset: ASSET, node: { type: 'string', description: 'Id of the state node, or "".' } }, [
|
|
'asset',
|
|
'node',
|
|
]),
|
|
build: (args) => ({ command: new SetMachineStartCommand(text(args, 'asset'), text(args, 'node')) }),
|
|
shows: theAsset,
|
|
},
|
|
{
|
|
name: 'set_variables_scope',
|
|
description:
|
|
'How long the values of a Variables asset live: global, the whole run; scene, built again with every scene ' +
|
|
'(which also switches persistent off).',
|
|
args: object({ asset: ASSET, scope: oneOf(['global', 'scene'], 'The scope.') }, ['asset', 'scope']),
|
|
build: (args) => ({
|
|
command: new SetVariablesScopeCommand(text(args, 'asset'), text(args, 'scope') as SharedScope),
|
|
}),
|
|
shows: theAsset,
|
|
},
|
|
{
|
|
name: 'set_variables_persistent',
|
|
description: 'Whether a Variables asset keeps its values past the end of the run, saved in the browser.',
|
|
args: object({ asset: ASSET, persistent: flag('Keep them.') }, ['asset', 'persistent']),
|
|
build: (args) => ({
|
|
command: new SetVariablesPersistentCommand(text(args, 'asset'), args.persistent as boolean),
|
|
}),
|
|
shows: theAsset,
|
|
},
|
|
{
|
|
name: 'make_project_asset',
|
|
description:
|
|
"Makes an asset a song keeps to itself (it has an owner in list_assets) one of the project's own, shown in the lists.",
|
|
args: object({ asset: ASSET }, ['asset']),
|
|
build: (args) => ({ command: new MakeProjectAssetCommand(text(args, 'asset')) }),
|
|
shows: theAsset,
|
|
},
|
|
];
|