@bitmagic/cli 0.1.65-dev.18 → 0.1.65-dev.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/README.md +13 -127
- package/dist/assets/materials.d.ts +0 -9
- package/dist/assets/materials.js +2 -10
- package/dist/assets/materials.js.map +1 -1
- package/dist/cli.d.ts +0 -9
- package/dist/cli.js +0 -2
- package/dist/cli.js.map +1 -1
- package/dist/commands/forge.d.ts +0 -15
- package/dist/commands/forge.js +38 -143
- package/dist/commands/forge.js.map +1 -1
- package/dist/commands/generate.d.ts +13 -31
- package/dist/commands/generate.js +56 -48
- package/dist/commands/generate.js.map +1 -1
- package/dist/commands/trailer.js +1 -1
- package/dist/commands/trailer.js.map +1 -1
- package/dist/editor/asset-viewer.js +8 -31
- package/dist/editor/asset-viewer.js.map +1 -1
- package/dist/forge/run-pipeline.js +1 -5
- package/dist/forge/run-pipeline.js.map +1 -1
- package/dist/forge/stream.d.ts +1 -5
- package/dist/forge/stream.js +0 -4
- package/dist/forge/stream.js.map +1 -1
- package/dist/mobile/asset-hosts.d.ts +9 -7
- package/dist/mobile/asset-hosts.js +16 -7
- package/dist/mobile/asset-hosts.js.map +1 -1
- package/dist/scaffold/blender-level-skill-files.js +2 -3
- package/dist/scaffold/blender-level-skill-files.js.map +1 -1
- package/dist/scaffold/project-files.js +12 -16
- package/dist/scaffold/project-files.js.map +1 -1
- package/dist/scaffold/project.js +1 -4
- package/dist/scaffold/project.js.map +1 -1
- package/dist/scaffold/skill-files.d.ts +5 -32
- package/dist/scaffold/skill-files.js +63 -102
- package/dist/scaffold/skill-files.js.map +1 -1
- package/dist/telemetry/creator-prompt.d.ts +2 -18
- package/dist/telemetry/creator-prompt.js +3 -24
- package/dist/telemetry/creator-prompt.js.map +1 -1
- package/dist/telemetry/report.js +16 -31
- package/dist/telemetry/report.js.map +1 -1
- package/package.json +4 -4
- package/assets/skills/trailer-craft.md +0 -180
- package/dist/commands/character.d.ts +0 -18
- package/dist/commands/character.js +0 -268
- package/dist/commands/character.js.map +0 -1
- package/dist/forge/edit-target.d.ts +0 -30
- package/dist/forge/edit-target.js +0 -88
- package/dist/forge/edit-target.js.map +0 -1
- package/dist/forge/prune-store.d.ts +0 -46
- package/dist/forge/prune-store.js +0 -86
- package/dist/forge/prune-store.js.map +0 -1
- package/dist/forge/remote-store.d.ts +0 -36
- package/dist/forge/remote-store.js +0 -113
- package/dist/forge/remote-store.js.map +0 -1
- package/dist/generate/character-body.d.ts +0 -79
- package/dist/generate/character-body.js +0 -100
- package/dist/generate/character-body.js.map +0 -1
- package/dist/project/character-search.d.ts +0 -30
- package/dist/project/character-search.js +0 -82
- package/dist/project/character-search.js.map +0 -1
- package/dist/scaffold/asset-pipeline-skill-files.d.ts +0 -38
- package/dist/scaffold/asset-pipeline-skill-files.js +0 -202
- package/dist/scaffold/asset-pipeline-skill-files.js.map +0 -1
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Forge-store housekeeping — the job directories under `.bitmagic/forge` that
|
|
3
|
-
* nothing will read again are removed once a forge has landed.
|
|
4
|
-
*
|
|
5
|
-
* Every edit is a NEW job and the level keeps only its newest job's id, so a
|
|
6
|
-
* level edited a dozen times leaves a dozen finished job directories behind
|
|
7
|
-
* (dev-games/alien held 13, 6 MB, after one afternoon). A job is kept while
|
|
8
|
-
* anything could still want it:
|
|
9
|
-
*
|
|
10
|
-
* - an asset of the world names it as its forge job (`parentForgeJobId`, the
|
|
11
|
-
* same reading `--edit` uses) — that is the parent an edit reuses bakes from;
|
|
12
|
-
* - it is the job that just ran;
|
|
13
|
-
* - it never finished (no `persisted` record) — an unfinished job is what
|
|
14
|
-
* `--resume` continues, and its local bakes are the progress a resume keeps.
|
|
15
|
-
*
|
|
16
|
-
* The server's copy of every job is untouched: it is what a resume or an edit
|
|
17
|
-
* from another machine reads, and its lifetime is the server's call. The
|
|
18
|
-
* resolution is pure over world.json and a listing, so the rules are testable
|
|
19
|
-
* without a project on disk; the removal is best-effort, since a directory
|
|
20
|
-
* that will not delete must never fail a forge that has already landed.
|
|
21
|
-
*/
|
|
22
|
-
import { type JsonObject } from '../project/world-json.js';
|
|
23
|
-
export interface ForgeJobDir {
|
|
24
|
-
jobId: string;
|
|
25
|
-
/** The job wrote its `persisted` record: world.json has what it built. */
|
|
26
|
-
finished: boolean;
|
|
27
|
-
}
|
|
28
|
-
/** The job ids the world's assets name — the jobs an edit could reuse bakes from. */
|
|
29
|
-
export declare function referencedForgeJobs(world: JsonObject): Set<string>;
|
|
30
|
-
/** Of `jobs`, the finished ones neither the world nor `keep` refers to, in listing order. */
|
|
31
|
-
export declare function staleForgeJobs(world: JsonObject, jobs: ReadonlyArray<ForgeJobDir>, keep: ReadonlyArray<string>): string[];
|
|
32
|
-
/** `<root>/.bitmagic/forge/worlds/v3/forged-work` — the store's job directories, by the shared key layout. */
|
|
33
|
-
export declare function forgeJobsDir(projectRoot: string): string;
|
|
34
|
-
/** The store's job directories, finished or not; an absent store lists nothing. */
|
|
35
|
-
export declare function listForgeJobDirs(projectRoot: string): ForgeJobDir[];
|
|
36
|
-
/**
|
|
37
|
-
* Remove the finished jobs the project no longer refers to. One line when
|
|
38
|
-
* something was removed, a warning when something would not go; silent otherwise.
|
|
39
|
-
*/
|
|
40
|
-
export declare function pruneForgeStore(options: {
|
|
41
|
-
projectRoot: string;
|
|
42
|
-
world: JsonObject;
|
|
43
|
-
/** Jobs to keep whatever the world says — the one that just ran. */
|
|
44
|
-
keep: ReadonlyArray<string>;
|
|
45
|
-
log: (message: string) => void;
|
|
46
|
-
}): string[];
|
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Forge-store housekeeping — the job directories under `.bitmagic/forge` that
|
|
3
|
-
* nothing will read again are removed once a forge has landed.
|
|
4
|
-
*
|
|
5
|
-
* Every edit is a NEW job and the level keeps only its newest job's id, so a
|
|
6
|
-
* level edited a dozen times leaves a dozen finished job directories behind
|
|
7
|
-
* (dev-games/alien held 13, 6 MB, after one afternoon). A job is kept while
|
|
8
|
-
* anything could still want it:
|
|
9
|
-
*
|
|
10
|
-
* - an asset of the world names it as its forge job (`parentForgeJobId`, the
|
|
11
|
-
* same reading `--edit` uses) — that is the parent an edit reuses bakes from;
|
|
12
|
-
* - it is the job that just ran;
|
|
13
|
-
* - it never finished (no `persisted` record) — an unfinished job is what
|
|
14
|
-
* `--resume` continues, and its local bakes are the progress a resume keeps.
|
|
15
|
-
*
|
|
16
|
-
* The server's copy of every job is untouched: it is what a resume or an edit
|
|
17
|
-
* from another machine reads, and its lifetime is the server's call. The
|
|
18
|
-
* resolution is pure over world.json and a listing, so the rules are testable
|
|
19
|
-
* without a project on disk; the removal is best-effort, since a directory
|
|
20
|
-
* that will not delete must never fail a forge that has already landed.
|
|
21
|
-
*/
|
|
22
|
-
import * as fs from 'fs';
|
|
23
|
-
import * as path from 'path';
|
|
24
|
-
import { forgeArtifactKey, parentForgeJobId } from '@bitmagic/world-forger/pipeline/index.js';
|
|
25
|
-
import { FORGE_STORE_DIR } from './local-store.js';
|
|
26
|
-
import { isJsonObject } from '../project/world-json.js';
|
|
27
|
-
/** The job ids the world's assets name — the jobs an edit could reuse bakes from. */
|
|
28
|
-
export function referencedForgeJobs(world) {
|
|
29
|
-
const assets = Array.isArray(world.assets) ? world.assets.filter(isJsonObject) : [];
|
|
30
|
-
const jobs = new Set();
|
|
31
|
-
for (const asset of assets) {
|
|
32
|
-
const jobId = parentForgeJobId(asset);
|
|
33
|
-
if (jobId !== null)
|
|
34
|
-
jobs.add(jobId);
|
|
35
|
-
}
|
|
36
|
-
return jobs;
|
|
37
|
-
}
|
|
38
|
-
/** Of `jobs`, the finished ones neither the world nor `keep` refers to, in listing order. */
|
|
39
|
-
export function staleForgeJobs(world, jobs, keep) {
|
|
40
|
-
const referenced = referencedForgeJobs(world);
|
|
41
|
-
for (const jobId of keep)
|
|
42
|
-
referenced.add(jobId);
|
|
43
|
-
return jobs.filter((job) => job.finished && !referenced.has(job.jobId)).map((job) => job.jobId);
|
|
44
|
-
}
|
|
45
|
-
/** `<root>/.bitmagic/forge/worlds/v3/forged-work` — the store's job directories, by the shared key layout. */
|
|
46
|
-
export function forgeJobsDir(projectRoot) {
|
|
47
|
-
const oneJob = path.dirname(forgeArtifactKey('job', 'persisted'));
|
|
48
|
-
return path.join(projectRoot, FORGE_STORE_DIR, path.dirname(oneJob));
|
|
49
|
-
}
|
|
50
|
-
/** The store's job directories, finished or not; an absent store lists nothing. */
|
|
51
|
-
export function listForgeJobDirs(projectRoot) {
|
|
52
|
-
const dir = forgeJobsDir(projectRoot);
|
|
53
|
-
if (!fs.existsSync(dir))
|
|
54
|
-
return [];
|
|
55
|
-
return fs.readdirSync(dir, { withFileTypes: true })
|
|
56
|
-
.filter((entry) => entry.isDirectory())
|
|
57
|
-
.map((entry) => ({
|
|
58
|
-
jobId: entry.name,
|
|
59
|
-
finished: fs.existsSync(path.join(projectRoot, FORGE_STORE_DIR, forgeArtifactKey(entry.name, 'persisted'))),
|
|
60
|
-
}));
|
|
61
|
-
}
|
|
62
|
-
/**
|
|
63
|
-
* Remove the finished jobs the project no longer refers to. One line when
|
|
64
|
-
* something was removed, a warning when something would not go; silent otherwise.
|
|
65
|
-
*/
|
|
66
|
-
export function pruneForgeStore(options) {
|
|
67
|
-
const { projectRoot, world, keep, log } = options;
|
|
68
|
-
const stale = staleForgeJobs(world, listForgeJobDirs(projectRoot), keep);
|
|
69
|
-
const removed = [];
|
|
70
|
-
for (const jobId of stale) {
|
|
71
|
-
const dir = path.join(forgeJobsDir(projectRoot), jobId);
|
|
72
|
-
try {
|
|
73
|
-
fs.rmSync(dir, { recursive: true, force: true });
|
|
74
|
-
removed.push(jobId);
|
|
75
|
-
}
|
|
76
|
-
catch (error) {
|
|
77
|
-
const detail = error instanceof Error ? error.message : String(error);
|
|
78
|
-
log(`warning: could not remove the finished forge job ${jobId} from ${FORGE_STORE_DIR} (${detail}); it is safe to delete by hand.`);
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
if (removed.length > 0) {
|
|
82
|
-
log(`Removed ${removed.length} finished forge job${removed.length === 1 ? '' : 's'} from ${FORGE_STORE_DIR} that no level refers to any more.`);
|
|
83
|
-
}
|
|
84
|
-
return removed;
|
|
85
|
-
}
|
|
86
|
-
//# sourceMappingURL=prune-store.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"prune-store.js","sourceRoot":"","sources":["../../src/forge/prune-store.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The forge store with a server behind it.
|
|
3
|
-
*
|
|
4
|
-
* The CLI keeps every forge artifact in the project's `.bitmagic/forge` (see
|
|
5
|
-
* local-store.ts). This wraps that storage so the artifacts the BROWSER steps
|
|
6
|
-
* write are also PUT to api-server, and anything missing locally is fetched
|
|
7
|
-
* from it — so a job can be resumed, and a forged level edited, from a
|
|
8
|
-
* machine that never ran the original forge. The server owns `input`, `spec`
|
|
9
|
-
* and `forge` and refuses a client write of them; those are written locally
|
|
10
|
-
* only (they arrive on the forge's terminal frame anyway).
|
|
11
|
-
*
|
|
12
|
-
* The mirror is best-effort by design: the local write is the one the run
|
|
13
|
-
* depends on, and a server that cannot be reached must not fail a bake that
|
|
14
|
-
* has already been paid for. A failed mirror is said once, plainly, because
|
|
15
|
-
* its cost is real — the artifact will not be there for another machine.
|
|
16
|
-
* Reads that fall through to the server are cached locally, so a resumed job
|
|
17
|
-
* reads from disk from then on.
|
|
18
|
-
*/
|
|
19
|
-
import type { ForgeStorageEnv } from '@bitmagic/world-forger/pipeline/index.js';
|
|
20
|
-
import type { Environment } from '../config/environments.js';
|
|
21
|
-
export interface RemoteForgeStoreDeps {
|
|
22
|
-
environment: Environment;
|
|
23
|
-
/**
|
|
24
|
-
* Resolved on the FIRST remote call, not when the store is built: the store
|
|
25
|
-
* is created before the command's cheap pre-request checks, and a run that
|
|
26
|
-
* never leaves the machine (a fresh forge with every artifact local) must
|
|
27
|
-
* not demand a login it would not otherwise need until the request.
|
|
28
|
-
*/
|
|
29
|
-
accessToken: () => Promise<string>;
|
|
30
|
-
fetch: typeof globalThis.fetch;
|
|
31
|
-
/** Where a failed mirror or fetch is said. */
|
|
32
|
-
warn: (message: string) => void;
|
|
33
|
-
}
|
|
34
|
-
export declare function forgeArtifactUrl(environment: Environment, jobId: string, name: string): string;
|
|
35
|
-
/** Wrap a local storage env so forged-work artifacts are mirrored to, and fetched from, the server. */
|
|
36
|
-
export declare function createMirroredForgeStorage(local: ForgeStorageEnv, deps: RemoteForgeStoreDeps): ForgeStorageEnv;
|
|
@@ -1,113 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The forge store with a server behind it.
|
|
3
|
-
*
|
|
4
|
-
* The CLI keeps every forge artifact in the project's `.bitmagic/forge` (see
|
|
5
|
-
* local-store.ts). This wraps that storage so the artifacts the BROWSER steps
|
|
6
|
-
* write are also PUT to api-server, and anything missing locally is fetched
|
|
7
|
-
* from it — so a job can be resumed, and a forged level edited, from a
|
|
8
|
-
* machine that never ran the original forge. The server owns `input`, `spec`
|
|
9
|
-
* and `forge` and refuses a client write of them; those are written locally
|
|
10
|
-
* only (they arrive on the forge's terminal frame anyway).
|
|
11
|
-
*
|
|
12
|
-
* The mirror is best-effort by design: the local write is the one the run
|
|
13
|
-
* depends on, and a server that cannot be reached must not fail a bake that
|
|
14
|
-
* has already been paid for. A failed mirror is said once, plainly, because
|
|
15
|
-
* its cost is real — the artifact will not be there for another machine.
|
|
16
|
-
* Reads that fall through to the server are cached locally, so a resumed job
|
|
17
|
-
* reads from disk from then on.
|
|
18
|
-
*/
|
|
19
|
-
import { CLIENT_FORGE_ARTIFACTS, parseForgeArtifactKey } from '@bitmagic/world-forger/pipeline/index.js';
|
|
20
|
-
import { apiServerHeaders } from '../telemetry/request-headers.js';
|
|
21
|
-
export function forgeArtifactUrl(environment, jobId, name) {
|
|
22
|
-
return `${environment.apiUrl}/api/cli/v1/forge/jobs/${encodeURIComponent(jobId)}/artifacts/${encodeURIComponent(name)}`;
|
|
23
|
-
}
|
|
24
|
-
/** Wrap a local storage env so forged-work artifacts are mirrored to, and fetched from, the server. */
|
|
25
|
-
export function createMirroredForgeStorage(local, deps) {
|
|
26
|
-
const said = new Set();
|
|
27
|
-
const warnOnce = (key, message) => {
|
|
28
|
-
if (said.has(key))
|
|
29
|
-
return;
|
|
30
|
-
said.add(key);
|
|
31
|
-
deps.warn(message);
|
|
32
|
-
};
|
|
33
|
-
const headers = async () => ({
|
|
34
|
-
...apiServerHeaders(),
|
|
35
|
-
Authorization: `Bearer ${await deps.accessToken()}`,
|
|
36
|
-
});
|
|
37
|
-
const failure = (error) => (error instanceof Error ? error.message : String(error));
|
|
38
|
-
const client = {
|
|
39
|
-
async putObject(params) {
|
|
40
|
-
const written = await local.storageClient.putObject(params);
|
|
41
|
-
const parsed = parseForgeArtifactKey(params.key);
|
|
42
|
-
if (parsed === null || !CLIENT_FORGE_ARTIFACTS.includes(parsed.name))
|
|
43
|
-
return written;
|
|
44
|
-
const body = typeof params.body === 'string' ? params.body : new TextDecoder().decode(params.body);
|
|
45
|
-
try {
|
|
46
|
-
const response = await deps.fetch(forgeArtifactUrl(deps.environment, parsed.jobId, parsed.name), {
|
|
47
|
-
method: 'PUT',
|
|
48
|
-
headers: { ...(await headers()), 'Content-Type': 'application/json' },
|
|
49
|
-
body,
|
|
50
|
-
});
|
|
51
|
-
if (!response.ok) {
|
|
52
|
-
warnOnce(`put:${parsed.name}`, `Could not mirror the forge's "${parsed.name}" record to api-server (HTTP ${response.status}). The run continues from `
|
|
53
|
-
+ 'the local copy, but resuming or editing this level from another machine will re-bake it.');
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
catch (error) {
|
|
57
|
-
warnOnce(`put:${parsed.name}`, `Could not mirror the forge's "${parsed.name}" record to api-server (${failure(error)}). The run continues from `
|
|
58
|
-
+ 'the local copy, but resuming or editing this level from another machine will re-bake it.');
|
|
59
|
-
}
|
|
60
|
-
return written;
|
|
61
|
-
},
|
|
62
|
-
async headObject(params) {
|
|
63
|
-
if (await local.storageClient.headObject(params))
|
|
64
|
-
return true;
|
|
65
|
-
const parsed = parseForgeArtifactKey(params.key);
|
|
66
|
-
if (parsed === null)
|
|
67
|
-
return false;
|
|
68
|
-
try {
|
|
69
|
-
const response = await deps.fetch(forgeArtifactUrl(deps.environment, parsed.jobId, parsed.name), {
|
|
70
|
-
method: 'HEAD',
|
|
71
|
-
headers: await headers(),
|
|
72
|
-
});
|
|
73
|
-
return response.ok;
|
|
74
|
-
}
|
|
75
|
-
catch (error) {
|
|
76
|
-
warnOnce('head', `Could not ask api-server for the job's saved state (${failure(error)}) — working from the local copy only.`);
|
|
77
|
-
return false;
|
|
78
|
-
}
|
|
79
|
-
},
|
|
80
|
-
async getObject(params) {
|
|
81
|
-
const here = await local.storageClient.getObject(params);
|
|
82
|
-
if (here !== null)
|
|
83
|
-
return here;
|
|
84
|
-
const parsed = parseForgeArtifactKey(params.key);
|
|
85
|
-
if (parsed === null)
|
|
86
|
-
return null;
|
|
87
|
-
try {
|
|
88
|
-
const response = await deps.fetch(forgeArtifactUrl(deps.environment, parsed.jobId, parsed.name), {
|
|
89
|
-
method: 'GET',
|
|
90
|
-
headers: await headers(),
|
|
91
|
-
});
|
|
92
|
-
if (response.status === 404)
|
|
93
|
-
return null;
|
|
94
|
-
if (!response.ok) {
|
|
95
|
-
warnOnce(`get:${parsed.name}`, `api-server refused the job's "${parsed.name}" record (HTTP ${response.status}) — working from the local copy only.`);
|
|
96
|
-
return null;
|
|
97
|
-
}
|
|
98
|
-
const bytes = new Uint8Array(await response.arrayBuffer());
|
|
99
|
-
// Cached locally so the rest of the run, and the next one, read from disk.
|
|
100
|
-
await local.storageClient.putObject({
|
|
101
|
-
bucket: params.bucket, key: params.key, body: bytes, contentType: 'application/json', cacheControl: 'no-store, max-age=0',
|
|
102
|
-
});
|
|
103
|
-
return bytes;
|
|
104
|
-
}
|
|
105
|
-
catch (error) {
|
|
106
|
-
warnOnce('get', `Could not fetch the job's saved state from api-server (${failure(error)}) — working from the local copy only.`);
|
|
107
|
-
return null;
|
|
108
|
-
}
|
|
109
|
-
},
|
|
110
|
-
};
|
|
111
|
-
return { ...local, storageClient: client };
|
|
112
|
-
}
|
|
113
|
-
//# sourceMappingURL=remote-store.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"remote-store.js","sourceRoot":"","sources":["../../src/forge/remote-store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AASH,OAAO,EAAE,sBAAsB,EAAE,qBAAqB,EAAE,MAAM,0CAA0C,CAAC;AAEzG,OAAO,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AAgBnE,MAAM,UAAU,gBAAgB,CAAC,WAAwB,EAAE,KAAa,EAAE,IAAY;IACpF,OAAO,GAAG,WAAW,CAAC,MAAM,0BAA0B,kBAAkB,CAAC,KAAK,CAAC,cAAc,kBAAkB,CAAC,IAAI,CAAC,EAAE,CAAC;AAC1H,CAAC;AAED,uGAAuG;AACvG,MAAM,UAAU,0BAA0B,CAAC,KAAsB,EAAE,IAA0B;IAC3F,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,MAAM,QAAQ,GAAG,CAAC,GAAW,EAAE,OAAe,EAAQ,EAAE;QACtD,IAAI,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;YAAE,OAAO;QAC1B,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACd,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACrB,CAAC,CAAC;IACF,MAAM,OAAO,GAAG,KAAK,IAAqC,EAAE,CAAC,CAAC;QAC5D,GAAG,gBAAgB,EAAE;QACrB,aAAa,EAAE,UAAU,MAAM,IAAI,CAAC,WAAW,EAAE,EAAE;KACpD,CAAC,CAAC;IACH,MAAM,OAAO,GAAG,CAAC,KAAc,EAAU,EAAE,CAAC,CAAC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;IAErG,MAAM,MAAM,GAAuB;QACjC,KAAK,CAAC,SAAS,CAAC,MAA4B;YAC1C,MAAM,OAAO,GAAG,MAAM,KAAK,CAAC,aAAa,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;YAC5D,MAAM,MAAM,GAAG,qBAAqB,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACjD,IAAI,MAAM,KAAK,IAAI,IAAI,CAAC,sBAAsB,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC;gBAAE,OAAO,OAAO,CAAC;YACrF,MAAM,IAAI,GAAG,OAAO,MAAM,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;YACnG,IAAI,CAAC;gBACH,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,gBAAgB,CAAC,IAAI,CAAC,WAAW,EAAE,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,IAAI,CAAC,EAAE;oBAC/F,MAAM,EAAE,KAAK;oBACb,OAAO,EAAE,EAAE,GAAG,CAAC,MAAM,OAAO,EAAE,CAAC,EAAE,cAAc,EAAE,kBAAkB,EAAE;oBACrE,IAAI;iBACL,CAAC,CAAC;gBACH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;oBACjB,QAAQ,CACN,OAAO,MAAM,CAAC,IAAI,EAAE,EACpB,iCAAiC,MAAM,CAAC,IAAI,gCAAgC,QAAQ,CAAC,MAAM,4BAA4B;0BACrH,0FAA0F,CAC7F,CAAC;gBACJ,CAAC;YACH,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,QAAQ,CACN,OAAO,MAAM,CAAC,IAAI,EAAE,EACpB,iCAAiC,MAAM,CAAC,IAAI,2BAA2B,OAAO,CAAC,KAAK,CAAC,4BAA4B;sBAC/G,0FAA0F,CAC7F,CAAC;YACJ,CAAC;YACD,OAAO,OAAO,CAAC;QACjB,CAAC;QAED,KAAK,CAAC,UAAU,CAAC,MAA6B;YAC5C,IAAI,MAAM,KAAK,CAAC,aAAa,CAAC,UAAU,CAAC,MAAM,CAAC;gBAAE,OAAO,IAAI,CAAC;YAC9D,MAAM,MAAM,GAAG,qBAAqB,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACjD,IAAI,MAAM,KAAK,IAAI;gBAAE,OAAO,KAAK,CAAC;YAClC,IAAI,CAAC;gBACH,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,gBAAgB,CAAC,IAAI,CAAC,WAAW,EAAE,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,IAAI,CAAC,EAAE;oBAC/F,MAAM,EAAE,MAAM;oBACd,OAAO,EAAE,MAAM,OAAO,EAAE;iBACzB,CAAC,CAAC;gBACH,OAAO,QAAQ,CAAC,EAAE,CAAC;YACrB,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,QAAQ,CAAC,MAAM,EAAE,uDAAuD,OAAO,CAAC,KAAK,CAAC,uCAAuC,CAAC,CAAC;gBAC/H,OAAO,KAAK,CAAC;YACf,CAAC;QACH,CAAC;QAED,KAAK,CAAC,SAAS,CAAC,MAA4B;YAC1C,MAAM,IAAI,GAAG,MAAM,KAAK,CAAC,aAAa,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;YACzD,IAAI,IAAI,KAAK,IAAI;gBAAE,OAAO,IAAI,CAAC;YAC/B,MAAM,MAAM,GAAG,qBAAqB,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACjD,IAAI,MAAM,KAAK,IAAI;gBAAE,OAAO,IAAI,CAAC;YACjC,IAAI,CAAC;gBACH,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,gBAAgB,CAAC,IAAI,CAAC,WAAW,EAAE,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,IAAI,CAAC,EAAE;oBAC/F,MAAM,EAAE,KAAK;oBACb,OAAO,EAAE,MAAM,OAAO,EAAE;iBACzB,CAAC,CAAC;gBACH,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG;oBAAE,OAAO,IAAI,CAAC;gBACzC,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;oBACjB,QAAQ,CAAC,OAAO,MAAM,CAAC,IAAI,EAAE,EAAE,iCAAiC,MAAM,CAAC,IAAI,kBAAkB,QAAQ,CAAC,MAAM,uCAAuC,CAAC,CAAC;oBACrJ,OAAO,IAAI,CAAC;gBACd,CAAC;gBACD,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,MAAM,QAAQ,CAAC,WAAW,EAAE,CAAC,CAAC;gBAC3D,2EAA2E;gBAC3E,MAAM,KAAK,CAAC,aAAa,CAAC,SAAS,CAAC;oBAClC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,EAAE,MAAM,CAAC,GAAG,EAAE,IAAI,EAAE,KAAK,EAAE,WAAW,EAAE,kBAAkB,EAAE,YAAY,EAAE,qBAAqB;iBAC1H,CAAC,CAAC;gBACH,OAAO,KAAK,CAAC;YACf,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,QAAQ,CAAC,KAAK,EAAE,0DAA0D,OAAO,CAAC,KAAK,CAAC,uCAAuC,CAAC,CAAC;gBACjI,OAAO,IAAI,CAAC;YACd,CAAC;QACH,CAAC;KACF,CAAC;IAEF,OAAO,EAAE,GAAG,KAAK,EAAE,aAAa,EAAE,MAAM,EAAE,CAAC;AAC7C,CAAC"}
|
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
export interface CharacterArgs {
|
|
2
|
-
name: string;
|
|
3
|
-
prompt: string;
|
|
4
|
-
applyToPlayer?: boolean;
|
|
5
|
-
headScale?: string;
|
|
6
|
-
/** `--fresh`: forge a new one, never substitute a stored body. */
|
|
7
|
-
fresh?: boolean;
|
|
8
|
-
/**
|
|
9
|
-
* citty's negative boolean: `--no-library` arrives as `false`; the flag has no positive form.
|
|
10
|
-
* The deprecated spelling of `--fresh`, kept working because every scaffolded AGENTS.md
|
|
11
|
-
* written before the rename teaches it.
|
|
12
|
-
*/
|
|
13
|
-
library?: boolean;
|
|
14
|
-
/** `--library-only`: take the closest stored body, never forge, never charge. */
|
|
15
|
-
libraryOnly?: boolean;
|
|
16
|
-
/** A row a prior search returned, which `bitmagic character add --id` adds verbatim. */
|
|
17
|
-
libraryPick?: {
|
|
18
|
-
sid: string;
|
|
19
|
-
assetUrl: string;
|
|
20
|
-
description?: string;
|
|
21
|
-
similarity: number;
|
|
22
|
-
};
|
|
23
|
-
/** Absent = the generator's default (true); the command fills it from the project's art style. */
|
|
24
|
-
voxelize?: boolean;
|
|
25
|
-
/** Asset Forger image-to-mesh model; absent = the Forger default. */
|
|
26
|
-
meshModel?: string;
|
|
27
|
-
}
|
|
28
|
-
/**
|
|
29
|
-
* The character default a project's art style implies: a low-poly game keeps the textured rig.
|
|
30
|
-
* Read from the cwd's project like every other generate command; outside a project the answer
|
|
31
|
-
* is "declares nothing", so the generator's own default (voxelize) stands and `loadProjectContext`
|
|
32
|
-
* reports the missing project on the very next line.
|
|
33
|
-
*/
|
|
34
|
-
export declare function defaultVoxelizeForProject(): boolean | undefined;
|
|
35
|
-
export declare function buildCharacterBody(args: CharacterArgs): Record<string, unknown>;
|
|
36
|
-
export declare const NAME_ARG: {
|
|
37
|
-
readonly type: "string";
|
|
38
|
-
readonly required: true;
|
|
39
|
-
readonly description: "Unique name for the character.";
|
|
40
|
-
};
|
|
41
|
-
export declare const PROMPT_ARG: {
|
|
42
|
-
readonly type: "string";
|
|
43
|
-
readonly required: true;
|
|
44
|
-
readonly description: "Description of the character.";
|
|
45
|
-
};
|
|
46
|
-
export declare const APPLY_TO_PLAYER_ARG: {
|
|
47
|
-
readonly type: "boolean";
|
|
48
|
-
readonly description: "Set this character as the PLAYER. Omit to use the generator default (true).";
|
|
49
|
-
};
|
|
50
|
-
export declare const HEAD_SCALE_ARG: {
|
|
51
|
-
readonly type: "string";
|
|
52
|
-
readonly description: "Head size as a percentage of normal, 50-300. Omit to use the generator default.";
|
|
53
|
-
};
|
|
54
|
-
export declare const FRESH_ARG: {
|
|
55
|
-
readonly type: "boolean";
|
|
56
|
-
readonly description: string;
|
|
57
|
-
};
|
|
58
|
-
export declare const VOXELIZE_ARG: {
|
|
59
|
-
readonly type: "boolean";
|
|
60
|
-
readonly description: "Voxelize the rigged body. Omit to follow game.json artStyle: voxel games voxelize, low-poly games keep the textured rig.";
|
|
61
|
-
readonly negativeDescription: "Keep the textured low-poly rig instead of voxelizing it.";
|
|
62
|
-
};
|
|
63
|
-
export declare const MESH_MODEL_ARG: {
|
|
64
|
-
readonly type: "string";
|
|
65
|
-
readonly description: "Image-to-mesh model. Low-poly characters already default to 'runware-rodin-gen-2', which bills 60 sparks and takes ~3 min; pass 'unified-trellis' to put one back on the cheap lane at 15 sparks. Voxel characters ignore the default and use the Forger's.";
|
|
66
|
-
};
|
|
67
|
-
/**
|
|
68
|
-
* The deprecated spelling of `--fresh`.
|
|
69
|
-
*
|
|
70
|
-
* Kept declared because citty derives `--no-library` from an argument NAMED
|
|
71
|
-
* `library`, so there is no way to accept the old flag without it — and no way
|
|
72
|
-
* to hide it either: citty's `ArgDef` has no `hidden` field (only `CommandMeta`
|
|
73
|
-
* does). So it stays visible and says what it is.
|
|
74
|
-
*/
|
|
75
|
-
export declare const LIBRARY_ARG: {
|
|
76
|
-
readonly type: "boolean";
|
|
77
|
-
readonly description: "Deprecated and unnecessary — the library is consulted by default. Use --fresh to skip it.";
|
|
78
|
-
readonly negativeDescription: "Deprecated spelling of --fresh. Always makes a new character.";
|
|
79
|
-
};
|
|
@@ -1,100 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The character request: its flags, and the body they map onto.
|
|
3
|
-
*
|
|
4
|
-
* Lives here rather than in either command because TWO commands present it —
|
|
5
|
-
* `bitmagic character generate` and the deprecated `bitmagic generate character`
|
|
6
|
-
* it replaced — and a deprecated alias whose flags have drifted from the command
|
|
7
|
-
* it aliases is worse than no alias at all. One definition, imported by both.
|
|
8
|
-
*
|
|
9
|
-
* Field names are exactly what `characterParamsSchema`
|
|
10
|
-
* (shared/asset-core/src/generators/character.ts) expects, and a flag the
|
|
11
|
-
* creator did not pass is OMITTED rather than sent as `undefined` or as a
|
|
12
|
-
* restated default — the generator owns its defaults.
|
|
13
|
-
*/
|
|
14
|
-
import { findProjectRootOrNull } from '../project/context.js';
|
|
15
|
-
import { readArtStyleDeclaration } from '../project/art-style.js';
|
|
16
|
-
import { parseNumberFlag } from '../commands/number-flag.js';
|
|
17
|
-
/** Drops the keys an absent flag left `undefined`; `false` and `0` are deliberate values. */
|
|
18
|
-
function withoutAbsentFlags(fields) {
|
|
19
|
-
return Object.fromEntries(Object.entries(fields).filter(([, value]) => value !== undefined));
|
|
20
|
-
}
|
|
21
|
-
/**
|
|
22
|
-
* The character default a project's art style implies: a low-poly game keeps the textured rig.
|
|
23
|
-
* Read from the cwd's project like every other generate command; outside a project the answer
|
|
24
|
-
* is "declares nothing", so the generator's own default (voxelize) stands and `loadProjectContext`
|
|
25
|
-
* reports the missing project on the very next line.
|
|
26
|
-
*/
|
|
27
|
-
export function defaultVoxelizeForProject() {
|
|
28
|
-
const root = findProjectRootOrNull();
|
|
29
|
-
if (root === null)
|
|
30
|
-
return undefined;
|
|
31
|
-
return readArtStyleDeclaration(root).artStyle === 'low-poly' ? false : undefined;
|
|
32
|
-
}
|
|
33
|
-
export function buildCharacterBody(args) {
|
|
34
|
-
return withoutAbsentFlags({
|
|
35
|
-
name: args.name,
|
|
36
|
-
prompt: args.prompt,
|
|
37
|
-
applyToPlayer: args.applyToPlayer,
|
|
38
|
-
headScale: parseNumberFlag('head-scale', args.headScale, { min: 50, max: 300 }),
|
|
39
|
-
// `--fresh` and the deprecated `--no-library` are the same request. Neither
|
|
40
|
-
// passed leaves the field absent, so the generator's default (search first)
|
|
41
|
-
// stands rather than being restated here.
|
|
42
|
-
useLibrary: args.fresh === true ? false : args.library,
|
|
43
|
-
libraryOnly: args.libraryOnly,
|
|
44
|
-
libraryPick: args.libraryPick,
|
|
45
|
-
voxelize: args.voxelize,
|
|
46
|
-
meshModel: args.meshModel,
|
|
47
|
-
});
|
|
48
|
-
}
|
|
49
|
-
// ============================================================================
|
|
50
|
-
// Flag definitions, shared by `character generate` and the deprecated alias
|
|
51
|
-
// ============================================================================
|
|
52
|
-
export const NAME_ARG = {
|
|
53
|
-
type: 'string',
|
|
54
|
-
required: true,
|
|
55
|
-
description: 'Unique name for the character.',
|
|
56
|
-
};
|
|
57
|
-
export const PROMPT_ARG = {
|
|
58
|
-
type: 'string',
|
|
59
|
-
required: true,
|
|
60
|
-
description: 'Description of the character.',
|
|
61
|
-
};
|
|
62
|
-
export const APPLY_TO_PLAYER_ARG = {
|
|
63
|
-
type: 'boolean',
|
|
64
|
-
description: 'Set this character as the PLAYER. Omit to use the generator default (true).',
|
|
65
|
-
};
|
|
66
|
-
export const HEAD_SCALE_ARG = {
|
|
67
|
-
type: 'string',
|
|
68
|
-
description: 'Head size as a percentage of normal, 50-300. Omit to use the generator default.',
|
|
69
|
-
};
|
|
70
|
-
export const FRESH_ARG = {
|
|
71
|
-
type: 'boolean',
|
|
72
|
-
description: 'Forge a new character even when the library has a close match. '
|
|
73
|
-
+ 'Use it when you want this exact brief made rather than the nearest ready-made body.',
|
|
74
|
-
};
|
|
75
|
-
export const VOXELIZE_ARG = {
|
|
76
|
-
type: 'boolean',
|
|
77
|
-
description: 'Voxelize the rigged body. Omit to follow game.json artStyle: voxel games voxelize, low-poly games keep the textured rig.',
|
|
78
|
-
negativeDescription: 'Keep the textured low-poly rig instead of voxelizing it.',
|
|
79
|
-
};
|
|
80
|
-
export const MESH_MODEL_ARG = {
|
|
81
|
-
type: 'string',
|
|
82
|
-
description: "Image-to-mesh model. Low-poly characters already default to 'runware-rodin-gen-2', which bills 60 sparks and takes ~3 min; pass 'unified-trellis' to put one back on the cheap lane at 15 sparks. Voxel characters ignore the default and use the Forger's.",
|
|
83
|
-
};
|
|
84
|
-
/**
|
|
85
|
-
* The deprecated spelling of `--fresh`.
|
|
86
|
-
*
|
|
87
|
-
* Kept declared because citty derives `--no-library` from an argument NAMED
|
|
88
|
-
* `library`, so there is no way to accept the old flag without it — and no way
|
|
89
|
-
* to hide it either: citty's `ArgDef` has no `hidden` field (only `CommandMeta`
|
|
90
|
-
* does). So it stays visible and says what it is.
|
|
91
|
-
*/
|
|
92
|
-
export const LIBRARY_ARG = {
|
|
93
|
-
type: 'boolean',
|
|
94
|
-
// Both forms get a description, because citty renders a positive row for any
|
|
95
|
-
// boolean arg whether or not the flag is meant to be used. Left undescribed it
|
|
96
|
-
// was a blank line in `--help` sitting next to `--fresh`.
|
|
97
|
-
description: 'Deprecated and unnecessary — the library is consulted by default. Use --fresh to skip it.',
|
|
98
|
-
negativeDescription: 'Deprecated spelling of --fresh. Always makes a new character.',
|
|
99
|
-
};
|
|
100
|
-
//# sourceMappingURL=character-body.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"character-body.js","sourceRoot":"","sources":["../../src/generate/character-body.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAC9D,OAAO,EAAE,uBAAuB,EAAE,MAAM,yBAAyB,CAAC;AAClE,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAE7D,6FAA6F;AAC7F,SAAS,kBAAkB,CAAC,MAA+B;IACzD,OAAO,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC;AAC/F,CAAC;AAyBD;;;;;GAKG;AACH,MAAM,UAAU,yBAAyB;IACvC,MAAM,IAAI,GAAG,qBAAqB,EAAE,CAAC;IACrC,IAAI,IAAI,KAAK,IAAI;QAAE,OAAO,SAAS,CAAC;IACpC,OAAO,uBAAuB,CAAC,IAAI,CAAC,CAAC,QAAQ,KAAK,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;AACnF,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,IAAmB;IACpD,OAAO,kBAAkB,CAAC;QACxB,IAAI,EAAE,IAAI,CAAC,IAAI;QACf,MAAM,EAAE,IAAI,CAAC,MAAM;QACnB,aAAa,EAAE,IAAI,CAAC,aAAa;QACjC,SAAS,EAAE,eAAe,CAAC,YAAY,EAAE,IAAI,CAAC,SAAS,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC;QAC/E,4EAA4E;QAC5E,4EAA4E;QAC5E,0CAA0C;QAC1C,UAAU,EAAE,IAAI,CAAC,KAAK,KAAK,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO;QACtD,WAAW,EAAE,IAAI,CAAC,WAAW;QAC7B,WAAW,EAAE,IAAI,CAAC,WAAW;QAC7B,QAAQ,EAAE,IAAI,CAAC,QAAQ;QACvB,SAAS,EAAE,IAAI,CAAC,SAAS;KAC1B,CAAC,CAAC;AACL,CAAC;AAED,+EAA+E;AAC/E,4EAA4E;AAC5E,+EAA+E;AAE/E,MAAM,CAAC,MAAM,QAAQ,GAAG;IACtB,IAAI,EAAE,QAAQ;IACd,QAAQ,EAAE,IAAI;IACd,WAAW,EAAE,gCAAgC;CACrC,CAAC;AAEX,MAAM,CAAC,MAAM,UAAU,GAAG;IACxB,IAAI,EAAE,QAAQ;IACd,QAAQ,EAAE,IAAI;IACd,WAAW,EAAE,+BAA+B;CACpC,CAAC;AAEX,MAAM,CAAC,MAAM,mBAAmB,GAAG;IACjC,IAAI,EAAE,SAAS;IACf,WAAW,EAAE,6EAA6E;CAClF,CAAC;AAEX,MAAM,CAAC,MAAM,cAAc,GAAG;IAC5B,IAAI,EAAE,QAAQ;IACd,WAAW,EAAE,iFAAiF;CACtF,CAAC;AAEX,MAAM,CAAC,MAAM,SAAS,GAAG;IACvB,IAAI,EAAE,SAAS;IACf,WAAW,EAAE,iEAAiE;UAC1E,qFAAqF;CACjF,CAAC;AAEX,MAAM,CAAC,MAAM,YAAY,GAAG;IAC1B,IAAI,EAAE,SAAS;IACf,WAAW,EAAE,0HAA0H;IACvI,mBAAmB,EAAE,0DAA0D;CACvE,CAAC;AAEX,MAAM,CAAC,MAAM,cAAc,GAAG;IAC5B,IAAI,EAAE,QAAQ;IACd,WAAW,EAAE,6PAA6P;CAClQ,CAAC;AAEX;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG;IACzB,IAAI,EAAE,SAAS;IACf,6EAA6E;IAC7E,+EAA+E;IAC/E,0DAA0D;IAC1D,WAAW,EAAE,2FAA2F;IACxG,mBAAmB,EAAE,+DAA+D;CAC5E,CAAC"}
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
export declare function characterSearchPath(root: string): string;
|
|
2
|
-
/** One row as the search displayed it. The shape `libraryPick` needs, plus the caption. */
|
|
3
|
-
export interface CharacterCandidate {
|
|
4
|
-
sid: string;
|
|
5
|
-
assetUrl: string;
|
|
6
|
-
description: string;
|
|
7
|
-
subject: string | null;
|
|
8
|
-
similarity: number;
|
|
9
|
-
}
|
|
10
|
-
export interface CharacterSearchRecord {
|
|
11
|
-
/** The prompt that produced this list — `add --id` reuses it as the asset's brief. */
|
|
12
|
-
prompt: string;
|
|
13
|
-
/** Which shelf was searched. `add` sends the matching `voxelize` so the media cannot cross. */
|
|
14
|
-
representation: 'voxel' | 'lowpoly';
|
|
15
|
-
/** The floor automatic substitution would have applied, for the "auto" column. */
|
|
16
|
-
threshold: number;
|
|
17
|
-
searchedAt: string;
|
|
18
|
-
candidates: CharacterCandidate[];
|
|
19
|
-
}
|
|
20
|
-
/** The last search, or null when there is none to trust. */
|
|
21
|
-
export declare function readCharacterSearch(root: string): CharacterSearchRecord | null;
|
|
22
|
-
export declare function writeCharacterSearch(root: string, record: CharacterSearchRecord): void;
|
|
23
|
-
/**
|
|
24
|
-
* The cached row with this id, or null.
|
|
25
|
-
*
|
|
26
|
-
* Case-insensitive on the id because a creator reads it off a table and retypes
|
|
27
|
-
* it, and the corpus uses one case throughout — so a capital letter is a typo
|
|
28
|
-
* with an obvious intent, not a different character.
|
|
29
|
-
*/
|
|
30
|
-
export declare function findCachedCandidate(record: CharacterSearchRecord, sid: string): CharacterCandidate | null;
|
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The candidates the last `bitmagic character search` returned, so
|
|
3
|
-
* `bitmagic character add --id <sid>` can name one of them.
|
|
4
|
-
*
|
|
5
|
-
* The search already fetched every row it displayed — sid, URL, caption and
|
|
6
|
-
* score. Keeping them means `add --id` needs nothing but the id: no second
|
|
7
|
-
* query, no re-ranking, and no asking the creator to retype the prompt that
|
|
8
|
-
* produced the list they are looking at. It also means `add` cannot drift from
|
|
9
|
-
* what was on screen, which a re-search could (the catalogue grows).
|
|
10
|
-
*
|
|
11
|
-
* Lives under `.bitmagic/` like `reference.json` and `cover.json`: generated,
|
|
12
|
-
* machine-written state. NOT in `bitmagic.json`, deliberately — that file is
|
|
13
|
-
* inside the publish fingerprint (shared/asset-core's publish-source.ts), so
|
|
14
|
-
* recording a search there would invalidate a passing `bitmagic verify` every
|
|
15
|
-
* time somebody browsed the shelf.
|
|
16
|
-
*
|
|
17
|
-
* Readers are lenient, like `readCoverRecord` and the reference records: a
|
|
18
|
-
* corrupt or absent file reads as "no search yet", because the worst case is one
|
|
19
|
-
* re-run of a free command, and a hard error would wedge the very command that
|
|
20
|
-
* would have replaced the bad file.
|
|
21
|
-
*
|
|
22
|
-
* There is deliberately no expiry. The catalogue only changes when someone
|
|
23
|
-
* promotes to it, and a stale row fails loudly and harmlessly (the URL 404s) —
|
|
24
|
-
* where a timeout would expire a list the creator is still reading. `add` prints
|
|
25
|
-
* the search's own timestamp instead, so age is visible rather than enforced.
|
|
26
|
-
*/
|
|
27
|
-
import * as path from 'path';
|
|
28
|
-
import { readJsonFile, writeJsonAtomic } from '../atomic-json.js';
|
|
29
|
-
const SEARCH_FILE = path.join('.bitmagic', 'character-search.json');
|
|
30
|
-
export function characterSearchPath(root) {
|
|
31
|
-
return path.join(root, SEARCH_FILE);
|
|
32
|
-
}
|
|
33
|
-
function isCandidate(value) {
|
|
34
|
-
if (typeof value !== 'object' || value === null)
|
|
35
|
-
return false;
|
|
36
|
-
const row = value;
|
|
37
|
-
return typeof row.sid === 'string' && row.sid !== ''
|
|
38
|
-
&& typeof row.assetUrl === 'string' && row.assetUrl !== ''
|
|
39
|
-
&& typeof row.similarity === 'number';
|
|
40
|
-
}
|
|
41
|
-
/** The last search, or null when there is none to trust. */
|
|
42
|
-
export function readCharacterSearch(root) {
|
|
43
|
-
const raw = readJsonFile(characterSearchPath(root));
|
|
44
|
-
if (typeof raw !== 'object' || raw === null)
|
|
45
|
-
return null;
|
|
46
|
-
const record = raw;
|
|
47
|
-
if (typeof record.prompt !== 'string')
|
|
48
|
-
return null;
|
|
49
|
-
if (record.representation !== 'voxel' && record.representation !== 'lowpoly')
|
|
50
|
-
return null;
|
|
51
|
-
if (!Array.isArray(record.candidates))
|
|
52
|
-
return null;
|
|
53
|
-
const candidates = record.candidates.filter(isCandidate).map((row) => ({
|
|
54
|
-
sid: row.sid,
|
|
55
|
-
assetUrl: row.assetUrl,
|
|
56
|
-
description: typeof row.description === 'string' ? row.description : '',
|
|
57
|
-
subject: typeof row.subject === 'string' ? row.subject : null,
|
|
58
|
-
similarity: row.similarity,
|
|
59
|
-
}));
|
|
60
|
-
return {
|
|
61
|
-
prompt: record.prompt,
|
|
62
|
-
representation: record.representation,
|
|
63
|
-
threshold: typeof record.threshold === 'number' ? record.threshold : 0,
|
|
64
|
-
searchedAt: typeof record.searchedAt === 'string' ? record.searchedAt : '',
|
|
65
|
-
candidates,
|
|
66
|
-
};
|
|
67
|
-
}
|
|
68
|
-
export function writeCharacterSearch(root, record) {
|
|
69
|
-
writeJsonAtomic(characterSearchPath(root), record);
|
|
70
|
-
}
|
|
71
|
-
/**
|
|
72
|
-
* The cached row with this id, or null.
|
|
73
|
-
*
|
|
74
|
-
* Case-insensitive on the id because a creator reads it off a table and retypes
|
|
75
|
-
* it, and the corpus uses one case throughout — so a capital letter is a typo
|
|
76
|
-
* with an obvious intent, not a different character.
|
|
77
|
-
*/
|
|
78
|
-
export function findCachedCandidate(record, sid) {
|
|
79
|
-
const wanted = sid.trim().toLowerCase();
|
|
80
|
-
return record.candidates.find((row) => row.sid.toLowerCase() === wanted) ?? null;
|
|
81
|
-
}
|
|
82
|
-
//# sourceMappingURL=character-search.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"character-search.js","sourceRoot":"","sources":["../../src/project/character-search.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAC7B,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAElE,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,uBAAuB,CAAC,CAAC;AAEpE,MAAM,UAAU,mBAAmB,CAAC,IAAY;IAC9C,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC;AACtC,CAAC;AAsBD,SAAS,WAAW,CAAC,KAAc;IACjC,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,KAAK,CAAC;IAC9D,MAAM,GAAG,GAAG,KAAgC,CAAC;IAC7C,OAAO,OAAO,GAAG,CAAC,GAAG,KAAK,QAAQ,IAAI,GAAG,CAAC,GAAG,KAAK,EAAE;WAC/C,OAAO,GAAG,CAAC,QAAQ,KAAK,QAAQ,IAAI,GAAG,CAAC,QAAQ,KAAK,EAAE;WACvD,OAAO,GAAG,CAAC,UAAU,KAAK,QAAQ,CAAC;AAC1C,CAAC;AAED,4DAA4D;AAC5D,MAAM,UAAU,mBAAmB,CAAC,IAAY;IAC9C,MAAM,GAAG,GAAG,YAAY,CAAC,mBAAmB,CAAC,IAAI,CAAC,CAAC,CAAC;IACpD,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IACzD,MAAM,MAAM,GAAG,GAA8B,CAAC;IAC9C,IAAI,OAAO,MAAM,CAAC,MAAM,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAC;IACnD,IAAI,MAAM,CAAC,cAAc,KAAK,OAAO,IAAI,MAAM,CAAC,cAAc,KAAK,SAAS;QAAE,OAAO,IAAI,CAAC;IAC1F,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,UAAU,CAAC;QAAE,OAAO,IAAI,CAAC;IACnD,MAAM,UAAU,GAAG,MAAM,CAAC,UAAU,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;QACrE,GAAG,EAAE,GAAG,CAAC,GAAG;QACZ,QAAQ,EAAE,GAAG,CAAC,QAAQ;QACtB,WAAW,EAAE,OAAO,GAAG,CAAC,WAAW,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE;QACvE,OAAO,EAAE,OAAO,GAAG,CAAC,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI;QAC7D,UAAU,EAAE,GAAG,CAAC,UAAU;KAC3B,CAAC,CAAC,CAAC;IACJ,OAAO;QACL,MAAM,EAAE,MAAM,CAAC,MAAM;QACrB,cAAc,EAAE,MAAM,CAAC,cAAc;QACrC,SAAS,EAAE,OAAO,MAAM,CAAC,SAAS,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;QACtE,UAAU,EAAE,OAAO,MAAM,CAAC,UAAU,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE;QAC1E,UAAU;KACX,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,IAAY,EAAE,MAA6B;IAC9E,eAAe,CAAC,mBAAmB,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC,CAAC;AACrD,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,mBAAmB,CACjC,MAA6B,EAC7B,GAAW;IAEX,MAAM,MAAM,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IACxC,OAAO,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,WAAW,EAAE,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC;AACnF,CAAC"}
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* `<skills dir>/choosing-asset-pipelines/SKILL.md` — WHICH lane makes a given thing, before any
|
|
3
|
-
* command runs.
|
|
4
|
-
*
|
|
5
|
-
* Exists because the GDK grew several ways to make the same thing — a level from the baseline
|
|
6
|
-
* terrain, `bitmagic forge` (five modes), a Blender script or a Unity port; a character from the
|
|
7
|
-
* free block default, a free library hit, a voxel forge or a low-poly forge at four times the
|
|
8
|
-
* price — and the routing knowledge sat in five places: the per-command reference in
|
|
9
|
-
* `generating-assets`, the "one forge" rule in `planning-a-game`, the Blender skill's §0 gate, the
|
|
10
|
-
* hosted Creator agent's GLB-vs-voxel rules (which never reach a CLI project at all), and code
|
|
11
|
-
* comments. An agent took the first lane it remembered, and a creator had to know Bitmagic's
|
|
12
|
-
* internals to steer it. This file is the table by NEED: conditions (art style, model class,
|
|
13
|
-
* local tooling, prototype vs polished), rough cost, rough time, recommended order — and the rule
|
|
14
|
-
* for when the agent decides alone versus asks the creator with a recommendation.
|
|
15
|
-
*
|
|
16
|
-
* It is a shipped skill so that `bitmagic upgrade` re-renders it in every project with every CLI
|
|
17
|
-
* release — that is the whole update mechanism; nothing here is hand-maintained in a creator's
|
|
18
|
-
* project. Same file-layout contract as `skill-files.ts`: a pure function returning the markdown
|
|
19
|
-
* as a template literal, every backtick inside escaped as \` and every `${` escaped, except the
|
|
20
|
-
* `${PRIMARY_SKILLS_DIR}` interpolations, which are the point (sibling skills are cited by the
|
|
21
|
-
* fixed path every agent's project has, never by a vendor path). Imports only `agent-targets.js`
|
|
22
|
-
* so `project.ts` can import this without a cycle.
|
|
23
|
-
*
|
|
24
|
-
* What keeps it honest, and what does not:
|
|
25
|
-
* - `__tests__/asset-pipeline-skill-files.test.ts` fails when a `bitmagic generate` subcommand
|
|
26
|
-
* exists with no row here, when a row names a subcommand or a skill directory that does not
|
|
27
|
-
* exist, or when one of the need sections or the two defaults (audio opt-in, block characters)
|
|
28
|
-
* disappears. So a new generator cannot ship without a row.
|
|
29
|
-
* - Prices and timings are NOT test-checked. Sparks come from `api-server/src/llm/llm_cost.json`
|
|
30
|
-
* (`toolCosts`, 1 spark = $0.01): glb/model/prop 3, voxel character 15, low-poly character 60,
|
|
31
|
-
* library-only 0, skybox and background 5, image 3, cover and reference 6, block-type 3, sound
|
|
32
|
-
* 12, music 0.25/s, video 1.35/s, authored animation 1, video-to-motion 15; forge and vehicle
|
|
33
|
-
* are usage-priced, presets free. Timings are observed. The CLI cannot import that file, so a
|
|
34
|
-
* price, flag or backend change is invisible to the test — which is why the release checklist
|
|
35
|
-
* (`.claude/skills/generate-release-checklist`) asks for this file to be re-read whenever a
|
|
36
|
-
* generator or `toolCosts` changes. Every figure is written as approximate for the same reason.
|
|
37
|
-
*/
|
|
38
|
-
export declare function renderAssetPipelinesSkill(): string;
|