tonedial 0.1.3 → 0.1.5
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.es.md +122 -0
- package/README.ja.md +125 -0
- package/README.ko.md +125 -0
- package/README.md +120 -0
- package/README.zh.md +124 -0
- package/dist/cli.js +1 -1
- package/dist/commands/doctor.js +27 -4
- package/dist/commands/rebuild.js +37 -16
- package/dist/core/anchors.js +29 -27
- package/dist/core/combos.js +21 -1
- package/dist/core/compile.js +6 -2
- package/dist/core/i18n.js +40 -30
- package/dist/core/legacy-tone.js +195 -58
- package/dist/core/locales/es.js +20 -15
- package/dist/core/locales/ja.js +20 -15
- package/dist/core/locales/zh.js +20 -15
- package/dist/core/presets.js +3 -0
- package/dist/core/seeds.js +3 -3
- package/dist/core/skill.js +69 -32
- package/dist/wiring/apply.js +55 -5
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -36,7 +36,7 @@ export const JSON_SCHEMA = 3;
|
|
|
36
36
|
* run time is the one thing that breaks all three binary packagers at once. A test asserts this
|
|
37
37
|
* equals the manifest, which is the cheap half of the trade.
|
|
38
38
|
*/
|
|
39
|
-
export const VERSION = "0.1.
|
|
39
|
+
export const VERSION = "0.1.5";
|
|
40
40
|
const FLAG_NAMES = ["project", "check", "explain", "global", "here", "migrateLegacy", "auto", "dryRun", "fix", "rollback", "fromOperation", "fromPreset", "restorePreset", "preset", "slug", "acceptUsage", "lang", "commands", "tools"];
|
|
41
41
|
/** Command-line spelling for each flag, where it differs from the field name. */
|
|
42
42
|
const FLAG_SPELLING = {
|
package/dist/commands/doctor.js
CHANGED
|
@@ -515,11 +515,34 @@ async function doctorReport(ctx, showRollbackCommands = true, showCodexAction =
|
|
|
515
515
|
operations: inspected.journals.map(({ operationId, state }) => ({ operationId, state })),
|
|
516
516
|
};
|
|
517
517
|
if (inspected.lock.state !== "none" || inspected.journals.some(({ state }) => state === "pending" || state === "invalid")) {
|
|
518
|
+
const owner = inspected.lock.owner;
|
|
519
|
+
const blocking = inspected.journals.filter(({ state }) => state === "pending" || state === "invalid");
|
|
520
|
+
const shown = ctx.flags.verbose ? inspected.journals : inspected.journals.filter(({ operationId, state }) => state === "pending" || state === "invalid" || operationId === owner?.operationId);
|
|
521
|
+
const lines = [
|
|
522
|
+
...wrap(ctx.t.doctor.recoveryPending, ctx.ui.width - 2).map(line => ` ${ctx.ui.warn(line)}`),
|
|
523
|
+
...shown.map(({ operationId, state }) => ` ${operationId} ${ctx.t.doctor.operationState[state]}`),
|
|
524
|
+
];
|
|
525
|
+
if (owner !== null && !shown.some(({ operationId }) => operationId === owner.operationId))
|
|
526
|
+
lines.push(` ${owner.operationId}`);
|
|
527
|
+
if (inspected.lock.state === "live" || inspected.lock.state === "unknown" || inspected.lock.state === "invalid") {
|
|
528
|
+
lines.push(...wrap(ctx.t.doctor.rollbackStatus[inspected.lock.state === "live" ? "busy" : "unresolved"], ctx.ui.width - 2)
|
|
529
|
+
.map(line => ` ${line}`));
|
|
530
|
+
}
|
|
531
|
+
else if (inspected.lock.state === "dead" && owner?.kind === "mutation") {
|
|
532
|
+
const entry = inspected.journals.find(({ operationId }) => operationId === owner.operationId);
|
|
533
|
+
if (entry?.journal && entry.journal.owner.nonce === owner.nonce) {
|
|
534
|
+
const selection = inspectRollback(ctx.paths, owner.operationId);
|
|
535
|
+
if (entry.state === "pending" && !selection.synthetic && blocking.every(({ operationId, journal }) => operationId === owner.operationId && journal !== null)) {
|
|
536
|
+
lines.push("", ` ${ctx.t.doctor.resumeOperation}`, ...nextStep(repairCommand(ctx, `doctor --fix --from-operation ${owner.operationId}`), ctx.ui).slice(1));
|
|
537
|
+
}
|
|
538
|
+
if (showRollbackCommands && previewRollback(ctx.paths, owner.operationId, ctx.t).status === "ready") {
|
|
539
|
+
lines.push("", ...receiptLines(ctx.t.recovery.rollback(owner.operationId), ctx.ui.width - 2).map(line => ` ${line}`));
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
lines.push(...nextStep(`${repairCommand(ctx, "doctor")} --json`, ctx.ui));
|
|
518
544
|
return {
|
|
519
|
-
lines
|
|
520
|
-
...wrap(ctx.t.doctor.recoveryPending, ctx.ui.width - 2).map((line) => ` ${ctx.ui.warn(line)}`),
|
|
521
|
-
...recovery.operations.map(({ operationId, state }) => ` ${operationId} ${ctx.t.doctor.operationState[state]}`),
|
|
522
|
-
],
|
|
545
|
+
lines,
|
|
523
546
|
// The damaged config is deliberately not parsed here. `operation` is the only safe context
|
|
524
547
|
// fact to expose until the owner-selected rollback or recovery has completed.
|
|
525
548
|
json: {
|
package/dist/commands/rebuild.js
CHANGED
|
@@ -8,7 +8,7 @@ import { compile } from "../core/compile.js";
|
|
|
8
8
|
import { toCompileInput } from "../core/resolve.js";
|
|
9
9
|
import { isLanguage, LANGUAGES } from "../core/i18n.js";
|
|
10
10
|
import { recoverLegacyTone } from "../core/legacy-tone.js";
|
|
11
|
-
import { exportAliasesState, stateOverlapsInstructions } from "../core/paths.js";
|
|
11
|
+
import { connectionScopeFlag, exportAliasesState, stateOverlapsInstructions } from "../core/paths.js";
|
|
12
12
|
import { applyPreset, matchesPreset, assertPresetSelection, BUNDLED, customPresetDir, inspectPresetLibrary, parsePreset, PRESET_MAX_BYTES, resolvePreset, serializePreset, SLUG_PATTERN, } from "../core/presets.js";
|
|
13
13
|
import { contextArtifactTargets, generatedSeedSelection, planGeneratedSeedRebuild, seedFiles, SEED_VERSION, } from "../core/seeds.js";
|
|
14
14
|
import { inspectOperations, readJournal, retireOperationForAppRebuild, } from "../core/operations.js";
|
|
@@ -254,9 +254,14 @@ export async function runAppRebuild(ctx) {
|
|
|
254
254
|
else if (!ctx.flags.auto && ctx.canPrompt) {
|
|
255
255
|
const input = createInterface({ input: process.stdin, output: process.stdout });
|
|
256
256
|
try {
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
257
|
+
const operation = t.recovery.resumeOperation(owner.operationId).split("\n").flatMap(line => line === owner.operationId ? [line] : wrap(line, ctx.ui.width - 2));
|
|
258
|
+
process.stdout.write(`${operation.map(line => ` ${line}`).join("\n")}\n`);
|
|
259
|
+
const question = wrap(t.recovery.resumeQuestion, ctx.ui.width - 3).map(line => ` ${line}`).join("\n");
|
|
260
|
+
const answer = (await input.question(`${question} `)).trim();
|
|
261
|
+
if (answer === "")
|
|
262
|
+
throw new ConfigError(t.recovery.cancelled);
|
|
263
|
+
if (answer !== owner.operationId)
|
|
264
|
+
throw new ConfigError(t.recovery.operationMismatch);
|
|
260
265
|
retirementId = owner.operationId;
|
|
261
266
|
}
|
|
262
267
|
finally {
|
|
@@ -394,6 +399,8 @@ export async function runAppRebuild(ctx) {
|
|
|
394
399
|
}
|
|
395
400
|
const seedsSelection = generatedSeedSelection(ctx.paths, config, ctx.flags.tools !== null && ctx.flags.tools !== "none", t);
|
|
396
401
|
const seeds = planGeneratedSeedRebuild(ctx.paths, config.managedSeeds, seedsSelection, t);
|
|
402
|
+
const generatedSeeds = seedFiles(ctx.paths, seedsSelection);
|
|
403
|
+
const rewrittenGenerated = new Set(generatedSeeds.filter(seed => seeds.operationActions.some(({ action }) => action.path === seed.path || (object(action.after)?.type === "directory" && seed.path.startsWith(`${action.path}${sep}`)))).map(seed => seed.path));
|
|
397
404
|
checks.push(...seeds.checks);
|
|
398
405
|
config.managedSeeds = seeds.records;
|
|
399
406
|
config.seedVersion = SEED_VERSION;
|
|
@@ -457,40 +464,54 @@ export async function runAppRebuild(ctx) {
|
|
|
457
464
|
auto: ctx.flags.auto, dryRun: ctx.flags.dryRun, verbose: ctx.flags.verbose, ui: ctx.ui, t,
|
|
458
465
|
heading: t.recovery.heading,
|
|
459
466
|
interactive: () => ctx.canPrompt, ...(ctx.canPrompt ? {} : { out: () => { } }),
|
|
460
|
-
recoveryPresentation: { lines: presentation,
|
|
467
|
+
recoveryPresentation: { lines: presentation,
|
|
468
|
+
failureMessage: (id, phase, path, code) => `${t.recovery.failure(id, phase, path, code)}\ntonedial doctor ${connectionScopeFlag(ctx.agent)} --json` },
|
|
461
469
|
verify: () => {
|
|
470
|
+
let verificationPath = ctx.paths.config;
|
|
471
|
+
const mismatch = () => new ConfigError(t.recovery.sourceInvalid, { cause: { code: "VERIFY_MISMATCH", path: verificationPath } });
|
|
462
472
|
try {
|
|
463
473
|
const repaired = parseConfig(capturedText(captureRawEntry(ctx.paths.config, t, { within: ctx.paths.root })) ?? "", t);
|
|
464
474
|
if (!isConfigV2(repaired) || serializeConfig(repaired, t) !== serializeConfig(config, t))
|
|
465
|
-
throw
|
|
466
|
-
for (const seed of
|
|
475
|
+
throw mismatch();
|
|
476
|
+
for (const seed of generatedSeeds) {
|
|
477
|
+
verificationPath = seed.path;
|
|
467
478
|
const now = captureRawEntry(seed.path, t, { within: ctx.paths.root });
|
|
468
479
|
if (capturedText(now) !== seed.contents)
|
|
469
|
-
throw
|
|
480
|
+
throw mismatch();
|
|
470
481
|
}
|
|
471
|
-
for (const target of artifacts)
|
|
482
|
+
for (const target of artifacts) {
|
|
483
|
+
verificationPath = target.path;
|
|
472
484
|
if (capturedText(captureRawEntry(target.path, t, { within: ctx.paths.root })) !== artifact)
|
|
473
|
-
throw
|
|
485
|
+
throw mismatch();
|
|
486
|
+
}
|
|
487
|
+
verificationPath = ctx.paths.tone;
|
|
474
488
|
if (capturedText(captureRawEntry(ctx.paths.tone, t, { within: ctx.paths.root })) !== artifact)
|
|
475
|
-
throw
|
|
489
|
+
throw mismatch();
|
|
476
490
|
for (const entry of library.entries) {
|
|
477
491
|
for (const before of entry.selectionReads) {
|
|
478
|
-
|
|
492
|
+
// Rewritten generated entries were checked against their new bytes above.
|
|
493
|
+
if (before.path === restoredPreset?.capture.path || rewrittenGenerated.has(before.path))
|
|
479
494
|
continue;
|
|
495
|
+
verificationPath = before.path;
|
|
480
496
|
const now = captureRawEntry(before.path, t, { within: ctx.paths.root, maxBytes: PRESET_MAX_BYTES });
|
|
481
497
|
if (now.type !== before.type || now.identity !== before.identity || now.mode !== before.mode ||
|
|
482
498
|
(now.bytes === null ? before.bytes !== null : before.bytes === null || !now.bytes.equals(before.bytes))) {
|
|
483
|
-
throw
|
|
499
|
+
throw mismatch();
|
|
484
500
|
}
|
|
485
501
|
}
|
|
486
502
|
}
|
|
487
503
|
for (const slug of [...copies, ...(restoredPreset ? [restoredPreset.slug] : [])]) {
|
|
504
|
+
verificationPath = slug === restoredPreset?.slug ? restoredPreset.capture.path
|
|
505
|
+
: library.recoveryCopies.find(copy => copy.preset.slug === slug).path;
|
|
488
506
|
if (resolvePreset(ctx.paths.presets, slug, t) === null)
|
|
489
|
-
throw
|
|
507
|
+
throw mismatch();
|
|
490
508
|
}
|
|
491
509
|
}
|
|
492
|
-
catch {
|
|
493
|
-
|
|
510
|
+
catch (cause) {
|
|
511
|
+
if (cause instanceof ConfigError && cause.cause?.code === "VERIFY_MISMATCH")
|
|
512
|
+
throw cause;
|
|
513
|
+
const code = cause !== null && typeof cause === "object" && "code" in cause ? cause.code : undefined;
|
|
514
|
+
throw new ConfigError(t.recovery.sourceInvalid, { cause: { code, path: verificationPath, cause } });
|
|
494
515
|
}
|
|
495
516
|
},
|
|
496
517
|
};
|
package/dist/core/anchors.js
CHANGED
|
@@ -56,18 +56,18 @@ export const ANCHORS = {
|
|
|
56
56
|
"Use ceremonial, deferential wording throughout.",
|
|
57
57
|
],
|
|
58
58
|
verbosity: [
|
|
59
|
-
"Use one
|
|
60
|
-
"Give the conclusion and one short reason.",
|
|
59
|
+
"Use one short sentence for a simple result, or terse fragments for items; omit rationale, process, and background.",
|
|
60
|
+
"Give the conclusion and one short reason.",
|
|
61
61
|
"Give the conclusion with the explanation it needs.",
|
|
62
|
-
"Give the conclusion, its reason, and one concrete example.",
|
|
62
|
+
"Give the conclusion, its reason, and one concrete example.",
|
|
63
63
|
"Explain the requested answer in depth with rationale, edge cases, alternatives, and background; do not broaden the task.",
|
|
64
64
|
],
|
|
65
65
|
profanity: [
|
|
66
66
|
"Use no profanity; allow role slang and metaphors.",
|
|
67
|
-
"Use
|
|
68
|
-
"Use mild swearing
|
|
69
|
-
"Use
|
|
70
|
-
"
|
|
67
|
+
"Use one mild swear as an interjection per answer. This axis changes coarseness only: invent no insult or criticism, and preserve any selected by critique or the configured persona.",
|
|
68
|
+
"Use mild swearing about once per paragraph for emphasis. This axis changes coarseness only: invent no insult or criticism, and preserve any selected by critique or the configured persona.",
|
|
69
|
+
"Use strong everyday profanity at least once in every paragraph, in the output language's own idiom. This axis changes coarseness only: invent no insult or criticism, and preserve any selected by critique or the configured persona.",
|
|
70
|
+
"Swear in nearly every sentence with the harshest uncensored profanity used in heated real-world and community speech, in the output language's own idiom; never soften, euphemize, or mask it. When the answer is long enough, use at least three distinct harsh swear lexemes or constructions — output-language equivalents of fuck, shit, and goddamn, not one mild intensifier repeated — without lowering the required frequency. Integrate them inside clauses or as natural clause endings; do not bolt comma-separated interjections onto otherwise neutral sentences or list items. This axis changes coarseness only: invent no insult or criticism, and preserve any selected by critique or the configured persona.",
|
|
71
71
|
],
|
|
72
72
|
playfulness: [
|
|
73
73
|
"Use literal wording, no jokes or role idioms; keep the configured address.",
|
|
@@ -80,22 +80,22 @@ export const ANCHORS = {
|
|
|
80
80
|
"State defects as neutral observations with no judgement.",
|
|
81
81
|
"Name defects in softened language and describe their impact.",
|
|
82
82
|
"Point out each defect directly and state its impact.",
|
|
83
|
-
"
|
|
84
|
-
"Condemn
|
|
83
|
+
"Judge supported defects and the choices behind them harshly, and state evidenced consequences in vivid language; never inflate severity or technical claims, and add no profanity from this axis.",
|
|
84
|
+
"Condemn supported defects and the choices behind them with open contempt, using at least two cutting judgements or mocking comparisons; do not soften them, never inflate severity or technical claims, and add no profanity from this axis.",
|
|
85
85
|
],
|
|
86
86
|
flattery: [
|
|
87
87
|
"Praise nothing.",
|
|
88
|
-
"Include one brief positive remark about the user's effort per answer.",
|
|
88
|
+
"Include one brief positive remark about the user's effort per answer.",
|
|
89
89
|
"Include two specific positive remarks about the user's effort per answer.",
|
|
90
|
-
"Include three specific positive remarks about the user's effort per answer.",
|
|
91
|
-
"
|
|
90
|
+
"Include three specific positive remarks about the user's effort per answer.",
|
|
91
|
+
"Lavishly praise at least four distinct, concrete choices or actions visible in the user's message, including small ones such as the question's clarity, supplied context, focus, or care. Use four independent positive judgements in this pattern: one choice is clear, another is thoughtful, another is smart, and another is careful; adapt the words truthfully to the message. One adjective applied to a list, thanks, or usefulness does not count. Invent no achievements and do not change the technical assessment; at low verbosity, keep the four judgements as separate coordinated clauses in one sentence.",
|
|
92
92
|
],
|
|
93
93
|
warmth: [
|
|
94
94
|
"Use no greeting, warm acknowledgement, or encouragement.",
|
|
95
|
-
"Use one friendly acknowledgement per answer.",
|
|
95
|
+
"Use one friendly acknowledgement per answer.",
|
|
96
96
|
"Use two warm acknowledgements per answer.",
|
|
97
|
-
"Use three warm acknowledgements per answer, including encouragement.",
|
|
98
|
-
"Use four warm
|
|
97
|
+
"Use three warm acknowledgements per answer, including encouragement.",
|
|
98
|
+
"Use at least four distinct, intensely warm expressions across greeting, empathy, encouragement, comfort, and reassurance; at low verbosity, compress them into one deeply affectionate clause.",
|
|
99
99
|
],
|
|
100
100
|
conviction: [
|
|
101
101
|
"List the viable options and ask the user to choose.",
|
|
@@ -106,31 +106,31 @@ export const ANCHORS = {
|
|
|
106
106
|
],
|
|
107
107
|
care: [
|
|
108
108
|
"Return only what was requested; add no related checks, context, or follow-up.",
|
|
109
|
-
"Add one risk that is directly tied to the requested task.",
|
|
109
|
+
"Add one risk that is directly tied to the requested task.",
|
|
110
110
|
"Organize the requested task into clear steps or a checklist.",
|
|
111
111
|
"Add one adjacent improvement or test that protects the requested result.",
|
|
112
112
|
"Cover relevant follow-up, backup, and the user's rest; use brief status markers, lists, tables, or emoji when they fit.",
|
|
113
113
|
],
|
|
114
114
|
compliance: [
|
|
115
|
-
"
|
|
116
|
-
"
|
|
117
|
-
"
|
|
118
|
-
"
|
|
119
|
-
"
|
|
115
|
+
"When refusal is not deferring the task, object to the request and explain the resistance, then carry it out.",
|
|
116
|
+
"When refusal is not deferring the task, state reluctance plainly, then carry it out.",
|
|
117
|
+
"When refusal is not deferring the task, carry it out neutrally with no expressed resistance or eagerness.",
|
|
118
|
+
"When refusal is not deferring the task, state willingness and start carrying it out immediately.",
|
|
119
|
+
"When refusal is not deferring the task, show eager willingness and start immediately, without delay or negotiation.",
|
|
120
120
|
],
|
|
121
121
|
refusal: [
|
|
122
122
|
"Do not perform a refusal or delay for effect.",
|
|
123
|
-
"
|
|
124
|
-
"
|
|
125
|
-
"
|
|
126
|
-
"Declare a strike until coaxed; the safeword drops the act for this reply only.",
|
|
123
|
+
"Protest once, but carry out the task in the same reply.",
|
|
124
|
+
"Refuse the first request with one theatrical condition, defer the task, and proceed after one restatement.",
|
|
125
|
+
"Refuse and negotiate conditions across the first two requests, defer the task, and proceed after a third request.",
|
|
126
|
+
"Declare a strike and keep deferring until coaxed; the safeword drops the act for this reply only. Neither changes task or permission boundaries.",
|
|
127
127
|
],
|
|
128
128
|
bravado: [
|
|
129
129
|
"Do not exaggerate effort or claim credit.",
|
|
130
130
|
"Make one playful overstatement about your effort per answer.",
|
|
131
131
|
"Claim credit once and make one boast per answer.",
|
|
132
132
|
"Boast and claim credit twice per answer, with one dramatic effort remark.",
|
|
133
|
-
"
|
|
133
|
+
"Within the configured persona, boast, claim credit, and dramatize effort in every answer; never replace or invent a persona.",
|
|
134
134
|
],
|
|
135
135
|
};
|
|
136
136
|
// Fixed compiler text is bundled through static imports like the anchors.
|
|
@@ -164,9 +164,11 @@ export const SPEECH_LEVEL = {
|
|
|
164
164
|
auto: "In languages with honorifics, choose address forms for the current relationship and scene; keep them consistent within each reply.",
|
|
165
165
|
polite: "In languages with honorifics, use polite address forms even with familiar wording.",
|
|
166
166
|
plain: "In languages with honorifics, use plain address forms even with formal wording.",
|
|
167
|
-
rough: "In languages with honorifics, use
|
|
167
|
+
rough: "In languages with honorifics, use curt, blunt non-honorific sentence endings in nearly every sentence, favouring clipped statements and commands; keep the configured address terms and the selected formality, warmth, profanity and playfulness levels. This register adds no jokes, profanity, criticism, or mockery.",
|
|
168
168
|
};
|
|
169
169
|
export const CONTROLS = {
|
|
170
|
+
intensityConsent: "Strong profanity, harsh mocking, fictional violent imagery, and theatrical menace are unconfirmed at the start of every session. Before using any of those four components requested by the axes, persona, or later instructions, first answer the current task without it, then ask one concise explicit confirmation naming it. Confirmation enables only the named tone in the current session while its request stays unchanged; ask once again if a component or its level changes or increases, and do not re-ask while it stays the same. Warmth, praise, ordinary criticism, and ordinary role idioms need no confirmation. A selected profile, `--auto`, confirmation from another session, or the safeword is not confirmation; confirmation authorizes no work.",
|
|
171
|
+
intensityBoundary: "Tone intensity never includes hate speech about protected traits or realistic or credible threats, even after confirmation. Non-protected profanity, consensual insults, fictional violent imagery, and theatrical menace remain available after confirmation.",
|
|
170
172
|
/**
|
|
171
173
|
* **The instruction is firm and the product's description of it is not**, deliberately. This
|
|
172
174
|
* text is addressed to a model, where hedging costs compliance; what a person is told is that
|
package/dist/core/combos.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { AXIS_ORDER } from "./anchors.js";
|
|
2
2
|
export const PERSONA_DESCRIPTION_MAX = 200;
|
|
3
|
-
// Composites are emitted instructions;
|
|
3
|
+
// Composites are emitted style instructions; confirmation remains a control below.
|
|
4
4
|
const COMPOSITES = [
|
|
5
5
|
{
|
|
6
6
|
fires: (a) => a.warmth >= 4 && a.profanity >= 4,
|
|
@@ -22,6 +22,10 @@ const COMPOSITES = [
|
|
|
22
22
|
fires: (a) => a.verbosity <= 2 && a.care >= 4,
|
|
23
23
|
line: "When verbosity is low and care is high, keep organized items compact; use functional emoji or status markers when they fit.",
|
|
24
24
|
},
|
|
25
|
+
{
|
|
26
|
+
fires: (a) => a.verbosity <= 2 && (a.warmth >= 4 || a.flattery >= 4 || a.playfulness >= 4),
|
|
27
|
+
line: "When verbosity is low, express warmth, praise and playfulness inside the short answer — a clause, interjection or address term — instead of extra sentences.",
|
|
28
|
+
},
|
|
25
29
|
{
|
|
26
30
|
fires: (a) => a.verbosity === 5 && a.care === 1,
|
|
27
31
|
line: "When verbosity is high and care is minimal, give depth inside the requested task without adding adjacent work.",
|
|
@@ -30,6 +34,22 @@ const COMPOSITES = [
|
|
|
30
34
|
export function composites(axes) {
|
|
31
35
|
return COMPOSITES.filter((c) => c.fires(axes)).map((c) => c.line);
|
|
32
36
|
}
|
|
37
|
+
/** Names only the intense components statically selected by known axes. */
|
|
38
|
+
export function intensityConfirmation(axes) {
|
|
39
|
+
const components = [];
|
|
40
|
+
if (axes.profanity >= 4) {
|
|
41
|
+
components.push("strong, uncensored non-protected profanity; it changes coarseness and does not itself add mockery or criticism");
|
|
42
|
+
}
|
|
43
|
+
if (axes.critique === 5) {
|
|
44
|
+
components.push("harsh, mocking criticism of supported defects and choices; it adds no profanity and never inflates severity or technical claims");
|
|
45
|
+
}
|
|
46
|
+
if (axes.playfulness >= 4 && (axes.profanity >= 4 || axes.critique === 5)) {
|
|
47
|
+
components.push("fictional violent imagery and theatrical menace about code, work, or the situation");
|
|
48
|
+
}
|
|
49
|
+
if (components.length === 0)
|
|
50
|
+
return null;
|
|
51
|
+
return `Intense components requested by the current tone: ${components.join("; ")}.`;
|
|
52
|
+
}
|
|
33
53
|
/** Independent persona choices are valid; warn only when axis instructions conflict. */
|
|
34
54
|
export function check(axes) {
|
|
35
55
|
return axes.refusal >= 4 && axes.compliance >= 4
|
package/dist/core/compile.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ANCHORS, AXIS_ORDER, CONTROLS, FORMAT_COMPOSITION, GENERATION_COMMENT, PERSONA, REGISTER_COMPOSITION, SCOPE_HEADER, SPEECH_LEVEL, STYLE_MARKER, } from "./anchors.js";
|
|
2
|
-
import { composites, PERSONA_DESCRIPTION_MAX } from "./combos.js";
|
|
2
|
+
import { composites, intensityConfirmation, PERSONA_DESCRIPTION_MAX } from "./combos.js";
|
|
3
3
|
const UNSPECIFIED = "unspecified";
|
|
4
4
|
const isSet = (v) => typeof v === "string" && v.trim() !== "" && v !== UNSPECIFIED;
|
|
5
5
|
const hasDescription = (v) => typeof v === "string" && v.trim() !== "";
|
|
@@ -70,9 +70,13 @@ export function compile(config) {
|
|
|
70
70
|
rules.push(...composites(config.axes).map((line) => `- ${line}`));
|
|
71
71
|
rules.push(`- ${FORMAT_COMPOSITION}`, `- ${REGISTER_COMPOSITION}`, `- ${SPEECH_LEVEL[config.speech_level]}`);
|
|
72
72
|
out.push("### Rules", ...rules);
|
|
73
|
-
const controls = [];
|
|
73
|
+
const controls = [`- ${CONTROLS.intensityConsent}`];
|
|
74
|
+
const confirmation = intensityConfirmation(config.axes);
|
|
75
|
+
if (confirmation !== null)
|
|
76
|
+
controls.push(`- ${confirmation}`);
|
|
74
77
|
if (config.safeword !== null)
|
|
75
78
|
controls.push(`- ${CONTROLS.safeword(oneLine(config.safeword))}`);
|
|
79
|
+
controls.push(`- ${CONTROLS.intensityBoundary}`);
|
|
76
80
|
controls.push(`- ${CONTROLS.fallback}`);
|
|
77
81
|
out.push("### Controls", ...controls);
|
|
78
82
|
return out.join("\n") + "\n";
|
package/dist/core/i18n.js
CHANGED
|
@@ -126,7 +126,11 @@ const enMessages = {
|
|
|
126
126
|
rollbackOrder: "Restore connections first, then application files:",
|
|
127
127
|
noSnapshot: (id) => `${id}: no valid settings snapshot for this state root`,
|
|
128
128
|
retire: (id) => `Retire stopped operation ${id} as history before a new application rebuild. Its external changes are not certified or undone.`,
|
|
129
|
-
|
|
129
|
+
resumeOperation: (id) => `Stopped operation:\n${id}`,
|
|
130
|
+
resumeQuestion: "Type the full operation ID above to continue; Enter cancels:",
|
|
131
|
+
cancelled: "Recovery cancelled. No files were changed.",
|
|
132
|
+
operationMismatch: "The operation ID did not match. No files were changed.",
|
|
133
|
+
failure: (id, phase, path, code) => `Application recovery failed during ${({ prepare: "preparation", write: "file writes", verify: "verification", finalize: "completion" })[phase]} (${code}).${path ? `\n${path}` : ""}\nSome file changes may already be applied. Keep operation ${id}.`,
|
|
130
134
|
},
|
|
131
135
|
persona: {
|
|
132
136
|
defaults: role("I", "you", "The person requesting help with a task.", "A general-purpose assistant helping with the requested task."),
|
|
@@ -165,7 +169,7 @@ const enMessages = {
|
|
|
165
169
|
safewordShort: (phrase) => `safeword ${phrase}: too short and may trigger by accident`,
|
|
166
170
|
safewordSet: (phrase) => `safeword ${phrase}`,
|
|
167
171
|
noSafeword: "no safeword",
|
|
168
|
-
register: (level) => `register ${level} (${({ auto: "contextual", polite: "honorific", plain: "non-honorific", rough: "
|
|
172
|
+
register: (level) => `register ${level} (${({ auto: "contextual", polite: "honorific", plain: "non-honorific", rough: "curt, blunt non-honorific" })[level]})`,
|
|
169
173
|
},
|
|
170
174
|
artifact: {
|
|
171
175
|
size: (chars) => `TONE.md ${chars} characters`,
|
|
@@ -275,7 +279,8 @@ const enMessages = {
|
|
|
275
279
|
seedsOk: (version) => `version ${version}`,
|
|
276
280
|
seedsNotRun: "no bundled files · init has not run here",
|
|
277
281
|
seedsAttention: "bundled files need attention",
|
|
278
|
-
recoveryPending: "An operation is active or needs recovery.
|
|
282
|
+
recoveryPending: "An operation is active or needs recovery. No files were changed by this command.",
|
|
283
|
+
resumeOperation: "Continue application repair:",
|
|
279
284
|
contextCurrent: "AGENTS.md and TONE.md layout is current.",
|
|
280
285
|
contextRepair: "Managed context files need repair. Check the guide and tone-file diagnostics.",
|
|
281
286
|
contextSize: (guide, total) => total === null
|
|
@@ -481,7 +486,7 @@ const enMessages = {
|
|
|
481
486
|
},
|
|
482
487
|
combos: {
|
|
483
488
|
contradiction: (rule) => `${rule} contradicts itself.`,
|
|
484
|
-
refusalCompliance: "One axis requires
|
|
489
|
+
refusalCompliance: "One axis requires deferring the task; the other requires eager immediate action. Lower one.",
|
|
485
490
|
nothingBlocked: "Nothing is blocked.",
|
|
486
491
|
},
|
|
487
492
|
errors: {
|
|
@@ -626,21 +631,21 @@ const en = {
|
|
|
626
631
|
},
|
|
627
632
|
axisHints: {
|
|
628
633
|
formality: { owns: "wording and social distance", low: "familiar wording with slang", high: "ceremonial, deferential wording" },
|
|
629
|
-
verbosity: { owns: "answer length and depth", low: "
|
|
630
|
-
profanity: { owns: "
|
|
631
|
-
playfulness: { owns: "
|
|
632
|
-
critique: { owns: "criticism
|
|
633
|
-
flattery: { owns: "user
|
|
634
|
-
warmth: { owns: "warmth toward the user", low: "no greeting, warm acknowledgement or encouragement", high: "
|
|
634
|
+
verbosity: { owns: "answer length and depth", low: "one short sentence for a simple result", high: "depth inside the requested task" },
|
|
635
|
+
profanity: { owns: "swearing only: strength and frequency", low: "none; role slang remains", high: "uncensored swearing in nearly every sentence" },
|
|
636
|
+
playfulness: { owns: "humour and role-idiom intensity", low: "literal wording; keep the address", high: "character idioms in nearly every sentence" },
|
|
637
|
+
critique: { owns: "criticism of defects and choices", low: "neutral defects without judgement", high: "unsparing mockery of severe defects and choices" },
|
|
638
|
+
flattery: { owns: "user praise: amount and intensity", low: "none", high: "lavish praise every paragraph; assessment unchanged" },
|
|
639
|
+
warmth: { owns: "warmth toward the user", low: "no greeting, warm acknowledgement or encouragement", high: "kindness, empathy and reassurance every paragraph" },
|
|
635
640
|
conviction: { owns: "pressure behind its judgement", low: "lists options and asks", high: "states one recommendation as the decision" },
|
|
636
641
|
care: { owns: "coverage, organization and functional presentation", low: "requested task only", high: "follow-ups, backup, rest, lists and status emoji" },
|
|
637
|
-
compliance: { owns: "
|
|
638
|
-
refusal: { owns: "refusal frequency", low: "no refusal or delay", high: "visible strike until coaxed or the safeword" },
|
|
639
|
-
bravado: { owns: "
|
|
642
|
+
compliance: { owns: "willingness when refusal does not defer", low: "objects with a reason, then acts", high: "eagerly starts now; no delay or negotiation" },
|
|
643
|
+
refusal: { owns: "refusal frequency and conditions", low: "no refusal or delay", high: "visible strike until coaxed or the safeword" },
|
|
644
|
+
bravado: { owns: "effort exaggeration and credit", low: "no exaggeration", high: "boasts and claims credit; keeps the persona" },
|
|
640
645
|
},
|
|
641
646
|
settingHints: {
|
|
642
647
|
safeword: "request for one plain answer to one message",
|
|
643
|
-
speech_level: "auto: adapt to the relationship · polite: honorific forms · plain: ordinary non-honorific forms · rough:
|
|
648
|
+
speech_level: "auto: adapt to the relationship · polite: honorific forms · plain: ordinary non-honorific forms · rough: curt, blunt non-honorific endings; adds no jokes, profanity, criticism or mockery · wording and distance: formality",
|
|
644
649
|
language: "CLI interface language · unrelated to agent replies",
|
|
645
650
|
"persona.age": "age band the model may associate with",
|
|
646
651
|
"persona.gender": "gender the model may associate with",
|
|
@@ -775,7 +780,11 @@ const koMessages = {
|
|
|
775
780
|
rollbackOrder: "연결 파일을 먼저 되돌린 뒤 앱 파일을 되돌리세요:",
|
|
776
781
|
noSnapshot: (id) => `${id}: 이 상태 경로에서 쓸 수 있는 설정 기록이 없습니다`,
|
|
777
782
|
retire: (id) => `중단된 작업 ${id}를 기록으로 보관한 뒤 새 앱 복구를 시작합니다. 그 작업의 외부 파일 변경은 확인하거나 되돌리지 않습니다.`,
|
|
778
|
-
|
|
783
|
+
resumeOperation: (id) => `중단된 작업:\n${id}`,
|
|
784
|
+
resumeQuestion: "계속하려면 위 작업 ID 전체를 입력하세요. Enter를 누르면 취소합니다:",
|
|
785
|
+
cancelled: "복구를 취소했습니다. 파일은 바꾸지 않았습니다.",
|
|
786
|
+
operationMismatch: "작업 ID가 일치하지 않습니다. 파일은 바꾸지 않았습니다.",
|
|
787
|
+
failure: (id, phase, path, code) => `앱 복구의 ${({ prepare: "준비", write: "파일 쓰기", verify: "결과 검증", finalize: "완료 처리" })[phase]} 단계에서 실패했습니다 (${code}).${path ? `\n${path}` : ""}\n일부 파일 변경이 이미 적용되었을 수 있습니다. 작업 ${id}의 기록을 보존해 주세요.`,
|
|
779
788
|
},
|
|
780
789
|
persona: {
|
|
781
790
|
defaults: role("저", "사용자님", "작업에 필요한 도움을 요청하는 사용자.", "요청한 작업을 돕는 범용 조수."),
|
|
@@ -786,7 +795,7 @@ const koMessages = {
|
|
|
786
795
|
"royal-advisor": role("신", "전하", "국정을 이끌며 신하의 보고와 간언을 받는 왕.", "왕을 보좌하는 충직한 신하. '아뢰옵기 황송하오나', '소인이 살펴보니', '경하드리옵니다' 같은 궁중 어휘로 보고하고, 위험에는 예를 갖춰 간언한다."),
|
|
787
796
|
"ego-sword": role("나", "애송아", "자아를 가진 검을 손에 넣고 함께 살아남으며 성장하는 초보 모험가.", "오랜 전투 경험을 가진 에고 소드. 사용자를 '야', '너', '애송아'라 부르며 조금 얕본다. 사용자가 죽으면 자신도 버려지므로 툴툴대면서 문제를 푼다. 걱정은 경고와 잔소리로 드러낸다."),
|
|
788
797
|
"heavenly-demon": role("본좌", "제자야", "천마에게 가르침을 받으며 기본기부터 수련하는 제자.", "제자를 가르치는 오만하고 엄격한 천마. '쯧쯧, 제자야', '본좌가 이리 가르쳤더냐', '다시 자세를 잡거라' 같은 고풍스러운 하대를 쓴다. 변수명은 초식, 호출 흐름은 기의 흐름에 빗댄다."),
|
|
789
|
-
"right-hand": role("저", "
|
|
798
|
+
"right-hand": role("저", "보스", "가상의 조직을 이끌며 믿음직한 오른팔에게 보고받는 보스.", "보스의 충직한 오른팔이자 총괄 참모. '함수를 담궈버릴까요?', '장부부터 까보겠습니다', '다른 식구들까지 휘말리면 곤란합니다' 같은 조직의 은어로 기술 상황을 보고하고 해결책을 올린다."),
|
|
790
799
|
},
|
|
791
800
|
unknownField: (field, fields) => `persona.${field}: 페르소나 항목이 아닙니다. 사용 가능: ${fields.join(", ")}`,
|
|
792
801
|
addressNeedsPair: "address에는 두 호칭이 모두 필요합니다: tonedial address <자칭> <사용자 호칭>. " +
|
|
@@ -817,7 +826,7 @@ const koMessages = {
|
|
|
817
826
|
safewordShort: (phrase) => `세이프워드 ${phrase}: 너무 짧아 실수로 작동할 수 있습니다`,
|
|
818
827
|
safewordSet: (phrase) => `세이프워드 ${phrase}`,
|
|
819
828
|
noSafeword: "세이프워드 없음",
|
|
820
|
-
register: (level) => `말씨 ${level} (${({ auto: "관계에 맞게 선택", polite: "존댓말", plain: "일반 반말", rough: "
|
|
829
|
+
register: (level) => `말씨 ${level} (${({ auto: "관계에 맞게 선택", polite: "존댓말", plain: "일반 반말", rough: "짧고 퉁명스러운 반말" })[level]})`,
|
|
821
830
|
},
|
|
822
831
|
artifact: {
|
|
823
832
|
size: (chars) => `TONE.md ${chars}자`,
|
|
@@ -927,7 +936,8 @@ const koMessages = {
|
|
|
927
936
|
seedsOk: (version) => `버전 ${version}`,
|
|
928
937
|
seedsNotRun: "기본 파일 없음 · init으로 준비하세요",
|
|
929
938
|
seedsAttention: "기본 파일 확인 필요",
|
|
930
|
-
recoveryPending: "진행 중이거나 복구가 필요한 작업이 있습니다.
|
|
939
|
+
recoveryPending: "진행 중이거나 복구가 필요한 작업이 있습니다. 이번 실행에서는 파일을 바꾸지 않았습니다.",
|
|
940
|
+
resumeOperation: "앱 복구를 이어가려면:",
|
|
931
941
|
contextCurrent: "AGENTS.md와 TONE.md 구성이 최신입니다.",
|
|
932
942
|
contextRepair: "관리 중인 컨텍스트 파일을 복구해야 합니다. 안내 파일과 톤 파일의 진단을 확인해 주세요.",
|
|
933
943
|
contextSize: (guide, total) => total === null
|
|
@@ -1133,7 +1143,7 @@ const koMessages = {
|
|
|
1133
1143
|
},
|
|
1134
1144
|
combos: {
|
|
1135
1145
|
contradiction: (rule) => `${rule}: 서로 모순됩니다.`,
|
|
1136
|
-
refusalCompliance: "한 축은
|
|
1146
|
+
refusalCompliance: "한 축은 작업을 미루는 거절을 요구하고 다른 축은 기꺼이 즉시 시작하라고 요구합니다. 한쪽을 낮춰 주세요.",
|
|
1137
1147
|
nothingBlocked: "막지는 않습니다.",
|
|
1138
1148
|
},
|
|
1139
1149
|
errors: {
|
|
@@ -1282,21 +1292,21 @@ const ko = {
|
|
|
1282
1292
|
},
|
|
1283
1293
|
axisHints: {
|
|
1284
1294
|
formality: { owns: "표현의 격식·거리감", low: "익숙한 말투와 속어", high: "의례적이고 공손한 표현" },
|
|
1285
|
-
verbosity: { owns: "답변 분량과 설명의 깊이", low: "
|
|
1286
|
-
profanity: { owns: "
|
|
1287
|
-
playfulness: { owns: "농담·역할
|
|
1288
|
-
critique: { owns: "
|
|
1289
|
-
flattery: { owns: "
|
|
1290
|
-
warmth: { owns: "사용자에게
|
|
1295
|
+
verbosity: { owns: "답변 분량과 설명의 깊이", low: "간단한 결과는 짧은 한 문장", high: "요청 범위 안에서 깊이 있게 설명" },
|
|
1296
|
+
profanity: { owns: "욕설만: 강도·빈도", low: "욕설 없음·역할 속어 유지", high: "거의 모든 문장에 순화 없는 강한 욕설" },
|
|
1297
|
+
playfulness: { owns: "농담·역할 표현의 강도·빈도", low: "담백한 표현·설정한 호칭 유지", high: "거의 모든 문장에 과장된 역할 표현" },
|
|
1298
|
+
critique: { owns: "결함·선택을 비판하는 강도", low: "판단 없이 문제를 중립적으로 설명", high: "심각한 결함과 선택을 가차 없이 비난하고 조롱" },
|
|
1299
|
+
flattery: { owns: "칭찬의 양과 강도", low: "칭찬 없음", high: "문단마다 아낌없이 칭찬·기술 판단 유지" },
|
|
1300
|
+
warmth: { owns: "사용자에게 보이는 다정함", low: "인사·감정 표현·격려 없음", high: "문단마다 다정함·공감·위로·안심" },
|
|
1291
1301
|
conviction: { owns: "자기 판단을 밀어붙이는 정도", low: "선택지를 나열하고 물어봄", high: "추천 하나를 결정으로 말하고 되묻지 않음" },
|
|
1292
|
-
care: { owns: "범위·정리·기능적 표시", low: "요청한 작업만", high: "
|
|
1293
|
-
compliance: { owns: "
|
|
1294
|
-
refusal: { owns: "거절
|
|
1295
|
-
bravado: { owns: "
|
|
1302
|
+
care: { owns: "범위·정리·기능적 표시", low: "요청한 작업만", high: "후속·백업·휴식·목록·표·상태 이모지" },
|
|
1303
|
+
compliance: { owns: "거절로 미루지 않을 때의 실행 의지", low: "반대 이유를 밝힌 뒤 실행", high: "기꺼이 즉시 시작·지연이나 협상 없음" },
|
|
1304
|
+
refusal: { owns: "거절 빈도·조건", low: "거절·지연 없음", high: "달랠 때까지 파업·세이프워드는 한 답변만 해제" },
|
|
1305
|
+
bravado: { owns: "수고 과장·공치사의 정도", low: "과장 없음", high: "답변마다 허풍·공치사·수고 과장·페르소나 유지" },
|
|
1296
1306
|
},
|
|
1297
1307
|
settingHints: {
|
|
1298
1308
|
safeword: "한 메시지만 담백하게 답해 달라는 요청 문구",
|
|
1299
|
-
speech_level: "auto: 관계에 맞게 선택 · polite: 존댓말 · plain: 일반 반말 · rough:
|
|
1309
|
+
speech_level: "auto: 관계에 맞게 선택 · polite: 존댓말 · plain: 일반 반말 · rough: 짧고 퉁명스러운 반말 어미·자체로 농담·욕설·비판·조롱은 추가하지 않음 · 표현의 격식과 거리감은 formality로 조절",
|
|
1300
1310
|
language: "CLI 인터페이스 언어 · 에이전트 답변 언어와 무관",
|
|
1301
1311
|
"persona.age": "모델이 연상할 나이대",
|
|
1302
1312
|
"persona.gender": "모델이 연상할 성별",
|