@7ots/cli 0.1.7 → 0.1.8
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 +1 -1
- package/cli/7ots.mjs +13 -1
- package/cli/lib/account.mjs +152 -2
- package/cli/lib/assistant.mjs +106 -41
- package/cli/lib/brain.mjs +13 -2
- package/cli/lib/config.mjs +3 -0
- package/cli/lib/inferences.mjs +30 -6
- package/cli/lib/integrations.mjs +69 -5
- package/cli/lib/orquesta.mjs +44 -1
- package/cli/lib/pet-server.mjs +344 -11
- package/cli/pet/electron/director.cjs +37 -5
- package/cli/pet/electron/main.cjs +92 -10
- package/cli/pet/pet.html +149 -10
- package/cli/pet/settings.html +545 -42
- package/dist/7ots.esm.js +216 -137
- package/dist/7ots.esm.js.map +4 -4
- package/dist/7ots.iife.js +216 -137
- package/dist/7ots.iife.js.map +4 -4
- package/package.json +1 -1
- package/server/channels/agent.mjs +7 -1
- package/server/channels/index.mjs +3 -2
- package/server/platform/connect.mjs +4 -1
- package/server/platform/db.mjs +9 -1
- package/server/platform/device.mjs +101 -4
- package/server/platform/mods.mjs +222 -0
- package/server/platform/orquesta.mjs +78 -14
- package/server/platform/profile.mjs +161 -0
- package/server/platform/routes.mjs +38 -33
- package/server/platform/runtime.mjs +3 -1
- package/server/platform/store.mjs +1 -1
- package/server/platform/vm.mjs +370 -91
- package/server/server.mjs +12 -2
- package/src/avatar/three.js +3 -2
- package/src/character/AvatarEditor.js +95 -7
- package/src/character/Character.js +116 -17
- package/src/character/TradingCard.js +226 -0
- package/src/character/mods/index.js +4 -0
- package/src/character/mods/orc.js +64 -0
- package/src/character/mods.js +251 -0
- package/src/character/more/acc-head.js +213 -0
- package/src/character/more/acc-rest.js +342 -0
- package/src/character/more/brows.js +39 -0
- package/src/character/more/cheeks.js +78 -0
- package/src/character/more/eyes.js +288 -0
- package/src/character/more/mouths.js +259 -0
- package/src/character/more/patterns.js +120 -0
- package/src/character/parts.js +90 -0
- package/src/character/skin.js +166 -1
- package/src/character/styles.js +1285 -9
- package/src/character3d/Character3D.js +148 -35
- package/src/character3d/index.js +7 -1
- package/src/character3d/model.js +367 -0
- package/src/i18n/messages/character.js +34 -22
- package/src/i18n/messages/platform.js +15 -0
- package/src/identity/random.js +17 -3
- package/src/identity/schema.js +10 -0
- package/src/index.js +1 -0
|
@@ -74,7 +74,7 @@ const es = {
|
|
|
74
74
|
},
|
|
75
75
|
},
|
|
76
76
|
editor: {
|
|
77
|
-
kinds: { label: 'Tipo de avatar', character: 'Personaje 2D', plush: 'Personaje 3D', image: '
|
|
77
|
+
kinds: { label: 'Tipo de avatar', character: 'Personaje 2D', plush: 'Personaje 3D', image: 'Carta' },
|
|
78
78
|
tabs: { styles: 'Estilos', shape: 'Forma', color: 'Color y acabado', eyes: 'Ojos', mouth: 'Boca', face: 'Cara', acc: 'Accesorios' },
|
|
79
79
|
controls: 'Controles de edición',
|
|
80
80
|
preview: 'Vista previa del avatar',
|
|
@@ -102,15 +102,19 @@ const es = {
|
|
|
102
102
|
unavailable: 'Este navegador no puede mostrar el 3D; ves la vista 2D (el widget hará lo mismo).',
|
|
103
103
|
},
|
|
104
104
|
image: {
|
|
105
|
-
title: '
|
|
106
|
-
intro: '
|
|
107
|
-
|
|
108
|
-
|
|
105
|
+
title: 'Carta coleccionable',
|
|
106
|
+
intro: 'La carta holográfica de tu ot, con su personaje, nombre, rasgos y rareza. Muévela con el puntero.',
|
|
107
|
+
foil: 'Lámina',
|
|
108
|
+
foils: { auto: 'Según rareza', holo: 'Holo', prism: 'Prisma', cosmos: 'Cosmos', gold: 'Oro', none: 'Sin lámina' },
|
|
109
|
+
url: 'Arte propio (opcional)',
|
|
110
|
+
hint: 'Si pones una imagen (PNG, JPG, WebP o SVG), reemplaza al personaje en la carta y como avatar.',
|
|
111
|
+
placeholder: 'https://…/arte.png',
|
|
109
112
|
alt: 'Vista previa del retrato',
|
|
110
113
|
},
|
|
111
114
|
styles: {
|
|
112
|
-
title: '
|
|
113
|
-
hint: '
|
|
115
|
+
title: 'Ots al azar sin dueño',
|
|
116
|
+
hint: 'Caras que nadie tiene todavía. Elegir una reemplaza el personaje; después puedes ajustar cada pieza.',
|
|
117
|
+
more: 'Otros',
|
|
114
118
|
keepBody: 'Conservar mi forma y color al cambiar de estilo',
|
|
115
119
|
},
|
|
116
120
|
shape: {
|
|
@@ -129,7 +133,7 @@ const es = {
|
|
|
129
133
|
custom: 'Personalizado',
|
|
130
134
|
finish: 'Acabado',
|
|
131
135
|
outline: 'Contorno',
|
|
132
|
-
outlines: { auto: 'Automático', none: 'Sin contorno', thin: 'Fino', bold: 'Grueso' },
|
|
136
|
+
outlines: { auto: 'Automático', none: 'Sin contorno', thin: 'Fino', bold: 'Grueso', tone: 'Tono', sticker: 'Pegatina' },
|
|
133
137
|
pattern: 'Patrón',
|
|
134
138
|
patternColor: 'Color del patrón',
|
|
135
139
|
},
|
|
@@ -272,15 +276,19 @@ const en = {
|
|
|
272
276
|
unavailable: 'This browser can’t show 3D; you see the 2D preview (the widget will do the same).',
|
|
273
277
|
},
|
|
274
278
|
image: {
|
|
275
|
-
title: '
|
|
276
|
-
intro: '
|
|
277
|
-
|
|
278
|
-
|
|
279
|
+
title: 'Trading card',
|
|
280
|
+
intro: 'Your ot’s holographic card, with its character, name, traits and rarity. Move your pointer over it.',
|
|
281
|
+
foil: 'Foil',
|
|
282
|
+
foils: { auto: 'By rarity', holo: 'Holo', prism: 'Prism', cosmos: 'Cosmos', gold: 'Gold', none: 'No foil' },
|
|
283
|
+
url: 'Custom art (optional)',
|
|
284
|
+
hint: 'An image (PNG, JPG, WebP or SVG) replaces the character on the card and as the avatar.',
|
|
285
|
+
placeholder: 'https://…/art.png',
|
|
279
286
|
alt: 'Portrait preview',
|
|
280
287
|
},
|
|
281
288
|
styles: {
|
|
282
|
-
title: '
|
|
283
|
-
hint: '
|
|
289
|
+
title: 'Random unclaimed ots',
|
|
290
|
+
hint: 'Faces nobody has yet. Picking one replaces the character; you can then adjust each part.',
|
|
291
|
+
more: 'Shuffle',
|
|
284
292
|
keepBody: 'Keep my shape and color when changing style',
|
|
285
293
|
},
|
|
286
294
|
shape: {
|
|
@@ -299,7 +307,7 @@ const en = {
|
|
|
299
307
|
custom: 'Custom',
|
|
300
308
|
finish: 'Finish',
|
|
301
309
|
outline: 'Outline',
|
|
302
|
-
outlines: { auto: 'Automatic', none: 'No outline', thin: 'Thin', bold: 'Bold' },
|
|
310
|
+
outlines: { auto: 'Automatic', none: 'No outline', thin: 'Thin', bold: 'Bold', tone: 'Tone', sticker: 'Sticker' },
|
|
303
311
|
pattern: 'Pattern',
|
|
304
312
|
patternColor: 'Pattern color',
|
|
305
313
|
},
|
|
@@ -442,15 +450,19 @@ const pt = {
|
|
|
442
450
|
unavailable: 'Este navegador não consegue mostrar o 3D; você vê a prévia 2D (o widget fará o mesmo).',
|
|
443
451
|
},
|
|
444
452
|
image: {
|
|
445
|
-
title: '
|
|
446
|
-
intro: '
|
|
447
|
-
|
|
448
|
-
|
|
453
|
+
title: 'Carta colecionável',
|
|
454
|
+
intro: 'A carta holográfica do seu ot, com personagem, nome, atributos e raridade. Passe o ponteiro sobre ela.',
|
|
455
|
+
foil: 'Lâmina',
|
|
456
|
+
foils: { auto: 'Pela raridade', holo: 'Holo', prism: 'Prisma', cosmos: 'Cosmos', gold: 'Ouro', none: 'Sem lâmina' },
|
|
457
|
+
url: 'Arte própria (opcional)',
|
|
458
|
+
hint: 'Uma imagem (PNG, JPG, WebP ou SVG) substitui o personagem na carta e como avatar.',
|
|
459
|
+
placeholder: 'https://…/arte.png',
|
|
449
460
|
alt: 'Prévia do retrato',
|
|
450
461
|
},
|
|
451
462
|
styles: {
|
|
452
|
-
title: '
|
|
453
|
-
hint: '
|
|
463
|
+
title: 'Ots aleatórios sem dono',
|
|
464
|
+
hint: 'Rostos que ninguém tem ainda. Escolher um substitui o personagem; depois você pode ajustar cada peça.',
|
|
465
|
+
more: 'Outros',
|
|
454
466
|
keepBody: 'Manter minha forma e cor ao trocar de estilo',
|
|
455
467
|
},
|
|
456
468
|
shape: {
|
|
@@ -469,7 +481,7 @@ const pt = {
|
|
|
469
481
|
custom: 'Personalizada',
|
|
470
482
|
finish: 'Acabamento',
|
|
471
483
|
outline: 'Contorno',
|
|
472
|
-
outlines: { auto: 'Automático', none: 'Sem contorno', thin: 'Fino', bold: 'Grosso' },
|
|
484
|
+
outlines: { auto: 'Automático', none: 'Sem contorno', thin: 'Fino', bold: 'Grosso', tone: 'Tom', sticker: 'Adesivo' },
|
|
473
485
|
pattern: 'Padrão',
|
|
474
486
|
patternColor: 'Cor do padrão',
|
|
475
487
|
},
|
|
@@ -74,6 +74,7 @@ const es = {
|
|
|
74
74
|
busy: 'Ya hay una tarea en marcha ({id}); espera a que acabe',
|
|
75
75
|
noAgent: 'Ese proyecto de Orquesta no tiene agente: configura uno en Orquesta ({url})',
|
|
76
76
|
noProject: 'Ese proyecto de Orquesta no existe o no está compartido con 7ots',
|
|
77
|
+
notLinked: 'Este ot no está conectado a ese proyecto en Orquesta, o no tiene permiso para ejecutar tareas ahí. Conéctalo en el proyecto → Identidad → Ots conectados: {url}',
|
|
77
78
|
rateLimited: 'Orquesta está recibiendo muchas peticiones; espera un momento',
|
|
78
79
|
submitFailed: 'Orquesta no aceptó la tarea (error {status})',
|
|
79
80
|
agentOffline: 'El agente de este proyecto está desconectado: la tarea queda en cola y empezará cuando vuelva',
|
|
@@ -101,6 +102,10 @@ const es = {
|
|
|
101
102
|
accountLimit: 'Tu cuenta ya tiene {max} servidor(es) de 7ots (su límite)',
|
|
102
103
|
full: 'No quedan servidores de 7ots disponibles por ahora; inténtalo más tarde',
|
|
103
104
|
badSize: 'Tamaño de servidor no disponible',
|
|
105
|
+
needsPayment: 'Falta el pago del servidor de 7ots: vuelve a pulsar «Pagar y crear servidor»',
|
|
106
|
+
userNeedsKey: 'Para crear el servidor en tu cuenta de Orquesta, conéctala con una clave oak_ que tenga los permisos projects:write y vms:write (Orquesta → Ajustes → API keys). La conexión por OAuth no puede crear servidores.',
|
|
107
|
+
userScopes: 'Tu cuenta de Orquesta no dejó crear el servidor: vuelve a conectarla con una clave oak_ que tenga los permisos projects:write y vms:write (Orquesta → Ajustes → API keys)',
|
|
108
|
+
subscriptionInUse: 'Elimina antes tus servidores de 7ots; luego puedes cancelar la suscripción',
|
|
104
109
|
},
|
|
105
110
|
},
|
|
106
111
|
};
|
|
@@ -173,6 +178,7 @@ const en = {
|
|
|
173
178
|
busy: 'A task is already running ({id}); wait for it to finish',
|
|
174
179
|
noAgent: 'That Orquesta project has no agent: set up an agent in Orquesta ({url})',
|
|
175
180
|
noProject: 'That Orquesta project does not exist or is not shared with 7ots',
|
|
181
|
+
notLinked: 'This ot is not connected to that Orquesta project, or may not run tasks there. Connect it in the project → Identity → Connected ots: {url}',
|
|
176
182
|
rateLimited: 'Orquesta is getting too many requests; wait a moment',
|
|
177
183
|
submitFailed: 'Orquesta did not accept the task (error {status})',
|
|
178
184
|
agentOffline: "This project's agent is offline: the task is queued and will start when it is back",
|
|
@@ -200,6 +206,10 @@ const en = {
|
|
|
200
206
|
accountLimit: 'Your account already has {max} 7ots server(s) (its limit)',
|
|
201
207
|
full: 'No 7ots servers are available right now; try again later',
|
|
202
208
|
badSize: 'That server size is not available',
|
|
209
|
+
needsPayment: 'The 7ots server has not been paid for yet: click "Pay and create server" again',
|
|
210
|
+
userNeedsKey: 'To create the server in your Orquesta account, connect it with an oak_ key that has the projects:write and vms:write scopes (Orquesta → Settings → API keys). An OAuth connection cannot create servers.',
|
|
211
|
+
userScopes: 'Your Orquesta account did not allow creating the server: reconnect it with an oak_ key that has the projects:write and vms:write scopes (Orquesta → Settings → API keys)',
|
|
212
|
+
subscriptionInUse: 'Delete your 7ots servers first; then you can cancel the subscription',
|
|
203
213
|
},
|
|
204
214
|
},
|
|
205
215
|
};
|
|
@@ -272,6 +282,7 @@ const pt = {
|
|
|
272
282
|
busy: 'Já há uma tarefa em andamento ({id}); espere ela terminar',
|
|
273
283
|
noAgent: 'Esse projeto do Orquesta não tem agente: configure um agente no Orquesta ({url})',
|
|
274
284
|
noProject: 'Esse projeto do Orquesta não existe ou não está compartilhado com o 7ots',
|
|
285
|
+
notLinked: 'Este ot não está conectado a esse projeto no Orquesta, ou não pode executar tarefas lá. Conecte-o no projeto → Identidade → Ots conectados: {url}',
|
|
275
286
|
rateLimited: 'O Orquesta está recebendo muitas solicitações; espere um momento',
|
|
276
287
|
submitFailed: 'O Orquesta não aceitou a tarefa (erro {status})',
|
|
277
288
|
agentOffline: 'O agente deste projeto está desconectado: a tarefa fica na fila e começa quando ele voltar',
|
|
@@ -299,6 +310,10 @@ const pt = {
|
|
|
299
310
|
accountLimit: 'Sua conta já tem {max} servidor(es) do 7ots (seu limite)',
|
|
300
311
|
full: 'Não há servidores do 7ots disponíveis agora; tente mais tarde',
|
|
301
312
|
badSize: 'Esse tamanho de servidor não está disponível',
|
|
313
|
+
needsPayment: 'O servidor da 7ots ainda não foi pago: clique de novo em «Pagar e criar servidor»',
|
|
314
|
+
userNeedsKey: 'Para criar o servidor na sua conta do Orquesta, conecte-a com uma chave oak_ que tenha as permissões projects:write e vms:write (Orquesta → Configurações → API keys). A conexão por OAuth não pode criar servidores.',
|
|
315
|
+
userScopes: 'Sua conta do Orquesta não permitiu criar o servidor: reconecte-a com uma chave oak_ que tenha as permissões projects:write e vms:write (Orquesta → Configurações → API keys)',
|
|
316
|
+
subscriptionInUse: 'Exclua antes seus servidores da 7ots; depois você pode cancelar a assinatura',
|
|
302
317
|
},
|
|
303
318
|
},
|
|
304
319
|
};
|
package/src/identity/random.js
CHANGED
|
@@ -33,13 +33,27 @@ const TEXT = {
|
|
|
33
33
|
},
|
|
34
34
|
};
|
|
35
35
|
|
|
36
|
-
/**
|
|
36
|
+
/**
|
|
37
|
+
* Semilla corta y legible (7 caracteres base36). Las de 7 caracteres sortean entre el catálogo
|
|
38
|
+
* completo de piezas; cualquier otra longitud (las de 6 de antes de 2026-10, las escritas a mano)
|
|
39
|
+
* usa solo el catálogo 1, así que sigue dando exactamente el mismo ot que siempre.
|
|
40
|
+
*/
|
|
37
41
|
export function newSeed() {
|
|
38
42
|
let s = '';
|
|
39
|
-
for (let i = 0; i <
|
|
43
|
+
for (let i = 0; i < 7; i++) s += Math.floor(Math.random() * 36).toString(36);
|
|
40
44
|
return s;
|
|
41
45
|
}
|
|
42
46
|
|
|
47
|
+
/** ¿La semilla usa el catálogo 1 (todas salvo las de 7 caracteres, ver newSeed)? */
|
|
48
|
+
export function isLegacySeed(seed) {
|
|
49
|
+
return cleanSeed(seed).length !== 7;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/** Personaje de una semilla (el mismo en la web, el CLI, la mascota y el visor 3D). */
|
|
53
|
+
export function seedCharacter(seed) {
|
|
54
|
+
return randomCharacter(seedNumber(seed), { legacy: isLegacySeed(seed) });
|
|
55
|
+
}
|
|
56
|
+
|
|
43
57
|
/** Normaliza una semilla escrita por una persona: minúsculas, [a-z0-9-], máx. 32. */
|
|
44
58
|
export function cleanSeed(seed) {
|
|
45
59
|
return String(seed ?? '').toLowerCase().replace(/[^a-z0-9-]/g, '').slice(0, 32);
|
|
@@ -78,7 +92,7 @@ export function randomIdentity(seed, { lang = 'en', name } = {}) {
|
|
|
78
92
|
const L = TEXT[lang] ? lang : 'en';
|
|
79
93
|
const tx = TEXT[L];
|
|
80
94
|
const { rnd, pick } = rng(seedNumber(sd));
|
|
81
|
-
const character =
|
|
95
|
+
const character = seedCharacter(sd);
|
|
82
96
|
const nm = String(name || '').trim().slice(0, 40) || randomName(sd);
|
|
83
97
|
const traits = [];
|
|
84
98
|
while (traits.length < 3) {
|
package/src/identity/schema.js
CHANGED
|
@@ -66,6 +66,9 @@ export const IDENTITY_DEFAULTS = Object.freeze({
|
|
|
66
66
|
* @param {object} input
|
|
67
67
|
* @param {object} [base] identidad sobre la que se aplica (por defecto, los valores de serie)
|
|
68
68
|
*/
|
|
69
|
+
/** Campos de la ficha de personaje y su largo máximo. */
|
|
70
|
+
const SHEET = { backstory: 3000, style: 1500, quirks: 1500, scenario: 1500, greeting: 600, examples: 4000 };
|
|
71
|
+
|
|
69
72
|
export function defineIdentity(input = {}, base = IDENTITY_DEFAULTS) {
|
|
70
73
|
const i = input && typeof input === 'object' ? input : {};
|
|
71
74
|
const b = base;
|
|
@@ -87,6 +90,8 @@ export function defineIdentity(input = {}, base = IDENTITY_DEFAULTS) {
|
|
|
87
90
|
tone: str(personality.tone, 120),
|
|
88
91
|
traits: list(personality.traits, 12).map((t) => str(t, 40)).filter(Boolean),
|
|
89
92
|
instructions: str(personality.instructions, 4000),
|
|
93
|
+
// ficha de personaje (la misma del pet de escritorio; privada como las instrucciones)
|
|
94
|
+
sheet: Object.fromEntries(Object.entries(SHEET).map(([k, n]) => [k, str(personality.sheet?.[k], n)]).filter(([, v]) => v)),
|
|
90
95
|
},
|
|
91
96
|
look: {
|
|
92
97
|
kind: LOOK_KINDS.includes(look.kind) ? look.kind : look.image ? 'image' : 'character',
|
|
@@ -96,6 +101,7 @@ export function defineIdentity(input = {}, base = IDENTITY_DEFAULTS) {
|
|
|
96
101
|
accent: color(look.accent) || IDENTITY_DEFAULTS.look.accent,
|
|
97
102
|
emoji: str(look.emoji, 8),
|
|
98
103
|
image: url(look.image),
|
|
104
|
+
card: { foil: ['holo', 'prism', 'cosmos', 'gold', 'none'].includes(look.card?.foil) ? look.card.foil : '' },
|
|
99
105
|
avatar: {
|
|
100
106
|
url: url(look.avatar?.url),
|
|
101
107
|
body: look.avatar?.body === 'M' ? 'M' : 'F',
|
|
@@ -195,6 +201,10 @@ export function identityPrompt(id, locale = id.language) {
|
|
|
195
201
|
id.bio ? t('identity.prompt.about', { bio: id.bio }) : '',
|
|
196
202
|
p.tone ? t('identity.prompt.tone', { tone: p.tone }) : '',
|
|
197
203
|
p.traits.length ? t('identity.prompt.traits', { traits: p.traits.join(', ') }) : '',
|
|
204
|
+
p.sheet?.backstory,
|
|
205
|
+
p.sheet?.style,
|
|
206
|
+
p.sheet?.quirks,
|
|
207
|
+
p.sheet?.examples,
|
|
198
208
|
p.instructions,
|
|
199
209
|
]
|
|
200
210
|
.filter(Boolean)
|
package/src/index.js
CHANGED
|
@@ -79,6 +79,7 @@ export { createFace, IdentityCard };
|
|
|
79
79
|
export {
|
|
80
80
|
createCharacter, renderCharacter, normalizeCharacter, randomCharacter, applyPreset, DEFAULT_CHARACTER,
|
|
81
81
|
CHARACTER_MOODS, CHARACTER_GESTURES, CHARACTER_MORPHS, CHARACTER_EFFECTS, CHARACTER_GESTURE_ALIAS, VISEMES, textToVisemes, SHAPES, EYES, BROWS, MOUTHS, CHEEKS, PATTERNS, FINISHES, ACCESSORIES, ACCESSORY_GROUPS, PRESETS, partLabel,
|
|
82
|
+
resolveCharacter, normalizeMods, normalizeMod, sanitizeSvg, modName, MOD_ANCHORS, MAX_MODS,
|
|
82
83
|
} from './character/Character.js';
|
|
83
84
|
import { createAvatarEditor, AvatarEditor } from './character/AvatarEditor.js';
|
|
84
85
|
import { renderCharacter as _renderCharacter, createCharacter as _createCharacter } from './character/Character.js';
|