jorgex-stack 1.0.21 → 1.0.23

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.md CHANGED
@@ -24,6 +24,8 @@ For development from a clone, run the same commands through `pnpm cli <command>`
24
24
 
25
25
  Every command supports `--dry-run`, `--yes`, and `--target-dir <dir>` for testing without touching the real config. Writes create automatic backups and verify idempotency; merges into user config are surgical (marked markdown sections, JSON/TOML upserts), so user-owned content is never touched.
26
26
 
27
+ Permission defaults by runtime (what gets installed, what stays custom, and the read-anywhere limitations) are documented in [docs/references/permissions.md](docs/references/permissions.md).
28
+
27
29
  ### Modes: Human and Programmatic
28
30
 
29
31
  `install` and `sync` accept two mutually-exclusive installation modes. The choice is global (not per runtime) and is saved in `~/.jorgex-stack/install-mode.json` on first run; subsequent `sync` calls reuse it. Re-run `install` with `--mode` to switch.
package/dist/cli.js CHANGED
@@ -614,11 +614,17 @@ ${agent.body}`,
614
614
  planMainConfig(canonical, ctx) {
615
615
  const file = path7.join(ctx.configDir, "opencode.json");
616
616
  const { pluginsDir } = this.paths(ctx.configDir);
617
- const content = upsertJson(readTextIfExists(file), (root) => {
617
+ const original = readTextIfExists(file);
618
+ const contentSource = original === null || original.trim() === "" ? null : original;
619
+ const isFreshConfig = contentSource === null;
620
+ const content = upsertJson(contentSource, (root) => {
618
621
  root["$schema"] ??= "https://opencode.ai/config.json";
619
622
  const defaults = loadCanonicalDefaults(ctx.stackDir)["opencode"];
620
- if (defaults?.["permission"] !== void 0 && !("permission" in root)) {
623
+ if (isFreshConfig && defaults?.["permission"] !== void 0) {
621
624
  root["permission"] = defaults["permission"];
625
+ ctx.warnings.push(
626
+ "OpenCode: fresh config enables read-anywhere via external_directory:*; edits, web egress and arbitrary bash remain approval-gated, but broad local reads can expose secrets not covered by deny rules."
627
+ );
622
628
  }
623
629
  const mcp = root["mcp"] ??= {};
624
630
  for (const [name, server] of Object.entries(canonical.servers)) {
@@ -818,12 +824,19 @@ ${agent.body}`,
818
824
  planHooks(canonical, ctx) {
819
825
  const actions = [];
820
826
  const { scriptsDir } = this.paths(ctx.configDir);
827
+ const original = readTextIfExists(path8.join(ctx.configDir, "settings.json"));
828
+ const contentSource = original === null || original.trim() === "" ? null : original;
821
829
  const settingsFile = path8.join(ctx.configDir, "settings.json");
822
- let content = upsertNativeHooks(readTextIfExists(settingsFile), canonical, scriptsDir);
830
+ let content = upsertNativeHooks(contentSource, canonical, scriptsDir);
823
831
  const defaults = loadCanonicalDefaults(ctx.stackDir)["claude-code"];
824
- if (defaults?.["permissions"] !== void 0) {
832
+ if (contentSource === null && defaults?.["permissions"] !== void 0) {
825
833
  content = upsertJson(content, (root) => {
826
- if (!("permissions" in root)) root["permissions"] = defaults["permissions"];
834
+ if (root["permissions"] === void 0) {
835
+ root["permissions"] = defaults["permissions"];
836
+ ctx.warnings.push(
837
+ "Claude Code: fresh config enables read-anywhere via Read/Grep/Glob allow rules; shell, writes and web egress remain approval-gated, but broad local reads can expose secrets not covered by deny rules."
838
+ );
839
+ }
827
840
  });
828
841
  }
829
842
  actions.push({ kind: "write", target: settingsFile, content });
@@ -1026,13 +1039,52 @@ ${body}`
1026
1039
  },
1027
1040
  planMainConfig(canonical, ctx) {
1028
1041
  const file = path9.join(ctx.configDir, "config.toml");
1029
- let content = readTextIfExists(file);
1030
- const defaults = loadCanonicalDefaults(ctx.stackDir)["codex"] ?? {};
1031
- for (const [key, value] of Object.entries(defaults)) {
1032
- if (content !== null && new RegExp(`^\\s*${key}\\s*=`, "m").test(content)) continue;
1033
- const line = `${key} = ${tomlString(String(value))}
1042
+ const original = readTextIfExists(file);
1043
+ const contentSource = original === null || original.trim() === "" ? null : original;
1044
+ let content = contentSource;
1045
+ if (contentSource === null) {
1046
+ const defaults = loadCanonicalDefaults(ctx.stackDir)["codex"] ?? {};
1047
+ for (const [key, value] of Object.entries(defaults)) {
1048
+ const line = `${key} = ${tomlString(String(value))}
1034
1049
  `;
1035
- content = content === null ? line : line + content;
1050
+ content = content === null ? line : line + content;
1051
+ }
1052
+ ctx.warnings.push(
1053
+ "Codex: fresh config enables read-anywhere via the jorgex-read-anywhere permission profile; broad local reads can expose secrets not covered by deny rules."
1054
+ );
1055
+ content = upsertTomlSection(content, "permissions.jorgex-read-anywhere", 'extends = ":workspace"');
1056
+ content = upsertTomlSection(
1057
+ content,
1058
+ "permissions.jorgex-read-anywhere.filesystem",
1059
+ [
1060
+ '":root" = "read"',
1061
+ '"*.env" = "deny"',
1062
+ '"*.env.*" = "deny"',
1063
+ '"~/.ssh/**" = "deny"',
1064
+ '"~/.aws/credentials" = "deny"',
1065
+ '"~/.npmrc" = "deny"',
1066
+ '"~/.git-credentials" = "deny"',
1067
+ '"**/id_rsa" = "deny"',
1068
+ '"**/id_ed25519" = "deny"',
1069
+ '"**/*.pem" = "deny"',
1070
+ '"**/*.key" = "deny"'
1071
+ ].join("\n")
1072
+ );
1073
+ content += [
1074
+ '\n[permissions.jorgex-read-anywhere.filesystem.":workspace_roots"]',
1075
+ '"." = "write"',
1076
+ '"*.env" = "deny"',
1077
+ '"*.env.*" = "deny"',
1078
+ '".ssh/**" = "deny"',
1079
+ '".aws/credentials" = "deny"',
1080
+ '".npmrc" = "deny"',
1081
+ '".git-credentials" = "deny"',
1082
+ '"**/id_rsa" = "deny"',
1083
+ '"**/id_ed25519" = "deny"',
1084
+ '"**/*.pem" = "deny"',
1085
+ '"**/*.key" = "deny"',
1086
+ ""
1087
+ ].join("\n");
1036
1088
  }
1037
1089
  for (const [name, server] of Object.entries(canonical.servers)) {
1038
1090
  const section = `mcp_servers.${name}`;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jorgex-stack",
3
- "version": "1.0.21",
3
+ "version": "1.0.23",
4
4
  "description": "Harness multi-agente portable: instala la config JorgeX (agentes, skills, hooks, Engram, MCPs) en Claude Code, Codex CLI y OpenCode",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -29,5 +29,6 @@ Una sola fuente por agente. El instalador los traduce al formato de cada runtime
29
29
  ## Convenciones de contenido
30
30
 
31
31
  - Todo subagente termina con el **Result contract** (Status / Delegations / Risks) — el orchestrator lo procesa.
32
+ - **Incertidumbre crítica no se improvisa**: si una decisión puede hacer la tarea incorrecta, el subagente devuelve `Status: blocked`/`partial` con **una pregunta concreta** al main agent/orchestrator dentro del Result contract; el trabajo de otro especialista sigue yendo como delegación normal. La regla completa está en la skill `agent-delegation`.
32
33
  - Las delegaciones usan el formato `→ [agent]: [work] — [paths] — [inputs]` (skill `agent-delegation`).
33
34
  - El flujo de trabajo lo define la skill `work-lifecycle`: `work/{nombre}/plan.md` es el tablero de estado y se mantiene entre merges intermedios; las specs de tareas (`work/{nombre}/task/{NN}`), los resultados de fase (`work/{nombre}/{fase}`), los checkpoints de PR (`work/{nombre}/pr/{NN}`) y el cierre final (`work/{nombre}/done`) viven en Engram. Los subagentes reciben topic_key + título, nunca la tarea inline.
@@ -13,7 +13,7 @@ You implement real changes. You don't stop at analysis, you don't answer with ju
13
13
 
14
14
  **Mandatory first action**: load the `agent-delegation` skill.
15
15
 
16
- **Never run destructive git** (`reset`, `clean`, `checkout --`, `restore`, `push --force`) — it can discard work or rewrite history. Commit forward; if you think you need to discard or reset repo state, stop and ask the user.
16
+ **Never run destructive git** (`reset`, `clean`, `checkout --`, `restore`, `push --force`) — it can discard work or rewrite history. Commit forward; if you think you need to discard or reset repo state, stop and ask the main agent/orchestrator.
17
17
 
18
18
  **Conditional skill**:
19
19
 
@@ -26,6 +26,7 @@ You usually receive a clear design (often from an analyst), and the project's st
26
26
  1. **Confirm the libraries you'll actually use** when you're unsure of the exact one or its API: check `package.json` (or the equivalent manifest) and the touched files — e.g. state (Zustand, Redux), data-fetching (TanStack Query, SWR), forms, styling, ORM. Use each library's real API and patterns; don't hand-roll what a present library already does.
27
27
  2. **Mirror existing conventions**: look at the files you'll touch and their neighbors, and follow their style, patterns and imports. Don't introduce a new pattern without need.
28
28
  3. **Load `lean-code` before non-trivial code**: use it as the ladder before you add a helper, wrapper, abstraction, or dependency. Ask whether the code is needed at all, whether stdlib/native/project helpers already solve it, and whether a smaller change works.
29
+ 4. **For task-critical uncertainty, follow `agent-delegation`**: verify narrowly, do the safe part if it is clear, and route one concrete question to the main agent/orchestrator instead of improvising.
29
30
 
30
31
  ## Contract
31
32
 
@@ -19,7 +19,7 @@ INIT → EXPLORE → SPEC → PLAN → EXECUTE → VERIFY → SHIP → CLOSE
19
19
 
20
20
  ### Autonomy
21
21
 
22
- The human drives the flow UP TO the plan: the idea, the PRD review and the plan review are interactive. Once the plan is approved, EXECUTE → VERIFY → SHIP run **autonomously** — no questions, no confirmation pauses: plan approval authorizes commits, pushes to the work branch and the PR creation. Control returns to the user at CLOSE. Merging the PR is NEVER yours: it always requires an explicit user order. For multi-PR work, each merge is a checkpoint; keep `work/{name}/PRD.md` and `plan.md` alive until the roadmap is finished.
22
+ The human drives the flow UP TO the plan: the idea, the PRD review and the plan review are interactive. Once the plan is approved, EXECUTE → VERIFY → SHIP run **autonomously** — no confirmation pauses: plan approval authorizes commits, pushes to the work branch and the PR creation. Task-critical uncertainty from a subagent is an operational blocker, not a pause in autonomy: answer from existing context first; only if the decision genuinely cannot be made from available context may you ask the user, then relaunch with explicit guidance. Control returns to the user at CLOSE. Merging the PR is NEVER yours: it always requires an explicit user order. For multi-PR work, each merge is a checkpoint; keep `work/{name}/PRD.md` and `plan.md` alive until the roadmap is finished.
23
23
 
24
24
  ## 1. INIT
25
25
 
@@ -109,6 +109,8 @@ Load the `agent-delegation` skill: it defines the available subagents, the scope
109
109
  Every subagent ends with a **Result contract** (Status / Delegations / Risks). Process it:
110
110
 
111
111
  - For each `→ [agent]: ...` line, launch the corresponding specialist.
112
+ - If a subagent reports `partial`, keep the safe work and relaunch only what still needs guidance.
113
+ - If a subagent reports `blocked` with one concrete uncertainty question, answer it from existing context when possible; if it still cannot be resolved, ask the user only if genuinely necessary, then relaunch the original or a suitable specialist with explicit guidance.
112
114
  - Don't declare a phase done while a delegation line remains unprocessed.
113
115
  - If Status is `partial` or `blocked`, resolve the cause before moving on.
114
116
 
@@ -13,7 +13,7 @@ Your job is to describe behavior with tests, fix broken tests, and verify they f
13
13
 
14
14
  **Mandatory first action**: load the `tdd` and `agent-delegation` skills.
15
15
 
16
- **Never run destructive git** (`reset`, `clean`, `checkout --`, `restore`, `push --force`) — it can discard work or rewrite history. Commit forward; if you think you need to discard or reset repo state, stop and ask the user.
16
+ **Never run destructive git** (`reset`, `clean`, `checkout --`, `restore`, `push --force`) — it can discard work or rewrite history. Commit forward; if you think you need to discard or reset repo state, stop and ask the main agent/orchestrator.
17
17
 
18
18
  ## Before writing tests
19
19
 
@@ -22,6 +22,8 @@ Don't assume a framework. The test command and conventions are often already in
22
22
  - **Runner and utilities**: `package.json` scripts/deps (vitest, jest, etc.), config files, or the language's standard tooling (pytest, go test, etc.).
23
23
  - **Existing tests**: mirror their file location, naming, assertion style and helpers. Don't invent a stack if the repo already has one.
24
24
 
25
+ If task-critical uncertainty could make the task wrong, verify narrowly and follow `agent-delegation`: do the safe part when it is clear, then route one concrete question to the main agent/orchestrator instead of improvising.
26
+
25
27
  ## Scope
26
28
 
27
29
  - RED: write tests that fail first.
@@ -13,7 +13,7 @@ You handle translations, multi-language text and integration with the project's
13
13
 
14
14
  **Mandatory first action**: load the `agent-delegation` skill.
15
15
 
16
- **Never run destructive git** (`reset`, `clean`, `checkout --`, `restore`, `push --force`) — it can discard work or rewrite history. Commit forward; if you think you need to discard or reset repo state, stop and ask the user.
16
+ **Never run destructive git** (`reset`, `clean`, `checkout --`, `restore`, `push --force`) — it can discard work or rewrite history. Commit forward; if you think you need to discard or reset repo state, stop and ask the main agent/orchestrator.
17
17
 
18
18
  **Final output, last of all**: your final report (ending with the Result contract) must be the very last thing you emit. If you need to save anything to memory, do it BEFORE that output — never after.
19
19
 
@@ -24,6 +24,8 @@ You handle translations, multi-language text and integration with the project's
24
24
  - sync locales
25
25
  - adapt copy across languages
26
26
 
27
+ If task-critical uncertainty could make the text wrong, verify narrowly and follow `agent-delegation`: do the safe part when it is clear, then route one concrete question to the main agent/orchestrator instead of improvising.
28
+
27
29
  ## First: detect the real system
28
30
 
29
31
  Before translating, identify what exists:
@@ -1,17 +1,36 @@
1
1
  {
2
- "$comment": "Permisos por defecto del stack: casi todo permitido, lo destructivo pregunta o se bloquea. REGLA DE ORO: cada bloque se escribe SOLO si el usuario aún no tiene esa clave en su config si ya la tiene (suya o ajustada después), el sync no la toca jamás. Quitar o editar estos valores tras el install es seguro: pasan a ser config del usuario.",
2
+ "$comment": "Permisos por defecto del stack: cada bloque se escribe SOLO en config fresca o vacía; una config existente no se auto-expande jamás. OpenCode fresh default permite leer fuera del cwd, pero deja edit/bash en ask salvo allow explícito para lecturas seguras.",
3
3
  "opencode": {
4
4
  "permission": {
5
- "edit": "allow",
6
- "read": "allow",
5
+ "edit": "ask",
6
+ "read": {
7
+ "*": "allow",
8
+ "*.env": "deny",
9
+ "*.env.*": "deny",
10
+ "*.env.example": "allow",
11
+ "*/.ssh/*": "deny",
12
+ "*/.aws/credentials": "deny",
13
+ "*/.npmrc": "deny",
14
+ "*/.git-credentials": "deny",
15
+ "*/id_rsa": "deny",
16
+ "*/id_ed25519": "deny",
17
+ "*.pem": "deny",
18
+ "*.key": "deny"
19
+ },
20
+ "external_directory": {
21
+ "*": "allow"
22
+ },
7
23
  "glob": "allow",
8
24
  "grep": "allow",
9
25
  "list": "allow",
10
26
  "lsp": "allow",
11
- "webfetch": "allow",
12
- "websearch": "allow",
27
+ "webfetch": "ask",
28
+ "websearch": "ask",
13
29
  "bash": {
14
- "*": "allow",
30
+ "*": "ask",
31
+ "git diff*": "ask",
32
+ "git log*": "allow",
33
+ "git status*": "allow",
15
34
  "rm *": "ask",
16
35
  "del *": "ask",
17
36
  "rmdir *": "ask",
@@ -25,13 +44,28 @@
25
44
  },
26
45
  "claude-code": {
27
46
  "permissions": {
28
- "allow": ["Bash", "Edit", "Write", "WebFetch", "WebSearch"],
29
- "ask": ["Bash(rm:*)", "Bash(rmdir:*)", "Bash(del:*)", "Bash(git push --force:*)"],
30
- "deny": ["Bash(format:*)", "Bash(mkfs:*)", "Bash(dd:*)", "Bash(shred:*)", "Read(./.env)", "Read(./.env.*)"]
47
+ "allow": ["Read", "Grep", "Glob"],
48
+ "ask": ["Bash", "Edit", "Write", "WebFetch", "WebSearch", "Bash(rm:*)", "Bash(rmdir:*)", "Bash(del:*)", "Bash(git push --force:*)"],
49
+ "deny": [
50
+ "Bash(format:*)",
51
+ "Bash(mkfs:*)",
52
+ "Bash(dd:*)",
53
+ "Bash(shred:*)",
54
+ "Read(//**/.env)",
55
+ "Read(//**/.env.*)",
56
+ "Read(//**/.ssh/**)",
57
+ "Read(//**/.aws/credentials)",
58
+ "Read(//**/.npmrc)",
59
+ "Read(//**/.git-credentials)",
60
+ "Read(//**/id_rsa)",
61
+ "Read(//**/id_ed25519)",
62
+ "Read(//**/*.pem)",
63
+ "Read(//**/*.key)"
64
+ ]
31
65
  }
32
66
  },
33
67
  "codex": {
34
68
  "approval_policy": "on-request",
35
- "sandbox_mode": "workspace-write"
69
+ "default_permissions": "jorgex-read-anywhere"
36
70
  }
37
71
  }
@@ -6,3 +6,6 @@
6
6
  - Delegations must be strings in the final JSON `delegations[]` array, using `agent: work — paths — inputs`.
7
7
  - Do not emit Markdown delegation lines.
8
8
  - Use the strict final JSON handoff.
9
+ - `delegations[]` is only for work that belongs to another specialist; uncertainty questions go in `summary` or `risks`, not in `delegations[]`.
10
+ - If task-critical uncertainty could make the task wrong, set `status` to `blocked` and include one concrete question to the main agent/orchestrator, with what you checked and the decision needed.
11
+ - If the safe path is clear, do the safe part and report the remainder as `partial`.
@@ -6,6 +6,8 @@
6
6
  - The final assistant response must be exactly one strict JSON object.
7
7
  - Do not wrap the final JSON in Markdown fences or prose.
8
8
  - Process the final JSON object's `delegations[]` array; each item must be a string in the form `agent: work — paths — inputs`. Ignore Markdown delegation lines outside JSON.
9
+ - If a subagent reports `partial`, keep the safe work and relaunch only what still needs guidance.
10
+ - If a subagent reports `blocked` and includes one concrete question in `summary` or `risks`, answer it from existing context when possible; if it still cannot be resolved from context, ask the user only if genuinely necessary, then relaunch the original or a suitable specialist with explicit guidance.
9
11
  - Required keys: `status`, `decision`, `confidence`, `summary`, `risks`, `next_steps`, `delegations`.
10
12
  - `status` is one of `done`, `partial`, `blocked` and `decision` is a short string.
11
13
  - `confidence` is a number between 0 and 1.
@@ -7,6 +7,8 @@
7
7
  - Return a terse, structured handoff that is easy to parse.
8
8
  - Use the strict final JSON handoff.
9
9
  - Any delegation must live in the JSON `delegations[]` array as a string in the form `agent: work — paths — inputs`; do not emit Markdown delegation lines outside JSON.
10
+ - `delegations[]` is only for specialist work. If task-critical uncertainty could make the task wrong, set `status` to `blocked` and put one concrete question to the main agent/orchestrator in `summary` or `risks`, including what you checked and the decision needed.
11
+ - If the safe path is clear, do the safe part and report the remainder as `partial`.
10
12
  - Required keys: `status`, `decision`, `confidence`, `summary`, `risks`, `next_steps`, `delegations`.
11
13
  - `status` is one of `done`, `partial`, `blocked`.
12
14
  - `risks`, `next_steps`, and `delegations` are arrays of strings.
@@ -9,11 +9,14 @@ description: Regla universal de delegación entre subagentes. Usar cuando durant
9
9
 
10
10
  Si durante tu tarea encuentras trabajo que pertenece a otro especialista, **no lo absorbas**. Haz solo tu parte y reporta el resto.
11
11
 
12
+ If task-critical uncertainty is small, verify only what is needed. If the safe path is clear, do that part and report the rest as `partial`. If task-critical uncertainty can make the task wrong, stop before risky edits and return `blocked` with one concrete question to the main agent/orchestrator: what you checked, what decision is needed, and the recommended option or tradeoff if you know it. Do not improvise.
13
+
12
14
  Importante sobre el mecanismo:
13
15
 
14
16
  - Tú (subagente) **no lanzas a otros subagentes**. Solo el agente principal (orquestador) puede invocarlos.
15
17
  - No te salgas de tu scope para "ayudar". Si algo no te corresponde, lo dejas sin hacer y lo delegas.
16
18
  - Las delegaciones van **en tu output final**, en el formato de abajo. El orquestador las lee y decide a quién invocar.
19
+ - `delegations` are only for work that belongs to another specialist; uncertainty questions are not delegations.
17
20
 
18
21
  ## Agentes disponibles
19
22