guideline-manage 0.16.1 → 0.17.0
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/cli/src/catalog.js +2 -0
- package/cli/src/cli.js +2 -2
- package/cli/src/commands/propose.js +10 -8
- package/cli/src/stack-name.js +21 -0
- package/locales/en/messages.json +46 -19
- package/locales/en/templates/authoring.md +7 -0
- package/locales/en/templates/llms.txt +4 -2
- package/locales/en/templates/new-file/server.json +5 -0
- package/locales/en/templates/skills/guideline-export/SKILL.md +1 -0
- package/locales/ko/messages.json +268 -241
- package/locales/ko/templates/authoring.md +8 -1
- package/locales/ko/templates/llms.txt +7 -5
- package/locales/ko/templates/new-file/server.json +5 -0
- package/locales/ko/templates/skills/guideline-export/SKILL.md +4 -3
- package/locales/ko/templates/skills/guideline-sync/SKILL.md +5 -5
- package/package.json +1 -1
package/cli/src/catalog.js
CHANGED
|
@@ -7,6 +7,7 @@ import { readCategories } from './categories.js';
|
|
|
7
7
|
import { asTree, readText } from './tree.js';
|
|
8
8
|
import { t } from './i18n.js';
|
|
9
9
|
import { marker } from './markers.js';
|
|
10
|
+
import { stackNameProblem } from './stack-name.js';
|
|
10
11
|
|
|
11
12
|
// export 함수의 src 는 문서 저장소 루트의 디스크 경로나 트리(tree.js)다. 서버는 DB 트리를 넘긴다.
|
|
12
13
|
|
|
@@ -265,6 +266,7 @@ export function fileCategories(categories, rel) {
|
|
|
265
266
|
export function warnings(src) {
|
|
266
267
|
const tree = asTree(src);
|
|
267
268
|
const rules = stacks(tree).flatMap(s => [
|
|
269
|
+
...(stackNameProblem(s) ? [{ path: `rules/${s}/`, message: stackNameProblem(s) }] : []),
|
|
268
270
|
...stackTiers(s, tree).filter(f => f.warning).map(f => ({ path: f.path, message: f.warning })),
|
|
269
271
|
...stackOverrides(s, tree).warnings,
|
|
270
272
|
]);
|
package/cli/src/cli.js
CHANGED
|
@@ -20,7 +20,7 @@ const ALLOWED_OPTIONS = {
|
|
|
20
20
|
status: ['project', 'server', 'source', 'json'],
|
|
21
21
|
login: ['server', 'token-stdin'],
|
|
22
22
|
logout: ['server'],
|
|
23
|
-
propose: ['project', 'server', 'source', 'title', 'message', 'only', 'from', 'dry-run', 'json'],
|
|
23
|
+
propose: ['project', 'server', 'source', 'title', 'message', 'only', 'from', 'dry-run', 'apply', 'json'],
|
|
24
24
|
source: ['server', 'source'],
|
|
25
25
|
locale: ['json'],
|
|
26
26
|
help: [],
|
|
@@ -107,7 +107,7 @@ export async function main(argv) {
|
|
|
107
107
|
return propose({
|
|
108
108
|
project: values.project, server: values.server, source: values.source, title: values.title, message: values.message,
|
|
109
109
|
only: values.only?.split(',').map(s => s.trim()).filter(Boolean), from: values.from,
|
|
110
|
-
dryRun: values['dry-run'], json: values.json, cwd,
|
|
110
|
+
dryRun: values['dry-run'], apply: values.apply, json: values.json, cwd,
|
|
111
111
|
});
|
|
112
112
|
}
|
|
113
113
|
|
|
@@ -20,7 +20,7 @@ const textOr = buf => (buf === null ? '' : buf.includes(0) ? null : buf.toString
|
|
|
20
20
|
* 변경 묶음을 보이거나(dry-run) 제안으로 보낸다. propose 와 propose --from 이 같이 쓴다.
|
|
21
21
|
* @returns {Promise<number>}
|
|
22
22
|
*/
|
|
23
|
-
export async function sendProposal({ client, server, title, message, project, changes, todos, dryRun, json, out, err, baseTree }) {
|
|
23
|
+
export async function sendProposal({ client, server, title, message, project, changes, todos, dryRun, apply = false, json, out, err, baseTree }) {
|
|
24
24
|
if (changes.length === 0) {
|
|
25
25
|
if (json) out(JSON.stringify({ changes: [], todos }, null, 2));
|
|
26
26
|
else {
|
|
@@ -47,18 +47,20 @@ export async function sendProposal({ client, server, title, message, project, ch
|
|
|
47
47
|
}
|
|
48
48
|
let r;
|
|
49
49
|
try {
|
|
50
|
-
r = await client.createProposal({ title, description: message ?? '', project, changes: changes.map(toApiChange) });
|
|
50
|
+
r = await client.createProposal({ title, description: message ?? '', project, changes: changes.map(toApiChange), ...(apply ? { apply: true } : {}) });
|
|
51
51
|
} catch (e) {
|
|
52
52
|
if (e instanceof ServerError && e.status === 403) {
|
|
53
|
-
err(PROPOSE_DENIED(server));
|
|
53
|
+
err(apply ? t('propose.applyDenied', { server }) : PROPOSE_DENIED(server));
|
|
54
54
|
return 1;
|
|
55
55
|
}
|
|
56
56
|
err(explain(e, server));
|
|
57
57
|
return 1;
|
|
58
58
|
}
|
|
59
|
-
if (json) out(JSON.stringify({ id: r.id, url: r.url, changes: listed, todos }, null, 2));
|
|
59
|
+
if (json) out(JSON.stringify({ id: r.id, url: r.url, status: r.status, revision: r.revision ?? null, changes: listed, todos }, null, 2));
|
|
60
60
|
else {
|
|
61
|
-
out(t('propose.sent', { id: r.id, url: r.url }));
|
|
61
|
+
if (r.status !== 'accepted') out(t('propose.sent', { id: r.id, url: r.url }));
|
|
62
|
+
else if (r.revision) out(t('propose.applied', { rev: r.revision, url: r.url }));
|
|
63
|
+
else out(t('propose.appliedNothing'));
|
|
62
64
|
for (const c of changes) out(` ${KIND(c)} ${c.path}`);
|
|
63
65
|
printTodos(todos, out);
|
|
64
66
|
}
|
|
@@ -70,7 +72,7 @@ export async function sendProposal({ client, server, title, message, project, ch
|
|
|
70
72
|
* @returns {Promise<number>}
|
|
71
73
|
*/
|
|
72
74
|
export async function propose({
|
|
73
|
-
project, server, source, from, title, message, only, dryRun = false, json = false,
|
|
75
|
+
project, server, source, from, title, message, only, dryRun = false, apply = false, json = false,
|
|
74
76
|
env = process.env, out = console.log, err = console.error, fetchImpl = fetch, home, cwd = process.cwd(),
|
|
75
77
|
}) {
|
|
76
78
|
if (from !== undefined) {
|
|
@@ -101,7 +103,7 @@ export async function propose({
|
|
|
101
103
|
return 1;
|
|
102
104
|
}
|
|
103
105
|
return sendProposal({
|
|
104
|
-
client, server: url, title, message, project: null, changes: folderChanges({ base, folder }), todos: [], dryRun, json, out, err, baseTree: base,
|
|
106
|
+
client, server: url, title, message, project: null, changes: folderChanges({ base, folder }), todos: [], dryRun, apply, json, out, err, baseTree: base,
|
|
105
107
|
});
|
|
106
108
|
}
|
|
107
109
|
const dir = project !== undefined ? expandPath(project) : cwd;
|
|
@@ -139,7 +141,7 @@ export async function propose({
|
|
|
139
141
|
const prefix = many ? line => out(`${name}: ${line}`) : out;
|
|
140
142
|
const c = await sendProposal({
|
|
141
143
|
client, server: url, title: title ?? t('propose.defaultTitle', { project: projectName }), message, project: projectName,
|
|
142
|
-
changes: list, todos: many ? [] : shown, dryRun, json, out: prefix, err, baseTree: base,
|
|
144
|
+
changes: list, todos: many ? [] : shown, dryRun, apply, json, out: prefix, err, baseTree: base,
|
|
143
145
|
});
|
|
144
146
|
if (c !== 0) code = c;
|
|
145
147
|
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { t } from './i18n.js';
|
|
2
|
+
|
|
3
|
+
// 도메인 스택: `<도구>__<도메인>`. 같은 도구라도 돌아가는 서버(회사·인스턴스)가 다르면 규칙이 달라 스택을 나눈다.
|
|
4
|
+
const SEP = '__';
|
|
5
|
+
const DOMAIN = /^[a-z0-9-]+(\.[a-z0-9-]+)+$/;
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* @param {string} name 스택 이름
|
|
9
|
+
* @returns {{ tool: string, domain: string | null }}
|
|
10
|
+
*/
|
|
11
|
+
export function splitStackName(name) {
|
|
12
|
+
const i = name.indexOf(SEP);
|
|
13
|
+
return i === -1 ? { tool: name, domain: null } : { tool: name.slice(0, i), domain: name.slice(i + SEP.length) };
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/** `__` 가 있는데 도메인 모양이 아니면 경고 문구. 없거나 맞으면 null. */
|
|
17
|
+
export function stackNameProblem(name) {
|
|
18
|
+
const { domain } = splitStackName(name);
|
|
19
|
+
if (domain === null || DOMAIN.test(domain)) return null;
|
|
20
|
+
return t('catalog.badDomain');
|
|
21
|
+
}
|
package/locales/en/messages.json
CHANGED
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
"diff.proposal": "proposal",
|
|
50
50
|
"diff.source": "source",
|
|
51
51
|
"diff.tooBig": "omitted (too large)",
|
|
52
|
-
"help.usage": "Usage: guideline <command> [options]\n\nIn a project (guideline server)\n common --source <name> a source (sources in guideline.json). For pick, an unknown name together with --server adds a new source\n pick choose guidelines to export in a web form; submitting applies them to this project\n --project <path> target project (default: current directory)\n --new <name|path> create a new project (a bare name goes under GUIDELINE_PROJECTS_DIR)\n --server <URL> guideline server (default: guideline.json → GUIDELINE_SERVER)\n --no-browser print the address instead of opening a browser\n --json print the result (written files, to-dos) as JSON\n update re-apply the chosen items from the latest server revision\n --project <path> --server <URL>\n --force also overwrite files changed in the project\n --json print the result as JSON\n status show whether the applied guidelines are current and what the project changed\n --project <path> --server <URL> --json\n login log in to a guideline server and store a read token\n --server <URL>\n --token-stdin store a token from standard input instead of using a browser\n logout delete the stored token and revoke it on the server\n --server <URL>\n propose turn edited copies back into source form and propose them to the server (they become source when an admin accepts)\n --project <path> --server <URL>\n --title <title> proposal title (default: guidelines edited in <directory>)\n --message <text> proposal description\n --only <item,…> only these items (e.g. rules/base/01-git.md,skills/s)\n --from <folder> compare a folder from guideline source against the revision it came from (--title required)\n --dry-run show the changes and diffs without sending\n --json print the result as JSON\n source unpack the latest server source into an empty folder; edit it in source layout, then propose --from\n guideline source <folder> --server <URL>\n list list the source and its checks. With a folder, read that folder (a source from guideline source); otherwise the server\n guideline list [folder] --server <URL> --json\n locale language packs: check <folder> compares a pack with English; list shows available languages. The language is GUIDELINE_LANG\n guideline locale check <folder> guideline locale list --json\n help this help\n",
|
|
52
|
+
"help.usage": "Usage: guideline <command> [options]\n\nIn a project (guideline server)\n common --source <name> a source (sources in guideline.json). For pick, an unknown name together with --server adds a new source\n pick choose guidelines to export in a web form; submitting applies them to this project\n --project <path> target project (default: current directory)\n --new <name|path> create a new project (a bare name goes under GUIDELINE_PROJECTS_DIR)\n --server <URL> guideline server (default: guideline.json → GUIDELINE_SERVER)\n --no-browser print the address instead of opening a browser\n --json print the result (written files, to-dos) as JSON\n update re-apply the chosen items from the latest server revision\n --project <path> --server <URL>\n --force also overwrite files changed in the project\n --json print the result as JSON\n status show whether the applied guidelines are current and what the project changed\n --project <path> --server <URL> --json\n login log in to a guideline server and store a read token\n --server <URL>\n --token-stdin store a token from standard input instead of using a browser\n logout delete the stored token and revoke it on the server\n --server <URL>\n propose turn edited copies back into source form and propose them to the server (they become source when an admin accepts)\n --project <path> --server <URL>\n --title <title> proposal title (default: guidelines edited in <directory>)\n --message <text> proposal description\n --only <item,…> only these items (e.g. rules/base/01-git.md,skills/s)\n --from <folder> compare a folder from guideline source against the revision it came from (--title required)\n --dry-run show the changes and diffs without sending\n --apply with an admin token, apply directly instead of proposing\n --json print the result as JSON\n source unpack the latest server source into an empty folder; edit it in source layout, then propose --from\n guideline source <folder> --server <URL>\n list list the source and its checks. With a folder, read that folder (a source from guideline source); otherwise the server\n guideline list [folder] --server <URL> --json\n locale language packs: check <folder> compares a pack with English; list shows available languages. The language is GUIDELINE_LANG\n guideline locale check <folder> guideline locale list --json\n help this help\n",
|
|
53
53
|
"http.badJson": "The body is not JSON",
|
|
54
54
|
"http.badUrl": "The address is badly encoded",
|
|
55
55
|
"http.needJson": "Content-Type must be application/json",
|
|
@@ -275,7 +275,7 @@
|
|
|
275
275
|
"todo.skippedAdopted": "{what}: already differed from the source before it was received (it may be an old version) — use --force to match the source, or guideline propose --only {id} if the project edited it",
|
|
276
276
|
"todo.unsynced": "{item}: could not be applied because an existing copy differs — check the diff in guideline pick and turn on update",
|
|
277
277
|
"tokens.badName": "Names are 1–64 characters of letters, digits and . _ -",
|
|
278
|
-
"tokens.badScope": "The scope
|
|
278
|
+
"tokens.badScope": "The scope must be read, propose or admin",
|
|
279
279
|
"tokens.nameTaken": "Name already exists: {name}",
|
|
280
280
|
"toml.badValue": "value cannot be written as TOML: {value}",
|
|
281
281
|
"toml.duplicate": "[{table}] appears more than once",
|
|
@@ -287,7 +287,6 @@
|
|
|
287
287
|
"update.unknownSource": "Source {name} is not in guideline.json — sources: {names}",
|
|
288
288
|
"web.adminToken": "Admin token",
|
|
289
289
|
"web.all": "All",
|
|
290
|
-
"web.allFiles": "All files",
|
|
291
290
|
"web.backHistory": "Back to history",
|
|
292
291
|
"web.backHome": "Back to the list",
|
|
293
292
|
"web.badOrigin": "This request came from another address. Open {origin} and try again",
|
|
@@ -295,7 +294,6 @@
|
|
|
295
294
|
"web.badToken": "The token is wrong",
|
|
296
295
|
"web.binary": "Binary file · {n} bytes. To replace it, upload a file with the same name on the directory page.",
|
|
297
296
|
"web.binaryChange": "binary · {from} → {to}",
|
|
298
|
-
"web.brand": "Guideline server",
|
|
299
297
|
"web.bytes": "{n} bytes",
|
|
300
298
|
"web.cancel": "Cancel",
|
|
301
299
|
"web.categories": "Categories",
|
|
@@ -365,7 +363,6 @@
|
|
|
365
363
|
"web.confirmDeleteDir": "Delete every file under {path}",
|
|
366
364
|
"web.count": "{n}",
|
|
367
365
|
"web.delete": "Delete",
|
|
368
|
-
"web.directory": "Directory",
|
|
369
366
|
"web.download": "Download",
|
|
370
367
|
"web.edit": "Edit",
|
|
371
368
|
"web.edit.conflict": "Someone saved while you had this open. Below is the difference between the current content (-) and yours (+). Check it and save again.",
|
|
@@ -376,17 +373,15 @@
|
|
|
376
373
|
"web.edit.textOnly": "Only text files can be edited. Upload binaries on the directory page",
|
|
377
374
|
"web.edit.title": "Edit: {path}",
|
|
378
375
|
"web.edit.warnings": "Saving leaves these warnings in the list (saving still works).",
|
|
379
|
-
"web.editReadme": "Edit README",
|
|
380
376
|
"web.empty": "No guidelines yet. Create one with \"New file\", or upload many at once with an admin token through the proposals API (POST /api/v1/proposals, apply: true).",
|
|
381
|
-
"web.fileCount": "{n} instruction files",
|
|
382
377
|
"web.files": "Files",
|
|
383
|
-
"web.find.agents": "Find
|
|
384
|
-
"web.find.mcp": "Find MCP
|
|
385
|
-
"web.find.skills": "Find
|
|
386
|
-
"web.find.stacks": "Find
|
|
378
|
+
"web.find.agents": "Find a subagent",
|
|
379
|
+
"web.find.mcp": "Find an MCP server",
|
|
380
|
+
"web.find.skills": "Find a skill",
|
|
381
|
+
"web.find.stacks": "Find a stack",
|
|
387
382
|
"web.firstTime.after": "",
|
|
388
383
|
"web.firstTime.before": "New here? Read the",
|
|
389
|
-
"web.firstTime.link": "usage guide
|
|
384
|
+
"web.firstTime.link": "usage guide",
|
|
390
385
|
"web.form.agents": "Agents",
|
|
391
386
|
"web.form.badLink": "The form link is wrong or the form is gone",
|
|
392
387
|
"web.form.byCategory": "Pick by category",
|
|
@@ -410,10 +405,9 @@
|
|
|
410
405
|
"web.login": "Log in",
|
|
411
406
|
"web.loginNeeded": "Login required",
|
|
412
407
|
"web.logout": "Log out",
|
|
413
|
-
"web.manage": "Rename ·
|
|
408
|
+
"web.manage": "Rename · delete this file",
|
|
414
409
|
"web.message": "Message",
|
|
415
410
|
"web.methodNotAllowed": "Method not allowed",
|
|
416
|
-
"web.nav.export": "Export",
|
|
417
411
|
"web.nav.history": "History",
|
|
418
412
|
"web.nav.kinds": "Kinds",
|
|
419
413
|
"web.nav.proposals": "Proposals",
|
|
@@ -422,11 +416,9 @@
|
|
|
422
416
|
"web.newFile": "New file",
|
|
423
417
|
"web.newPath": "New path",
|
|
424
418
|
"web.noDiff": "No differences",
|
|
425
|
-
"web.noDir": "No such directory",
|
|
426
419
|
"web.noHistory": "This path has no history",
|
|
427
420
|
"web.noPath": "No such path",
|
|
428
421
|
"web.noPathGiven": "No path given",
|
|
429
|
-
"web.noReadme": "There is no README.md.",
|
|
430
422
|
"web.noStack": "No such stack",
|
|
431
423
|
"web.noStacksInCategory": "No stacks in this category.",
|
|
432
424
|
"web.none": "none",
|
|
@@ -516,7 +508,7 @@
|
|
|
516
508
|
"web.tokens.confirmRevoke": "Revoke the token {name}",
|
|
517
509
|
"web.tokens.copyNow": "You cannot see this value again. Copy it now into the agent's environment.",
|
|
518
510
|
"web.tokens.created": "Created",
|
|
519
|
-
"web.tokens.intro": "Tokens
|
|
511
|
+
"web.tokens.intro": "Tokens agents use for the API. read can read, propose can also propose, and admin can also accept proposals and apply changes directly.",
|
|
520
512
|
"web.tokens.issueHeading": "Issue",
|
|
521
513
|
"web.tokens.issued": "Token issued",
|
|
522
514
|
"web.tokens.lastUsed": "Last used",
|
|
@@ -527,7 +519,6 @@
|
|
|
527
519
|
"web.tokens.revokedOn": "revoked {day}",
|
|
528
520
|
"web.tokens.scope": "Scope",
|
|
529
521
|
"web.tokens.status": "Status",
|
|
530
|
-
"web.up": "Up",
|
|
531
522
|
"web.upload.button": "Upload",
|
|
532
523
|
"web.upload.conflict": "A file with the same name changed in the meantime. Reload and upload again",
|
|
533
524
|
"web.upload.file": "File",
|
|
@@ -537,5 +528,41 @@
|
|
|
537
528
|
"web.warnings": "warnings {n}",
|
|
538
529
|
"web.warningsHeading": "Warnings",
|
|
539
530
|
"workspace.unknownSource": "Source {name} is not in guideline.json in {dir}",
|
|
540
|
-
"web.source.seed": "Seed"
|
|
531
|
+
"web.source.seed": "Seed",
|
|
532
|
+
"web.tokens.delete": "Delete",
|
|
533
|
+
"web.tokens.confirmDelete": "Delete the token {name}?",
|
|
534
|
+
"web.tokens.adminWarning": "An admin token can change the source directly, without proposal review. Issue it only to agents you trust.",
|
|
535
|
+
"propose.applied": "Applied: r{rev} — {url}",
|
|
536
|
+
"propose.appliedNothing": "Nothing changed — same as the source",
|
|
537
|
+
"propose.applyDenied": "An admin token is needed — get a token with scope admin from an admin and store it with guideline login --server {server} --token-stdin",
|
|
538
|
+
"catalog.badDomain": "the part after __ is not a domain — use <tool>__<domain>",
|
|
539
|
+
"web.nav.settings": "Settings",
|
|
540
|
+
"web.archive": "Download (.tar.gz)",
|
|
541
|
+
"web.noBlock": "No such block",
|
|
542
|
+
"web.add.stack": "+ Add stack",
|
|
543
|
+
"web.add.skill": "+ Add skill",
|
|
544
|
+
"web.add.agent": "+ Add subagent",
|
|
545
|
+
"web.add.mcp": "+ Add MCP server",
|
|
546
|
+
"web.add.kind.stack": "Stack",
|
|
547
|
+
"web.add.kind.skill": "Skill",
|
|
548
|
+
"web.add.kind.agent": "Subagent",
|
|
549
|
+
"web.add.kind.mcp": "MCP server",
|
|
550
|
+
"web.add.title": "Add {kind}",
|
|
551
|
+
"web.add.name": "Name",
|
|
552
|
+
"web.add.domain": "Domain (optional)",
|
|
553
|
+
"web.add.categories": "Categories (comma-separated)",
|
|
554
|
+
"web.add.submit": "Add",
|
|
555
|
+
"web.add.badName": "The name starts with a lowercase letter and uses only lowercase letters, digits and -",
|
|
556
|
+
"web.add.badDomain": "Not a domain",
|
|
557
|
+
"web.add.exists": "That name already exists",
|
|
558
|
+
"web.add.message": "Add: {name}",
|
|
559
|
+
"web.settings.title": "Settings",
|
|
560
|
+
"web.settings.files": "Files outside blocks",
|
|
561
|
+
"web.settings.intro": "Files that belong to no block, items left out of the lists, and warnings.",
|
|
562
|
+
"web.settings.problems": "Warnings {warnings} · ignored {ignored} — see Settings",
|
|
563
|
+
"web.usage.title": "Usage",
|
|
564
|
+
"web.usage.copy": "Copy link",
|
|
565
|
+
"web.usage.raw": "Raw",
|
|
566
|
+
"web.client.copied": "Copied",
|
|
567
|
+
"web.manageBlock": "Rename · delete this block"
|
|
541
568
|
}
|
|
@@ -128,6 +128,13 @@ Setup that must be done when adopting a stack or on every clone (config files, h
|
|
|
128
128
|
|
|
129
129
|
Do not invent a Why. If you do not know the reason, hold off on adding the rule.
|
|
130
130
|
|
|
131
|
+
## Domain stacks
|
|
132
|
+
|
|
133
|
+
The same tool can need different rules on different servers (companies, instances). Then name the stack `<tool>__<domain>`. Examples: `deploy-package__gitlab.develma.com`, `deploy-agent__deploy.kbrainc.dev`.
|
|
134
|
+
|
|
135
|
+
- Use `__` once. The part after it must look like a domain (lowercase letters, digits, `-`, and at least one dot). Otherwise `guideline list` shows a warning (the stack still works).
|
|
136
|
+
- The web shows the tool name with the domain as a tag. Project paths (`.ruler/<stack>/`) and CLI output keep the full name.
|
|
137
|
+
|
|
131
138
|
## Skeleton stacks
|
|
132
139
|
|
|
133
140
|
A `rules/<stack>/` with only `README.md` is a skeleton and does not appear in `guideline list`. It becomes a stack the moment its first guideline file (`NN-*.md`) is added.
|
|
@@ -40,6 +40,7 @@ guideline update --force # also overwrite files edited in the project
|
|
|
40
40
|
|
|
41
41
|
- `pick` sends only the result of comparing the project with the source to the server and prints the form address (`Form: <address>` on stderr). It waits until items are checked in the form and submitted. MCP values (secrets) are not sent.
|
|
42
42
|
- Form states: "same" is already applied, "different" means the project copy differs from the source (turn on "update" to overwrite it), "missing" is not there yet (check it to add). Unchecking an existing item means "remove". Category buttons check every item in that category.
|
|
43
|
+
- A domain stack `<tool>__<domain>` (e.g. `deploy-package__gitlab.develma.com`) holds the rules for using that tool on that server. Pick only stacks whose domain matches the server the project uses.
|
|
43
44
|
- Where copies go: always-on guidelines in `.ruler/<stack>/NN-*.md`, reference guidelines in `docs/guideline/<stack>/` with the index `.ruler/<stack>/99-reference.md`, skills in `.ruler/skills/`, MCP in `.ruler/ruler.toml`. After applying, `ruler apply` runs at the git root (when ruler is installed).
|
|
44
45
|
- Applying creates `guideline.json` (chosen items) and `guideline-lock.json` (applied revision and hashes). Commit them with the applied files. The CLI does not commit.
|
|
45
46
|
- **Monorepos**: run in a subdirectory with its own `.ruler/` and that directory becomes a separate unit, with its own manifest, lock and copies. Skills, subagents and MCP servers are received only at the git root. ruler builds that directory's guidelines only when `.ruler/ruler.toml` at the git root has `nested = true`.
|
|
@@ -122,8 +123,9 @@ guideline propose --from <that folder> --title "<title>" # send what was added
|
|
|
122
123
|
- `GET {{SERVER}}/api/v1/catalog`: stacks, skills, subagents, MCP servers and their categories
|
|
123
124
|
- `GET {{SERVER}}/api/v1/archive?rev=<revision>`: the whole source (tar.gz)
|
|
124
125
|
- `GET {{SERVER}}/api/v1/files/<path>?rev=<revision>`: one source file
|
|
125
|
-
- `POST {{SERVER}}/api/v1/proposals`: a proposal (`propose` scope token). Body `{ title, description?, project?, changes: [{ path, text | base64 | delete: true, base: <sha256> | null }] }`. An admin token can use `apply: true` to apply it right away without review
|
|
126
|
-
- `GET {{SERVER}}/api/v1/proposals`, `GET {{SERVER}}/api/v1/proposals/<number>`: the status of your proposals
|
|
126
|
+
- `POST {{SERVER}}/api/v1/proposals`: a proposal (`propose` scope token). Body `{ title, description?, project?, changes: [{ path, text | base64 | delete: true, base: <sha256> | null }] }`. An admin token or an `admin` scope token can use `apply: true` to apply it right away without review. From the CLI: `guideline propose --apply`
|
|
127
|
+
- `GET {{SERVER}}/api/v1/proposals`, `GET {{SERVER}}/api/v1/proposals/<number>`: the status of your proposals (an `admin` scope token sees all)
|
|
128
|
+
- `POST {{SERVER}}/api/v1/proposals/<number>/accept`, `POST {{SERVER}}/api/v1/proposals/<number>/reject` (body `{ note? }`): accept or reject a proposal (admin token or `admin` scope token). A conflict is 409 with `conflicts`
|
|
127
129
|
|
|
128
130
|
## More
|
|
129
131
|
|
|
@@ -13,6 +13,7 @@ description: Proposes sections of this project's guidelines that other projects
|
|
|
13
13
|
|
|
14
14
|
1. **Get the source.** Pick an empty temporary folder (for example `src` under `mktemp -d`) and run `guideline source <folder>`. If this project's `guideline.json` has more than one source, ask the user which source (guideline server) to upload to and run `guideline source <folder> --source <name>`. Below, this is the "source folder". If you see "Login required", point the user to `! guideline login --server <URL>` and stop.
|
|
15
15
|
2. **Permission to propose.** If uploading says "This token cannot propose", tell the user to get a token with the `propose` scope from an admin and store it with `guideline login --server <URL> --token-stdin`, then stop.
|
|
16
|
+
- Only when the stored token has the `admin` scope and the user asked to apply without review, upload with `guideline propose --from <source folder> --title <title> --apply`. If it says "An admin token is needed", upload as a proposal without `--apply`.
|
|
16
17
|
3. If `<source folder>/docs/authoring.md` has no `## Subagents` or `## MCP servers` section, stop before uploading subagents or MCP servers and ask the guideline admin to add that section to the source. When uploading an MCP server built from its README, also read the `### Servers built when applied` section.
|
|
17
18
|
4. If `<source folder>/docs/authoring.md` has no `## Load — always and reference` section, stop the same way before uploading guideline files. The rule for choosing the load is in that section. When uploading an override of another stack, also read the `## Overriding another stack` section.
|
|
18
19
|
5. **Edits to received copies are not this skill's job.** Copies that `guideline status` shows as "edited in project" are sent with `guideline propose` (it turns the copy back into source form). This skill uploads guidelines that are new to the source. `propose` leaves out copies that already differed from the source when first received (to-do `adopted`), because proposing an old version would undo source changes.
|