Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 81 additions & 0 deletions .github/workflows/artist-intent-experimental.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
name: Artist Context experimental gate

on:
push:
branches:
- integration/artist-intent-core-2026-10-10
workflow_dispatch:

permissions:
contents: read

jobs:
intent-contract:
runs-on: ubuntu-latest
timeout-minutes: 20
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '22'
cache: npm
- name: Install project dependencies (no lifecycle scripts)
run: npm ci --ignore-scripts --no-audit --no-fund
- name: Assert test source parses
run: node --check src/areas/workflows/nodes/intent-travel/processor.test.mjs
- name: Artist Context unit tests
run: node --test src/areas/workflows/nodes/intent-travel/processor.test.mjs
- name: Typed built-in processors
run: ./node_modules/.bin/tsc --noEmit -p tsconfig.builtins.json
- name: Full Node suite (staged integration)
id: node_suite
continue-on-error: true
run: npm run test:node
- name: Main-process typecheck (staged integration)
id: main_types
continue-on-error: true
run: ./node_modules/.bin/tsc --noEmit -p tsconfig.node.json
- name: ESLint (staged integration)
id: lint
continue-on-error: true
run: npm run lint
- name: Electron desktop bundle (not a packaged Windows app)
id: build
continue-on-error: true
run: npm run build
- uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Install API dependencies
run: python -m pip install --disable-pip-version-check -r api/requirements.txt
- name: Python suite (staged integration)
id: python_suite
continue-on-error: true
run: npm run test:py
- name: Integrations gate
if: steps.node_suite.outcome != 'success' || steps.main_types.outcome != 'success' || steps.lint.outcome != 'success' || steps.build.outcome != 'success' || steps.python_suite.outcome != 'success'
run: |
echo 'At least one integrated check failed; see the individual check logs.'
exit 1

windows-smoke:
runs-on: windows-latest
timeout-minutes: 20
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '22'
cache: npm
- name: Install dependencies (no lifecycle scripts)
run: npm ci --ignore-scripts --no-audit --no-fund
- name: Windows destructive-storage regression
run: node --test --experimental-strip-types --experimental-loader ./scripts/node-ts-extensionless-loader.mjs electron/main/storage-directory-guard.test.ts
- name: Windows artist-intent regression
run: node --test src/areas/workflows/nodes/intent-travel/processor.test.mjs
- name: Windows main-process typecheck
run: npx --no-install tsc --noEmit -p tsconfig.node.json
- name: Windows built-ins typecheck
run: npx --no-install tsc --noEmit -p tsconfig.builtins.json
- name: Build desktop bundle on Windows
run: npm run build
58 changes: 58 additions & 0 deletions docs/experimental-artist-intent.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# Experimental Artist Context — first slice of upstream #252

This is a **candidate**, not a validated Modly release. Original feature author:
[OmarB97](https://github.com/OmarB97), source:
[lightningpixel/modly#252](https://github.com/lightningpixel/modly/pull/252).

## Why a separate experiment?

The upstream PR combines a versioned artist-intent sidecar, automatic workflow
propagation, animation/quality hints and live texture hot reload. It predates
the current v0.4.3 shared mesh operations, scene artifacts and llama.cpp agent.
Importing the entire old branch would replace working new code.

This branch includes *only* the explicit `intent-travel` process extension:
- **Remember Artist Context** accepts an image, creates a unique staged copy
below `workspace/Workflows/intent-sources/<id>/source.<ext>`, and writes its
`.tags.json` with an append-only-style `modly.intent.v1` record.
- **Carry Artist Context** accepts a workspace asset *whose sidecar already
has intent*, plus a separate **existing** workspace destination asset
selected by `destinationPath`. It verifies both paths physically remain
inside the workspace and merges the intent by ID, refusing disagreement.

Each start has a fresh ID. Fields cover project, movement, extra details,
style name and style prompt, and the source image's filename. The original
external image is not modified.

**Critical limitation:** this does **not** automatically carry intent
across a generator that outputs a new mesh. After a normal image→3D step,
the resulting mesh will not necessarily have the source image's sidecar.
The carry node therefore requires an explicit source asset that already
contains an intent record. Do not advertise this as a complete end-to-end
artist-memory workflow yet.

## Safety contract

- Managed sidecars and carry source/destination must remain within the
canonical workspace; symlinked sidecars and staging ancestors that escape
the workspace are rejected.
- A source image can be read from outside only after its extension is
verified and its size is capped at 64 MiB, then it is copied into the
managed workspace. Sidecars and records are limited to 1 MiB.
- A conflicting `intent_id` fails without overwriting the destination
metadata. Existing metadata fields are retained.
- This is not an OS-level sandbox, and symlink races/external modifications
still require broader runtime/security review.

## Verification ledger

- [x] Files written to a dedicated branch, separate from `main`.
- [x] Nine regression test cases added, including workspace escapes,
symlinks, oversized sidecars, missing destinations, and intent conflicts.
- [ ] Run targeted Node tests against the full repository dependencies.
- [ ] Run full Node/Python test suites, TypeScript checking, lint and Electron.
- [ ] Test on Windows, including junctions, long paths, and normal asset flows.
- [ ] Test actual UI/extension wiring, existing project data and data retention.

The live-texture-watch component of #252 is intentionally **not** part of this
slice. Integrate and validate it separately.
18 changes: 15 additions & 3 deletions docs/experimental-library-integration-ledger.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,14 @@ Modly repository. The adaptations in this fork do not supersede their source PRs
and responsive Library placement. Seven isolated Node tests passed for the
binding helper, including orphaned/self references and prototype-safe keys.
Native Electron/browser smoke tests and combined project CI remain unrun.
- **#252 (Artist intent record and texture hot reload):** much larger divergent
patch (workflow and API changes, new watcher services, extra proof assets).
Requires separate rebase and validation against 0.4.3 and #246/#251.
- **#252 (Artist intent + texture hot reload):** divided into separately
reviewable features. The child branch `integration/artist-intent-core-2026-10-10`
now stages **explicit** Artist Context start/carry nodes and the versioned
`modly.intent.v1` record. The carrying operations verify physical workspace
containment, reject sidecar symlinks and cap input and metadata sizes.
**Automatic** intent propagation through generated model stages, texture
hot-reloading, and proof assets are **NOT** integrated. The nine regression
tests are added to the Node test command; full suite and Windows smoke are pending.

## Validation checklist — currently not executed on the combined branch

Expand All @@ -62,6 +67,13 @@ Modly repository. The adaptations in this fork do not supersede their source PRs
ancestry labels in the exported .tags.json, with symlink and multi-parent cases.
- [ ] Check chat context with sidecars, embedded GLB extras, long/malicious labels,
and its tool responses under both local and external LLM providers.
- [ ] Exercise the explicit #252 start/carry nodes in a real workflow with valid
PNG input and GLB output, including restart, conflicting intent IDs,
temporary workspace cleanup and sidecar read/write failures.
- [ ] Design separate additive automation for carrying `modly.intent.v1` through
model generation; do not gate ordinary existing workflows on its presence.
- [ ] Review #252 live texture watcher on another branch; avoid importing the
old fork UI/renderer files wholesale.
- [ ] Verify source #370 destructive-storage safeguards and related tests in
the final combined branch.
- [ ] Review source #266 local API security separately (not included).
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
"prepare-resources": "node scripts/download-python-embed.js",
"test": "npm run test:py && npm run test:node",
"test:py": "node scripts/run-pytests.mjs",
"test:node": "node --test --experimental-strip-types --experimental-loader ./scripts/node-ts-extensionless-loader.mjs src/shared/types/assetLibrary.test.ts src/areas/generate/assetLibraryProjection.test.ts src/areas/generate/assetLibraryService.test.ts src/areas/generate/assetLibraryUi.test.ts src/areas/generate/orcaSlicerLink.test.ts electron/main/artifact-registry-service.test.ts electron/main/extension-path-guard.test.ts electron/main/storage-directory-guard.test.ts electron/preload/artifact-registry-preload.test.ts && node --test electron/main/*.test.mjs src/**/*.test.mjs && node --experimental-strip-types --test src/areas/workflows/workflowParamBindings.test.mjs src/areas/workflows/nodes/mesh-exporter/lineage.test.mjs",
"test:node": "node --test --experimental-strip-types --experimental-loader ./scripts/node-ts-extensionless-loader.mjs src/shared/types/assetLibrary.test.ts src/areas/generate/assetLibraryProjection.test.ts src/areas/generate/assetLibraryService.test.ts src/areas/generate/assetLibraryUi.test.ts src/areas/generate/orcaSlicerLink.test.ts electron/main/artifact-registry-service.test.ts electron/main/extension-path-guard.test.ts electron/main/storage-directory-guard.test.ts electron/preload/artifact-registry-preload.test.ts && node --test electron/main/*.test.mjs src/**/*.test.mjs && node --experimental-strip-types --test src/areas/workflows/workflowParamBindings.test.mjs src/areas/workflows/nodes/mesh-exporter/lineage.test.mjs && node --test src/areas/workflows/nodes/intent-travel/processor.test.mjs",
"package": "cross-env CSC_IDENTITY_AUTO_DISCOVERY=false npm run build && npm run prepare-resources && electron-builder",
"package:mac": "cross-env CSC_IDENTITY_AUTO_DISCOVERY=false npm run build && npm run prepare-resources && electron-builder --mac --arm64",
"lint": "eslint ."
Expand Down
67 changes: 67 additions & 0 deletions src/areas/workflows/nodes/intent-travel/manifest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
{
"id": "intent-travel",
"name": "Artist Context",
"type": "process",
"entry": "processor.js",
"version": "1.0.0",
"author": "Modly",
"description": "Carries the artist's exact request alongside every workflow asset.",
"nodes": [
{
"id": "start",
"name": "Remember Artist Context",
"input": "image",
"output": "image",
"params_schema": [
{
"id": "project",
"label": "Project",
"type": "text",
"default": ""
},
{
"id": "extraDetails",
"label": "Extra details",
"type": "text",
"multiline": true,
"default": ""
},
{
"id": "movement",
"label": "Movement brief",
"type": "text",
"multiline": true,
"default": ""
},
{
"id": "styleName",
"label": "Style name",
"type": "text",
"default": ""
},
{
"id": "stylePrompt",
"label": "Style prompt",
"type": "text",
"multiline": true,
"default": ""
}
]
},
{
"id": "carry",
"name": "Carry Artist Context",
"input": "mesh",
"output": "mesh",
"params_schema": [
{
"id": "destinationPath",
"label": "Destination asset (existing)",
"type": "string",
"pickerIntent": "mesh",
"default": ""
}
]
}
]
}
Loading
Loading