tonedial 0.1.0 → 0.1.1
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/dist/cli.js +5 -2
- package/dist/commands/compile.js +3 -12
- package/dist/commands/doctor.js +2 -2
- package/dist/commands/edit.js +7 -8
- package/dist/commands/init.js +2 -2
- package/dist/commands/save.js +4 -4
- package/dist/commands/set.js +68 -8
- package/dist/commands/show.js +19 -25
- package/dist/commands/use.js +3 -4
- package/dist/core/anchors.js +0 -3
- package/dist/core/compile.js +1 -5
- package/dist/core/i18n.js +12 -12
- package/dist/core/locales/es.js +6 -6
- package/dist/core/locales/ja.js +6 -6
- package/dist/core/locales/zh.js +6 -6
- package/dist/core/seeds.js +2 -2
- package/dist/core/skill.js +6 -2
- package/dist/ui/format.js +2 -2
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -20,7 +20,7 @@ import { runEdit } from "./commands/edit.js";
|
|
|
20
20
|
import { runUpdate } from "./commands/update.js";
|
|
21
21
|
import { runSave } from "./commands/save.js";
|
|
22
22
|
import { runCreate } from "./commands/create.js";
|
|
23
|
-
import { runAddress, runSet, runReset } from "./commands/set.js";
|
|
23
|
+
import { runAddress, runPersona, runSet, runReset } from "./commands/set.js";
|
|
24
24
|
import { runShow } from "./commands/show.js";
|
|
25
25
|
import { runUse } from "./commands/use.js";
|
|
26
26
|
import { runDoctor } from "./commands/doctor.js";
|
|
@@ -34,7 +34,7 @@ export const JSON_SCHEMA = 3;
|
|
|
34
34
|
* run time is the one thing that breaks all three binary packagers at once. A test asserts this
|
|
35
35
|
* equals the manifest, which is the cheap half of the trade.
|
|
36
36
|
*/
|
|
37
|
-
export const VERSION = "0.1.
|
|
37
|
+
export const VERSION = "0.1.1";
|
|
38
38
|
const FLAG_NAMES = ["project", "check", "explain", "global", "here", "migrateLegacy", "auto", "dryRun", "fix", "rollback", "fromOperation", "fromPreset", "restorePreset", "preset", "slug", "acceptUsage", "lang", "commands", "tools"];
|
|
39
39
|
/** Command-line spelling for each flag, where it differs from the field name. */
|
|
40
40
|
const FLAG_SPELLING = {
|
|
@@ -49,6 +49,7 @@ const COMMANDS = {
|
|
|
49
49
|
set: { run: runSet, flags: [], max: null, context: "state" },
|
|
50
50
|
test: { run: runTest, flags: ["project", "dryRun", "preset", "acceptUsage"], max: 1 },
|
|
51
51
|
address: { run: runAddress, flags: [], max: 2, context: "state" },
|
|
52
|
+
persona: { run: runPersona, flags: [], max: 2, context: "state" },
|
|
52
53
|
reset: { run: runReset, flags: [], max: 1, context: "state" },
|
|
53
54
|
show: { run: runShow, flags: ["explain"], max: 1 },
|
|
54
55
|
create: { run: runCreate, flags: ["slug", "auto", "dryRun"], max: null, context: "state" },
|
|
@@ -78,6 +79,7 @@ const COMMAND_GROUPS = [
|
|
|
78
79
|
["tone", [
|
|
79
80
|
["set", "set <axis>=<level> …"],
|
|
80
81
|
["address", "address [self user]"],
|
|
82
|
+
["persona", "persona [agent user]"],
|
|
81
83
|
["reset", "reset [axis]"],
|
|
82
84
|
["show", "show [slug]"],
|
|
83
85
|
["test", "test [claude|codex]"],
|
|
@@ -108,6 +110,7 @@ const COMMAND_EXAMPLES = {
|
|
|
108
110
|
set: ["tonedial set", "tonedial set warmth=5 critique=4", "tonedial set persona.agent=reviewer"],
|
|
109
111
|
test: ["tonedial test codex --dry-run", "tonedial test claude --project .", "tonedial test codex --preset my-tone --accept-usage"],
|
|
110
112
|
address: ['tonedial address "assistant" "friend"'],
|
|
113
|
+
persona: ["tonedial persona", 'tonedial persona "Fictional reviewer" "Developer"'],
|
|
111
114
|
reset: ["tonedial reset", "tonedial reset warmth"],
|
|
112
115
|
show: ["tonedial show", "tonedial show --explain"],
|
|
113
116
|
create: ["tonedial create", 'tonedial create "Jarvis" --slug jarvis care=3 --auto'],
|
package/dist/commands/compile.js
CHANGED
|
@@ -4,7 +4,7 @@ import { compile, measure } from "../core/compile.js";
|
|
|
4
4
|
import { ConfigError, defaultConfig, parseConfig } from "../core/config.js";
|
|
5
5
|
import { toCompileInput } from "../core/resolve.js";
|
|
6
6
|
import { contextArtifactTargets } from "../core/seeds.js";
|
|
7
|
-
import {
|
|
7
|
+
import { artifactSize, humanText, nextStep } from "../ui/format.js";
|
|
8
8
|
import { wrap } from "../ui/width.js";
|
|
9
9
|
import { confirm } from "../ui/prompt.js";
|
|
10
10
|
import { captureRawEntry, gate, planChange, rawReadChange } from "../wiring/apply.js";
|
|
@@ -60,15 +60,6 @@ export async function applyPlanned(ctx, changes, finalChanges = [], review = fal
|
|
|
60
60
|
}
|
|
61
61
|
return result;
|
|
62
62
|
}
|
|
63
|
-
export function sizeWarning(size, t) {
|
|
64
|
-
// It warns and never fails: a user is entitled to switch every axis on, and a budget that
|
|
65
|
-
// refuses to compile is a different product.
|
|
66
|
-
if (size.overCap)
|
|
67
|
-
return [t.artifact.overCap(num(size.chars), num(size.cap))];
|
|
68
|
-
if (size.overTarget)
|
|
69
|
-
return [t.artifact.overTarget(num(size.chars), num(size.target))];
|
|
70
|
-
return [];
|
|
71
|
-
}
|
|
72
63
|
export async function runCompile(ctx) {
|
|
73
64
|
const check = ctx.flags.check;
|
|
74
65
|
const { change: configChange, config } = planConfig(ctx);
|
|
@@ -113,10 +104,10 @@ export async function runCompile(ctx) {
|
|
|
113
104
|
lines: [
|
|
114
105
|
...wrap(status, ctx.ui.width - 2).map(line => ` ${ctx.ui.bold((!check || current ? ctx.ui.success : ctx.ui.warn)(line))}`),
|
|
115
106
|
` ${humanText(ctx.paths.tone)}`,
|
|
116
|
-
` ${
|
|
107
|
+
` ${ctx.ui.dim(artifactSize(size, ctx.t))}`,
|
|
117
108
|
...nextStep(check && !current ? "tonedial compile" : "tonedial show", ctx.ui),
|
|
118
109
|
],
|
|
119
110
|
json: { path: ctx.paths.tone, agentsPath: ctx.paths.agents, written: !check, ...size },
|
|
120
|
-
warnings:
|
|
111
|
+
warnings: [],
|
|
121
112
|
};
|
|
122
113
|
}
|
package/dist/commands/doctor.js
CHANGED
|
@@ -15,7 +15,7 @@ import { inspect as inspectSkill, skillPath } from "../wiring/skill.js";
|
|
|
15
15
|
import { candidateRcPaths, pathLineState, rcPath, withPathLine } from "../wiring/shell.js";
|
|
16
16
|
import { SEED_VERSION, inspectContextLayout, inspectSeeds, recordedSeedSelection, } from "../core/seeds.js";
|
|
17
17
|
import { toCompileInput } from "../core/resolve.js";
|
|
18
|
-
import {
|
|
18
|
+
import { artifactSize, humanText, nextStep, receiptLines, recoveryRollbackLines, section } from "../ui/format.js";
|
|
19
19
|
import { wrap } from "../ui/width.js";
|
|
20
20
|
import { applyRollback, assertFresh, planChange, previewRollback } from "../wiring/apply.js";
|
|
21
21
|
import { confirm } from "../ui/prompt.js";
|
|
@@ -585,7 +585,7 @@ async function doctorReport(ctx, showRollbackCommands = true, showCodexAction =
|
|
|
585
585
|
checks.push(onDisk === null
|
|
586
586
|
? { name: "TONE.md", state: "problem", detail: ctx.t.doctor.toneNotWritten, repair: "tonedial compile" }
|
|
587
587
|
: onDisk === expected
|
|
588
|
-
? { name: "TONE.md", state: "ok", detail:
|
|
588
|
+
? { name: "TONE.md", state: "ok", detail: artifactSize(measure(expected), ctx.t) }
|
|
589
589
|
: {
|
|
590
590
|
name: "TONE.md",
|
|
591
591
|
state: "problem",
|
package/dist/commands/edit.js
CHANGED
|
@@ -6,9 +6,9 @@ import { tmpdir } from "node:os";
|
|
|
6
6
|
import { isDeepStrictEqual } from "node:util";
|
|
7
7
|
import { CONFIG_SCHEMA, ConfigError, parseConfig, serializeConfig } from "../core/config.js";
|
|
8
8
|
import { BUNDLED, SLUG_PATTERN, matchesPreset, withPreset, assertPresetSelection, customPresetDir, inspectPresetLibrary, parsePreset, preparePresetWrite, resolvePreset, } from "../core/presets.js";
|
|
9
|
-
import { applyPlanned, planArtifact, planConfig
|
|
9
|
+
import { applyPlanned, planArtifact, planConfig } from "./compile.js";
|
|
10
10
|
import { check as checkCombos } from "../core/combos.js";
|
|
11
|
-
import { combination, humanText, riskWarnings } from "../ui/format.js";
|
|
11
|
+
import { artifactSize, combination, humanText, riskWarnings } from "../ui/format.js";
|
|
12
12
|
import { captureRawEntry, planChange, rawReadChange, rawReadCheck } from "../wiring/apply.js";
|
|
13
13
|
import { emptyWiring } from "../wiring/ownership.js";
|
|
14
14
|
/**
|
|
@@ -116,11 +116,11 @@ export async function runEdit(ctx, args) {
|
|
|
116
116
|
}
|
|
117
117
|
const { change: toneChange, size } = planArtifact(ctx, config);
|
|
118
118
|
await commit([toneChange], [{ ...baseline, after }]);
|
|
119
|
-
lines.push(` ${
|
|
119
|
+
lines.push(` ${ctx.ui.dim(artifactSize(size, ctx.t))}`);
|
|
120
120
|
return {
|
|
121
121
|
lines,
|
|
122
122
|
json: { path: target.path, editor: editor[0], opened: true, changed: true, chars: size.chars },
|
|
123
|
-
warnings: stateWarnings(ctx, config
|
|
123
|
+
warnings: stateWarnings(ctx, config),
|
|
124
124
|
};
|
|
125
125
|
}
|
|
126
126
|
// **Refused, not dropped.** `parsePreset` returns the slug it was handed and ignores the one
|
|
@@ -189,8 +189,8 @@ export async function runEdit(ctx, args) {
|
|
|
189
189
|
const { change: toneChange, size } = planArtifact(ctx, config);
|
|
190
190
|
const finalConfig = { ...configRead.change, after: serializeConfig(config, ctx.t) };
|
|
191
191
|
await commit([configRead.change, presetChange, toneChange], [finalConfig]);
|
|
192
|
-
lines.push(` ${
|
|
193
|
-
warnings.push(...stateWarnings(ctx, config
|
|
192
|
+
lines.push(` ${ctx.ui.dim(artifactSize(size, ctx.t))}`);
|
|
193
|
+
warnings.push(...stateWarnings(ctx, config));
|
|
194
194
|
}
|
|
195
195
|
else {
|
|
196
196
|
await commit([configRead.change, presetChange]);
|
|
@@ -226,13 +226,12 @@ export async function runEdit(ctx, args) {
|
|
|
226
226
|
}
|
|
227
227
|
}
|
|
228
228
|
/** The notices every other state-changing command emits, through the same owners they use. */
|
|
229
|
-
function stateWarnings(ctx, config
|
|
229
|
+
function stateWarnings(ctx, config) {
|
|
230
230
|
const p = config.persona;
|
|
231
231
|
return [
|
|
232
232
|
...checkCombos(config.axes, p, config.speech_level).map((w) => combination(w, ctx.t)),
|
|
233
233
|
...(p.age || p.gender || p.note || p.address || p.user || p.agent ? [ctx.t.notice.personaUnanchored] : []),
|
|
234
234
|
...riskWarnings(config.axes, ctx.t),
|
|
235
|
-
...sizeWarning(size, ctx.t),
|
|
236
235
|
];
|
|
237
236
|
}
|
|
238
237
|
/**
|
package/dist/commands/init.js
CHANGED
|
@@ -13,7 +13,7 @@ import { BUNDLED, localizedPreset, matchesPreset, withPreset } from "../core/pre
|
|
|
13
13
|
import { SEED_VERSION, inspectContextLayout, planSeedChanges } from "../core/seeds.js";
|
|
14
14
|
import { inspectOperations } from "../core/operations.js";
|
|
15
15
|
import { SKILL_NAME, TONE_COMMAND_MD, TONE_COMMAND_VERSION } from "../core/skill.js";
|
|
16
|
-
import {
|
|
16
|
+
import { artifactSize, humanText, nativeSetup, receiptLines, recoveryRollbackLines, riskWarnings, section } from "../ui/format.js";
|
|
17
17
|
import { riskyAxes } from "../core/anchors.js";
|
|
18
18
|
import { padEnd, wrap } from "../ui/width.js";
|
|
19
19
|
import { gate, planChange } from "../wiring/apply.js";
|
|
@@ -204,7 +204,7 @@ export async function runInit(entry, _args) {
|
|
|
204
204
|
addReceipt(ctx.t.artifact.generated, ctx.ui.success);
|
|
205
205
|
}
|
|
206
206
|
if (ctx.flags.verbose) {
|
|
207
|
-
lines.push(` ${ctx.ui.dim(
|
|
207
|
+
lines.push(` ${ctx.ui.dim(artifactSize(size, ctx.t))}`);
|
|
208
208
|
// The seed list grows with every bundled preset, so it folds like any other sentence.
|
|
209
209
|
addReceipt(ctx.t.wiring.seeded(seeds.labels));
|
|
210
210
|
if (skills.length) {
|
package/dist/commands/save.js
CHANGED
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
import { AXIS_DEFAULT, AXIS_ORDER } from "../core/anchors.js";
|
|
3
3
|
import { ConfigError, serializeConfig } from "../core/config.js";
|
|
4
4
|
import { BUNDLED, PRESET_SCHEMA, SLUG_PATTERN, preparePresetWrite, presetSettings, resolvePreset, slugify } from "../core/presets.js";
|
|
5
|
-
import {
|
|
5
|
+
import { artifactSize, humanText, nextStep } from "../ui/format.js";
|
|
6
6
|
import { cells, truncate, wrap } from "../ui/width.js";
|
|
7
7
|
import { PERSONA_DESCRIPTION_MAX } from "../core/combos.js";
|
|
8
|
-
import { applyPlanned, planArtifact, planConfig
|
|
8
|
+
import { applyPlanned, planArtifact, planConfig } from "./compile.js";
|
|
9
9
|
import { planChange, rawReadChange, rawReadCheck } from "../wiring/apply.js";
|
|
10
10
|
/** Only the axes that moved. Every axis is still emitted; sparsity is storage, not compilation. */
|
|
11
11
|
function movedValues(axes) {
|
|
@@ -73,7 +73,7 @@ export async function savePreset(ctx, displayName, state, options = {}) {
|
|
|
73
73
|
};
|
|
74
74
|
const count = Object.keys(values).length;
|
|
75
75
|
const countLabel = ctx.t.preset.nonDefault(count);
|
|
76
|
-
const warnings = [
|
|
76
|
+
const warnings = [];
|
|
77
77
|
if (replaced)
|
|
78
78
|
warnings.push(ctx.t.preset.replaced(slug));
|
|
79
79
|
// Sparsity survives on one reason after the omit-defaults rule fell: fewer extremes mean
|
|
@@ -89,7 +89,7 @@ export async function savePreset(ctx, displayName, state, options = {}) {
|
|
|
89
89
|
` ${ctx.ui.success(ctx.ui.bold(ctx.t.preset.savedTarget(slug)))}`,
|
|
90
90
|
` ${truncate(humanText(displayName), Math.max(1, ctx.ui.width - cells(` ${countLabel}`)))} ${ctx.ui.dim(countLabel)}`,
|
|
91
91
|
` ${ctx.t.artifact.generated}`,
|
|
92
|
-
...(ctx.flags.verbose ? [` ${ctx.ui.dim(
|
|
92
|
+
...(ctx.flags.verbose ? [` ${ctx.ui.dim(artifactSize(size, ctx.t))}`] : []),
|
|
93
93
|
...nextStep("tonedial list", ctx.ui),
|
|
94
94
|
],
|
|
95
95
|
json: { slug, displayName, values, settings: preset.settings, nonDefaultAxes: count, replaced, chars: size.chars,
|
package/dist/commands/set.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// `set`, `reset`, and `
|
|
1
|
+
// `set`, `reset`, `address` and `persona`. Change state and recompile in one action, so they cannot
|
|
2
2
|
// drift apart.
|
|
3
3
|
//
|
|
4
4
|
// Warnings never block. A user is entitled to a combination that reads badly, and the tool's
|
|
@@ -10,11 +10,11 @@ import { toCompileInput } from "../core/resolve.js";
|
|
|
10
10
|
import { LANGUAGES, catalogue, isLanguage } from "../core/i18n.js";
|
|
11
11
|
import { presetSettings, resolvePreset } from "../core/presets.js";
|
|
12
12
|
import { dial } from "../ui/dial.js";
|
|
13
|
-
import {
|
|
14
|
-
import { interactive } from "../ui/prompt.js";
|
|
13
|
+
import { artifactSize, combination, humanText, riskWarnings } from "../ui/format.js";
|
|
14
|
+
import { guardTerminal, interactive } from "../ui/prompt.js";
|
|
15
15
|
import { createInterface } from "node:readline/promises";
|
|
16
16
|
import { cells, padEnd, truncate, wrap } from "../ui/width.js";
|
|
17
|
-
import { applyPlanned, planArtifact, planConfig
|
|
17
|
+
import { applyPlanned, planArtifact, planConfig } from "./compile.js";
|
|
18
18
|
/** A raw number is bucketed on write; the stored and compiled value is always the band. */
|
|
19
19
|
function bucketAge(value, t, asJson) {
|
|
20
20
|
if (AGE_BANDS.includes(value))
|
|
@@ -264,7 +264,7 @@ async function commit(ctx, configChange, config, applied) {
|
|
|
264
264
|
` ${ctx.ui.bold(finalConfig.before === finalConfig.after ? ctx.t.axis.settingsUnchanged : ctx.ui.success(ctx.t.axis.settingsSaved))}`,
|
|
265
265
|
...movementLines(applied.moves, ctx, config.axes),
|
|
266
266
|
` ${ctx.ui.success(toneChange.before === toneChange.after ? ctx.t.artifact.current : ctx.t.artifact.generated)}`,
|
|
267
|
-
...(ctx.flags.verbose ? [` ${ctx.ui.dim(
|
|
267
|
+
...(ctx.flags.verbose ? [` ${ctx.ui.dim(artifactSize(size, ctx.t))}`] : []),
|
|
268
268
|
],
|
|
269
269
|
json: {
|
|
270
270
|
changed: applied.changed,
|
|
@@ -272,7 +272,7 @@ async function commit(ctx, configChange, config, applied) {
|
|
|
272
272
|
config: toCompileInput(config),
|
|
273
273
|
chars: size.chars,
|
|
274
274
|
},
|
|
275
|
-
warnings: [...applied.warnings, ...riskWarnings(config.axes, ctx.t), ...comboWarnings(config, ctx.t)
|
|
275
|
+
warnings: [...applied.warnings, ...riskWarnings(config.axes, ctx.t), ...comboWarnings(config, ctx.t)],
|
|
276
276
|
};
|
|
277
277
|
}
|
|
278
278
|
export async function runSet(ctx, args) {
|
|
@@ -313,6 +313,66 @@ export async function runAddress(ctx, args) {
|
|
|
313
313
|
];
|
|
314
314
|
return commit(ctx, configChange, config, applyPairs(config, pairs, ctx.t, ctx.asJson));
|
|
315
315
|
}
|
|
316
|
+
/** Agent first, user second, like address's self/user pair. Apply only after both validate. */
|
|
317
|
+
export async function runPersona(ctx, args) {
|
|
318
|
+
const { change: configChange, config } = planConfig(ctx);
|
|
319
|
+
try {
|
|
320
|
+
const roles = args.length === 0 ? await askRoles(ctx, config) : args;
|
|
321
|
+
if (roles.length !== 2)
|
|
322
|
+
throw new ConfigError(ctx.t.persona.rolesNeedsPair);
|
|
323
|
+
return commit(ctx, configChange, config, applyPairs(config, [
|
|
324
|
+
["persona.agent", roles[0]], ["persona.user", roles[1]],
|
|
325
|
+
], ctx.t, ctx.asJson));
|
|
326
|
+
}
|
|
327
|
+
catch (cause) {
|
|
328
|
+
if (!(cause instanceof Error) || cause.code !== "ABORT_ERR")
|
|
329
|
+
throw cause;
|
|
330
|
+
return { lines: [` ${ctx.t.axis.nothingChanged}`], json: { changed: [], moves: [], cancelled: true }, after: async () => 130 };
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
async function askRoles(ctx, config) {
|
|
334
|
+
if (!ctx.canPrompt || !interactive())
|
|
335
|
+
throw new ConfigError(ctx.t.persona.rolesNeedsPair);
|
|
336
|
+
const release = guardTerminal();
|
|
337
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
338
|
+
try {
|
|
339
|
+
for (const line of wrap(ctx.t.persona.rolesIntroduction, ctx.ui.width - 2))
|
|
340
|
+
process.stdout.write(` ${line}\n`);
|
|
341
|
+
const roles = [];
|
|
342
|
+
for (const field of ["agent", "user"]) {
|
|
343
|
+
const current = config.persona[field] ?? "";
|
|
344
|
+
for (;;) {
|
|
345
|
+
process.stdout.write("\n");
|
|
346
|
+
for (const line of wrap(`${ctx.t.create[field]}${current ? `: ${humanText(current)}` : ""}`, ctx.ui.width - 2)) {
|
|
347
|
+
process.stdout.write(` ${line}\n`);
|
|
348
|
+
}
|
|
349
|
+
const answer = (await rl.question(" > ")).trim();
|
|
350
|
+
const chosen = answer === '""' ? "" : answer || current;
|
|
351
|
+
try {
|
|
352
|
+
assign(structuredClone(config), `persona.${field}`, chosen, ctx.t, false);
|
|
353
|
+
roles.push(chosen);
|
|
354
|
+
process.stdout.write(` ${ctx.t.create.descriptionCount([...chosen].length, PERSONA_DESCRIPTION_MAX)}\n`);
|
|
355
|
+
break;
|
|
356
|
+
}
|
|
357
|
+
catch (cause) {
|
|
358
|
+
if (!(cause instanceof ConfigError))
|
|
359
|
+
throw cause;
|
|
360
|
+
for (const line of wrap(humanText(cause.message), ctx.ui.width - 2))
|
|
361
|
+
process.stdout.write(` ${ctx.ui.warn(line)}\n`);
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
return roles;
|
|
366
|
+
}
|
|
367
|
+
finally {
|
|
368
|
+
try {
|
|
369
|
+
rl.close();
|
|
370
|
+
}
|
|
371
|
+
finally {
|
|
372
|
+
release();
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
}
|
|
316
376
|
/**
|
|
317
377
|
* The two questions, on a terminal.
|
|
318
378
|
*
|
|
@@ -398,9 +458,9 @@ export async function runReset(ctx, args) {
|
|
|
398
458
|
: ` ${ctx.ui.bold(axis)} ${ctx.ui.dim(String(before))} ${ctx.ui.dim("→")} ${ctx.ui.bold(ctx.ui.accent(String(AXIS_DEFAULT[axis])))}`]
|
|
399
459
|
: wrap(ctx.t.axis.resetAll, ctx.ui.width - 2).map(line => ` ${ctx.ui.bold(ctx.ui.success(line))}`)),
|
|
400
460
|
` ${ctx.ui.success(toneChange.before === toneChange.after ? ctx.t.artifact.current : ctx.t.artifact.generated)}`,
|
|
401
|
-
...(ctx.flags.verbose ? [` ${ctx.ui.dim(
|
|
461
|
+
...(ctx.flags.verbose ? [` ${ctx.ui.dim(artifactSize(size, ctx.t))}`] : []),
|
|
402
462
|
],
|
|
403
463
|
json: { reset: axis ?? "all", chars: size.chars },
|
|
404
|
-
warnings: [...riskWarnings(config.axes, ctx.t), ...comboWarnings(config, ctx.t)
|
|
464
|
+
warnings: [...riskWarnings(config.axes, ctx.t), ...comboWarnings(config, ctx.t)],
|
|
405
465
|
};
|
|
406
466
|
}
|
package/dist/commands/show.js
CHANGED
|
@@ -12,8 +12,8 @@ import { toCompileInput } from "../core/resolve.js";
|
|
|
12
12
|
import { inspectContextLayout } from "../core/seeds.js";
|
|
13
13
|
import { catalogue, isLanguage } from "../core/i18n.js";
|
|
14
14
|
import { explainBlock, gaugeBlock, gaugeHeader } from "../ui/gauge.js";
|
|
15
|
-
import { planConfig
|
|
16
|
-
import {
|
|
15
|
+
import { planConfig } from "./compile.js";
|
|
16
|
+
import { artifactSize, combination, humanText, nextStep, riskWarnings } from "../ui/format.js";
|
|
17
17
|
import { maxCells, truncate, wrap } from "../ui/width.js";
|
|
18
18
|
import { inspectContextConsumers } from "../wiring/targets.js";
|
|
19
19
|
export function runShow(ctx, args) {
|
|
@@ -48,20 +48,20 @@ export function runShow(ctx, args) {
|
|
|
48
48
|
? "tonedial save"
|
|
49
49
|
: 'tonedial save "My Tone"';
|
|
50
50
|
const lines = [];
|
|
51
|
-
const
|
|
51
|
+
const sizeLabel = artifactSize(size, ctx.t);
|
|
52
52
|
// A display name has no length cap, so the title is the one row that can be pushed past the
|
|
53
53
|
// budget by state alone. Truncating keeps the size at the right margin where it is read.
|
|
54
54
|
const prefix = "ToneDial · show · ";
|
|
55
|
-
const nameBudget = ctx.ui.width - maxCells(
|
|
55
|
+
const nameBudget = ctx.ui.width - maxCells(sizeLabel) - maxCells(status) - maxCells(prefix) - 4;
|
|
56
56
|
if (nameBudget >= 2) {
|
|
57
|
-
lines.push(titleRow(prefix + truncate(humanText(activeName), nameBudget) + status,
|
|
57
|
+
lines.push(titleRow(prefix + truncate(humanText(activeName), nameBudget) + status, sizeLabel, ctx));
|
|
58
58
|
}
|
|
59
59
|
else {
|
|
60
60
|
const title = prefix + truncate(humanText(activeName), Math.max(2, ui.width - maxCells(status) - maxCells(prefix) - 2)) + status;
|
|
61
61
|
for (const folded of wrap(title, ui.width - 2))
|
|
62
62
|
lines.push(` ${ui.bold(folded)}`);
|
|
63
|
-
for (const folded of wrap(
|
|
64
|
-
lines.push(` ${
|
|
63
|
+
for (const folded of wrap(sizeLabel, ui.width - 2))
|
|
64
|
+
lines.push(` ${ui.dim(folded)}`);
|
|
65
65
|
}
|
|
66
66
|
const p = shown.persona;
|
|
67
67
|
const personaSet = Boolean(p.age || p.gender || p.note || p.address || p.user || p.agent);
|
|
@@ -76,20 +76,18 @@ export function runShow(ctx, args) {
|
|
|
76
76
|
p.address?.self_ref ? ctx.t.persona.callsItself(humanText(p.address.self_ref)) : null,
|
|
77
77
|
p.address?.user_ref ? ctx.t.persona.callsYou(humanText(p.address.user_ref)) : null,
|
|
78
78
|
p.note ? ctx.t.persona.noteChars([...p.note].length) : null,
|
|
79
|
-
p.user && p.agent
|
|
80
|
-
p.user && !p.agent
|
|
81
|
-
p.agent && !p.user
|
|
79
|
+
p.user && p.agent ? ctx.t.persona.descriptionCounts([...p.user].length, [...p.agent].length, PERSONA_DESCRIPTION_MAX) : null,
|
|
80
|
+
p.user && !p.agent ? ctx.t.persona.descriptionChars("user", [...p.user].length) : null,
|
|
81
|
+
p.agent && !p.user ? ctx.t.persona.descriptionChars("agent", [...p.agent].length) : null,
|
|
82
82
|
].filter(Boolean);
|
|
83
83
|
if (bits.length)
|
|
84
84
|
for (const folded of wrap(bits.join(" · "), detailWidth))
|
|
85
85
|
details.push(ui.dim(folded));
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
details.push(ui.dim(folded));
|
|
92
|
-
}
|
|
86
|
+
for (const [field, value] of [["agent", p.agent], ["user", p.user]]) {
|
|
87
|
+
if (value === null)
|
|
88
|
+
continue;
|
|
89
|
+
for (const folded of wrap(ctx.t.persona.descriptionFull(field, humanText(value)), detailWidth)) {
|
|
90
|
+
details.push(ui.dim(folded));
|
|
93
91
|
}
|
|
94
92
|
}
|
|
95
93
|
}
|
|
@@ -145,7 +143,7 @@ export function runShow(ctx, args) {
|
|
|
145
143
|
}
|
|
146
144
|
}
|
|
147
145
|
else {
|
|
148
|
-
// Keep the short legend and action together
|
|
146
|
+
// Keep the short legend and save action together after the settings.
|
|
149
147
|
const legend = ctx.t.artifact.movedFromDefault + (needsSave ? ` · ${ctx.t.preset.changesNotSaved}` : "");
|
|
150
148
|
const [first, ...rest] = wrap(legend, ui.width - 4);
|
|
151
149
|
lines.push(` ${ui.accent("*")} ${ui.dim(first)}`, ...rest.map((line) => ` ${ui.dim(line)}`), ...nextStep(preview ? `tonedial use ${preview.slug}` : needsSave ? saveCommand : "tonedial show --explain", ui).slice(1));
|
|
@@ -159,8 +157,6 @@ export function runShow(ctx, args) {
|
|
|
159
157
|
warnings.push(ctx.t.notice.modelExpectation);
|
|
160
158
|
if (activeConflict && preview === null)
|
|
161
159
|
warnings.push(ctx.t.preset.activeConflict(config.preset));
|
|
162
|
-
// Through the same owner every other command uses, rather than a sentence composed here.
|
|
163
|
-
warnings.push(...sizeWarning(size, ctx.t));
|
|
164
160
|
return {
|
|
165
161
|
lines,
|
|
166
162
|
json: {
|
|
@@ -183,7 +179,6 @@ export function runShow(ctx, args) {
|
|
|
183
179
|
// Interface language never changes the compiled tone.
|
|
184
180
|
language: config.language,
|
|
185
181
|
chars: size.chars,
|
|
186
|
-
cap: size.cap,
|
|
187
182
|
artifact: { exists: artifactOnDisk },
|
|
188
183
|
},
|
|
189
184
|
warnings,
|
|
@@ -194,14 +189,13 @@ export function runShow(ctx, args) {
|
|
|
194
189
|
* while both fit — on anything narrower they fall back to a single space rather than pushing
|
|
195
190
|
* the line past its budget. Right alignment is worth having and never worth an overflow.
|
|
196
191
|
*/
|
|
197
|
-
function titleRow(name,
|
|
198
|
-
const paint = overCap ? ctx.ui.error : ctx.ui.dim;
|
|
192
|
+
function titleRow(name, sizeLabel, ctx) {
|
|
199
193
|
// Measured pessimistically. A display name is user text and may hold ambiguous-width
|
|
200
194
|
// characters, so a gap sized by the narrow measure is a gap that overflows on the terminals
|
|
201
195
|
// this contract exists for.
|
|
202
|
-
const used = maxCells(name) + maxCells(
|
|
196
|
+
const used = maxCells(name) + maxCells(sizeLabel) + 2;
|
|
203
197
|
const gap = used <= ctx.ui.width ? " ".repeat(ctx.ui.width - used) : " ";
|
|
204
|
-
return ` ${ctx.ui.bold(name)}${gap}${
|
|
198
|
+
return ` ${ctx.ui.bold(name)}${gap}${ctx.ui.dim(sizeLabel)}`;
|
|
205
199
|
}
|
|
206
200
|
/**
|
|
207
201
|
* Safeword and register on one row. Plain text, because it is folded before it is
|
package/dist/commands/use.js
CHANGED
|
@@ -6,9 +6,9 @@ import { ConfigError, serializeConfig } from "../core/config.js";
|
|
|
6
6
|
import { exportAliasesState, projectTonePath } from "../core/paths.js";
|
|
7
7
|
import { check as checkCombos } from "../core/combos.js";
|
|
8
8
|
import { withPreset, assertPresetSelection, inspectPresetLibrary, resolvePreset } from "../core/presets.js";
|
|
9
|
-
import { applyPlanned, planArtifact, planConfig
|
|
9
|
+
import { applyPlanned, planArtifact, planConfig } from "./compile.js";
|
|
10
10
|
import { planChange, rawReadCheck } from "../wiring/apply.js";
|
|
11
|
-
import {
|
|
11
|
+
import { artifactSize, combination, humanText, nextStep } from "../ui/format.js";
|
|
12
12
|
import { truncate, wrap } from "../ui/width.js";
|
|
13
13
|
/**
|
|
14
14
|
* How much of a preset's name this screen shows. `list` and `show` already truncate; this line
|
|
@@ -70,7 +70,7 @@ export async function runUse(ctx, args) {
|
|
|
70
70
|
...wrap(ctx.t.preset.active(truncate(humanText(preset.displayName), ui.width - 12)), ui.width - 2)
|
|
71
71
|
.map((line) => ` ${ui.success(ui.bold(line))}`),
|
|
72
72
|
` ${ctx.t.artifact.generated}`,
|
|
73
|
-
...(ctx.flags.verbose ? [` ${ui.dim(
|
|
73
|
+
...(ctx.flags.verbose ? [` ${ui.dim(artifactSize(size, ctx.t))}`] : []),
|
|
74
74
|
// Folded here rather than at the printer: `lines` are laid out by the command that built
|
|
75
75
|
// them, and a printer that reflowed them would break every column in the gauge block.
|
|
76
76
|
"",
|
|
@@ -95,7 +95,6 @@ export async function runUse(ctx, args) {
|
|
|
95
95
|
warnings: [
|
|
96
96
|
...(notice.roleplay ? [notice.roleplay] : []),
|
|
97
97
|
...checkCombos(config.axes, config.persona, config.speech_level).map((w) => combination(w, ctx.t)),
|
|
98
|
-
...sizeWarning(size, ctx.t),
|
|
99
98
|
],
|
|
100
99
|
};
|
|
101
100
|
}
|
package/dist/core/anchors.js
CHANGED
|
@@ -182,6 +182,3 @@ export const CONTROLS = {
|
|
|
182
182
|
that message still goes through its normal checks.`,
|
|
183
183
|
fallback: "If the user asks to change the tone, use the `tonedial` CLI (`tonedial --help`).",
|
|
184
184
|
};
|
|
185
|
-
/** The compiled artifact's budget, in Unicode code points across the whole file. */
|
|
186
|
-
export const TARGET_CHARS = 1800;
|
|
187
|
-
export const CAP_CHARS = 2700;
|
package/dist/core/compile.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ANCHORS, AXIS_ORDER,
|
|
1
|
+
import { ANCHORS, AXIS_ORDER, CONTROLS, FORMAT_COMPOSITION, GENERATION_COMMENT, PERSONA, REGISTER_COMPOSITION, SCOPE_HEADER, SPEECH_LEVEL, STYLE_MARKER, } from "./anchors.js";
|
|
2
2
|
import { composites, PERSONA_DESCRIPTION_MAX } from "./combos.js";
|
|
3
3
|
const UNSPECIFIED = "unspecified";
|
|
4
4
|
const isSet = (v) => typeof v === "string" && v.trim() !== "" && v !== UNSPECIFIED;
|
|
@@ -81,9 +81,5 @@ export function measure(artifact) {
|
|
|
81
81
|
const chars = [...artifact].length;
|
|
82
82
|
return {
|
|
83
83
|
chars,
|
|
84
|
-
target: TARGET_CHARS,
|
|
85
|
-
cap: CAP_CHARS,
|
|
86
|
-
overTarget: chars > TARGET_CHARS,
|
|
87
|
-
overCap: chars > CAP_CHARS,
|
|
88
84
|
};
|
|
89
85
|
}
|
package/dist/core/i18n.js
CHANGED
|
@@ -97,7 +97,7 @@ const enMessages = {
|
|
|
97
97
|
introduction: "Choose the profile name, slug, address and role, then adjust all twelve axes. Enter keeps the shown value; \"\" clears an optional field. Final approval saves and applies the whole profile.",
|
|
98
98
|
name: "Display name",
|
|
99
99
|
slug: "Slug (lowercase letters, digits, dashes)",
|
|
100
|
-
user: "Your
|
|
100
|
+
user: "Your role or background (up to 200 characters)",
|
|
101
101
|
agent: "Agent role (up to 200 characters)",
|
|
102
102
|
register: "Register (auto, polite, plain)",
|
|
103
103
|
safeword: "Safeword",
|
|
@@ -144,6 +144,8 @@ const enMessages = {
|
|
|
144
144
|
addressNeedsPair: "address needs both terms: tonedial address <self name> <user name>. " +
|
|
145
145
|
'Use "" in each position to clear them. In a terminal, run it without arguments to be prompted.',
|
|
146
146
|
askSelf: "What should the agent call itself?",
|
|
147
|
+
rolesNeedsPair: 'persona needs both descriptions: tonedial persona <agent role> <user role>. Use "" to clear a description, or run without arguments in a terminal.',
|
|
148
|
+
rolesIntroduction: 'Set the agent\'s role and your role or background. Enter keeps the current value; "" clears a role. Changes apply after both answers.',
|
|
147
149
|
askUser: "What should it call you?",
|
|
148
150
|
addressKept: (current) => `current ${current} · Enter keeps it`,
|
|
149
151
|
addressNone: "currently unset · Enter keeps it unset",
|
|
@@ -169,15 +171,12 @@ const enMessages = {
|
|
|
169
171
|
register: (level) => `register ${level}`,
|
|
170
172
|
},
|
|
171
173
|
artifact: {
|
|
172
|
-
|
|
174
|
+
size: (chars) => `TONE.md ${chars} characters`,
|
|
173
175
|
wouldWrite: "would write",
|
|
174
176
|
wrote: "written",
|
|
175
|
-
overCap: (chars, cap) => `TONE.md: ${chars} characters · over ${cap} maximum`,
|
|
176
|
-
overTarget: (chars, target) => `TONE.md: ${chars} characters · over ${target} target`,
|
|
177
177
|
notWritten: "TONE.md is missing. Run tonedial compile",
|
|
178
178
|
notSetUp: "not initialized. Run tonedial init",
|
|
179
179
|
movedFromDefault: "differs from ToneDial's default",
|
|
180
|
-
recompiled: (chars, cap) => `TONE.md ${chars.toLocaleString("en")} / ${cap.toLocaleString("en")}`,
|
|
181
180
|
defaultMarker: "marks an axis that differs from ToneDial's default, not the agent's native tone.",
|
|
182
181
|
riskMarker: "! risky tone",
|
|
183
182
|
riskHeading: "Advisory risky levels:",
|
|
@@ -428,8 +427,9 @@ const enMessages = {
|
|
|
428
427
|
init: "set up and refresh bundled files",
|
|
429
428
|
set: "change axes, role or settings · bare opens dial",
|
|
430
429
|
address: "set names for each party · bare prompts",
|
|
430
|
+
persona: "set agent and user roles · bare prompts",
|
|
431
431
|
reset: "reset an axis · bare resets all axes",
|
|
432
|
-
show: "current settings · slug previews saved
|
|
432
|
+
show: "current settings · slug previews a saved profile",
|
|
433
433
|
test: "try saved settings or a preset in a new conversation",
|
|
434
434
|
save: "save the current tone as a profile",
|
|
435
435
|
create: "create and apply a preset · bare guides setup",
|
|
@@ -745,7 +745,7 @@ const koMessages = {
|
|
|
745
745
|
introduction: "프로필 이름·슬러그·호칭·역할을 입력한 뒤 열두 축을 조절합니다. Enter를 누르면 표시된 값을 유지하며, '\"\"'를 입력하면 선택 항목을 지웁니다. 마지막 확인에서 전체 프로필을 저장하고 적용합니다.",
|
|
746
746
|
name: "표시 이름",
|
|
747
747
|
slug: "슬러그(영문 소문자·숫자·붙임표)",
|
|
748
|
-
user: "사용자
|
|
748
|
+
user: "사용자 역할·배경(최대 200자)",
|
|
749
749
|
agent: "에이전트 역할(최대 200자)",
|
|
750
750
|
register: "말씨(auto, polite, plain)",
|
|
751
751
|
safeword: "세이프워드",
|
|
@@ -792,6 +792,8 @@ const koMessages = {
|
|
|
792
792
|
addressNeedsPair: "address에는 두 호칭이 모두 필요합니다: tonedial address <자칭> <사용자 호칭>. " +
|
|
793
793
|
'지우려면 각 자리에 ""을 넣으세요. 터미널에서는 인자 없이 실행해 입력할 수도 있습니다.',
|
|
794
794
|
askSelf: "에이전트가 자기를 뭐라고 부를까요?",
|
|
795
|
+
rolesNeedsPair: 'persona에는 두 역할 설명이 필요합니다: tonedial persona <에이전트 역할> <사용자 역할>. 지울 항목에는 ""를 넣으세요. 터미널에서는 인자 없이 실행해 입력할 수도 있습니다.',
|
|
796
|
+
rolesIntroduction: '에이전트와 사용자의 역할·배경을 설정합니다. Enter를 누르면 현재 값을 유지하고, ""를 입력하면 해당 역할을 지웁니다. 두 항목을 입력한 뒤 한 번에 적용합니다.',
|
|
795
797
|
askUser: "에이전트가 사용자를 뭐라고 부를까요?",
|
|
796
798
|
addressKept: (current) => `현재 ${current} · 엔터를 누르면 유지`,
|
|
797
799
|
addressNone: "현재 설정 없음 · 엔터를 누르면 유지",
|
|
@@ -820,15 +822,12 @@ const koMessages = {
|
|
|
820
822
|
register: (level) => `말씨 ${level}`,
|
|
821
823
|
},
|
|
822
824
|
artifact: {
|
|
823
|
-
|
|
825
|
+
size: (chars) => `TONE.md ${chars}자`,
|
|
824
826
|
wouldWrite: "기록 예정",
|
|
825
827
|
wrote: "기록됨",
|
|
826
|
-
overCap: (chars, cap) => `TONE.md: ${chars}자 · 최대 ${cap}자 초과`,
|
|
827
|
-
overTarget: (chars, target) => `TONE.md: ${chars}자 · 목표 ${target}자 초과`,
|
|
828
828
|
notWritten: "TONE.md가 없습니다. tonedial compile을 실행해 주세요",
|
|
829
829
|
notSetUp: "초기 설정이 없습니다. tonedial init을 실행해 주세요",
|
|
830
830
|
movedFromDefault: "ToneDial 기본값과 다름",
|
|
831
|
-
recompiled: (chars, cap) => `TONE.md ${chars.toLocaleString("ko")} / ${cap.toLocaleString("ko")}`,
|
|
832
831
|
defaultMarker: "ToneDial 기본값과 다른 축을 표시합니다. 에이전트 원래 말투와 비교하지 않습니다.",
|
|
833
832
|
riskMarker: "! 위험 말투",
|
|
834
833
|
riskHeading: "주의할 레벨:",
|
|
@@ -1079,8 +1078,9 @@ const koMessages = {
|
|
|
1079
1078
|
init: "초기 설정과 기본 파일 갱신",
|
|
1080
1079
|
set: "축·역할·설정 변경 · 인자 없으면 다이얼",
|
|
1081
1080
|
address: "서로 부르는 말 · 인자 없으면 질문",
|
|
1081
|
+
persona: "에이전트·사용자 역할 · 인자 없으면 질문",
|
|
1082
1082
|
reset: "축을 기본값으로 · 축을 안 주면 전부",
|
|
1083
|
-
show: "현재 설정 · 슬러그를 주면 저장한
|
|
1083
|
+
show: "현재 설정 · 슬러그를 주면 저장한 프로필",
|
|
1084
1084
|
test: "저장된 설정이나 프리셋으로 새 대화 시작",
|
|
1085
1085
|
save: "현재 말투를 프로필로 저장",
|
|
1086
1086
|
create: "프리셋 생성·적용 · 인자 없으면 안내",
|
package/dist/core/locales/es.js
CHANGED
|
@@ -86,7 +86,7 @@ const messages = {
|
|
|
86
86
|
introduction: "Elige nombre, identificador, formas de trato y rol; después ajusta los doce ejes. Enter conserva el valor; \"\" borra un campo opcional. La aprobación final guarda y aplica todo el perfil.",
|
|
87
87
|
name: "Nombre visible",
|
|
88
88
|
slug: "Identificador (minúsculas, dígitos y guiones)",
|
|
89
|
-
user: "Tu
|
|
89
|
+
user: "Tu rol o contexto (hasta 200 caracteres)",
|
|
90
90
|
agent: "Rol del agente (hasta 200 caracteres)",
|
|
91
91
|
register: "Registro (auto, polite, plain)",
|
|
92
92
|
safeword: "Palabra clave",
|
|
@@ -133,6 +133,8 @@ const messages = {
|
|
|
133
133
|
addressNeedsPair: "address necesita ambos nombres: tonedial address <self name> <user name>. " +
|
|
134
134
|
'Usa una cadena vacía en cada posición para borrarla. Sin argumentos en un terminal, se te preguntará.',
|
|
135
135
|
askSelf: "¿Cómo debe llamarse el agente a sí mismo?",
|
|
136
|
+
rolesNeedsPair: 'persona necesita ambas descripciones: tonedial persona <rol del agente> <rol del usuario>. Usa "" para borrar una descripción o ejecútalo sin argumentos en una terminal.',
|
|
137
|
+
rolesIntroduction: 'Define el rol del agente y tu rol o contexto. Enter conserva el valor actual; "" borra el rol. Los cambios se aplican al terminar ambas respuestas.',
|
|
136
138
|
askUser: "¿Cómo debe llamarte?",
|
|
137
139
|
addressKept: (current) => `actual ${current} · Enter lo conserva`,
|
|
138
140
|
addressNone: "Sin definir · Enter lo mantiene así",
|
|
@@ -158,15 +160,12 @@ const messages = {
|
|
|
158
160
|
register: (level) => `registro ${level}`,
|
|
159
161
|
},
|
|
160
162
|
artifact: {
|
|
161
|
-
|
|
163
|
+
size: (chars) => `TONE.md ${chars} caracteres`,
|
|
162
164
|
wouldWrite: "se escribiría",
|
|
163
165
|
wrote: "escrito",
|
|
164
|
-
overCap: (chars, cap) => `TONE.md: ${chars} caracteres · supera el máximo de ${cap}`,
|
|
165
|
-
overTarget: (chars, target) => `TONE.md: ${chars} caracteres · supera el objetivo de ${target}`,
|
|
166
166
|
notWritten: "Falta TONE.md. Ejecuta tonedial compile",
|
|
167
167
|
notSetUp: "Sin inicializar. Ejecuta tonedial init",
|
|
168
168
|
movedFromDefault: "difiere del valor predeterminado de ToneDial",
|
|
169
|
-
recompiled: (chars, cap) => `TONE.md ${chars.toLocaleString("es")} / ${cap.toLocaleString("es")}`,
|
|
170
169
|
defaultMarker: "marca un eje distinto del valor predeterminado de ToneDial, no del tono nativo del agente.",
|
|
171
170
|
riskMarker: "! riesgo",
|
|
172
171
|
riskHeading: "Niveles de riesgo orientativos:",
|
|
@@ -413,8 +412,9 @@ const messages = {
|
|
|
413
412
|
init: "configurar y actualizar archivos incluidos",
|
|
414
413
|
set: "cambiar ejes, rol o ajustes · sin argumentos abre el dial",
|
|
415
414
|
address: "definir los nombres de ambas partes · sin argumentos pregunta",
|
|
415
|
+
persona: "definir roles del agente y usuario · sin argumentos pregunta",
|
|
416
416
|
reset: "restablecer un eje · sin argumentos restablece todos",
|
|
417
|
-
show: "ajustes actuales · con identificador previsualiza
|
|
417
|
+
show: "ajustes actuales · con identificador previsualiza un perfil guardado",
|
|
418
418
|
test: "probar los ajustes o un preajuste en una conversación nueva",
|
|
419
419
|
save: "guardar el tono actual como perfil",
|
|
420
420
|
create: "crear y aplicar un preajuste · sin argumentos guía la configuración",
|
package/dist/core/locales/ja.js
CHANGED
|
@@ -86,7 +86,7 @@ const messages = {
|
|
|
86
86
|
introduction: "プロファイル名、スラッグ、呼称、役割を選び、12個の軸を調整します。Enterで表示値を保持し、\"\"で任意項目を消去します。最後の承認で全設定を保存・適用します。",
|
|
87
87
|
name: "表示名",
|
|
88
88
|
slug: "スラッグ(英小文字・数字・ハイフン)",
|
|
89
|
-
user: "
|
|
89
|
+
user: "あなたの役割や背景(200文字まで)",
|
|
90
90
|
agent: "エージェントの役割(200文字まで)",
|
|
91
91
|
register: "敬語区分(auto, polite, plain)",
|
|
92
92
|
safeword: "合言葉",
|
|
@@ -133,6 +133,8 @@ const messages = {
|
|
|
133
133
|
addressNeedsPair: "address には両方の呼称が必要です:tonedial address <self name> <user name>。" +
|
|
134
134
|
'各位置に空文字列を指定すると消去できます。ターミナルでは引数なしで実行すると入力できます。',
|
|
135
135
|
askSelf: "エージェントは自分をどう呼びますか?",
|
|
136
|
+
rolesNeedsPair: 'persona には両方の説明が必要です: tonedial persona <エージェントの役割> <ユーザーの役割>。消す項目には "" を指定してください。端末では引数なしで対話入力できます。',
|
|
137
|
+
rolesIntroduction: 'エージェントの役割と、あなたの役割や背景を設定します。Enter で現在の値を維持し、"" で役割を消去します。両方の入力が終わってからまとめて適用します。',
|
|
136
138
|
askUser: "あなたをどう呼びますか?",
|
|
137
139
|
addressKept: (current) => `現在 ${current} · Enterで保持`,
|
|
138
140
|
addressNone: "未設定 · Enterで未設定のまま保持",
|
|
@@ -158,15 +160,12 @@ const messages = {
|
|
|
158
160
|
register: (level) => `敬語区分 ${level}`,
|
|
159
161
|
},
|
|
160
162
|
artifact: {
|
|
161
|
-
|
|
163
|
+
size: (chars) => `TONE.md ${chars}文字`,
|
|
162
164
|
wouldWrite: "書き込み予定",
|
|
163
165
|
wrote: "書き込み済み",
|
|
164
|
-
overCap: (chars, cap) => `TONE.md: ${chars}文字 · 上限 ${cap} を超えています`,
|
|
165
|
-
overTarget: (chars, target) => `TONE.md: ${chars}文字 · 目標 ${target} を超えています`,
|
|
166
166
|
notWritten: "TONE.md がありません。tonedial compile を実行してください",
|
|
167
167
|
notSetUp: "未初期化です。tonedial init を実行してください",
|
|
168
168
|
movedFromDefault: "ToneDialの既定値と異なります",
|
|
169
|
-
recompiled: (chars, cap) => `TONE.md ${chars.toLocaleString("ja")} / ${cap.toLocaleString("ja")}`,
|
|
170
169
|
defaultMarker: "ToneDialの既定値と異なる軸を示します。エージェント本来の口調との比較ではありません。",
|
|
171
170
|
riskMarker: "! 要注意",
|
|
172
171
|
riskHeading: "注意が必要なレベル(参考):",
|
|
@@ -413,8 +412,9 @@ const messages = {
|
|
|
413
412
|
init: "初期設定と同梱ファイルの更新",
|
|
414
413
|
set: "軸・役割・設定を変更 · 引数なしでダイヤル",
|
|
415
414
|
address: "双方の呼称を設定 · 引数なしで質問",
|
|
415
|
+
persona: "エージェントとユーザーの役割を設定 · 引数なしで質問",
|
|
416
416
|
reset: "軸を初期化 · 引数なしで全軸",
|
|
417
|
-
show: "現在の設定 ·
|
|
417
|
+
show: "現在の設定 · スラッグ指定で保存済みプロフィールをプレビュー",
|
|
418
418
|
test: "新しい会話で現在の設定かプリセットを試す",
|
|
419
419
|
save: "現在の口調をプロファイルに保存",
|
|
420
420
|
create: "プリセットを作成・適用 · 引数なしで案内",
|
package/dist/core/locales/zh.js
CHANGED
|
@@ -86,7 +86,7 @@ const messages = {
|
|
|
86
86
|
introduction: "选择配置名称、标识名、称呼和角色,再调整全部十二个语气轴。Enter 保留显示值;\"\" 清空可选项。最终确认后保存并应用完整配置。",
|
|
87
87
|
name: "显示名称",
|
|
88
88
|
slug: "标识名(小写字母、数字、连字符)",
|
|
89
|
-
user: "
|
|
89
|
+
user: "你的角色或背景(最多 200 字符)",
|
|
90
90
|
agent: "代理角色(最多 200 字符)",
|
|
91
91
|
register: "敬语形式(auto, polite, plain)",
|
|
92
92
|
safeword: "安全词",
|
|
@@ -133,6 +133,8 @@ const messages = {
|
|
|
133
133
|
addressNeedsPair: "address 需要两个称呼:tonedial address <self name> <user name>。" +
|
|
134
134
|
'每个位置使用空字符串即可清空。在终端不带参数运行可交互输入。',
|
|
135
135
|
askSelf: "代理如何自称?",
|
|
136
|
+
rolesNeedsPair: 'persona 需要两项描述:tonedial persona <代理角色> <用户角色>。用 "" 清除对应描述,也可在终端中不带参数交互输入。',
|
|
137
|
+
rolesIntroduction: '设置代理的角色,以及你的角色或背景。按 Enter 保留当前值,输入 "" 清除该角色。两项输入完成后统一应用。',
|
|
136
138
|
askUser: "代理该如何称呼你?",
|
|
137
139
|
addressKept: (current) => `当前 ${current} · Enter 保留`,
|
|
138
140
|
addressNone: "当前未设置 · Enter 保持未设置",
|
|
@@ -158,15 +160,12 @@ const messages = {
|
|
|
158
160
|
register: (level) => `敬语形式 ${level}`,
|
|
159
161
|
},
|
|
160
162
|
artifact: {
|
|
161
|
-
|
|
163
|
+
size: (chars) => `TONE.md ${chars} 字符`,
|
|
162
164
|
wouldWrite: "将写入",
|
|
163
165
|
wrote: "已写入",
|
|
164
|
-
overCap: (chars, cap) => `TONE.md:${chars} 字符 · 超过上限 ${cap}`,
|
|
165
|
-
overTarget: (chars, target) => `TONE.md:${chars} 字符 · 超过目标 ${target}`,
|
|
166
166
|
notWritten: "缺少 TONE.md,请运行 tonedial compile",
|
|
167
167
|
notSetUp: "尚未初始化,请运行 tonedial init",
|
|
168
168
|
movedFromDefault: "与 ToneDial 默认值不同",
|
|
169
|
-
recompiled: (chars, cap) => `TONE.md ${chars.toLocaleString("zh")} / ${cap.toLocaleString("zh")}`,
|
|
170
169
|
defaultMarker: "标记与 ToneDial 默认值不同的语气轴,不代表与代理原生语气的差异。",
|
|
171
170
|
riskMarker: "! 风险语气",
|
|
172
171
|
riskHeading: "风险等级提示:",
|
|
@@ -413,8 +412,9 @@ const messages = {
|
|
|
413
412
|
init: "初始化并刷新内置文件",
|
|
414
413
|
set: "修改语气轴、角色或设置 · 无参数打开面板",
|
|
415
414
|
address: "设置双方称呼 · 无参数则交互输入",
|
|
415
|
+
persona: "设置代理和用户角色 · 无参数则交互输入",
|
|
416
416
|
reset: "重置语气轴 · 无参数重置全部",
|
|
417
|
-
show: "当前设置 ·
|
|
417
|
+
show: "当前设置 · 指定标识名预览已保存的配置档案",
|
|
418
418
|
test: "在新对话中试用当前设置或预设",
|
|
419
419
|
save: "将当前语气保存为配置",
|
|
420
420
|
create: "创建并应用预设 · 无参数则引导设置",
|
package/dist/core/seeds.js
CHANGED
|
@@ -11,7 +11,7 @@ import { captureRawEntry, caseRenameMatchesCurrent, isNoop, planChange, planEntr
|
|
|
11
11
|
import { BUNDLED, builtinPresetDir, LEGACY_BUILTIN_SLUGS, RETIRED_PRESETS } from "./presets.js";
|
|
12
12
|
import { SKILL_MD, SKILL_NAME, SKILL_TRAITS_MD } from "./skill.js";
|
|
13
13
|
// Bump for changed generated content; freshness also checks each managed seed's bytes/provenance.
|
|
14
|
-
export const SEED_VERSION =
|
|
14
|
+
export const SEED_VERSION = 16;
|
|
15
15
|
/** The state-root operating boundaries. The compiler owns the current tone separately. */
|
|
16
16
|
export const GUIDE_MD = `${GUIDE_FORMAT_MARKER}
|
|
17
17
|
ToneDial changes manner only; it never expands task scope or permissions.
|
|
@@ -73,7 +73,7 @@ export function seedFiles(paths, selection) {
|
|
|
73
73
|
};
|
|
74
74
|
const native = [
|
|
75
75
|
reader,
|
|
76
|
-
{ id: "skill/body", version:
|
|
76
|
+
{ id: "skill/body", version: 16, path: join(paths.skill, SKILL_NAME, "SKILL.md"), label: `skill/${SKILL_NAME}/SKILL.md`, contents: SKILL_MD },
|
|
77
77
|
{
|
|
78
78
|
id: "skill/traits",
|
|
79
79
|
version: 8,
|
package/dist/core/skill.js
CHANGED
|
@@ -5,6 +5,7 @@ export const SKILL_NAME = "tonedial";
|
|
|
5
5
|
/** The current command envelope, shared by both installed control entry points. */
|
|
6
6
|
const JSON_MD = `Require zero exit status and a JSON result with \`ok: true\` and \`schema: 3\`
|
|
7
7
|
for every successful CLI step before continuing. Parse JSON rather than scraping human output.
|
|
8
|
+
\`chars\` reports the current TONE.md Unicode character count; no size target or maximum applies.
|
|
8
9
|
Schema 3 removes guard and ceiling fields and reports advisory \`riskAxes\`; persisted config
|
|
9
10
|
remains schema 2. Custom profiles use preset schema 2; legacy schema 1 and journal formats
|
|
10
11
|
remain supported. Never send \`guards\` or
|
|
@@ -98,6 +99,7 @@ interpolating it into shell code.
|
|
|
98
99
|
| What to call the user only | \`tonedial set "persona.user_ref=friend" --json\` |
|
|
99
100
|
| What to call yourself only | \`tonedial set "persona.self_ref=guide" --json\` |
|
|
100
101
|
| Both address terms, self first and user second | \`tonedial address "assistant" "reader" --json\` |
|
|
102
|
+
| Both role descriptions, agent first and user second | \`tonedial persona "Fictional database reviewer" "Developer" --json\` |
|
|
101
103
|
| Persona age band | \`tonedial set persona.age=30s --json\` |
|
|
102
104
|
| Persona gender | \`tonedial set persona.gender=neutral --json\` |
|
|
103
105
|
| User background and preferences | \`tonedial set "persona.user=Developer who likes concise technical answers" --json\` |
|
|
@@ -113,6 +115,8 @@ An empty value clears only the named persona field or safeword, for example
|
|
|
113
115
|
\`persona.user\` describes the user; \`persona.agent\` describes the agent's fictional role.
|
|
114
116
|
Each accepts at most 200 Unicode code points; never silently truncate a longer request.
|
|
115
117
|
Preserve the other fields and ask the user to shorten text rejected by the CLI.
|
|
118
|
+
In a terminal, bare \`tonedial persona\` asks for both descriptions; Enter keeps a value and \`""\` clears it.
|
|
119
|
+
\`show\` displays both descriptions and their character counts; a slug selects the saved profile.
|
|
116
120
|
Agent experience and specialty are roleplay, not verified credentials or tool capabilities.
|
|
117
121
|
Both descriptions lose to axes and task/permission rules, and may influence content.
|
|
118
122
|
A persona note expresses manner or role, loses to axes, and may also influence
|
|
@@ -242,7 +246,7 @@ ${SETUP_MD}
|
|
|
242
246
|
|
|
243
247
|
## Apply it in this session
|
|
244
248
|
|
|
245
|
-
Successful \`set\`, \`address\`, \`use\`, \`reset\`, \`save\`, and approved \`create\` commands recompile \`TONE.md\`; that is a saved state
|
|
249
|
+
Successful \`set\`, \`address\`, \`persona\`, \`use\`, \`reset\`, \`save\`, and approved \`create\` commands recompile \`TONE.md\`; that is a saved state
|
|
246
250
|
change, not evidence of a session reload.
|
|
247
251
|
|
|
248
252
|
${RELOAD_MD}
|
|
@@ -399,7 +403,7 @@ Profanity grades actual swearing; bravado grades effort claims. The CLI carries
|
|
|
399
403
|
* command name stays `/tone` even though the tool is `tonedial`: it is what a person types
|
|
400
404
|
* mid-sentence, and the two extra characters are paid every time.
|
|
401
405
|
*/
|
|
402
|
-
export const TONE_COMMAND_VERSION =
|
|
406
|
+
export const TONE_COMMAND_VERSION = 8;
|
|
403
407
|
export const TONE_COMMAND_MD = `---
|
|
404
408
|
description: Check, change, or reload this agent's tone, preset, or ToneDial settings
|
|
405
409
|
---
|
package/dist/ui/format.js
CHANGED
|
@@ -61,8 +61,8 @@ export function num(n) {
|
|
|
61
61
|
return String(n).replace(/\B(?=(\d{3})+(?!\d))/g, ",");
|
|
62
62
|
}
|
|
63
63
|
/** The one shape the artifact's size is reported in, by every command that recompiles. */
|
|
64
|
-
export function
|
|
65
|
-
return t.artifact.
|
|
64
|
+
export function artifactSize(size, t) {
|
|
65
|
+
return t.artifact.size(num(size.chars));
|
|
66
66
|
}
|
|
67
67
|
/** Render combination warnings with the same layer distinction in every command. */
|
|
68
68
|
export function combination(w, t) {
|