@alpsckr/unitycli 0.4.1 → 0.4.3
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/README.md +15 -12
- package/contracts/init-contract.json +11 -4
- package/contracts/package-files.json +3 -3
- package/dist/cli-commands/init-discovery.d.ts +9 -2
- package/dist/cli-commands/init-discovery.js +60 -50
- package/dist/cli-commands/init-discovery.js.map +1 -1
- package/dist/cli-commands/init-help.js +13 -9
- package/dist/cli-commands/init-help.js.map +1 -1
- package/dist/cli-commands/init-skill.d.ts +1 -1
- package/dist/cli-commands/init-skill.js +92 -26
- package/dist/cli-commands/init-skill.js.map +1 -1
- package/dist/cli-commands/package.js +59 -12
- package/dist/cli-commands/package.js.map +1 -1
- package/dist/cli-commands/skill-installer.d.ts +15 -7
- package/dist/cli-commands/skill-installer.js +106 -66
- package/dist/cli-commands/skill-installer.js.map +1 -1
- package/dist/cli-commands/types.d.ts +3 -0
- package/dist/cli.js +5 -3
- package/dist/cli.js.map +1 -1
- package/dist/package-manager.d.ts +5 -1
- package/dist/package-manager.js +21 -9
- package/dist/package-manager.js.map +1 -1
- package/dist/unity-project-processes.d.ts +7 -0
- package/dist/unity-project-processes.js +54 -0
- package/dist/unity-project-processes.js.map +1 -1
- package/docs/architecture.md +3 -3
- package/docs/error-codes.md +16 -0
- package/docs/extensions.md +3 -1
- package/package.json +1 -1
- package/schemas/init.schema.json +95 -10
- package/skills/unitycli/SKILL.md +26 -42
- package/skills/unitycli/manifest.json +1 -1
- package/skills/unitycli/references/operation-protocol.md +1 -1
- package/skills/unitycli/reports/output_quality_scorecard.md +1 -1
- package/skills/unitycli/reports/trust-report.md +1 -1
- package/unitypkg/package.json +1 -1
package/README.md
CHANGED
|
@@ -8,7 +8,7 @@ Windows-first Unity Editor automation CLI for AI agents. The executable is `unit
|
|
|
8
8
|
- Node.js 20 or newer
|
|
9
9
|
- Unity 2022.3 or newer
|
|
10
10
|
- A Unity project when installing the Bridge
|
|
11
|
-
- An opened Unity Editor only when using live Unity capabilities; installation
|
|
11
|
+
- An opened Unity Editor only when using live Unity capabilities; installation may normally close only the exact target Editor after explicit user approval
|
|
12
12
|
|
|
13
13
|
## Install
|
|
14
14
|
|
|
@@ -22,14 +22,7 @@ Start your AI in the directory where you normally work and tell it:
|
|
|
22
22
|
|
|
23
23
|
> 执行 unitycli init help,然后照做。
|
|
24
24
|
|
|
25
|
-
`init help` contains the complete AI installation protocol.
|
|
26
|
-
|
|
27
|
-
- which discovered Unity projects should receive the Bridge;
|
|
28
|
-
- whether the Skill target is generic Agent Skills (`.agents`) or Claude;
|
|
29
|
-
- whether the Skill belongs to one workspace or to the current user;
|
|
30
|
-
- which directory is your normal AI workspace when workspace scope is selected.
|
|
31
|
-
|
|
32
|
-
The AI does not silently choose these values. Multiple Bridge projects are installed one at a time. Installation does not start, close, restart, or terminate Unity.
|
|
25
|
+
`init help` contains the complete AI installation protocol. Read-only discovery uses the unique current Unity project and workspace without asking you to repeat them, reports the installed and available Bridge versions, and accepts any exact Skill directory you already named. It asks only when a real choice remains, including permission to normally close the exact target Unity Editor before replacing an in-use Bridge. It never force-terminates Unity or decides an unsaved-scene prompt.
|
|
33
26
|
|
|
34
27
|
## Manual Setup
|
|
35
28
|
|
|
@@ -40,14 +33,22 @@ unitycli init help
|
|
|
40
33
|
unitycli init discover
|
|
41
34
|
```
|
|
42
35
|
|
|
43
|
-
Install or repair the Bridge in one explicit Unity project:
|
|
36
|
+
Install or repair the Bridge in one explicit Unity project. Use `--close-editor` only after the user approves normally closing that exact project:
|
|
44
37
|
|
|
45
38
|
```powershell
|
|
46
39
|
unitycli init package --project C:\path\UnityProject
|
|
40
|
+
unitycli init package --project C:\path\UnityProject --close-editor
|
|
47
41
|
unitycli init package --project C:\path\UnityProject --check
|
|
48
42
|
```
|
|
49
43
|
|
|
50
|
-
Install or check
|
|
44
|
+
Install or check an exact user-selected Skill directory, including Pi:
|
|
45
|
+
|
|
46
|
+
```powershell
|
|
47
|
+
unitycli init skill --target C:\path\Workspace\.pi\skills\unitycli
|
|
48
|
+
unitycli init skill --target C:\path\Workspace\.pi\skills\unitycli --check
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Generic Agent Skills remain available as a preset:
|
|
51
52
|
|
|
52
53
|
```powershell
|
|
53
54
|
unitycli init skill --agent .agents --scope workspace --workspace C:\path\Workspace
|
|
@@ -71,7 +72,7 @@ unitycli init skill --agent claude --scope user
|
|
|
71
72
|
unitycli init skill --agent claude --scope user --check
|
|
72
73
|
```
|
|
73
74
|
|
|
74
|
-
|
|
75
|
+
Preset workspace and user scope are separate choices. An exact `--target` is final user intent and cannot be combined with preset agent/scope options. Bridge and Skill are independently authorized effects; failure of one does not invalidate or block the other.
|
|
75
76
|
|
|
76
77
|
## Verify And Diagnose
|
|
77
78
|
|
|
@@ -79,6 +80,7 @@ Package and Skill checks are read-only:
|
|
|
79
80
|
|
|
80
81
|
```powershell
|
|
81
82
|
unitycli init package --project C:\path\UnityProject --check
|
|
83
|
+
unitycli init skill --target C:\path\Workspace\.pi\skills\unitycli --check
|
|
82
84
|
unitycli init skill --agent .agents --scope workspace --workspace C:\path\Workspace --check
|
|
83
85
|
```
|
|
84
86
|
|
|
@@ -161,6 +163,7 @@ unitycli init help
|
|
|
161
163
|
To remove a workspace or user Skill, delete only the selected `unitycli` Skill directory:
|
|
162
164
|
|
|
163
165
|
```text
|
|
166
|
+
<explicit-target>/unitycli
|
|
164
167
|
<workspace>/.agents/skills/unitycli
|
|
165
168
|
<workspace>/.claude/skills/unitycli
|
|
166
169
|
~/.agents/skills/unitycli
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version":
|
|
2
|
+
"version": 2,
|
|
3
3
|
"topLevel": "init",
|
|
4
4
|
"schema": "schemas/init.schema.json",
|
|
5
5
|
"subcommands": {
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
"package": {
|
|
13
13
|
"options": [
|
|
14
14
|
"project",
|
|
15
|
+
"close-editor",
|
|
15
16
|
"check",
|
|
16
17
|
"timeout-ms"
|
|
17
18
|
],
|
|
@@ -31,12 +32,18 @@
|
|
|
31
32
|
"agent",
|
|
32
33
|
"scope",
|
|
33
34
|
"workspace",
|
|
35
|
+
"target",
|
|
34
36
|
"check",
|
|
35
37
|
"timeout-ms"
|
|
36
38
|
],
|
|
37
|
-
"
|
|
38
|
-
|
|
39
|
-
|
|
39
|
+
"requiredAnyOf": [
|
|
40
|
+
[
|
|
41
|
+
"target"
|
|
42
|
+
],
|
|
43
|
+
[
|
|
44
|
+
"agent",
|
|
45
|
+
"scope"
|
|
46
|
+
]
|
|
40
47
|
],
|
|
41
48
|
"agents": [
|
|
42
49
|
".agents",
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": 1,
|
|
3
3
|
"packageName": "com.alpsckr.unitycli",
|
|
4
|
-
"packageVersion": "0.4.
|
|
5
|
-
"sourceHash": "
|
|
4
|
+
"packageVersion": "0.4.3",
|
|
5
|
+
"sourceHash": "1dc579796f92655e727bc4409af186091a9ba460ac76477af260f2955d1ca29a",
|
|
6
6
|
"files": [
|
|
7
7
|
{
|
|
8
8
|
"path": "Editor/Bridge/BridgeCommandContext.cs",
|
|
@@ -1947,7 +1947,7 @@
|
|
|
1947
1947
|
{
|
|
1948
1948
|
"path": "package.json",
|
|
1949
1949
|
"size": 268,
|
|
1950
|
-
"sha256": "
|
|
1950
|
+
"sha256": "ebd1f3b6489fdb9916f254b81e3976c7258fe697308c01ca4912aa779403e20a"
|
|
1951
1951
|
}
|
|
1952
1952
|
]
|
|
1953
1953
|
}
|
|
@@ -1,4 +1,11 @@
|
|
|
1
|
+
import { type PackageBridgeInspection } from "../package-manager.js";
|
|
1
2
|
import type { CliResult } from "../types.js";
|
|
2
|
-
|
|
3
|
+
import type { Runtime } from "./types.js";
|
|
4
|
+
export interface InitDiscoveryRuntime {
|
|
5
|
+
findUnityProjectProcesses?: Runtime["findUnityProjectProcesses"];
|
|
6
|
+
inspectPackageBridge?: (projectPath: string) => Promise<PackageBridgeInspection>;
|
|
7
|
+
}
|
|
8
|
+
/** 当前项目常见路径返回完整安装计划;多项目搜索只保留选择所需信息。 */
|
|
9
|
+
export declare function discoverInitEnvironment(cwdInput: string, userHomeInput: string, runtime?: InitDiscoveryRuntime): Promise<Record<string, unknown>>;
|
|
3
10
|
/** 从当前工作目录有界发现安装现场,不修改文件或进程。 */
|
|
4
|
-
export declare function handleInitDiscover(args: string[], flags: Record<string, string | boolean>, requestId: string): Promise<CliResult>;
|
|
11
|
+
export declare function handleInitDiscover(args: string[], flags: Record<string, string | boolean>, runtime: Runtime, requestId: string): Promise<CliResult>;
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import { lstat, readFile, readdir, realpath, stat } from "node:fs/promises";
|
|
2
2
|
import { dirname, join, resolve } from "node:path";
|
|
3
3
|
import { homedir } from "node:os";
|
|
4
|
+
import { inspectPackageBridge } from "../package-manager.js";
|
|
5
|
+
import { resolveProjectIdentityAsync } from "../project-identity.js";
|
|
4
6
|
import { failure, success } from "../output.js";
|
|
7
|
+
import { findUnityProjectProcesses } from "../unity-project-processes.js";
|
|
5
8
|
import { findSkillSourcePath, inspectSkillTarget, resolveSkillTarget } from "./skill-installer.js";
|
|
6
9
|
const maxDescendantDepth = 4;
|
|
7
10
|
const maxScannedDirectories = 2000;
|
|
8
11
|
const maxUnityProjects = 100;
|
|
9
|
-
const maxWorkspaceCandidates = 20;
|
|
10
12
|
const ignoredDirectories = new Set([".git", "node_modules", "library", "temp", "logs", "obj"]);
|
|
11
13
|
async function directoryExists(path) { try {
|
|
12
14
|
return (await stat(path)).isDirectory();
|
|
@@ -65,7 +67,9 @@ async function discoverUnityProjects(cwd) {
|
|
|
65
67
|
};
|
|
66
68
|
let ancestor = cwd;
|
|
67
69
|
for (let depth = 0; depth < 64; depth += 1) {
|
|
68
|
-
|
|
70
|
+
const candidate = await unityProjectCandidate(ancestor, depth === 0 ? "cwd" : "ancestor", depth);
|
|
71
|
+
if (candidate)
|
|
72
|
+
return { projects: [candidate], scannedDirectories: 0, truncated: false };
|
|
69
73
|
const parent = dirname(ancestor);
|
|
70
74
|
if (parent === ancestor)
|
|
71
75
|
break;
|
|
@@ -104,69 +108,75 @@ async function discoverUnityProjects(cwd) {
|
|
|
104
108
|
projects.sort((left, right) => left.path < right.path ? -1 : left.path > right.path ? 1 : 0);
|
|
105
109
|
return { projects, scannedDirectories: Math.min(scannedDirectories, maxScannedDirectories), truncated };
|
|
106
110
|
}
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
if (repositoryRoot && pathIdentity(repositoryRoot) !== pathIdentity(cwd))
|
|
110
|
-
values.push({ path: repositoryRoot, reason: "repository-root" });
|
|
111
|
-
for (const project of projects)
|
|
112
|
-
values.push({ path: dirname(project.path), reason: "unity-project-parent" });
|
|
113
|
-
const seen = new Set();
|
|
114
|
-
return values.filter((item) => { const id = pathIdentity(item.path); if (seen.has(id) || seen.size >= maxWorkspaceCandidates)
|
|
115
|
-
return false; seen.add(id); return true; });
|
|
116
|
-
}
|
|
117
|
-
export async function discoverInitEnvironment(cwdInput, userHomeInput) {
|
|
111
|
+
/** 当前项目常见路径返回完整安装计划;多项目搜索只保留选择所需信息。 */
|
|
112
|
+
export async function discoverInitEnvironment(cwdInput, userHomeInput, runtime = {}) {
|
|
118
113
|
const cwd = await realpath(resolve(cwdInput));
|
|
119
|
-
|
|
114
|
+
await realpath(resolve(userHomeInput));
|
|
120
115
|
const repositoryRoot = await findRepositoryRoot(cwd);
|
|
121
116
|
const discovery = await discoverUnityProjects(cwd);
|
|
122
|
-
const
|
|
123
|
-
const
|
|
124
|
-
const
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
117
|
+
const inspectBridge = runtime.inspectPackageBridge ?? inspectPackageBridge;
|
|
118
|
+
const findEditors = runtime.findUnityProjectProcesses ?? findUnityProjectProcesses;
|
|
119
|
+
const inspectLiveState = discovery.projects.length === 1;
|
|
120
|
+
const unityProjects = [];
|
|
121
|
+
for (const project of discovery.projects) {
|
|
122
|
+
let bridge = { status: "not-inspected" };
|
|
123
|
+
let editor = { status: "not-inspected" };
|
|
124
|
+
if (inspectLiveState) {
|
|
125
|
+
try {
|
|
126
|
+
const inspection = await inspectBridge(project.path);
|
|
127
|
+
bridge = {
|
|
128
|
+
status: inspection.status,
|
|
129
|
+
availableVersion: inspection.availableVersion,
|
|
130
|
+
...(inspection.installedVersion ? { installedVersion: inspection.installedVersion } : {}),
|
|
131
|
+
...(inspection.reasonCode ? { reasonCode: inspection.reasonCode } : {}),
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
catch {
|
|
135
|
+
bridge = { status: "unverifiable", reasonCode: "INIT_BRIDGE_STATE_UNVERIFIABLE" };
|
|
136
|
+
}
|
|
137
|
+
try {
|
|
138
|
+
const identity = await resolveProjectIdentityAsync(project.path, { timeoutMs: 3_000 });
|
|
139
|
+
const processes = await findEditors(identity.instanceId, identity.canonicalProjectPath, 3_000);
|
|
140
|
+
editor = { status: processes.length ? "running" : "stopped", processCount: processes.length };
|
|
141
|
+
}
|
|
142
|
+
catch {
|
|
143
|
+
editor = { status: "unverifiable" };
|
|
144
|
+
}
|
|
129
145
|
}
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
146
|
+
unityProjects.push({ ...project, bridge, editor });
|
|
147
|
+
}
|
|
148
|
+
const sourcePath = await findSkillSourcePath();
|
|
149
|
+
const recommendedTarget = resolveSkillTarget(cwd, ".agents");
|
|
150
|
+
const recommendedSkill = await inspectSkillTarget(sourcePath, recommendedTarget);
|
|
151
|
+
const requiredDecisions = [];
|
|
152
|
+
if (unityProjects.length > 1) {
|
|
153
|
+
requiredDecisions.push({ id: "bridgeProjects", question: "Which discovered Unity projects should receive the UnityCLI Bridge?", choices: unityProjects.map((project) => project.path), multiple: true });
|
|
154
|
+
}
|
|
155
|
+
else if ((unityProjects[0]?.editor?.status) === "running") {
|
|
156
|
+
requiredDecisions.push({ id: "closeEditor", question: "May UnityCLI normally close the exact target Unity project before Bridge installation?", projectPath: unityProjects[0].path, multiple: false });
|
|
133
157
|
}
|
|
134
|
-
const shadowingRisks = [".agents", "claude"].flatMap((agent) => {
|
|
135
|
-
const matches = copies.filter((copy) => copy.agent === agent && copy.status !== "missing");
|
|
136
|
-
if (matches.length < 2)
|
|
137
|
-
return [];
|
|
138
|
-
return [{
|
|
139
|
-
skill: "unitycli",
|
|
140
|
-
agent,
|
|
141
|
-
precedence: agent === "claude" ? ["user", "workspace"] : ["workspace", "user"],
|
|
142
|
-
copies: matches,
|
|
143
|
-
note: agent === "claude" ? "Claude personal skills override workspace skills." : "Generic Agent Skills commonly prefer workspace skills over user skills.",
|
|
144
|
-
}];
|
|
145
|
-
});
|
|
146
158
|
return {
|
|
147
|
-
action: "init_discover",
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
unityProjects
|
|
151
|
-
|
|
152
|
-
requiredDecisions
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
],
|
|
158
|
-
nextActions: ["Ask the user every required decision before running any installation effect.", "Use the exact command templates returned by `unitycli init help` after the user answers."],
|
|
159
|
+
action: "init_discover",
|
|
160
|
+
cwd,
|
|
161
|
+
repositoryRoot: repositoryRoot ?? null,
|
|
162
|
+
unityProjects,
|
|
163
|
+
skill: { workspace: cwd, recommendedTarget, explicitTargetSupported: true, ...recommendedSkill },
|
|
164
|
+
requiredDecisions,
|
|
165
|
+
...(discovery.scannedDirectories > 0 || discovery.truncated ? { scan: { scannedDirectories: discovery.scannedDirectories, truncated: discovery.truncated, maxDescendantDepth, maxScannedDirectories, maxUnityProjects } } : {}),
|
|
166
|
+
nextActions: requiredDecisions.length
|
|
167
|
+
? ["Ask only the returned required decisions; keep any target the user already specified."]
|
|
168
|
+
: ["Use the unique current project and the user's explicit Skill target, or the recommended workspace target when none was specified."],
|
|
159
169
|
};
|
|
160
170
|
}
|
|
161
171
|
/** 从当前工作目录有界发现安装现场,不修改文件或进程。 */
|
|
162
|
-
export async function handleInitDiscover(args, flags, requestId) {
|
|
172
|
+
export async function handleInitDiscover(args, flags, runtime, requestId) {
|
|
163
173
|
if (args.length)
|
|
164
174
|
return failure(requestId, "E_INIT_ARGUMENT_UNEXPECTED", "init discover does not accept positional arguments.", ["Run `unitycli init discover` without additional arguments."]);
|
|
165
175
|
const unknown = Object.keys(flags).find((name) => name !== "pretty");
|
|
166
176
|
if (unknown)
|
|
167
177
|
return failure(requestId, "E_UNKNOWN_OPTION", `Unknown option for init discover: --${unknown}.`, ["Run `unitycli init discover` without options."], { option: `--${unknown}` });
|
|
168
178
|
try {
|
|
169
|
-
return success(requestId, await discoverInitEnvironment(process.cwd(), homedir()));
|
|
179
|
+
return success(requestId, await discoverInitEnvironment(process.cwd(), homedir(), { findUnityProjectProcesses: runtime.findUnityProjectProcesses }));
|
|
170
180
|
}
|
|
171
181
|
catch (error) {
|
|
172
182
|
return failure(requestId, "INIT_DISCOVERY_FAILED", error instanceof Error ? error.message : String(error), ["Run `unitycli init discover` from an existing readable working directory."]);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"init-discovery.js","sourceRoot":"","sources":["../../src/cli-commands/init-discovery.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAC5E,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACnD,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAEhD,OAAO,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,kBAAkB,
|
|
1
|
+
{"version":3,"file":"init-discovery.js","sourceRoot":"","sources":["../../src/cli-commands/init-discovery.ts"],"names":[],"mappings":"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"}
|
|
@@ -2,7 +2,10 @@ import { failure, success } from "../output.js";
|
|
|
2
2
|
const commands = {
|
|
3
3
|
discover: "unitycli init discover",
|
|
4
4
|
packageInstall: "unitycli init package --project <UnityProject>",
|
|
5
|
+
packageInstallAndCloseEditor: "unitycli init package --project <UnityProject> --close-editor",
|
|
5
6
|
packageCheck: "unitycli init package --project <UnityProject> --check",
|
|
7
|
+
explicitSkillInstall: "unitycli init skill --target <SkillDirectory>",
|
|
8
|
+
explicitSkillCheck: "unitycli init skill --target <SkillDirectory> --check",
|
|
6
9
|
workspaceSkillInstall: "unitycli init skill --agent <.agents|claude> --scope workspace --workspace <path>",
|
|
7
10
|
workspaceSkillCheck: "unitycli init skill --agent <.agents|claude> --scope workspace --workspace <path> --check",
|
|
8
11
|
userSkillInstall: "unitycli init skill --agent <.agents|claude> --scope user",
|
|
@@ -18,16 +21,17 @@ export function handleInitHelp(args, flags, requestId) {
|
|
|
18
21
|
return success(requestId, {
|
|
19
22
|
action: "init_help",
|
|
20
23
|
audience: "ai",
|
|
21
|
-
protocolVersion:
|
|
24
|
+
protocolVersion: 2,
|
|
22
25
|
aiInstructions: [
|
|
23
|
-
"Run `unitycli init discover` from the user's current working directory
|
|
24
|
-
"
|
|
25
|
-
"
|
|
26
|
-
"
|
|
27
|
-
"
|
|
28
|
-
"
|
|
29
|
-
"
|
|
30
|
-
"
|
|
26
|
+
"Run `unitycli init discover` from the user's current working directory and use its compact current-project plan.",
|
|
27
|
+
"Treat every project, scope, host, or Skill directory the user already specified as final; never ask them to choose it again. Use `init skill --target` for an explicit directory such as `.pi/skills/unitycli`.",
|
|
28
|
+
"When discovery returns one current or ancestor Unity project, use it without another project-selection question. Ask only entries present in discovery.requiredDecisions.",
|
|
29
|
+
"If the exact target Unity project is running, ask once whether it may be closed normally. After approval use `init package --close-editor`; never force-terminate Unity or decide an unsaved-scene prompt for the user.",
|
|
30
|
+
"Bridge and Skill installation are independent authorized effects. A failure blocks only that effect and its check; continue other user-authorized independent installation effects and report every final status.",
|
|
31
|
+
"Run one corresponding `--check` after each successful package or Skill installation and verify its business status.",
|
|
32
|
+
"For a recoverable installation error, follow its exact nextActions after the required external state changes. Do not create unbounded retries or change the user's selected targets.",
|
|
33
|
+
"Do not start or restart Unity Editor during installation. Normal close is allowed only for the exact project and only through the explicitly authorized --close-editor package call.",
|
|
34
|
+
"The user's installation request authorizes the selected package and Skill effects; do not add confirmation gates except the separate close-Editor decision.",
|
|
31
35
|
],
|
|
32
36
|
commands,
|
|
33
37
|
nextCommand: commands.discover,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"init-help.js","sourceRoot":"","sources":["../../src/cli-commands/init-help.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAGhD,MAAM,QAAQ,GAAG;IACf,QAAQ,EAAE,wBAAwB;IAClC,cAAc,EAAE,gDAAgD;IAChE,YAAY,EAAE,wDAAwD;IACtE,qBAAqB,EAAE,mFAAmF;IAC1G,mBAAmB,EAAE,2FAA2F;IAChH,gBAAgB,EAAE,2DAA2D;IAC7E,cAAc,EAAE,mEAAmE;CAC3E,CAAC;AAEX,8BAA8B;AAC9B,MAAM,UAAU,cAAc,CAAC,IAAc,EAAE,KAAuC,EAAE,SAAiB;IACvG,IAAI,IAAI,CAAC,MAAM;QAAE,OAAO,OAAO,CAAC,SAAS,EAAE,4BAA4B,EAAE,iDAAiD,EAAE,CAAC,wDAAwD,CAAC,CAAC,CAAC;IACxL,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC;IACrE,IAAI,OAAO;QAAE,OAAO,OAAO,CAAC,SAAS,EAAE,kBAAkB,EAAE,mCAAmC,OAAO,GAAG,EAAE,CAAC,2CAA2C,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,OAAO,EAAE,EAAE,CAAC,CAAC;IACrL,OAAO,OAAO,CAAC,SAAS,EAAE;QACxB,MAAM,EAAE,WAAW;QACnB,QAAQ,EAAE,IAAI;QACd,eAAe,EAAE,CAAC;QAClB,cAAc,EAAE;YACd,
|
|
1
|
+
{"version":3,"file":"init-help.js","sourceRoot":"","sources":["../../src/cli-commands/init-help.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAGhD,MAAM,QAAQ,GAAG;IACf,QAAQ,EAAE,wBAAwB;IAClC,cAAc,EAAE,gDAAgD;IAChE,4BAA4B,EAAE,+DAA+D;IAC7F,YAAY,EAAE,wDAAwD;IACtE,oBAAoB,EAAE,+CAA+C;IACrE,kBAAkB,EAAE,uDAAuD;IAC3E,qBAAqB,EAAE,mFAAmF;IAC1G,mBAAmB,EAAE,2FAA2F;IAChH,gBAAgB,EAAE,2DAA2D;IAC7E,cAAc,EAAE,mEAAmE;CAC3E,CAAC;AAEX,8BAA8B;AAC9B,MAAM,UAAU,cAAc,CAAC,IAAc,EAAE,KAAuC,EAAE,SAAiB;IACvG,IAAI,IAAI,CAAC,MAAM;QAAE,OAAO,OAAO,CAAC,SAAS,EAAE,4BAA4B,EAAE,iDAAiD,EAAE,CAAC,wDAAwD,CAAC,CAAC,CAAC;IACxL,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC;IACrE,IAAI,OAAO;QAAE,OAAO,OAAO,CAAC,SAAS,EAAE,kBAAkB,EAAE,mCAAmC,OAAO,GAAG,EAAE,CAAC,2CAA2C,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,OAAO,EAAE,EAAE,CAAC,CAAC;IACrL,OAAO,OAAO,CAAC,SAAS,EAAE;QACxB,MAAM,EAAE,WAAW;QACnB,QAAQ,EAAE,IAAI;QACd,eAAe,EAAE,CAAC;QAClB,cAAc,EAAE;YACd,kHAAkH;YAClH,iNAAiN;YACjN,2KAA2K;YAC3K,yNAAyN;YACzN,mNAAmN;YACnN,qHAAqH;YACrH,sLAAsL;YACtL,sLAAsL;YACtL,6JAA6J;SAC9J;QACD,QAAQ;QACR,WAAW,EAAE,QAAQ,CAAC,QAAQ;QAC9B,WAAW,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC;KACjC,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -6,5 +6,5 @@ export declare function resolveInitSkillTarget(agent: AgentKind, scope: SkillSco
|
|
|
6
6
|
basePath: string;
|
|
7
7
|
targetPath: string;
|
|
8
8
|
};
|
|
9
|
-
/**
|
|
9
|
+
/** 安装或只读检查一个预设agent目标或用户明确给出的精确Skill目录。 */
|
|
10
10
|
export declare function handleInitSkill(args: string[], flags: Record<string, string | boolean>, runtime: Runtime, requestId: string): Promise<CliResult>;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { lstat, realpath, rm } from "node:fs/promises";
|
|
2
2
|
import { homedir } from "node:os";
|
|
3
|
-
import { join, resolve } from "node:path";
|
|
3
|
+
import { basename, dirname, isAbsolute, join, relative, resolve } from "node:path";
|
|
4
4
|
import { getBoolean, getString } from "../args.js";
|
|
5
5
|
import { failure, success } from "../output.js";
|
|
6
|
-
import { agentSkillInstaller, findSkillSourcePath, inspectSkillTarget, parseAgentList, resolveSkillTarget, SkillInstallerError } from "./skill-installer.js";
|
|
6
|
+
import { agentSkillInstaller, findSkillSourcePath, inspectSkillTarget, installSkillTarget, parseAgentList, resolveSkillTarget, SkillInstallerError } from "./skill-installer.js";
|
|
7
7
|
export function resolveInitSkillTarget(agent, scope, workspace, userHome) {
|
|
8
8
|
const basePath = scope === "user" ? resolve(userHome) : resolve(workspace);
|
|
9
9
|
return { basePath, targetPath: resolveSkillTarget(basePath, agent) };
|
|
@@ -41,43 +41,110 @@ function timeout(flags) {
|
|
|
41
41
|
const value = Number(raw);
|
|
42
42
|
return Number.isSafeInteger(value) && value > 0 ? value : undefined;
|
|
43
43
|
}
|
|
44
|
-
/**
|
|
44
|
+
/** 明确目标允许尚未创建,但所有既有祖先必须是真实目录且入口名固定为unitycli。 */
|
|
45
|
+
async function resolveExplicitSkillTarget(raw) {
|
|
46
|
+
const targetPath = resolve(raw);
|
|
47
|
+
if (basename(targetPath).toLowerCase() !== "unitycli") {
|
|
48
|
+
throw new SkillInstallerError("E_INIT_SKILL_TARGET_INVALID", "init skill --target must name the exact unitycli Skill directory.", ["Pass a path ending in the `unitycli` directory, such as `.pi/skills/unitycli`."]);
|
|
49
|
+
}
|
|
50
|
+
if (process.platform === "win32" && !/^[a-z]:\\/i.test(targetPath)) {
|
|
51
|
+
throw new SkillInstallerError("E_INIT_SKILL_TARGET_INVALID", "init skill --target must resolve to a fixed local Windows path.", ["Use a local drive path for the exact UnityCLI Skill directory."]);
|
|
52
|
+
}
|
|
53
|
+
if (targetPath.split(/[\\/]/).some((segment) => segment === ".unitycli-install")) {
|
|
54
|
+
throw new SkillInstallerError("E_INIT_SKILL_TARGET_INVALID", "init skill --target cannot be inside the installer transaction directory.", ["Choose the final UnityCLI Skill directory outside `.unitycli-install`."]);
|
|
55
|
+
}
|
|
56
|
+
let current = targetPath;
|
|
57
|
+
while (true) {
|
|
58
|
+
try {
|
|
59
|
+
const info = await lstat(current);
|
|
60
|
+
if (info.isSymbolicLink() || !info.isDirectory()) {
|
|
61
|
+
throw new SkillInstallerError("E_SKILL_TARGET_UNSAFE", `Skill target ancestors must be real directories: ${current}`, ["Replace the linked or non-directory target ancestor before retrying."]);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
catch (error) {
|
|
65
|
+
if (error.code !== "ENOENT")
|
|
66
|
+
throw error;
|
|
67
|
+
}
|
|
68
|
+
const parent = dirname(current);
|
|
69
|
+
if (parent === current)
|
|
70
|
+
break;
|
|
71
|
+
current = parent;
|
|
72
|
+
}
|
|
73
|
+
return targetPath;
|
|
74
|
+
}
|
|
75
|
+
function pathContains(parent, child) {
|
|
76
|
+
const fromParent = relative(parent, child);
|
|
77
|
+
return fromParent === "" || (!fromParent.startsWith("..") && !isAbsolute(fromParent));
|
|
78
|
+
}
|
|
79
|
+
/** bundled source与target不得互相包含,避免安装事务改写自己的准源。 */
|
|
80
|
+
function rejectSkillSourceOverlap(sourcePath, targetPath) {
|
|
81
|
+
const sourceRoot = resolve(dirname(sourcePath));
|
|
82
|
+
const targetRoot = resolve(targetPath);
|
|
83
|
+
const normalize = (value) => process.platform === "win32" ? value.toLowerCase() : value;
|
|
84
|
+
const sourceIdentity = normalize(sourceRoot);
|
|
85
|
+
const targetIdentity = normalize(targetRoot);
|
|
86
|
+
if (pathContains(sourceIdentity, targetIdentity) || pathContains(targetIdentity, sourceIdentity)) {
|
|
87
|
+
throw new SkillInstallerError("E_SKILL_TARGET_OVERLAPS_SOURCE", "The selected Skill target overlaps the bundled UnityCLI Skill source.", ["Choose a separate installed Skill directory."]);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
/** 安装或只读检查一个预设agent目标或用户明确给出的精确Skill目录。 */
|
|
45
91
|
export async function handleInitSkill(args, flags, runtime, requestId) {
|
|
46
92
|
if (args.length)
|
|
47
93
|
return failure(requestId, "E_INIT_ARGUMENT_UNEXPECTED", "init skill does not accept positional arguments.", ["Run `unitycli init skill` using only documented options."]);
|
|
48
94
|
const agentRaw = getString(flags, "agent");
|
|
49
95
|
const scopeRaw = getString(flags, "scope");
|
|
50
|
-
if (!agentRaw)
|
|
51
|
-
return failure(requestId, "E_INIT_AGENT_REQUIRED", "init skill requires --agent <.agents|claude>.", ["Choose the Skill host after asking the user."], { option: "--agent" });
|
|
52
|
-
let agent;
|
|
53
|
-
try {
|
|
54
|
-
const agents = parseAgentList(agentRaw);
|
|
55
|
-
if (agents.length !== 1)
|
|
56
|
-
throw new SkillInstallerError("E_INIT_AGENT_INVALID", "init skill accepts exactly one agent target.", ["Pass either --agent .agents or --agent claude."]);
|
|
57
|
-
agent = agents[0];
|
|
58
|
-
}
|
|
59
|
-
catch (error) {
|
|
60
|
-
if (error instanceof SkillInstallerError)
|
|
61
|
-
return failure(requestId, error.code, error.message, error.nextActions);
|
|
62
|
-
throw error;
|
|
63
|
-
}
|
|
64
|
-
if (scopeRaw !== "workspace" && scopeRaw !== "user")
|
|
65
|
-
return failure(requestId, "E_INIT_SCOPE_INVALID", "init skill requires --scope <workspace|user>.", ["Ask the user whether this Skill belongs to one workspace or the current user."], { option: "--scope", actual: scopeRaw ?? null });
|
|
66
|
-
const scope = scopeRaw;
|
|
67
96
|
const workspaceRaw = getString(flags, "workspace");
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
97
|
+
const explicitTargetRaw = getString(flags, "target");
|
|
98
|
+
if (explicitTargetRaw && (agentRaw || scopeRaw || workspaceRaw)) {
|
|
99
|
+
return failure(requestId, "E_INIT_SKILL_TARGET_CONFLICT", "init skill --target cannot be combined with --agent, --scope, or --workspace.", ["Use either one exact --target directory or one preset agent/scope target."], { option: "--target" });
|
|
100
|
+
}
|
|
101
|
+
if (!explicitTargetRaw && !agentRaw)
|
|
102
|
+
return failure(requestId, "E_INIT_SKILL_TARGET_REQUIRED", "init skill requires either --target <SkillDirectory> or --agent <.agents|claude> with --scope.", ["Use the user's explicit Skill directory when provided; otherwise choose one preset host."], { options: ["--target", "--agent"] });
|
|
72
103
|
const timeoutMs = timeout(flags);
|
|
73
104
|
if (timeoutMs === undefined)
|
|
74
105
|
return failure(requestId, "E_INIT_TIMEOUT_INVALID", "init skill --timeout-ms must be a positive integer.", ["Pass --timeout-ms <positive-integer>."], { option: "--timeout-ms" });
|
|
106
|
+
const deadlineMs = Date.now() + timeoutMs;
|
|
75
107
|
try {
|
|
108
|
+
const sourcePath = await findSkillSourcePath();
|
|
109
|
+
if (explicitTargetRaw) {
|
|
110
|
+
const targetPath = await resolveExplicitSkillTarget(explicitTargetRaw);
|
|
111
|
+
rejectSkillSourceOverlap(sourcePath, targetPath);
|
|
112
|
+
const installCommand = `unitycli init skill --target ${JSON.stringify(targetPath)}`;
|
|
113
|
+
if (getBoolean(flags, "check")) {
|
|
114
|
+
const inspection = await inspectSkillTarget(sourcePath, targetPath);
|
|
115
|
+
return success(requestId, { action: "init_skill_check", target: targetPath, skill: inspection, nextActions: inspection.status === "installed" ? [] : [installCommand] });
|
|
116
|
+
}
|
|
117
|
+
const installRoot = join(dirname(targetPath), ".unitycli-install");
|
|
118
|
+
const change = await installSkillTarget(sourcePath, targetPath, installRoot, deadlineMs);
|
|
119
|
+
const inspection = await inspectSkillTarget(sourcePath, targetPath);
|
|
120
|
+
if (inspection.status !== "installed")
|
|
121
|
+
throw new SkillInstallerError("E_SKILL_INSTALL_PROJECTION_INVALID", "Skill installation did not reach an installed readback state.", ["Inspect the reported target before retrying."]);
|
|
122
|
+
await rm(installRoot, { recursive: true, force: true });
|
|
123
|
+
return success(requestId, { action: "init_skill", target: targetPath, changes: [change], skill: inspection, nextActions: [`${installCommand} --check`] });
|
|
124
|
+
}
|
|
125
|
+
let agent;
|
|
126
|
+
try {
|
|
127
|
+
const agents = parseAgentList(agentRaw);
|
|
128
|
+
if (agents.length !== 1)
|
|
129
|
+
throw new SkillInstallerError("E_INIT_AGENT_INVALID", "init skill accepts exactly one preset agent target.", ["Pass either --agent .agents or --agent claude."]);
|
|
130
|
+
agent = agents[0];
|
|
131
|
+
}
|
|
132
|
+
catch (error) {
|
|
133
|
+
if (error instanceof SkillInstallerError)
|
|
134
|
+
return failure(requestId, error.code, error.message, error.nextActions);
|
|
135
|
+
throw error;
|
|
136
|
+
}
|
|
137
|
+
if (scopeRaw !== "workspace" && scopeRaw !== "user")
|
|
138
|
+
return failure(requestId, "E_INIT_SCOPE_INVALID", "Preset Skill installation requires --scope <workspace|user>.", ["Choose workspace for the current project or user for the current Windows account."], { option: "--scope", actual: scopeRaw ?? null });
|
|
139
|
+
const scope = scopeRaw;
|
|
140
|
+
if (scope === "workspace" && !workspaceRaw)
|
|
141
|
+
return failure(requestId, "E_INIT_WORKSPACE_REQUIRED", "Workspace Skill scope requires --workspace <path>.", ["Pass the user's normal AI working directory."], { option: "--workspace" });
|
|
142
|
+
if (scope === "user" && workspaceRaw)
|
|
143
|
+
return failure(requestId, "E_INIT_WORKSPACE_FORBIDDEN", "User Skill scope does not accept --workspace.", ["Remove --workspace or choose --scope workspace."], { option: "--workspace" });
|
|
76
144
|
const baseCandidate = scope === "user" ? resolve(runtime.userHome ?? homedir()) : resolve(workspaceRaw);
|
|
77
145
|
const basePath = await assertRealDirectory(baseCandidate, scope === "user" ? "User home" : "Workspace");
|
|
78
146
|
await rejectLinkedTargetAncestors(basePath, agent);
|
|
79
147
|
const targetPath = resolveSkillTarget(basePath, agent);
|
|
80
|
-
const sourcePath = await findSkillSourcePath();
|
|
81
148
|
if (getBoolean(flags, "check")) {
|
|
82
149
|
const inspection = await inspectSkillTarget(sourcePath, targetPath);
|
|
83
150
|
const installCommand = scope === "workspace"
|
|
@@ -88,7 +155,6 @@ export async function handleInitSkill(args, flags, runtime, requestId) {
|
|
|
88
155
|
const installRoot = scope === "user"
|
|
89
156
|
? join(runtime.dataDir, ".temp", "skill-install", agent === ".agents" ? "agents" : agent)
|
|
90
157
|
: join(basePath, agent === ".agents" ? ".agents" : ".claude", "skills", ".unitycli-install");
|
|
91
|
-
const deadlineMs = Date.now() + timeoutMs;
|
|
92
158
|
const changes = await agentSkillInstaller.installForAgents([agent], sourcePath, basePath, deadlineMs, installRoot);
|
|
93
159
|
const inspection = await inspectSkillTarget(sourcePath, targetPath);
|
|
94
160
|
if (inspection.status !== "installed")
|