@aefree/pi-unity 0.9.0 → 0.9.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/CHANGELOG.md +190 -173
- package/README.md +234 -197
- package/index.ts +1724 -1724
- package/package.json +75 -75
- package/skills/unity-batchmode-tests/SKILL.md +145 -145
- package/skills/unity-interactive-playmode-authoring/SKILL.md +91 -91
- package/skills/unity-pipeline-workflows/SKILL.md +52 -52
- package/src/unity-artifact-profile.ts +110 -110
- package/src/unity-batchmode.ts +355 -355
- package/src/unity-cli.ts +635 -635
- package/src/unity-file-discovery-filter.ts +89 -89
- package/src/unity-pipeline.ts +487 -487
|
@@ -1,91 +1,91 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: unity-interactive-playmode-authoring
|
|
3
|
-
description: Inspect and temporarily tune live Unity runtime objects through a reachable exact-copy Pipeline Editor while Play Mode remains active, then deliberately translate accepted runtime values into durable source or asset changes. Use only for explicit interactive Play Mode authoring or live visual experiments; not for ordinary compile, tests, planning, or batchmode.
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Unity Interactive Play Mode Authoring
|
|
7
|
-
|
|
8
|
-
Use this skill only when the user explicitly requests inspection or temporary mutation of live runtime state in an already-running exact Unity project copy. Typical examples include moving a runtime UI element while the user watches, tuning a value interactively, or exploring which connected Pipeline interaction mode can reach a live object.
|
|
9
|
-
|
|
10
|
-
Do not activate this skill for ordinary source edits, serialized-asset authoring, planning inspection, compilation, tests, screenshots alone, or opening Unity. Use the owning Unity workflow for those operations.
|
|
11
|
-
|
|
12
|
-
## Preconditions
|
|
13
|
-
|
|
14
|
-
1. Resolve the exact Unity project path; never route by display name or a similarly named workspace.
|
|
15
|
-
2. Call `unity_project_status` and require a verified matching Editor process, a reachable exact-copy Pipeline instance, and the advertised commands needed for the intended operation.
|
|
16
|
-
3. Inspect the advertised `editor_status` and require Play Mode to be active for a live-runtime experiment. If Play Mode is not active, do not enter it unless the user explicitly requested that lifecycle change.
|
|
17
|
-
4. Revalidate exact project path and Editor/Pipeline process identity before each mutation. Stop on unknown, stale, unreachable, or changed identity.
|
|
18
|
-
5. Establish the target object, requested temporary effect, and expected observation before mutation. Do not explore by changing unrelated live objects.
|
|
19
|
-
|
|
20
|
-
## Choose the Smallest Interaction Surface
|
|
21
|
-
|
|
22
|
-
Choose the smallest route that answers the question clearly:
|
|
23
|
-
|
|
24
|
-
1. **Advertised typed command.** Use a purpose-built command when its validation and result shape fit the task.
|
|
25
|
-
2. **One-shot connected command or `eval`.** Use advertised `eval` as the normal REPL escape hatch for project-specific properties, APIs, and operations that registered commands did not anticipate. Prefer one bounded invocation with an explicit return value over a long-lived interactive shell.
|
|
26
|
-
|
|
27
|
-
Typed commands are conveniences, not exclusive gateways. Do not force repository inference or add a new wrapper merely to avoid a direct connected property inspection.
|
|
28
|
-
|
|
29
|
-
GameObject transform and component commands do not operate on every runtime object. For example, UI Toolkit `VisualElement`s are not scene GameObjects, so `set_transform` is not an appropriate route for their layout styles.
|
|
30
|
-
|
|
31
|
-
`unity shell` is a human interactive convenience over the same connected Pipeline surface. It is not a stronger Editor capability and is not the preferred agent automation route.
|
|
32
|
-
|
|
33
|
-
## Command Discovery
|
|
34
|
-
|
|
35
|
-
- Prefer the command inventory returned by `unity_project_status`; do not fan out across CLI help, shell, and trial dispatch when availability is already known.
|
|
36
|
-
- If raw `unity list` is exceptionally needed, parse the outer JSON envelope and read command records from `data.tools`, not a guessed top-level `commands` field.
|
|
37
|
-
- Inspect one exact command schema before dispatch rather than repeatedly trialing argument forms against the live Editor.
|
|
38
|
-
- Treat outer CLI success as transport evidence only. Parse nested `success`, diagnostics, status, and result fields before claiming success.
|
|
39
|
-
|
|
40
|
-
## Bounded Eval Rules
|
|
41
|
-
|
|
42
|
-
Pipeline `eval` compiles C# with Roslyn and runs it on the connected Editor's main thread. It can inspect or call any reachable engine, Editor, or project API; it is not intrinsically read-only, and a static syntax/property allowlist is not a reliable side-effect boundary.
|
|
43
|
-
|
|
44
|
-
- Use one bounded, target-specific snippet with an explicit return value.
|
|
45
|
-
- Regular property and state inspection is allowed when it serves the active task.
|
|
46
|
-
- Resolve the exact target and check for a missing target before mutation.
|
|
47
|
-
- Mutations must match the user's request. Lifecycle, destructive, persistent-setting, asset, package, selection, scene-save, import, build, test, and source-file changes require the same authorization they would through a typed command.
|
|
48
|
-
- Research unfamiliar Unity/C# APIs when needed, but do not add a purpose-built wrapper solely to avoid `eval`.
|
|
49
|
-
- Avoid obsolete APIs; evaluator diagnostics may treat obsolete usage as a compilation failure.
|
|
50
|
-
- Fully qualify APIs when extension-method or namespace ambiguity is likely.
|
|
51
|
-
- Treat any compiler diagnostic, nested failure, null target, malformed result, or identity change as failure. Do not retry mutations speculatively.
|
|
52
|
-
|
|
53
|
-
Use `unity_pipeline_eval` for exact-copy connected C# queries and operations. Use `unity_pipeline_inspect` when one of its package-owned purpose-built inspection commands provides better evidence.
|
|
54
|
-
|
|
55
|
-
## Live Tuning Loop
|
|
56
|
-
|
|
57
|
-
For each requested adjustment:
|
|
58
|
-
|
|
59
|
-
1. Revalidate the exact-copy Pipeline identity and Play Mode state.
|
|
60
|
-
2. Read the current live value when needed to make the requested relative or absolute adjustment.
|
|
61
|
-
3. Apply one bounded temporary mutation.
|
|
62
|
-
4. Return the observed before/after values and ask for the next adjustment only when user observation is required.
|
|
63
|
-
5. State that the override is non-persistent and may be replaced by rendering, rebinding, a domain reload, or Play Mode exit.
|
|
64
|
-
|
|
65
|
-
Do not infer that a serialized asset or source edit updates an existing runtime instance. Confirm the relevant refresh, rebind, or reconstruction path before claiming a live result.
|
|
66
|
-
|
|
67
|
-
## Persisting an Accepted Runtime Result
|
|
68
|
-
|
|
69
|
-
A request to persist authorizes the durable source/asset edit, but lifecycle changes remain explicit unless already authorized.
|
|
70
|
-
|
|
71
|
-
1. Capture the final runtime values and the owning coordinate space, dimensions, scale, or other context needed to convert them into authored values.
|
|
72
|
-
2. Identify the authoritative source or serialized field and trace how it becomes the runtime value. Do not write a visual coordinate into a guessed representation.
|
|
73
|
-
3. Determine whether persistence triggers asset import, script compilation, domain reload, or runtime reconstruction, and whether the current instance can consume the change.
|
|
74
|
-
4. Inspect `editor_status`. If Play Mode must stop,
|
|
75
|
-
5. Apply the durable edit with the owning file/asset tool.
|
|
76
|
-
6. Use the `unity-pipeline-workflows` skill for any required connected compilation and terminal status validation.
|
|
77
|
-
7. Re-enter Play Mode only when requested. Report temporary live confirmation and durable verification as separate evidence.
|
|
78
|
-
|
|
79
|
-
## Stop Conditions
|
|
80
|
-
|
|
81
|
-
Stop and report uncertainty instead of changing routes when:
|
|
82
|
-
|
|
83
|
-
- the exact-copy identity changes or cannot be revalidated;
|
|
84
|
-
- Pipeline disconnects outside an expected, separately authorized compile/reload transition;
|
|
85
|
-
- the target is ambiguous or disappears;
|
|
86
|
-
- the required operation has no typed command and cannot be expressed as one bounded target-specific eval;
|
|
87
|
-
- eval returns diagnostics, malformed output, or an unknown side effect;
|
|
88
|
-
- persistence ownership or runtime conversion cannot be established;
|
|
89
|
-
- a required Play Mode stop, restart, compile, save, or other lifecycle mutation is not authorized.
|
|
90
|
-
|
|
91
|
-
Never launch batchmode or another Editor to continue an interactive live-authoring session.
|
|
1
|
+
---
|
|
2
|
+
name: unity-interactive-playmode-authoring
|
|
3
|
+
description: Inspect and temporarily tune live Unity runtime objects through a reachable exact-copy Pipeline Editor while Play Mode remains active, then deliberately translate accepted runtime values into durable source or asset changes. Use only for explicit interactive Play Mode authoring or live visual experiments; not for ordinary compile, tests, planning, or batchmode.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Unity Interactive Play Mode Authoring
|
|
7
|
+
|
|
8
|
+
Use this skill only when the user explicitly requests inspection or temporary mutation of live runtime state in an already-running exact Unity project copy. Typical examples include moving a runtime UI element while the user watches, tuning a value interactively, or exploring which connected Pipeline interaction mode can reach a live object.
|
|
9
|
+
|
|
10
|
+
Do not activate this skill for ordinary source edits, serialized-asset authoring, planning inspection, compilation, tests, screenshots alone, or opening Unity. Use the owning Unity workflow for those operations.
|
|
11
|
+
|
|
12
|
+
## Preconditions
|
|
13
|
+
|
|
14
|
+
1. Resolve the exact Unity project path; never route by display name or a similarly named workspace.
|
|
15
|
+
2. Call `unity_project_status` and require a verified matching Editor process, a reachable exact-copy Pipeline instance, and the advertised commands needed for the intended operation.
|
|
16
|
+
3. Inspect the advertised `editor_status` and require Play Mode to be active for a live-runtime experiment. If Play Mode is not active, do not enter it unless the user explicitly requested that lifecycle change.
|
|
17
|
+
4. Revalidate exact project path and Editor/Pipeline process identity before each mutation. Stop on unknown, stale, unreachable, or changed identity.
|
|
18
|
+
5. Establish the target object, requested temporary effect, and expected observation before mutation. Do not explore by changing unrelated live objects.
|
|
19
|
+
|
|
20
|
+
## Choose the Smallest Interaction Surface
|
|
21
|
+
|
|
22
|
+
Choose the smallest route that answers the question clearly:
|
|
23
|
+
|
|
24
|
+
1. **Advertised typed command.** Use a purpose-built command when its validation and result shape fit the task.
|
|
25
|
+
2. **One-shot connected command or `eval`.** Use advertised `eval` as the normal REPL escape hatch for project-specific properties, APIs, and operations that registered commands did not anticipate. Prefer one bounded invocation with an explicit return value over a long-lived interactive shell.
|
|
26
|
+
|
|
27
|
+
Typed commands are conveniences, not exclusive gateways. Do not force repository inference or add a new wrapper merely to avoid a direct connected property inspection.
|
|
28
|
+
|
|
29
|
+
GameObject transform and component commands do not operate on every runtime object. For example, UI Toolkit `VisualElement`s are not scene GameObjects, so `set_transform` is not an appropriate route for their layout styles.
|
|
30
|
+
|
|
31
|
+
`unity shell` is a human interactive convenience over the same connected Pipeline surface. It is not a stronger Editor capability and is not the preferred agent automation route.
|
|
32
|
+
|
|
33
|
+
## Command Discovery
|
|
34
|
+
|
|
35
|
+
- Prefer the command inventory returned by `unity_project_status`; do not fan out across CLI help, shell, and trial dispatch when availability is already known.
|
|
36
|
+
- If raw `unity list` is exceptionally needed, parse the outer JSON envelope and read command records from `data.tools`, not a guessed top-level `commands` field.
|
|
37
|
+
- Inspect one exact command schema before dispatch rather than repeatedly trialing argument forms against the live Editor.
|
|
38
|
+
- Treat outer CLI success as transport evidence only. Parse nested `success`, diagnostics, status, and result fields before claiming success.
|
|
39
|
+
|
|
40
|
+
## Bounded Eval Rules
|
|
41
|
+
|
|
42
|
+
Pipeline `eval` compiles C# with Roslyn and runs it on the connected Editor's main thread. It can inspect or call any reachable engine, Editor, or project API; it is not intrinsically read-only, and a static syntax/property allowlist is not a reliable side-effect boundary.
|
|
43
|
+
|
|
44
|
+
- Use one bounded, target-specific snippet with an explicit return value.
|
|
45
|
+
- Regular property and state inspection is allowed when it serves the active task.
|
|
46
|
+
- Resolve the exact target and check for a missing target before mutation.
|
|
47
|
+
- Mutations must match the user's request. Lifecycle, destructive, persistent-setting, asset, package, selection, scene-save, import, build, test, and source-file changes require the same authorization they would through a typed command.
|
|
48
|
+
- Research unfamiliar Unity/C# APIs when needed, but do not add a purpose-built wrapper solely to avoid `eval`.
|
|
49
|
+
- Avoid obsolete APIs; evaluator diagnostics may treat obsolete usage as a compilation failure.
|
|
50
|
+
- Fully qualify APIs when extension-method or namespace ambiguity is likely.
|
|
51
|
+
- Treat any compiler diagnostic, nested failure, null target, malformed result, or identity change as failure. Do not retry mutations speculatively.
|
|
52
|
+
|
|
53
|
+
Use `unity_pipeline_eval` for exact-copy connected C# queries and operations. Use `unity_pipeline_inspect` when one of its package-owned purpose-built inspection commands provides better evidence.
|
|
54
|
+
|
|
55
|
+
## Live Tuning Loop
|
|
56
|
+
|
|
57
|
+
For each requested adjustment:
|
|
58
|
+
|
|
59
|
+
1. Revalidate the exact-copy Pipeline identity and Play Mode state.
|
|
60
|
+
2. Read the current live value when needed to make the requested relative or absolute adjustment.
|
|
61
|
+
3. Apply one bounded temporary mutation.
|
|
62
|
+
4. Return the observed before/after values and ask for the next adjustment only when user observation is required.
|
|
63
|
+
5. State that the override is non-persistent and may be replaced by rendering, rebinding, a domain reload, or Play Mode exit.
|
|
64
|
+
|
|
65
|
+
Do not infer that a serialized asset or source edit updates an existing runtime instance. Confirm the relevant refresh, rebind, or reconstruction path before claiming a live result.
|
|
66
|
+
|
|
67
|
+
## Persisting an Accepted Runtime Result
|
|
68
|
+
|
|
69
|
+
A request to persist authorizes the durable source/asset edit, but lifecycle changes remain explicit unless already authorized.
|
|
70
|
+
|
|
71
|
+
1. Capture the final runtime values and the owning coordinate space, dimensions, scale, or other context needed to convert them into authored values.
|
|
72
|
+
2. Identify the authoritative source or serialized field and trace how it becomes the runtime value. Do not write a visual coordinate into a guessed representation.
|
|
73
|
+
3. Determine whether persistence triggers asset import, script compilation, domain reload, or runtime reconstruction, and whether the current instance can consume the change.
|
|
74
|
+
4. Inspect `editor_status`. If Play Mode must stop, dispatch the advertised `editor_stop` and verify Play Mode exited.
|
|
75
|
+
5. Apply the durable edit with the owning file/asset tool.
|
|
76
|
+
6. Use the `unity-pipeline-workflows` skill for any required connected compilation and terminal status validation.
|
|
77
|
+
7. Re-enter Play Mode only when requested. Report temporary live confirmation and durable verification as separate evidence.
|
|
78
|
+
|
|
79
|
+
## Stop Conditions
|
|
80
|
+
|
|
81
|
+
Stop and report uncertainty instead of changing routes when:
|
|
82
|
+
|
|
83
|
+
- the exact-copy identity changes or cannot be revalidated;
|
|
84
|
+
- Pipeline disconnects outside an expected, separately authorized compile/reload transition;
|
|
85
|
+
- the target is ambiguous or disappears;
|
|
86
|
+
- the required operation has no typed command and cannot be expressed as one bounded target-specific eval;
|
|
87
|
+
- eval returns diagnostics, malformed output, or an unknown side effect;
|
|
88
|
+
- persistence ownership or runtime conversion cannot be established;
|
|
89
|
+
- a required Play Mode stop, restart, compile, save, or other lifecycle mutation is not authorized.
|
|
90
|
+
|
|
91
|
+
Never launch batchmode or another Editor to continue an interactive live-authoring session.
|
|
@@ -1,52 +1,52 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: unity-pipeline-workflows
|
|
3
|
-
description: Recompile code or run focused Unity tests through a reachable com.unity.pipeline Editor without launching, closing, or manually polling another Unity process.
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Unity Pipeline Workflows
|
|
7
|
-
|
|
8
|
-
Use this workflow only for an already-running exact project copy with `com.unity.pipeline` installed and reachable.
|
|
9
|
-
|
|
10
|
-
## Preferred typed tools
|
|
11
|
-
|
|
12
|
-
Use one typed tool call for each supported connected operation:
|
|
13
|
-
|
|
14
|
-
- `unity_pipeline_recompile` for connected script compilation.
|
|
15
|
-
- `unity_pipeline_run_tests` for one focused `EditMode` or `PlayMode` test-name selection.
|
|
16
|
-
|
|
17
|
-
These tools resolve the exact copy, require advertised commands, inspect lifecycle state, dispatch once, validate identity, and poll internally with a fixed deadline. Do not recreate their wait loops with `bash`, `unity recompile_status`, or `unity test_status` calls.
|
|
18
|
-
|
|
19
|
-
A timeout or malformed response is uncertain: the Unity operation may still be running. Do not cancel, retry, launch batchmode, close the Editor, or claim a result without a new user-authorized decision.
|
|
20
|
-
|
|
21
|
-
## Preconditions and boundaries
|
|
22
|
-
|
|
23
|
-
1. Pass an explicit `path` when multiple project copies may be found; paths identify copies, not display names.
|
|
24
|
-
2. The typed tools require a reachable exact-copy Pipeline and advertised `editor_status` plus operation commands. A different connected client is not itself a project lock.
|
|
25
|
-
3.
|
|
26
|
-
4. Test success requires a well-formed terminal result, a known positive executed count, and zero failures. An asynchronous initiation with `Total: 0` and `running` is nonterminal.
|
|
27
|
-
5. Passing test records are intentionally discarded. Failures retain only a bounded set of failed/inconclusive names, messages, and stack excerpts.
|
|
28
|
-
|
|
29
|
-
## Compile
|
|
30
|
-
|
|
31
|
-
Call `unity_pipeline_recompile` with optional `path` and `timeoutSeconds` (default 180, maximum 3600). It reports either up-to-date scripts or a compact completion summary, including whether an explicit agent exit, Unity-policy-driven behavior, or unavailable policy applied. A defer policy can mean recompilation waits until Play Mode ends. Compiler failures, identity changes, cancellation, malformed evidence, and deadline expiry are tool errors.
|
|
32
|
-
|
|
33
|
-
## Focused tests
|
|
34
|
-
|
|
35
|
-
Call `unity_pipeline_run_tests` with:
|
|
36
|
-
|
|
37
|
-
- required `testPlatform`: `EditMode` or `PlayMode`;
|
|
38
|
-
- optional `testFilter`: one test-name filter only;
|
|
39
|
-
- optional `path` and `timeoutSeconds` (default 600, maximum 3600).
|
|
40
|
-
- before running PlayMode tests, check the Game View focus setting. Set it to Play Unfocused for the test run, then restore the previous setting afterward.
|
|
41
|
-
|
|
42
|
-
The tool treats `no_tests`, idle, and not-started statuses as safe inactivity, detects a pre-existing active connected test before dispatch, and stops rather than claiming or replacing active work. It captures returned mode/filter/run identity fields when available and stops as uncertain if status is clearly displaced by another run.
|
|
43
|
-
|
|
44
|
-
## Bounded raw CLI troubleshooting only
|
|
45
|
-
|
|
46
|
-
Normally call the typed tools, not raw CLI commands. If a typed tool is unavailable in an older installed package and a user specifically authorizes troubleshooting, first use `unity_project_status` and require advertised `recompile_status` or `run_tests` and `test_status`. Use the documented asynchronous form with `--async_tests true`, one fixed deadline, and bounded backoff; parse object and stringified nested JSON. `Total: 0` with `result: running` is a valid nonterminal initiating response. Passing evidence reports successful completion, a known positive executed-test count, and zero failures; nested `success:false`, changed exact-copy identity, or polling timeout is non-passing uncertainty. Do not silently fall back to batchmode after uncertain connected dispatch. Connected work does not guarantee NUnit XML.
|
|
47
|
-
|
|
48
|
-
## When not to use connected tools
|
|
49
|
-
|
|
50
|
-
Use `unity_run_test_batch` for a closed project, intentional isolation/CI, category or multiple filters, or required NUnit XML/log evidence. State the reason for that route. Do not use batchmode as an automatic fallback after an uncertain connected dispatch.
|
|
51
|
-
|
|
52
|
-
Use the typed compile/test tools when their polling and terminal evidence fit the task. Advertised Pipeline `eval` remains available through `unity_pipeline_eval` for bounded project-specific inspection or operations outside those typed workflows; it is an assistance surface, not a forbidden fallback or a substitute for the typed tools' completion protocol. Eval compiles arbitrary C# with Roslyn on the Editor main thread, so ordinary properties and local-variable snippets are valid; it is not expression-only or reliably statically read-only. Prefer typed tools for their stronger evidence, but let user intent and project guidance govern mutations. Lifecycle, persistent-setting, destructive, asset, scene-save, package, build, and test mutations require explicit authorization.
|
|
1
|
+
---
|
|
2
|
+
name: unity-pipeline-workflows
|
|
3
|
+
description: Recompile code or run focused Unity tests through a reachable com.unity.pipeline Editor without launching, closing, or manually polling another Unity process.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Unity Pipeline Workflows
|
|
7
|
+
|
|
8
|
+
Use this workflow only for an already-running exact project copy with `com.unity.pipeline` installed and reachable.
|
|
9
|
+
|
|
10
|
+
## Preferred typed tools
|
|
11
|
+
|
|
12
|
+
Use one typed tool call for each supported connected operation:
|
|
13
|
+
|
|
14
|
+
- `unity_pipeline_recompile` for connected script compilation.
|
|
15
|
+
- `unity_pipeline_run_tests` for one focused `EditMode` or `PlayMode` test-name selection.
|
|
16
|
+
|
|
17
|
+
These tools resolve the exact copy, require advertised commands, inspect lifecycle state, dispatch once, validate identity, and poll internally with a fixed deadline. Do not recreate their wait loops with `bash`, `unity recompile_status`, or `unity test_status` calls.
|
|
18
|
+
|
|
19
|
+
A timeout or malformed response is uncertain: the Unity operation may still be running. Do not cancel, retry, launch batchmode, close the Editor, or claim a result without a new user-authorized decision.
|
|
20
|
+
|
|
21
|
+
## Preconditions and boundaries
|
|
22
|
+
|
|
23
|
+
1. Pass an explicit `path` when multiple project copies may be found; paths identify copies, not display names.
|
|
24
|
+
2. The typed tools require a reachable exact-copy Pipeline and advertised `editor_status` plus operation commands. A different connected client is not itself a project lock.
|
|
25
|
+
3. `unity_pipeline_recompile` never sends `editor_stop` or overrides Unity's Script Changes While Playing preference. Known recompile-and-continue, stop-and-recompile, and defer policies proceed according to Unity's configured behavior. Pipeline 0.4 does not currently expose that preference, so the tool reports the unavailable policy while allowing recompilation to proceed. `unity_pipeline_run_tests` may dispatch advertised `editor_stop` when needed, then verifies Edit Mode before running tests. The tools never enter Play Mode, pause, save, launch, or close Unity; recompilation may perform Unity's normal asset refresh/import and script-change behavior.
|
|
26
|
+
4. Test success requires a well-formed terminal result, a known positive executed count, and zero failures. An asynchronous initiation with `Total: 0` and `running` is nonterminal.
|
|
27
|
+
5. Passing test records are intentionally discarded. Failures retain only a bounded set of failed/inconclusive names, messages, and stack excerpts.
|
|
28
|
+
|
|
29
|
+
## Compile
|
|
30
|
+
|
|
31
|
+
Call `unity_pipeline_recompile` with optional `path` and `timeoutSeconds` (default 180, maximum 3600). It reports either up-to-date scripts or a compact completion summary, including whether an explicit agent exit, Unity-policy-driven behavior, or unavailable policy applied. A defer policy can mean recompilation waits until Play Mode ends. Compiler failures, identity changes, cancellation, malformed evidence, and deadline expiry are tool errors.
|
|
32
|
+
|
|
33
|
+
## Focused tests
|
|
34
|
+
|
|
35
|
+
Call `unity_pipeline_run_tests` with:
|
|
36
|
+
|
|
37
|
+
- required `testPlatform`: `EditMode` or `PlayMode`;
|
|
38
|
+
- optional `testFilter`: one test-name filter only;
|
|
39
|
+
- optional `path` and `timeoutSeconds` (default 600, maximum 3600).
|
|
40
|
+
- before running PlayMode tests, check the Game View focus setting. Set it to Play Unfocused for the test run, then restore the previous setting afterward.
|
|
41
|
+
|
|
42
|
+
The tool treats `no_tests`, idle, and not-started statuses as safe inactivity, detects a pre-existing active connected test before dispatch, and stops rather than claiming or replacing active work. It captures returned mode/filter/run identity fields when available and stops as uncertain if status is clearly displaced by another run.
|
|
43
|
+
|
|
44
|
+
## Bounded raw CLI troubleshooting only
|
|
45
|
+
|
|
46
|
+
Normally call the typed tools, not raw CLI commands. If a typed tool is unavailable in an older installed package and a user specifically authorizes troubleshooting, first use `unity_project_status` and require advertised `recompile_status` or `run_tests` and `test_status`. Use the documented asynchronous form with `--async_tests true`, one fixed deadline, and bounded backoff; parse object and stringified nested JSON. `Total: 0` with `result: running` is a valid nonterminal initiating response. Passing evidence reports successful completion, a known positive executed-test count, and zero failures; nested `success:false`, changed exact-copy identity, or polling timeout is non-passing uncertainty. Do not silently fall back to batchmode after uncertain connected dispatch. Connected work does not guarantee NUnit XML.
|
|
47
|
+
|
|
48
|
+
## When not to use connected tools
|
|
49
|
+
|
|
50
|
+
Use `unity_run_test_batch` for a closed project, intentional isolation/CI, category or multiple filters, or required NUnit XML/log evidence. State the reason for that route. Do not use batchmode as an automatic fallback after an uncertain connected dispatch.
|
|
51
|
+
|
|
52
|
+
Use the typed compile/test tools when their polling and terminal evidence fit the task. Advertised Pipeline `eval` remains available through `unity_pipeline_eval` for bounded project-specific inspection or operations outside those typed workflows; it is an assistance surface, not a forbidden fallback or a substitute for the typed tools' completion protocol. Eval compiles arbitrary C# with Roslyn on the Editor main thread, so ordinary properties and local-variable snippets are valid; it is not expression-only or reliably statically read-only. Prefer typed tools for their stronger evidence, but let user intent and project guidance govern mutations. Lifecycle, persistent-setting, destructive, asset, scene-save, package, build, and test mutations require explicit authorization.
|
|
@@ -1,110 +1,110 @@
|
|
|
1
|
-
import { access } from "node:fs/promises";
|
|
2
|
-
import { fileURLToPath } from "node:url";
|
|
3
|
-
import * as path from "node:path";
|
|
4
|
-
import type {
|
|
5
|
-
ArtifactCandidateV1,
|
|
6
|
-
ArtifactProfileV1,
|
|
7
|
-
ArtifactValidationResultV1,
|
|
8
|
-
} from "@aefree/pi-project-artifacts/contracts/v1";
|
|
9
|
-
|
|
10
|
-
export const UNITY_ARTIFACT_PROFILE_ID_V1 = "unity.artifacts.v1" as const;
|
|
11
|
-
export const UNITY_RENDER_PIPELINES = ["builtin", "urp", "hdrp", "custom", "agnostic"] as const;
|
|
12
|
-
|
|
13
|
-
const OWNER = Object.freeze({
|
|
14
|
-
packageName: "@aefree/pi-unity",
|
|
15
|
-
packageVersion: "0.8.3",
|
|
16
|
-
packageRoot: path.resolve(fileURLToPath(new URL("..", import.meta.url))),
|
|
17
|
-
registeredBy: "index.ts",
|
|
18
|
-
});
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* Optional project-artifacts enrichment. These fields describe and validate
|
|
22
|
-
* metadata but never authorize raw discovery/filtering. Artifact paths already
|
|
23
|
-
* distinguish solutions from memories, while generic tags/module/component
|
|
24
|
-
* metadata remains project-owned and schema-open.
|
|
25
|
-
*/
|
|
26
|
-
export function createUnityArtifactProfileV1(): ArtifactProfileV1 {
|
|
27
|
-
return Object.freeze({
|
|
28
|
-
contractVersion: 1,
|
|
29
|
-
id: UNITY_ARTIFACT_PROFILE_ID_V1,
|
|
30
|
-
kind: "artifact-profile",
|
|
31
|
-
owner: OWNER,
|
|
32
|
-
artifactKinds: Object.freeze(["solution", "memory"]),
|
|
33
|
-
fields: Object.freeze([
|
|
34
|
-
{ name: "engine", type: "string", indexed: true, filterable: true, enumValues: Object.freeze(["unity"]) },
|
|
35
|
-
{ name: "unity_version", type: "string", indexed: true, filterable: true },
|
|
36
|
-
{ name: "unity_packages", type: "string_list", indexed: true, filterable: true },
|
|
37
|
-
{ name: "render_pipeline", type: "string", indexed: true, filterable: true, enumValues: UNITY_RENDER_PIPELINES },
|
|
38
|
-
{ name: "platforms", type: "string_list", indexed: true, filterable: true },
|
|
39
|
-
]),
|
|
40
|
-
validators: Object.freeze([{
|
|
41
|
-
id: "unity.artifact-metadata.v1",
|
|
42
|
-
async validate(_context, request) {
|
|
43
|
-
if (request.signal.aborted) return { outcome: "unavailable", code: "aborted", retryable: true };
|
|
44
|
-
return validateUnityArtifactMetadata(request.artifact);
|
|
45
|
-
},
|
|
46
|
-
}]),
|
|
47
|
-
async appliesTo(_context, request) {
|
|
48
|
-
if (request.signal.aborted) return false;
|
|
49
|
-
// A conventional docs path is not Unity authority. Require direct project
|
|
50
|
-
// evidence before contributing definitions or validation confidence.
|
|
51
|
-
try {
|
|
52
|
-
await access(path.join(request.workspaceRoot, "ProjectSettings", "ProjectVersion.txt"));
|
|
53
|
-
return true;
|
|
54
|
-
} catch {
|
|
55
|
-
return false;
|
|
56
|
-
}
|
|
57
|
-
},
|
|
58
|
-
});
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
/** Validate only declared Unity fields that are present; all fields are optional. */
|
|
62
|
-
export function validateUnityArtifactMetadata(artifact: ArtifactCandidateV1): ArtifactValidationResultV1 {
|
|
63
|
-
const frontmatter = artifact.frontmatter;
|
|
64
|
-
const issues: { code: string; field: string; summary: string }[] = [];
|
|
65
|
-
|
|
66
|
-
validateEnumString(frontmatter, "engine", ["unity"], issues);
|
|
67
|
-
validateNonEmptyString(frontmatter, "unity_version", issues);
|
|
68
|
-
validateStringList(frontmatter, "unity_packages", issues);
|
|
69
|
-
validateEnumString(frontmatter, "render_pipeline", UNITY_RENDER_PIPELINES, issues);
|
|
70
|
-
validateStringList(frontmatter, "platforms", issues);
|
|
71
|
-
|
|
72
|
-
return issues.length === 0 ? { outcome: "valid" } : { outcome: "invalid", issues };
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
function validateNonEmptyString(
|
|
76
|
-
frontmatter: Readonly<Record<string, unknown>>,
|
|
77
|
-
field: string,
|
|
78
|
-
issues: { code: string; field: string; summary: string }[],
|
|
79
|
-
): void {
|
|
80
|
-
const value = frontmatter[field];
|
|
81
|
-
if (value === undefined) return;
|
|
82
|
-
if (typeof value !== "string" || value.trim() === "") {
|
|
83
|
-
issues.push({ code: `unity_${field}_invalid`, field, summary: `Unity ${field} must be a non-empty string when present.` });
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
function validateEnumString(
|
|
88
|
-
frontmatter: Readonly<Record<string, unknown>>,
|
|
89
|
-
field: string,
|
|
90
|
-
values: readonly string[],
|
|
91
|
-
issues: { code: string; field: string; summary: string }[],
|
|
92
|
-
): void {
|
|
93
|
-
const value = frontmatter[field];
|
|
94
|
-
if (value === undefined) return;
|
|
95
|
-
if (typeof value !== "string" || !values.includes(value)) {
|
|
96
|
-
issues.push({ code: `unity_${field}_invalid`, field, summary: `Unity ${field} must be one of: ${values.join(", ")}.` });
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
function validateStringList(
|
|
101
|
-
frontmatter: Readonly<Record<string, unknown>>,
|
|
102
|
-
field: string,
|
|
103
|
-
issues: { code: string; field: string; summary: string }[],
|
|
104
|
-
): void {
|
|
105
|
-
const value = frontmatter[field];
|
|
106
|
-
if (value === undefined) return;
|
|
107
|
-
if (!Array.isArray(value) || value.length === 0 || value.some((item) => typeof item !== "string" || item.trim() === "")) {
|
|
108
|
-
issues.push({ code: `unity_${field}_invalid`, field, summary: `Unity ${field} must be a non-empty list of non-empty strings when present.` });
|
|
109
|
-
}
|
|
110
|
-
}
|
|
1
|
+
import { access } from "node:fs/promises";
|
|
2
|
+
import { fileURLToPath } from "node:url";
|
|
3
|
+
import * as path from "node:path";
|
|
4
|
+
import type {
|
|
5
|
+
ArtifactCandidateV1,
|
|
6
|
+
ArtifactProfileV1,
|
|
7
|
+
ArtifactValidationResultV1,
|
|
8
|
+
} from "@aefree/pi-project-artifacts/contracts/v1";
|
|
9
|
+
|
|
10
|
+
export const UNITY_ARTIFACT_PROFILE_ID_V1 = "unity.artifacts.v1" as const;
|
|
11
|
+
export const UNITY_RENDER_PIPELINES = ["builtin", "urp", "hdrp", "custom", "agnostic"] as const;
|
|
12
|
+
|
|
13
|
+
const OWNER = Object.freeze({
|
|
14
|
+
packageName: "@aefree/pi-unity",
|
|
15
|
+
packageVersion: "0.8.3",
|
|
16
|
+
packageRoot: path.resolve(fileURLToPath(new URL("..", import.meta.url))),
|
|
17
|
+
registeredBy: "index.ts",
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Optional project-artifacts enrichment. These fields describe and validate
|
|
22
|
+
* metadata but never authorize raw discovery/filtering. Artifact paths already
|
|
23
|
+
* distinguish solutions from memories, while generic tags/module/component
|
|
24
|
+
* metadata remains project-owned and schema-open.
|
|
25
|
+
*/
|
|
26
|
+
export function createUnityArtifactProfileV1(): ArtifactProfileV1 {
|
|
27
|
+
return Object.freeze({
|
|
28
|
+
contractVersion: 1,
|
|
29
|
+
id: UNITY_ARTIFACT_PROFILE_ID_V1,
|
|
30
|
+
kind: "artifact-profile",
|
|
31
|
+
owner: OWNER,
|
|
32
|
+
artifactKinds: Object.freeze(["solution", "memory"]),
|
|
33
|
+
fields: Object.freeze([
|
|
34
|
+
{ name: "engine", type: "string", indexed: true, filterable: true, enumValues: Object.freeze(["unity"]) },
|
|
35
|
+
{ name: "unity_version", type: "string", indexed: true, filterable: true },
|
|
36
|
+
{ name: "unity_packages", type: "string_list", indexed: true, filterable: true },
|
|
37
|
+
{ name: "render_pipeline", type: "string", indexed: true, filterable: true, enumValues: UNITY_RENDER_PIPELINES },
|
|
38
|
+
{ name: "platforms", type: "string_list", indexed: true, filterable: true },
|
|
39
|
+
]),
|
|
40
|
+
validators: Object.freeze([{
|
|
41
|
+
id: "unity.artifact-metadata.v1",
|
|
42
|
+
async validate(_context, request) {
|
|
43
|
+
if (request.signal.aborted) return { outcome: "unavailable", code: "aborted", retryable: true };
|
|
44
|
+
return validateUnityArtifactMetadata(request.artifact);
|
|
45
|
+
},
|
|
46
|
+
}]),
|
|
47
|
+
async appliesTo(_context, request) {
|
|
48
|
+
if (request.signal.aborted) return false;
|
|
49
|
+
// A conventional docs path is not Unity authority. Require direct project
|
|
50
|
+
// evidence before contributing definitions or validation confidence.
|
|
51
|
+
try {
|
|
52
|
+
await access(path.join(request.workspaceRoot, "ProjectSettings", "ProjectVersion.txt"));
|
|
53
|
+
return true;
|
|
54
|
+
} catch {
|
|
55
|
+
return false;
|
|
56
|
+
}
|
|
57
|
+
},
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/** Validate only declared Unity fields that are present; all fields are optional. */
|
|
62
|
+
export function validateUnityArtifactMetadata(artifact: ArtifactCandidateV1): ArtifactValidationResultV1 {
|
|
63
|
+
const frontmatter = artifact.frontmatter;
|
|
64
|
+
const issues: { code: string; field: string; summary: string }[] = [];
|
|
65
|
+
|
|
66
|
+
validateEnumString(frontmatter, "engine", ["unity"], issues);
|
|
67
|
+
validateNonEmptyString(frontmatter, "unity_version", issues);
|
|
68
|
+
validateStringList(frontmatter, "unity_packages", issues);
|
|
69
|
+
validateEnumString(frontmatter, "render_pipeline", UNITY_RENDER_PIPELINES, issues);
|
|
70
|
+
validateStringList(frontmatter, "platforms", issues);
|
|
71
|
+
|
|
72
|
+
return issues.length === 0 ? { outcome: "valid" } : { outcome: "invalid", issues };
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function validateNonEmptyString(
|
|
76
|
+
frontmatter: Readonly<Record<string, unknown>>,
|
|
77
|
+
field: string,
|
|
78
|
+
issues: { code: string; field: string; summary: string }[],
|
|
79
|
+
): void {
|
|
80
|
+
const value = frontmatter[field];
|
|
81
|
+
if (value === undefined) return;
|
|
82
|
+
if (typeof value !== "string" || value.trim() === "") {
|
|
83
|
+
issues.push({ code: `unity_${field}_invalid`, field, summary: `Unity ${field} must be a non-empty string when present.` });
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function validateEnumString(
|
|
88
|
+
frontmatter: Readonly<Record<string, unknown>>,
|
|
89
|
+
field: string,
|
|
90
|
+
values: readonly string[],
|
|
91
|
+
issues: { code: string; field: string; summary: string }[],
|
|
92
|
+
): void {
|
|
93
|
+
const value = frontmatter[field];
|
|
94
|
+
if (value === undefined) return;
|
|
95
|
+
if (typeof value !== "string" || !values.includes(value)) {
|
|
96
|
+
issues.push({ code: `unity_${field}_invalid`, field, summary: `Unity ${field} must be one of: ${values.join(", ")}.` });
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function validateStringList(
|
|
101
|
+
frontmatter: Readonly<Record<string, unknown>>,
|
|
102
|
+
field: string,
|
|
103
|
+
issues: { code: string; field: string; summary: string }[],
|
|
104
|
+
): void {
|
|
105
|
+
const value = frontmatter[field];
|
|
106
|
+
if (value === undefined) return;
|
|
107
|
+
if (!Array.isArray(value) || value.length === 0 || value.some((item) => typeof item !== "string" || item.trim() === "")) {
|
|
108
|
+
issues.push({ code: `unity_${field}_invalid`, field, summary: `Unity ${field} must be a non-empty list of non-empty strings when present.` });
|
|
109
|
+
}
|
|
110
|
+
}
|