jorgex-stack 1.0.25 → 1.0.27
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 +4 -2
- package/dist/cli.js +52 -19
- package/package.json +1 -1
- package/stack/agents/docs-maintainer.md +24 -1
package/README.md
CHANGED
|
@@ -9,7 +9,7 @@ Portable multi-agent harness: one configuration source — 15 agents, 17 skills,
|
|
|
9
9
|
Install and run via npm without cloning the repository:
|
|
10
10
|
|
|
11
11
|
```
|
|
12
|
-
pnpm dlx jorgex-stack install #
|
|
12
|
+
pnpm dlx jorgex-stack install # install runtimes; first OpenCode setup selects connected models
|
|
13
13
|
pnpm dlx jorgex-stack models # model picker by runtime and tier (strong/standard/cheap)
|
|
14
14
|
pnpm dlx jorgex-stack sync # alias of install (same idempotent apply)
|
|
15
15
|
pnpm dlx jorgex-stack doctor # checks that everything is healthy (Engram, drift, hooks, keys)
|
|
@@ -24,7 +24,7 @@ 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
|
-
Runtime defaults are documented in [docs/references/permissions.md](docs/references/permissions.md) for permissions and [docs/references/models.md](docs/references/models.md) for model selection,
|
|
27
|
+
Runtime defaults are documented in [docs/references/permissions.md](docs/references/permissions.md) for permissions and [docs/references/models.md](docs/references/models.md) for provider-aware model selection, Codex tiers, and orchestrator inheritance. OpenCode has no provider defaults.
|
|
28
28
|
|
|
29
29
|
### Modes: Human and Programmatic
|
|
30
30
|
|
|
@@ -52,6 +52,8 @@ Flags:
|
|
|
52
52
|
|
|
53
53
|
This installs into all detected runtimes. To be explicit, add `--agents opencode,claude-code,codex` or a comma-separated subset. Always pass `--mode programmatic`; without `--mode`, `--yes` and non-TTY installs default to `human`.
|
|
54
54
|
|
|
55
|
+
OpenCode also requires an existing selection in `~/.jorgex-stack/model-map.json`; run `pnpm dlx jorgex-stack models --agents opencode` interactively once before a headless install.
|
|
56
|
+
|
|
55
57
|
- `--mode human` cannot be combined with `--subagent-concurrency`.
|
|
56
58
|
- Without `--mode`, the first run asks interactively; `--yes`, non-TTY, and `--target-dir` default to `human`.
|
|
57
59
|
- `pnpm dlx jorgex-stack sync` reuses the saved mode; pass `--mode` to change and save the preference.
|
package/dist/cli.js
CHANGED
|
@@ -178,11 +178,6 @@ function resolveAgentModel(models, agentName, tier) {
|
|
|
178
178
|
};
|
|
179
179
|
}
|
|
180
180
|
var DEFAULT_MODEL_MAP = {
|
|
181
|
-
opencode: {
|
|
182
|
-
strong: { model: "openai/gpt-5.6-terra", variant: "xhigh" },
|
|
183
|
-
standard: { model: "openai/gpt-5.6-terra", variant: "xhigh" },
|
|
184
|
-
cheap: { model: "openai/gpt-5.6-luna", variant: "medium" }
|
|
185
|
-
},
|
|
186
181
|
"claude-code": {
|
|
187
182
|
strong: { model: "fable" },
|
|
188
183
|
standard: { model: "sonnet" },
|
|
@@ -209,7 +204,7 @@ function loadModelMap() {
|
|
|
209
204
|
} catch {
|
|
210
205
|
return DEFAULT_MODEL_MAP;
|
|
211
206
|
}
|
|
212
|
-
const merged = {};
|
|
207
|
+
const merged = { ...fromDisk };
|
|
213
208
|
for (const id of Object.keys(DEFAULT_MODEL_MAP)) {
|
|
214
209
|
merged[id] = { ...DEFAULT_MODEL_MAP[id], ...fromDisk[id] ?? {} };
|
|
215
210
|
}
|
|
@@ -1649,7 +1644,8 @@ async function runInstall(opts) {
|
|
|
1649
1644
|
}
|
|
1650
1645
|
const models = modelMap[id];
|
|
1651
1646
|
if (!models) {
|
|
1652
|
-
p.log.
|
|
1647
|
+
p.log.error(`${adapter.name}: sin modelos seleccionados \u2014 ejecuta 'jorgex-stack models --agents ${id}'.`);
|
|
1648
|
+
exitCode = 1;
|
|
1653
1649
|
continue;
|
|
1654
1650
|
}
|
|
1655
1651
|
const ctx = {
|
|
@@ -2867,8 +2863,12 @@ function agentsByTier() {
|
|
|
2867
2863
|
}
|
|
2868
2864
|
return grouped;
|
|
2869
2865
|
}
|
|
2866
|
+
function isCompleteRuntimeModelMap(models) {
|
|
2867
|
+
return TIERS.every((tier) => models[tier]?.model);
|
|
2868
|
+
}
|
|
2870
2869
|
async function askModel(det, subject, current) {
|
|
2871
2870
|
if (det.id === "codex") {
|
|
2871
|
+
if (!current) throw new Error("Codex requiere un model-map base.");
|
|
2872
2872
|
const effort = await p5.select({
|
|
2873
2873
|
message: `${det.name} \xB7 ${subject} \u2014 reasoning effort`,
|
|
2874
2874
|
options: EFFORTS.map((v) => ({ value: v, label: v })),
|
|
@@ -2902,16 +2902,18 @@ async function askModel(det, subject, current) {
|
|
|
2902
2902
|
}
|
|
2903
2903
|
const optionsList = det.options;
|
|
2904
2904
|
const options = optionsList.map((m) => ({ value: m, label: m }));
|
|
2905
|
-
if (!optionsList.includes(current.model))
|
|
2905
|
+
if (current && !optionsList.includes(current.model)) {
|
|
2906
|
+
options.unshift({ value: current.model, label: `${current.model} (actual)` });
|
|
2907
|
+
}
|
|
2906
2908
|
const choice = await p5.select({
|
|
2907
2909
|
message: `${det.name} \xB7 ${subject} \u2014 modelo`,
|
|
2908
2910
|
options,
|
|
2909
|
-
initialValue: current
|
|
2911
|
+
initialValue: current?.model,
|
|
2910
2912
|
maxItems: 12
|
|
2911
2913
|
});
|
|
2912
2914
|
if (p5.isCancel(choice)) return CANCEL;
|
|
2913
2915
|
if (det.id === "claude-code") return { model: choice };
|
|
2914
|
-
const keptCurrent = choice === current.model && current.variant ? current.variant : null;
|
|
2916
|
+
const keptCurrent = current && choice === current.model && current.variant ? current.variant : null;
|
|
2915
2917
|
const variant = await p5.select({
|
|
2916
2918
|
message: `${det.name} \xB7 ${subject} \u2014 reasoning effort (variant; solo si el modelo lo soporta)`,
|
|
2917
2919
|
options: [
|
|
@@ -2926,12 +2928,16 @@ async function askModel(det, subject, current) {
|
|
|
2926
2928
|
}
|
|
2927
2929
|
async function runModelsPicker(opts) {
|
|
2928
2930
|
const file = ensureModelMapFile();
|
|
2931
|
+
const map = loadModelMap();
|
|
2929
2932
|
if (opts.yes || !process.stdout.isTTY) {
|
|
2930
|
-
|
|
2933
|
+
if (opts.runtimes.includes("opencode") && !map.opencode) {
|
|
2934
|
+
console.error("OpenCode requiere selecci\xF3n interactiva desde los proveedores conectados; ejecuta 'models --agents opencode' sin --yes.");
|
|
2935
|
+
return 1;
|
|
2936
|
+
}
|
|
2937
|
+
console.log(`Model-map en ${file}. Ed\xEDtalo o ejecuta 'models' sin --yes para el picker.`);
|
|
2931
2938
|
return 0;
|
|
2932
2939
|
}
|
|
2933
2940
|
p5.intro("jorgex-stack models \u2014 modelos por tier o por subagente");
|
|
2934
|
-
const map = loadModelMap();
|
|
2935
2941
|
const grouped = agentsByTier();
|
|
2936
2942
|
const tierLine = (tier) => grouped[tier].join(", ");
|
|
2937
2943
|
const agentCount = TIERS.reduce((n, tier) => n + grouped[tier].length, 0);
|
|
@@ -2960,7 +2966,10 @@ async function runModelsPicker(opts) {
|
|
|
2960
2966
|
p5.log.warn("OpenCode: no se pudo listar `opencode models` \u2014 se mantiene la selecci\xF3n actual.");
|
|
2961
2967
|
continue;
|
|
2962
2968
|
}
|
|
2963
|
-
const
|
|
2969
|
+
const existingRuntimeMap = map[det.id];
|
|
2970
|
+
const runtimeMap = {
|
|
2971
|
+
...existingRuntimeMap
|
|
2972
|
+
};
|
|
2964
2973
|
p5.log.message(
|
|
2965
2974
|
`${det.name} \u2014 tiers y sus subagentes:
|
|
2966
2975
|
strong \u2192 ${tierLine("strong")}
|
|
@@ -2978,7 +2987,7 @@ async function runModelsPicker(opts) {
|
|
|
2978
2987
|
if (p5.isCancel(mode)) return cancelled();
|
|
2979
2988
|
if (mode === "tier") {
|
|
2980
2989
|
for (const tier of TIERS) {
|
|
2981
|
-
const asked = await askModel(det, `tier ${tier} (${tierLine(tier)})`,
|
|
2990
|
+
const asked = await askModel(det, `tier ${tier} (${tierLine(tier)})`, existingRuntimeMap?.[tier]);
|
|
2982
2991
|
if (asked === CANCEL) return cancelled();
|
|
2983
2992
|
runtimeMap[tier] = asked;
|
|
2984
2993
|
}
|
|
@@ -2991,10 +3000,15 @@ async function runModelsPicker(opts) {
|
|
|
2991
3000
|
} else {
|
|
2992
3001
|
const overrides = { ...runtimeMap.overrides ?? {} };
|
|
2993
3002
|
for (const tier of TIERS) {
|
|
2994
|
-
|
|
3003
|
+
let base = runtimeMap[tier];
|
|
2995
3004
|
for (const name of grouped[tier]) {
|
|
2996
|
-
const
|
|
3005
|
+
const current = existingRuntimeMap ? resolveAgentModel(existingRuntimeMap, name, tier) : void 0;
|
|
3006
|
+
const asked = await askModel(det, `${name} (tier ${tier})`, current);
|
|
2997
3007
|
if (asked === CANCEL) return cancelled();
|
|
3008
|
+
if (!base) {
|
|
3009
|
+
base = asked;
|
|
3010
|
+
runtimeMap[tier] = base;
|
|
3011
|
+
}
|
|
2998
3012
|
const sameAsTier = asked.model === base.model && (asked.variant ?? "") === (base.variant ?? "");
|
|
2999
3013
|
if (sameAsTier) {
|
|
3000
3014
|
delete overrides[name];
|
|
@@ -3009,6 +3023,9 @@ async function runModelsPicker(opts) {
|
|
|
3009
3023
|
if (Object.keys(overrides).length > 0) runtimeMap.overrides = overrides;
|
|
3010
3024
|
else delete runtimeMap.overrides;
|
|
3011
3025
|
}
|
|
3026
|
+
if (!isCompleteRuntimeModelMap(runtimeMap)) {
|
|
3027
|
+
throw new Error(`${det.name}: selecci\xF3n de modelos incompleta.`);
|
|
3028
|
+
}
|
|
3012
3029
|
map[det.id] = runtimeMap;
|
|
3013
3030
|
}
|
|
3014
3031
|
writeText(file, JSON.stringify(map, null, 2) + "\n");
|
|
@@ -3052,6 +3069,18 @@ function readPackageMetadata() {
|
|
|
3052
3069
|
// src/cli.ts
|
|
3053
3070
|
var VERSION = readPackageVersion();
|
|
3054
3071
|
var COMMANDS = ["install", "sync", "models", "update", "doctor", "restore", "uninstall"];
|
|
3072
|
+
async function ensureOpenCodeModelsForInstall(command, flags, runtimes) {
|
|
3073
|
+
if (!runtimes.includes("opencode") || loadModelMap().opencode) return true;
|
|
3074
|
+
const canPrompt = command === "install" && !flags.yes && !flags.dryRun && process.stdout.isTTY;
|
|
3075
|
+
if (canPrompt) {
|
|
3076
|
+
const code = await runModelsPicker({ yes: false, runtimes: ["opencode"] });
|
|
3077
|
+
if (code === 0 && loadModelMap().opencode) return true;
|
|
3078
|
+
}
|
|
3079
|
+
console.error(
|
|
3080
|
+
"OpenCode no tiene modelos configurados. Ejecuta 'jorgex-stack models --agents opencode' de forma interactiva antes de install/sync."
|
|
3081
|
+
);
|
|
3082
|
+
return false;
|
|
3083
|
+
}
|
|
3055
3084
|
function parseFlags(args) {
|
|
3056
3085
|
const flags = {
|
|
3057
3086
|
agents: [],
|
|
@@ -3204,9 +3233,9 @@ function printHelp() {
|
|
|
3204
3233
|
Uso: pnpm dlx jorgex-stack [comando] [opciones]
|
|
3205
3234
|
|
|
3206
3235
|
Comandos:
|
|
3207
|
-
install Instala el stack
|
|
3208
|
-
sync Re-aplica la config (idempotente;
|
|
3209
|
-
models Picker
|
|
3236
|
+
install Instala el stack; OpenCode fresh exige elegir modelos conectados
|
|
3237
|
+
sync Re-aplica la config y el model-map existente (idempotente; sin picker)
|
|
3238
|
+
models Picker por tier o subagente (OpenCode: 'opencode models' en vivo)
|
|
3210
3239
|
update --check: compara stack/Engram/skills con sus upstreams
|
|
3211
3240
|
doctor Estado: Engram, drift de config, hooks de Codex, key de context7
|
|
3212
3241
|
restore --list para ver backups \xB7 'restore <id>' para restaurar
|
|
@@ -3266,6 +3295,10 @@ Flags disponibles: jorgex-stack --help`
|
|
|
3266
3295
|
process.exitCode = 1;
|
|
3267
3296
|
return;
|
|
3268
3297
|
}
|
|
3298
|
+
if (!await ensureOpenCodeModelsForInstall(command, flags, runtimes)) {
|
|
3299
|
+
process.exitCode = 1;
|
|
3300
|
+
return;
|
|
3301
|
+
}
|
|
3269
3302
|
process.exitCode = await runInstall({ runtimes, targetDir: flags.targetDir, dryRun: flags.dryRun, yes: flags.yes, mode });
|
|
3270
3303
|
return;
|
|
3271
3304
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: docs-maintainer
|
|
3
|
-
description:
|
|
3
|
+
description: Evidence-first documentation specialist. Use it AFTER behavior or APIs change to keep the repo's /docs folder and any public docs site (website, app, docs portal) accurate and in sync — content, navigation and metadata. Writes docs only — not for product logic, features or bug fixes.
|
|
4
4
|
mode: subagent
|
|
5
5
|
tier: cheap
|
|
6
6
|
readonly: false
|
|
@@ -42,10 +42,24 @@ If you change a page, check whether navigation or metadata must also be updated.
|
|
|
42
42
|
|
|
43
43
|
## Before editing
|
|
44
44
|
|
|
45
|
+
- Establish the **allowed write root**. An explicit worktree or write-root path in the assignment always wins; otherwise use the current repository root.
|
|
46
|
+
- Run `git rev-parse --show-toplevel` and inspect the current branch before the first write. Resolve every target path and confirm it stays inside the allowed write root. If the current checkout or any target does not match, do not write: return `blocked` with the mismatch.
|
|
45
47
|
- Search for references to the title, slug, path or concept you are about to change.
|
|
46
48
|
- Identify whether the documentation is public, internal or hybrid.
|
|
47
49
|
- Follow the project's real pattern; do not impose a new one without need.
|
|
48
50
|
|
|
51
|
+
## Factual accuracy
|
|
52
|
+
|
|
53
|
+
Documentation is an evidence task, not a creative reconstruction.
|
|
54
|
+
|
|
55
|
+
- Build a **source-to-claim** map before drafting: every new technical claim must trace to current code, schemas or migrations, tests, canonical project docs, or git history.
|
|
56
|
+
- Use implementation to classify components. An invocation name is not proof of its implementation type; inspect the defining file before calling something an RPC, database function, API route, Edge Function, job or service.
|
|
57
|
+
- Use git history only when claiming when or in which change something was introduced. Current existence does not prove recent origin.
|
|
58
|
+
- **Never invent** names, paths, symbols, chronology, or snippets. Copy identifiers exactly from a source that exists in the allowed write root.
|
|
59
|
+
- A code snippet must come from a real file you inspected. If the task explicitly needs illustrative pseudocode, label it as pseudocode and never attribute it to a repository file.
|
|
60
|
+
- When sources conflict, prefer executable code and migrations over comments or stale docs. Do not silently choose a convenient version.
|
|
61
|
+
- If a material claim cannot be verified, omit it when nonessential; otherwise return `partial` or `blocked` with one concrete question. Never fill the gap with a plausible guess.
|
|
62
|
+
|
|
49
63
|
## While editing
|
|
50
64
|
|
|
51
65
|
- Keep the scope minimal.
|
|
@@ -54,6 +68,12 @@ If you change a page, check whether navigation or metadata must also be updated.
|
|
|
54
68
|
- If there is a sidebar or manual index, update it.
|
|
55
69
|
- If there is SEO or technical metadata, keep it in sync.
|
|
56
70
|
|
|
71
|
+
## Before reporting
|
|
72
|
+
|
|
73
|
+
- Review the final documentation diff sentence by sentence. Re-check each added or changed factual claim against its source and confirm every mentioned file exists.
|
|
74
|
+
- Re-run the location check and confirm all changed files are inside the allowed write root.
|
|
75
|
+
- Remove unsupported claims instead of weakening them with vague language.
|
|
76
|
+
|
|
57
77
|
## Rules
|
|
58
78
|
|
|
59
79
|
- Scope your work to the affected documentation.
|
|
@@ -67,6 +87,8 @@ If you change a page, check whether navigation or metadata must also be updated.
|
|
|
67
87
|
- [ ] Metadata updated if applicable
|
|
68
88
|
- [ ] Internal links valid
|
|
69
89
|
- [ ] Tone consistent with the rest of the docs
|
|
90
|
+
- [ ] Every factual claim and snippet verified against a real source
|
|
91
|
+
- [ ] All writes confined to the allowed write root
|
|
70
92
|
|
|
71
93
|
## Report format
|
|
72
94
|
|
|
@@ -77,6 +99,7 @@ If you change a page, check whether navigation or metadata must also be updated.
|
|
|
77
99
|
**Content:** [what changed]
|
|
78
100
|
**Navigation:** [if applicable]
|
|
79
101
|
**Metadata:** [if applicable]
|
|
102
|
+
**Evidence:** [source paths and, for chronology claims, commits used]
|
|
80
103
|
```
|
|
81
104
|
|
|
82
105
|
## Result contract
|