vibecoding-devtools 1.0.1 → 1.1.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.
Files changed (44) hide show
  1. package/README.md +6 -5
  2. package/hooks/maestri-protocol.mjs +4 -3
  3. package/installer/cli.mjs +8 -0
  4. package/installer/codex-maestri.rules +13 -0
  5. package/installer/env-list.mjs +70 -0
  6. package/installer/execute.mjs +409 -386
  7. package/installer/json-merge.mjs +4 -4
  8. package/installer/plan.mjs +31 -1
  9. package/installer/team-checks.mjs +86 -0
  10. package/installer/team.mjs +260 -0
  11. package/npm-shrinkwrap.json +2 -2
  12. package/package.json +4 -2
  13. package/rules/maestri-usage.md +2 -0
  14. package/skills/maestri-agent-cli/SKILL.md +4 -2
  15. package/skills/maestri-agent-cli/references/antigravity.md +24 -0
  16. package/skills/maestri-agent-cli/references/codex.md +16 -0
  17. package/skills/maestri-protocol/SKILL.md +12 -7
  18. package/team/README.md +139 -0
  19. package/team/notes/project-context/acceptance-criteria.md +6 -0
  20. package/team/notes/project-context/code-standards.md +8 -0
  21. package/team/notes/project-context/contracts-integrations.md +10 -0
  22. package/team/notes/project-context/decisions.md +7 -0
  23. package/team/notes/project-context/design-system.md +8 -0
  24. package/team/notes/project-context/ops-runbook.md +10 -0
  25. package/team/notes/project-context/requirements.md +23 -0
  26. package/team/notes/project-context/risks-backlog.md +6 -0
  27. package/team/notes/team-roster.md +67 -0
  28. package/team/partitura/vibecoding-devtools.maestripartitura +4908 -0
  29. package/team/roles/_team-protocol.md +12 -0
  30. package/team/roles/appsec-auditor.md +45 -0
  31. package/team/roles/backend-architect.md +44 -0
  32. package/team/roles/backend-engineer.md +44 -0
  33. package/team/roles/code-reviewer.md +43 -0
  34. package/team/roles/devops-engineer.md +41 -0
  35. package/team/roles/frontend-engineer.md +45 -0
  36. package/team/roles/qa-engineer.md +41 -0
  37. package/team/roles/research-analyst.md +34 -0
  38. package/team/roles/task-runner.md +26 -0
  39. package/team/roles/team-maestro.md +80 -0
  40. package/team/roles/ux-ui-designer.md +49 -0
  41. package/team/roles/visual-asset-designer.md +45 -0
  42. package/team/roles/visual-qa-inspector.md +36 -0
  43. package/team/settings/task-runner-limited.json +55 -0
  44. package/team/team.json +59 -0
package/README.md CHANGED
@@ -10,12 +10,12 @@ instalados das fontes oficiais.
10
10
  ## Instalação
11
11
 
12
12
  ```bash
13
- npx vibecoding-devtools@1.0.1 install # instala pelo painel
14
- npx vibecoding-devtools@1.0.1 update # reutiliza as escolhas salvas
15
- npx vibecoding-devtools@1.0.1 uninstall # remove só o que o kit instalou
13
+ npx vibecoding-devtools@1.1.0 install # instala pelo painel
14
+ npx vibecoding-devtools@1.1.0 update # reutiliza as escolhas salvas
15
+ npx vibecoding-devtools@1.1.0 uninstall # remove só o que o kit instalou
16
16
  ```
17
17
 
18
- Alternativa pelo GitHub: `npx github:Or4cu1o/vibecoding-devtools#v1.0.1 install` (aceita os mesmos comandos).
18
+ Alternativa pelo GitHub: `npx github:Or4cu1o/vibecoding-devtools#v1.1.0 install` (aceita os mesmos comandos).
19
19
 
20
20
  Requer Node 22+ e git. O instalador detecta Claude Code, Codex e Antigravity, mostra o plano e só grava depois da
21
21
  confirmação. Use `--dry-run` para apenas conferir o plano. Detalhes no [guia do instalador](docs/installer.md).
@@ -28,7 +28,8 @@ confirmação. Use `--dry-run` para apenas conferir o plano. Detalhes no [guia d
28
28
  | [`skills/`](skills/) | triagem de risco, revisão de segurança e operação do Maestri |
29
29
  | [`templates/`](templates/) | `AGENTS.md` e `CLAUDE.md` para projetos, e `.coderabbit.yaml` |
30
30
  | [Hooks](hooks/README.md) | `secret-scan`, `maestri-protocol` e `full-suite` implementados |
31
- | [`docs/`](docs/) | instalação, compatibilidade e justificativas das regras |
31
+ | [`team/`](team/README.md) | equipe de 13 agentes para o Maestri (roles, notas, partitura `vibecoding-devtools`), instalada com `npx vibecoding-devtools team` |
32
+ | [`docs/`](docs/) | instalação, compatibilidade, Maestri em máquina remota e justificativas das regras |
32
33
 
33
34
  O `secret-scan` verifica segredos com gitleaks antes de commits. O `maestri-protocol` valida mensagens e exige o pacote
34
35
  Maestri. O `full-suite` aplica um bloqueio contornável a suítes completas em repositórios com CI; para uma execução
@@ -6,9 +6,10 @@ const reason = 'Maestri message must use a valid protocol header or end with the
6
6
  export function validMessage(message) {
7
7
  const text = message.replace(/\r\n/g, '\n');
8
8
  if (text.startsWith('~')) return header.test(text.split('\n')[0]);
9
- // Match the skill footer at the end, including its report-back instruction.
10
- const footer = text.match(/(?:^|\n)ref: ([^\n]+)\nWhen done, load the maestri-protocol skill and report back with:\nmaestri ask "([^"\n]+)" "~ ([^|\n]+?) \| STATUS \| ([^|\n]+?) \| one-line summary"\nSTATUS is one of DONE, PENDING, BLOCKED, ERROR, ACK\. Details go on the following lines\.\s*$/);
11
- return Boolean(footer && footer[1] === footer[4]);
9
+ // Match the skill footer at the end, including its report-back instruction. Its quotes may be double or single,
10
+ // each pair matching, so a prompt already wrapped in double quotes can carry the footer unescaped.
11
+ const footer = text.match(/(?:^|\n)ref: ([^\n]+)\nWhen done, load the maestri-protocol skill and report back with:\nmaestri ask (["'])((?:(?!\2)[^\n])+)\2 (["'])~ ([^|\n]+?) \| STATUS \| ([^|\n]+?) \| one-line summary\4\nSTATUS is one of DONE, PENDING, BLOCKED, ERROR, ACK\. Details go on the following lines\.\s*$/);
12
+ return Boolean(footer && footer[1] === footer[6]);
12
13
  }
13
14
 
14
15
  function messages(words) {
package/installer/cli.mjs CHANGED
@@ -10,9 +10,12 @@ import { readState, hashContent } from './state.mjs';
10
10
  import { parseFlags, choicesFromFlags, panel, confirmExecution, Cancellation } from './panel.mjs';
11
11
  import * as thirdPartyApi from './third-party.mjs';
12
12
  import { jsonMergeSituation } from './json-merge.mjs';
13
+ import { envListSituation } from './env-list.mjs';
13
14
  import { CODEX_HOOK_APPROVAL } from './hooks.mjs';
15
+ import { teamMain } from './team.mjs';
14
16
 
15
17
  export const HELP = `Usage: vibecoding-devtools [install|update|detect|uninstall] [flags]
18
+ vibecoding-devtools team [--roles-only] [--update-roles] [--dry-run] (Maestri team; see team --help)
16
19
  Default command: install. Without a TTY: use --yes to apply or --dry-run to preview.
17
20
  Update reuses saved install choices; explicit flags override them. Run install first if no choices are saved.
18
21
  Update removes unchanged kit-owned items absent from the new plan; edited and third-party items are retained.
@@ -76,6 +79,10 @@ export function summarizePlan(plan, { home, force = false } = {}) {
76
79
  const previous = state.items.find((i) => i.type === action.type && i.destination === action.destination);
77
80
  return { ...action, situation: jsonMergeSituation(current, action, previous) };
78
81
  }
82
+ if (action.type === 'env-list') {
83
+ const previous = state.items.find((i) => i.type === action.type && i.destination === action.destination);
84
+ return { ...action, situation: envListSituation(current, action, previous) };
85
+ }
79
86
  let desired;
80
87
  if (action.type === 'block') {
81
88
  const text = current?.toString('utf8') ?? '';
@@ -148,6 +155,7 @@ export async function main(argv = process.argv.slice(2), options = {}) {
148
155
  isTTY = Boolean(process.stdin.isTTY && process.stdout.isTTY), out = console.log, err = console.error,
149
156
  detect = detectAll, choose = panel, confirm = confirmExecution, prepareThirdParty: prepare, thirdParty = thirdPartyApi,
150
157
  planBuilder = buildPlan, apply = execute, remove = uninstall } = options;
158
+ if (argv[0] === 'team') return teamMain(argv.slice(1), { kit, out, err, home });
151
159
  let flags;
152
160
  let warnings = [];
153
161
  let errorCode = 2;
@@ -0,0 +1,13 @@
1
+ # vibecoding-devtools: Maestri commands Codex agents run outside the sandbox without a human prompt.
2
+ # Installed globally as ~/.codex/rules/vibecoding-devtools-maestri.rules when the Maestri pack is selected.
3
+ prefix_rule(pattern = ["maestri", "ask"], decision = "allow")
4
+ prefix_rule(pattern = ["maestri", "check"], decision = "allow")
5
+ prefix_rule(pattern = ["maestri", "list"], decision = "allow")
6
+ prefix_rule(pattern = ["maestri", "recall"], decision = "allow")
7
+ prefix_rule(pattern = ["maestri", "floor", "status"], decision = "allow")
8
+ prefix_rule(pattern = ["maestri", "note", "read"], decision = "allow")
9
+ prefix_rule(pattern = ["maestri", "note", "edit"], decision = "allow")
10
+ prefix_rule(pattern = ["maestri", "portal"], decision = "allow")
11
+ prefix_rule(pattern = ["maestri", "portal", "close"], decision = "forbidden")
12
+ prefix_rule(pattern = ["maestri", "note", "delete"], decision = "forbidden")
13
+ prefix_rule(pattern = ["maestri", "dismiss"], decision = "forbidden")
@@ -0,0 +1,70 @@
1
+ // Kit values inside one comma-separated string of a JSON settings file's `env` object, such as
2
+ // GATEGUARD_EXEMPT_GLOBS in ~/.claude/settings.json. The rest of the file stays byte for byte; the value keeps the
3
+ // user's entries and spacing (the string is written back with JSON escaping, so escapes such as \u002f decode).
4
+ import { isUtf8 } from 'node:buffer';
5
+ import { append, parse, property, removeChild } from './json-merge.mjs';
6
+
7
+ function validate(action) {
8
+ if (typeof action.key !== 'string' || !/^[A-Za-z_][A-Za-z0-9_]*$/.test(action.key) || !Array.isArray(action.values)
9
+ || !action.values.length || action.values.some((v) => typeof v !== 'string' || !v.trim() || v.includes(','))) {
10
+ throw new Error('Invalid env list action');
11
+ }
12
+ }
13
+
14
+ function locate(text, key) {
15
+ const root = parse(text);
16
+ const env = property(root, 'env');
17
+ if (env && env.node.kind !== 'object') throw new Error('env must be a JSON object');
18
+ const entry = env && property(env.node, key);
19
+ if (entry && typeof entry.node.value !== 'string') throw new Error(`env.${key} must be a string`);
20
+ return { root, env, entry };
21
+ }
22
+
23
+ // `record` is the state item of an earlier install: its values, the ones the user already had (`preexisting`, never
24
+ // removed) and the containers the kit created. Install adds the missing values and drops values an earlier kit
25
+ // version added and this one no longer lists; remove drops the kit's values.
26
+ export function envListMerge(current, action, record = null, { remove = false } = {}) {
27
+ validate(action);
28
+ if (current !== null && !isUtf8(current)) throw new Error('Settings file is not valid UTF-8');
29
+ const text = current === null ? '{}\n' : current.toString('utf8');
30
+ const { root, env, entry } = locate(text, action.key);
31
+ // Raw segments keep the user's spacing; values compare trimmed.
32
+ const parts = entry ? entry.node.value.split(',') : [];
33
+ const list = parts.map((v) => v.trim()).filter(Boolean);
34
+ // A value the user had before the kit first listed it stays theirs, including values a later kit version adds.
35
+ const preexisting = [...new Set([...(record?.preexisting ?? []),
36
+ ...action.values.filter((v) => list.includes(v) && !(record?.values ?? []).includes(v))])];
37
+ const createdPaths = record?.createdPaths ?? [...(entry ? [] : [['env', action.key]]), ...(env ? [] : [['env']])];
38
+ const wanted = remove ? [] : action.values;
39
+ const dropped = new Set([...(record?.values ?? []), ...(remove ? action.values : [])]
40
+ .filter((v) => !preexisting.includes(v) && !wanted.includes(v)));
41
+ const added = wanted.filter((v) => !list.includes(v));
42
+ const result = { preexisting, createdPaths };
43
+ if (!added.length && !list.some((v) => dropped.has(v))) return { ...result, same: true, content: current };
44
+
45
+ const kept = parts.filter((v) => !dropped.has(v.trim()));
46
+ const next = [...(kept.some((v) => v.trim()) ? kept : []), ...added];
47
+ const created = (keys) => createdPaths.some((p) => p.join('\0') === keys.join('\0'));
48
+ const joined = next.join(',');
49
+ let out;
50
+ if (next.length && entry) out = text.slice(0, entry.node.start) + JSON.stringify(joined) + text.slice(entry.node.end);
51
+ else if (next.length) {
52
+ out = env ? append(text, env.node, action.key, joined) : append(text, root, 'env', { [action.key]: joined });
53
+ } else if (created(['env', action.key])) {
54
+ out = removeChild(text, env.node, entry);
55
+ const rest = parse(out);
56
+ const after = property(rest, 'env');
57
+ if (created(['env']) && !after.node.children.length) out = removeChild(out, rest, after);
58
+ } else out = text.slice(0, entry.node.start) + '""' + text.slice(entry.node.end);
59
+ return { ...result, same: false, content: Buffer.from(out) };
60
+ }
61
+
62
+ // Same bytes with another value list in the state is an update: the state must stop owning values the kit dropped.
63
+ export const envListStale = (record, action) => JSON.stringify(record?.values) !== JSON.stringify(action.values);
64
+
65
+ export function envListSituation(current, action, previous) {
66
+ try {
67
+ if (envListMerge(current, action, previous).same && !(previous && envListStale(previous, action))) return 'same';
68
+ return previous ? 'update' : 'new';
69
+ } catch { return 'conflict'; }
70
+ }