synthesisui 0.16.161 → 0.16.163
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/commands/add.js +35 -26
- package/dist/commands/align.js +37 -0
- package/dist/commands/doctor.js +21 -0
- package/dist/commands/import.js +11 -1
- package/dist/commands/mcp.js +74 -0
- package/dist/commands/use.js +10 -8
- package/dist/doctor/coverage.js +10 -1
- package/dist/guide.js +15 -8
- package/package.json +1 -1
package/dist/commands/add.js
CHANGED
|
@@ -129,13 +129,21 @@ export async function add(slug, opts) {
|
|
|
129
129
|
const leftOut = payload.ruleSet
|
|
130
130
|
? describeFiltered(payload.ruleSet, stack)
|
|
131
131
|
: null;
|
|
132
|
+
/**
|
|
133
|
+
* AS REGRAS VIAJAM COMO DADO, e não como prosa materializada.
|
|
134
|
+
*
|
|
135
|
+
* `rules.md` e `philosophy.md` eram escritos SÓ pelo `add` (e o `upgrade` chama o `add`), então
|
|
136
|
+
* entre um upgrade e outro eles eram uma cópia velha de um dado que é VERSIONADO do nosso lado - e
|
|
137
|
+
* o GUIDE chamava um deles de "maximum authority". Uma autoridade máxima que envelhece em silêncio
|
|
138
|
+
* é pior que nenhuma (dono, 06/08).
|
|
139
|
+
*
|
|
140
|
+
* O conteúdo não sai do disco, porque o agente precisa dele offline e sem aprovar servidor nenhum.
|
|
141
|
+
* O que muda é a FORMA e quem o apresenta: aqui fica o dado pinado na versão instalada, e o
|
|
142
|
+
* `system_doctrine` do MCP é quem o serve - dizendo qual versão ele está lendo e se existe uma mais
|
|
143
|
+
* nova, em vez de deixar a pessoa descobrir pela ausência.
|
|
144
|
+
*/
|
|
132
145
|
if (rules.length > 0) {
|
|
133
|
-
|
|
134
|
-
"> Accumulated rules for this design system. **Max authority - follow these first.**\n" +
|
|
135
|
-
`> Managed by synthesisui (edit in the studio). ${rules.length} rule(s).\n\n${rules
|
|
136
|
-
.map((r) => `- ${r}`)
|
|
137
|
-
.join("\n")}\n`;
|
|
138
|
-
await writeFile(join(slugDir, "rules.md"), body, "utf8");
|
|
146
|
+
await writeFile(join(slugDir, "doctrine.json"), `${JSON.stringify({ version: payload.version, name: payload.name, rules }, null, 2)}\n`, "utf8");
|
|
139
147
|
}
|
|
140
148
|
// NO SILENT DROPS. A rule removed because it belongs to another environment is
|
|
141
149
|
// a thing the person should hear once, not discover by its absence.
|
|
@@ -163,22 +171,17 @@ export async function add(slug, opts) {
|
|
|
163
171
|
if (required.length > 0) {
|
|
164
172
|
await writeFile(join(slugDir, "requires.json"), `${JSON.stringify(required, null, 2)}\n`, "utf8");
|
|
165
173
|
}
|
|
166
|
-
|
|
167
|
-
// Narrative guidance (mission, principles, voice, motion doctrine…); the
|
|
168
|
-
// GUIDE points the agent here right after rules.md.
|
|
174
|
+
/** A filosofia continua sendo CONTADA na saída, e ela vive no documento - ver abaixo. */
|
|
169
175
|
const philosophy = payload.document.philosophy;
|
|
170
176
|
const sections = philosophy?.sections ?? [];
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
}
|
|
180
|
-
await writeFile(join(slugDir, "philosophy.md"), `${parts.join("\n")}\n`, "utf8");
|
|
181
|
-
}
|
|
177
|
+
/**
|
|
178
|
+
* 5c. A FILOSOFIA NÃO É MATERIALIZADA - ela já está aqui.
|
|
179
|
+
*
|
|
180
|
+
* `philosophy` é campo do DOCUMENTO versionado (`design-system.ts`), e o `design-system.json`
|
|
181
|
+
* escrito no passo 2 a carrega inteira. O `philosophy.md` era uma segunda cópia do mesmo dado, no
|
|
182
|
+
* mesmo commit, que só era reescrita no upgrade seguinte - dois caminhos para uma verdade é como
|
|
183
|
+
* um deles começa a discordar do outro. O `system_doctrine` lê do documento.
|
|
184
|
+
*/
|
|
182
185
|
// 6. discovery by the agent
|
|
183
186
|
const claudeMd = await syncClaudeMd(projectRoot);
|
|
184
187
|
// outcome line
|
|
@@ -201,12 +204,18 @@ export async function add(slug, opts) {
|
|
|
201
204
|
"GUIDE.md",
|
|
202
205
|
];
|
|
203
206
|
console.log(` v${v}/: ${files.join(", ")}`);
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
207
|
+
/**
|
|
208
|
+
* O QUE O AGENTE VAI LER, e por qual porta - nomear o arquivo quando a porta é uma ferramenta
|
|
209
|
+
* mandaria alguém procurar um caminho que não existe mais.
|
|
210
|
+
*/
|
|
211
|
+
const doctrine = [
|
|
212
|
+
...(rules.length > 0 ? [`${rules.length} rule(s)`] : []),
|
|
213
|
+
...(sections.length > 0 || philosophy?.context
|
|
214
|
+
? [`${sections.length} section(s) of philosophy`]
|
|
215
|
+
: []),
|
|
216
|
+
];
|
|
217
|
+
if (doctrine.length > 0)
|
|
218
|
+
console.log(` ${doctrine.join(" and ")} → your agent reads them with \`system_doctrine\`, pinned to v${v}`);
|
|
210
219
|
console.log(` CLAUDE.md ${claudeMd.created ? "created" : "updated"} (${claudeMd.count} system(s) installed)`);
|
|
211
220
|
if (opts.setupHints === false)
|
|
212
221
|
return;
|
package/dist/commands/align.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { readdir, readFile } from "node:fs/promises";
|
|
2
2
|
import { homedir } from "node:os";
|
|
3
3
|
import { join, resolve } from "node:path";
|
|
4
|
+
import { readToken, resolveRegistry } from "../config.js";
|
|
4
5
|
import { readEvents } from "../doctor/ledger.js";
|
|
5
6
|
import { measuredScope } from "../measured-scope.js";
|
|
6
7
|
async function locksIn(root) {
|
|
@@ -100,6 +101,38 @@ opts = {}) {
|
|
|
100
101
|
});
|
|
101
102
|
return out;
|
|
102
103
|
}
|
|
104
|
+
/**
|
|
105
|
+
* A VERSÃO PUBLICADA CONTRA A INSTALADA - o estado que nenhuma verificação cobria.
|
|
106
|
+
*
|
|
107
|
+
* É o que faz disto um produto de TIME e não de uma pessoa: alguém edita o sistema no estúdio e
|
|
108
|
+
* publica, e o repo de todo mundo continua com o CSS e as regras da versão anterior, sem nada dizer.
|
|
109
|
+
* A doutrina que o agente lê é a da versão instalada de propósito (ver `system_doctrine`), então as
|
|
110
|
+
* duas metades andam juntas - e é justamente por isso que a defasagem precisa ser DITA.
|
|
111
|
+
*
|
|
112
|
+
* Melhor esforço: offline, sem sessão, ou registry fora do ar não produzem linha nenhuma. Uma
|
|
113
|
+
* verificação de abertura não pode transformar um voo sem internet num aviso.
|
|
114
|
+
*/
|
|
115
|
+
export async function versionBehind(root, opts = {}) {
|
|
116
|
+
const locks = (await locksIn(root)).filter((l) => l.slug && !l.adopted);
|
|
117
|
+
const lock = locks[0];
|
|
118
|
+
if (!lock?.slug || lock.version == null)
|
|
119
|
+
return null;
|
|
120
|
+
if (!(await credentials(opts.home ?? homedir())))
|
|
121
|
+
return null;
|
|
122
|
+
const token = await readToken();
|
|
123
|
+
if (!token)
|
|
124
|
+
return null;
|
|
125
|
+
const res = await fetch(`${lock.registry ?? resolveRegistry()}/api/registry/ds/${lock.slug}`, { headers: { Authorization: `Bearer ${token}` } }).catch(() => null);
|
|
126
|
+
if (!res?.ok)
|
|
127
|
+
return null;
|
|
128
|
+
const body = (await res.json().catch(() => null));
|
|
129
|
+
if (!body?.version || body.version <= lock.version)
|
|
130
|
+
return null;
|
|
131
|
+
return {
|
|
132
|
+
says: `v${body.version} of "${lock.slug}" is published and this repo is on v${lock.version}. The CSS here and the rules your agent reads are both v${lock.version} - they move together, which is why this is worth saying rather than applying.`,
|
|
133
|
+
run: `npx synthesisui upgrade ${lock.slug}`,
|
|
134
|
+
};
|
|
135
|
+
}
|
|
103
136
|
/**
|
|
104
137
|
* A linha que a sessão vê.
|
|
105
138
|
*
|
|
@@ -127,6 +160,10 @@ export async function align(opts) {
|
|
|
127
160
|
const items = await localMisalignments(root, {
|
|
128
161
|
...(opts.cli ? { cli: opts.cli } : {}),
|
|
129
162
|
}).catch(() => []);
|
|
163
|
+
/** A única linha que custa rede, e ela some inteira quando não há rede. */
|
|
164
|
+
const remote = await versionBehind(root).catch(() => null);
|
|
165
|
+
if (remote)
|
|
166
|
+
items.push(remote);
|
|
130
167
|
const text = describeMisalignments(items);
|
|
131
168
|
if (text)
|
|
132
169
|
console.log(text);
|
package/dist/commands/doctor.js
CHANGED
|
@@ -144,6 +144,7 @@ export async function loadSystem(root) {
|
|
|
144
144
|
recipes: new Map(),
|
|
145
145
|
documents: [],
|
|
146
146
|
requires: [],
|
|
147
|
+
doctrines: [],
|
|
147
148
|
};
|
|
148
149
|
}
|
|
149
150
|
// Several systems can live side by side; every token is prefixed --ds-, so
|
|
@@ -154,6 +155,7 @@ export async function loadSystem(root) {
|
|
|
154
155
|
const recipes = new Map();
|
|
155
156
|
const documents = [];
|
|
156
157
|
const requires = [];
|
|
158
|
+
const doctrines = [];
|
|
157
159
|
for (const slug of slugs) {
|
|
158
160
|
const dir = join(dsDir, slug);
|
|
159
161
|
const raw = await readFile(join(dir, ".lock"), "utf8").catch(() => "");
|
|
@@ -226,12 +228,31 @@ export async function loadSystem(root) {
|
|
|
226
228
|
// Unreadable costs this check, not the run.
|
|
227
229
|
}
|
|
228
230
|
}
|
|
231
|
+
/** Ausente é o caso normal: um sistema sem regra nenhuma não deixa arquivo. */
|
|
232
|
+
const doctrineRaw = await readFile(join(dir, "doctrine.json"), "utf8").catch(() => "");
|
|
233
|
+
if (doctrineRaw) {
|
|
234
|
+
try {
|
|
235
|
+
const parsed = JSON.parse(doctrineRaw);
|
|
236
|
+
if (Array.isArray(parsed.rules))
|
|
237
|
+
doctrines.push({
|
|
238
|
+
...(typeof parsed.version === "number"
|
|
239
|
+
? { version: parsed.version }
|
|
240
|
+
: {}),
|
|
241
|
+
...(typeof parsed.name === "string" ? { name: parsed.name } : {}),
|
|
242
|
+
rules: parsed.rules.filter((r) => typeof r === "string"),
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
catch {
|
|
246
|
+
// Ilegível custa a doutrina, nunca a rodada.
|
|
247
|
+
}
|
|
248
|
+
}
|
|
229
249
|
}
|
|
230
250
|
return {
|
|
231
251
|
table: buildTable({ css, lock, source: adopted ? "adopted" : "installed" }),
|
|
232
252
|
recipes,
|
|
233
253
|
documents,
|
|
234
254
|
requires,
|
|
255
|
+
doctrines,
|
|
235
256
|
};
|
|
236
257
|
}
|
|
237
258
|
/**
|
package/dist/commands/import.js
CHANGED
|
@@ -1205,7 +1205,17 @@ export async function takeCensus(root, opts) {
|
|
|
1205
1205
|
* product is broken, reasoning correctly from what they were shown. The gap was never
|
|
1206
1206
|
* the defect; the silence was (dono, 01/08).
|
|
1207
1207
|
*/
|
|
1208
|
-
|
|
1208
|
+
/**
|
|
1209
|
+
* O DENOMINADOR CONTA COMPONENTES, e contava ARQUIVOS.
|
|
1210
|
+
*
|
|
1211
|
+
* `looks` é por NOME e `componentFiles` é por arquivo, então um arquivo que exporta dois
|
|
1212
|
+
* componentes produzia "36 of 35 components came out with a look - 103%" (medido na biblioteca do
|
|
1213
|
+
* dono em 06/08). Uma porcentagem que passa de 100 por construção não é um arredondamento: é a
|
|
1214
|
+
* linha que declara a cobertura da esteira inteira se medindo contra outra unidade.
|
|
1215
|
+
*
|
|
1216
|
+
* `componentFiles` segue existindo para as formas de estilo, que SÃO por arquivo.
|
|
1217
|
+
*/
|
|
1218
|
+
const coverage = summarizeCoverage(shapes, defined.length || componentFiles, Object.keys(looks).length, Object.values(looks).reduce((n, look) => n +
|
|
1209
1219
|
Object.keys(look.base).length +
|
|
1210
1220
|
Object.keys(look.dark ?? {}).length +
|
|
1211
1221
|
Object.values(look.states).reduce((m, block) => m + Object.keys(block).length, 0) +
|
package/dist/commands/mcp.js
CHANGED
|
@@ -70,6 +70,11 @@ const TOOLS = [
|
|
|
70
70
|
required: ["value"],
|
|
71
71
|
},
|
|
72
72
|
},
|
|
73
|
+
{
|
|
74
|
+
name: "system_doctrine",
|
|
75
|
+
description: "The rules and the philosophy of the installed system - maximum authority, read this BEFORE building anything. It answers from the version this project has pinned, which is the same version whose tokens are on disk, so the rules you follow and the values you write come from one place. It also says when a newer version has been published, without applying it.",
|
|
76
|
+
inputSchema: { type: "object", properties: {} },
|
|
77
|
+
},
|
|
73
78
|
{
|
|
74
79
|
name: "list_components",
|
|
75
80
|
description: "The components this design system defines, with what each is for. Look here BEFORE writing any UI element from scratch - if something covers the purpose, materialize it with add_component instead.",
|
|
@@ -252,6 +257,73 @@ async function findToken(root, value) {
|
|
|
252
257
|
// same refusal every time.
|
|
253
258
|
return `No token in this system holds ${value}, and nothing is close. Do NOT invent one. Say which value you need and what you would call it, and let a person decide.`;
|
|
254
259
|
}
|
|
260
|
+
/**
|
|
261
|
+
* A DOUTRINA DO SISTEMA - as regras e a filosofia, servidas em vez de materializadas.
|
|
262
|
+
*
|
|
263
|
+
* `rules.md` e `philosophy.md` eram escritos SÓ pelo `add` (e o `upgrade` chama o `add`), então entre
|
|
264
|
+
* um upgrade e outro eram uma cópia velha de dado que é VERSIONADO do nosso lado - e o GUIDE chamava
|
|
265
|
+
* um deles de "maximum authority". Uma autoridade máxima que envelhece em silêncio é pior que
|
|
266
|
+
* nenhuma (dono, 06/08).
|
|
267
|
+
*
|
|
268
|
+
* DA VERSÃO PINADA, e essa é a decisão que mantém as duas metades coerentes: os tokens no disco são
|
|
269
|
+
* os da v2, então a regra que o agente segue tem que ser a da v2. Servir o rascunho faria o agente
|
|
270
|
+
* escrever contra uma regra que ainda não está instalada.
|
|
271
|
+
*
|
|
272
|
+
* A existência de uma versão mais nova é DITA, nunca aplicada - aplicar é o `upgrade`, que é uma
|
|
273
|
+
* palavra que a pessoa já tem. Sem rede, a doutrina responde igual e a checagem é que se cala: o
|
|
274
|
+
* dado é local justamente para não depender de servidor nenhum.
|
|
275
|
+
*/
|
|
276
|
+
async function systemDoctrine(root) {
|
|
277
|
+
const { documents, doctrines } = await loadSystem(root);
|
|
278
|
+
const rules = doctrines.flatMap((d) => d.rules);
|
|
279
|
+
const parts = [];
|
|
280
|
+
const pinned = doctrines[0]?.version;
|
|
281
|
+
for (const doc of documents) {
|
|
282
|
+
const p = doc.philosophy;
|
|
283
|
+
if (p?.context)
|
|
284
|
+
parts.push(`## What this product is\n\n${p.context}`);
|
|
285
|
+
for (const sec of p?.sections ?? [])
|
|
286
|
+
parts.push(`## ${sec.title}\n\n${sec.body}`);
|
|
287
|
+
}
|
|
288
|
+
if (rules.length === 0 && parts.length === 0)
|
|
289
|
+
return "This system carries no rules and no philosophy yet. Nothing here overrides your judgement - build with its tokens and its components, and say what you needed and could not find.";
|
|
290
|
+
const head = [
|
|
291
|
+
rules.length > 0
|
|
292
|
+
? `# Rules - maximum authority, ${rules.length} of them${pinned ? `, as of v${pinned}` : ""}`
|
|
293
|
+
: "",
|
|
294
|
+
...rules.map((r) => `- ${r}`),
|
|
295
|
+
].filter(Boolean);
|
|
296
|
+
const behind = await newerVersion(root, pinned);
|
|
297
|
+
return [
|
|
298
|
+
...head,
|
|
299
|
+
...(parts.length > 0 ? ["", "# Philosophy", "", ...parts] : []),
|
|
300
|
+
...(behind ? ["", behind] : []),
|
|
301
|
+
].join("\n");
|
|
302
|
+
}
|
|
303
|
+
/**
|
|
304
|
+
* Existe versão publicada acima da instalada?
|
|
305
|
+
*
|
|
306
|
+
* Melhor esforço e nunca bloqueante: offline, sem sessão, ou registry fora do ar devolvem `null` e a
|
|
307
|
+
* doutrina responde igual. Dizer "não consegui checar" a cada chamada seria ruído numa ferramenta que
|
|
308
|
+
* o agente chama antes de cada trabalho.
|
|
309
|
+
*/
|
|
310
|
+
async function newerVersion(root, pinned) {
|
|
311
|
+
if (pinned == null)
|
|
312
|
+
return null;
|
|
313
|
+
const slug = await installedSlug(root);
|
|
314
|
+
const token = await readToken();
|
|
315
|
+
if (!slug || !token)
|
|
316
|
+
return null;
|
|
317
|
+
const res = await fetch(`${resolveRegistry()}/api/registry/ds/${slug}`, {
|
|
318
|
+
headers: { Authorization: `Bearer ${token}` },
|
|
319
|
+
}).catch(() => null);
|
|
320
|
+
if (!res?.ok)
|
|
321
|
+
return null;
|
|
322
|
+
const body = (await res.json().catch(() => null));
|
|
323
|
+
if (!body?.version || body.version <= pinned)
|
|
324
|
+
return null;
|
|
325
|
+
return `> v${body.version} of this system has been published and this project is on v${pinned}. These rules are v${pinned}'s, and so are the tokens on disk - the two move together. \`npx synthesisui upgrade ${slug}\` brings both.`;
|
|
326
|
+
}
|
|
255
327
|
async function listComponents(root) {
|
|
256
328
|
const { documents } = await loadSystem(root);
|
|
257
329
|
const rows = [];
|
|
@@ -839,6 +911,8 @@ cli) {
|
|
|
839
911
|
return text(await checkFile(root, String(args.path ?? ".")));
|
|
840
912
|
case "find_token":
|
|
841
913
|
return text(await findToken(root, String(args.value ?? "")));
|
|
914
|
+
case "system_doctrine":
|
|
915
|
+
return text(await systemDoctrine(root));
|
|
842
916
|
case "list_components":
|
|
843
917
|
return text(await listComponents(root));
|
|
844
918
|
case "describe_component":
|
package/dist/commands/use.js
CHANGED
|
@@ -43,15 +43,17 @@ export async function use(slug, intent, opts) {
|
|
|
43
43
|
const config = await readProjectConfig(root);
|
|
44
44
|
const { version, name } = lock;
|
|
45
45
|
const base = `_synthesisui/ds/${slug}`;
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
46
|
+
/**
|
|
47
|
+
* A AUTORIDADE MÁXIMA VEM DE UMA FERRAMENTA, e o resto continua sendo caminho.
|
|
48
|
+
*
|
|
49
|
+
* `rules.md` e `philosophy.md` eram cópias velhas de dado versionado entre um upgrade e outro -
|
|
50
|
+
* ver `system_doctrine`. Um prompt que manda alguém abrir um arquivo que não existe mais é pior
|
|
51
|
+
* que um prompt sem a linha, então a condição passou a ser o DADO e não o arquivo.
|
|
52
|
+
*/
|
|
53
|
+
const hasDoctrine = await exists(join(slugDir, "doctrine.json"));
|
|
49
54
|
const readFirst = [
|
|
50
|
-
|
|
51
|
-
?
|
|
52
|
-
: "",
|
|
53
|
-
hasPhilosophy
|
|
54
|
-
? `- ${base}/philosophy.md — the mission, voice and principles; let it shape every screen`
|
|
55
|
+
hasDoctrine
|
|
56
|
+
? "- Call `system_doctrine` first — this system's rules and philosophy, pinned to the installed version; obey them above everything else"
|
|
55
57
|
: "",
|
|
56
58
|
`- ${base}/v${version}/GUIDE.md — how to apply the system, the recipes and the token vocabulary`,
|
|
57
59
|
].filter(Boolean);
|
package/dist/doctor/coverage.js
CHANGED
|
@@ -92,7 +92,16 @@ export function countShape(source, name, into) {
|
|
|
92
92
|
}
|
|
93
93
|
export function summarizeCoverage(counts, components, read, declarations) {
|
|
94
94
|
return {
|
|
95
|
-
|
|
95
|
+
/**
|
|
96
|
+
* NUNCA MENOS QUE O QUE FOI LIDO.
|
|
97
|
+
*
|
|
98
|
+
* `read` conta LOOKS por nome e o denominador chegava contando ARQUIVOS - um arquivo que exporta
|
|
99
|
+
* dois componentes produzia `36 of 35 components came out with a look - 103%` na biblioteca do
|
|
100
|
+
* dono (06/08). O conserto de verdade é o chamador passar a mesma unidade, e ele passa; isto é a
|
|
101
|
+
* trava, para que a linha que declara a cobertura da esteira inteira não possa afirmar mais do
|
|
102
|
+
* que existe se outro chamador errar a unidade de novo.
|
|
103
|
+
*/
|
|
104
|
+
components: Math.max(components, read),
|
|
96
105
|
read,
|
|
97
106
|
declarations,
|
|
98
107
|
counts: [...counts.values()].sort((a, b) => b.files - a.files),
|
package/dist/guide.js
CHANGED
|
@@ -426,14 +426,21 @@ own entry below says so.
|
|
|
426
426
|
const hasRules = (payload.rules?.length ?? 0) > 0;
|
|
427
427
|
const philosophy = payload.document.philosophy;
|
|
428
428
|
const hasPhilosophy = (philosophy?.sections?.length ?? 0) > 0 || !!philosophy?.context;
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
429
|
+
/**
|
|
430
|
+
* UMA PORTA SÓ, e ela é uma FERRAMENTA e não um caminho.
|
|
431
|
+
*
|
|
432
|
+
* Isto apontava para `rules.md` e `philosophy.md`, escritos apenas pelo `add` - então entre um
|
|
433
|
+
* upgrade e outro o agente lia uma cópia velha de dado versionado, sob a etiqueta "highest
|
|
434
|
+
* authority". `system_doctrine` serve os dois da versão PINADA (a mesma dos tokens no disco) e diz
|
|
435
|
+
* quando existe uma mais nova, em vez de deixar a defasagem ser descoberta pela ausência.
|
|
436
|
+
*/
|
|
437
|
+
const readFirst = hasRules || hasPhilosophy
|
|
438
|
+
? [
|
|
439
|
+
`**Call \`system_doctrine\` FIRST and obey it above everything else** - it carries ${hasRules
|
|
440
|
+
? "this system's accumulated, project-specific rules"
|
|
441
|
+
: "this system's mission, principles, voice and motion doctrine"}${hasRules && hasPhilosophy ? " and its philosophy" : ""}, pinned to the version installed here. On any conflict they win.`,
|
|
442
|
+
]
|
|
443
|
+
: [];
|
|
437
444
|
const rulesNote = readFirst.length > 0
|
|
438
445
|
? `
|
|
439
446
|
## Read first - highest authority
|
package/package.json
CHANGED