@gluecharm-lab/easyspecs-cli 0.3.0 → 0.3.2

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/commands.md CHANGED
@@ -38,7 +38,7 @@ When `**easyspecs-cli analysis`** exits **non-zero** with factory failures, huma
38
38
  | `**error**` | Orchestrator message; if several phases failed, a short appendix lists extra `**failureExitId`**s (see `[factoryValidationFailures.ts](../../src/factory/factoryValidationFailures.ts)`). |
39
39
 
40
40
 
41
- **Phase → OS exit (generate_context):** **84–86** **`diagnose_readiness`** when a **readiness gate (a)(c)** fails (**SRS-72** — install, credentials, model); **87** is reserved (mandatory **`opencode.json`** no longer blocks once **(a)(c)** pass); **50** `create_analysis_worktree`, **51** `materialize_opencode_agents`, **52** `synthesis_convergence`, **53** `reference_coverage`, **54** `zero_reference_remediation_convergence`, **55** `reference_coverage_execution_report`, **56** `link_mapping_pipeline`, **57** `assemble_application_context_index`, **58** `backend_context_sync`, **49** unknown / unattributed. Full table: `[error-code.md](./error-code.md)`.
41
+ **Phase → OS exit (generate_context):** **84–85** **`diagnose_readiness`** when a **readiness gate (a)** or **(b)** fails (**SRS-72** — OpenCode not installed, or credentials not ready); **86–87** are **reserved** (readiness no longer exits for a missing default model when **(a)** and **(b)** pass); **50** `create_analysis_worktree`, **51** `materialize_opencode_agents`, **52** `synthesis_convergence`, **53** `reference_coverage`, **54** `zero_reference_remediation_convergence`, **55** `reference_coverage_execution_report`, **56** `link_mapping_pipeline`, **57** `assemble_application_context_index`, **58** `backend_context_sync`, **49** unknown / unattributed. Full table: `[error-code.md](./error-code.md)`.
42
42
 
43
43
  **Optional `validationSubcode` (v1):** `**R5_MACRO_PING_PONG`** when synthesis `**detail**` notes **R5** unstable convergence; `**COVERAGE_PERCENT_THRESHOLD`** when reference-coverage `**detail**` matches the strict percent gate pattern.
44
44
 
package/dist/main.cjs CHANGED
@@ -10677,7 +10677,7 @@ var OsExit = {
10677
10677
  readinessOpenCodeNotInstalled: 84,
10678
10678
  /** SRS-72 readiness gate (b): credentials not ready. */
10679
10679
  readinessOpenCodeCredentials: 85,
10680
- /** SRS-72 readiness gate (c): default model not configured. */
10680
+ /** SRS-72: reserved — readiness no longer exits for missing default model when install + credentials pass. */
10681
10681
  readinessOpenCodeModel: 86,
10682
10682
  /** SRS-72 readiness gate (d): mandatory OpenCode config file missing. */
10683
10683
  readinessOpenCodeMandatoryConfig: 87
@@ -10778,9 +10778,9 @@ function describeExitCode(code) {
10778
10778
  case OsExit.readinessOpenCodeCredentials:
10779
10779
  return "OpenCode credentials not ready for factory run.";
10780
10780
  case OsExit.readinessOpenCodeModel:
10781
- return "OpenCode default model is not configured \u2014 add `model` (or equivalent) in repo `opencode.json` / `opencode.jsonc`, global `~/.config/opencode/opencode.json`, `OPENCODE_CONFIG` / `OPENCODE_CONFIG_DIR`, managed config (see OpenCode docs), or `easyspecs.openCodeRuntime.providers`.";
10781
+ return "Reserved exit code 86 \u2014 factory readiness no longer fails solely for a missing OpenCode default model when the CLI is installed and credentials are ready; configure a model in OpenCode or EasySpecs settings if agent runs fail later.";
10782
10782
  case OsExit.readinessOpenCodeMandatoryConfig:
10783
- return "Readiness gate (d) reserved \u2014 repo-root `opencode.json` is optional when OpenCode is installed, credentials are ready, and a model is configured.";
10783
+ return "Reserved exit code 87 \u2014 factory readiness does not fail for a missing repo-root `opencode.json` in the current product rules.";
10784
10784
  default:
10785
10785
  return `Non-zero exit (${String(code)}) \u2014 see stderr and any JSON \`error\` field for detail.`;
10786
10786
  }
@@ -14603,7 +14603,7 @@ function runOpenCodeAgent(cwd, args, options) {
14603
14603
  cwd,
14604
14604
  shell: USE_SHELL,
14605
14605
  env: spawnEnv,
14606
- stdio: ["ignore", "pipe", "pipe"]
14606
+ stdio: ["pipe", "pipe", "pipe"]
14607
14607
  });
14608
14608
  let childResourceLogged = false;
14609
14609
  let cpuBaseline;
@@ -21762,7 +21762,7 @@ function promoteContextDirectoryToWorkspaceFs(sourceContextDir, workspaceRootFs)
21762
21762
 
21763
21763
  // src/shared/factoryPipelineExitConditions.ts
21764
21764
  var FACTORY_PIPELINE_EXIT_CONDITIONS = {
21765
- diagnose_readiness: "OpenCode CLI, credentials, default model, and mandatory project `opencode.json` are ready before worktree / agent work (SRS-72).",
21765
+ diagnose_readiness: "OpenCode CLI and credentials are required before worktree / agent work; default model is reported (informational) but does not block readiness when install and credentials pass (SRS-72).",
21766
21766
  create_analysis_worktree: "Git analysis checkout exists under the configured temp parent (SRS-8); ready for agent materialization.",
21767
21767
  materialize_opencode_agents: "Bundled OpenCode agent definitions are copied into the analysis worktree (`.opencode/` tree).",
21768
21768
  synthesis_convergence: "Missing artefact count is 0. May run again after remediation (R5) if a refreshed check finds new expected outputs.",
@@ -21790,6 +21790,21 @@ function openCodeUserConfigDir() {
21790
21790
  const cfgRoot = xdg && xdg.length > 0 ? xdg : path34.join(os6.homedir(), ".config");
21791
21791
  return path34.join(cfgRoot, "opencode");
21792
21792
  }
21793
+ function openCodeMacUserApplicationSupportDir() {
21794
+ if (process.platform === "darwin") {
21795
+ return path34.join(os6.homedir(), "Library", "Application Support", "opencode");
21796
+ }
21797
+ return void 0;
21798
+ }
21799
+ function openCodeWindowsLocalAppDataDir() {
21800
+ if (process.platform === "win32") {
21801
+ const la = process.env.LOCALAPPDATA?.trim();
21802
+ if (la && la.length > 0) {
21803
+ return path34.join(la, "opencode");
21804
+ }
21805
+ }
21806
+ return void 0;
21807
+ }
21793
21808
  function managedOpenCodeConfigDir() {
21794
21809
  if (process.platform === "darwin") {
21795
21810
  return "/Library/Application Support/opencode";
@@ -21829,14 +21844,22 @@ function openCodeJsonModelFileCandidates(analysisRootAbs) {
21829
21844
  if (oc) {
21830
21845
  acc.push(path34.resolve(oc));
21831
21846
  }
21832
- pushConfigBasenames(acc, root);
21833
- pushConfigBasenames(acc, path34.join(root, ".opencode"));
21847
+ pushConfigBasenames(acc, openCodeUserConfigDir());
21848
+ const macAs = openCodeMacUserApplicationSupportDir();
21849
+ if (macAs) {
21850
+ pushConfigBasenames(acc, macAs);
21851
+ }
21852
+ const winLoc = openCodeWindowsLocalAppDataDir();
21853
+ if (winLoc) {
21854
+ pushConfigBasenames(acc, winLoc);
21855
+ }
21856
+ pushConfigBasenames(acc, path34.join(os6.homedir(), ".opencode"));
21834
21857
  const ocd = process.env.OPENCODE_CONFIG_DIR?.trim();
21835
21858
  if (ocd) {
21836
21859
  pushConfigBasenames(acc, path34.resolve(ocd));
21837
21860
  }
21838
- pushConfigBasenames(acc, openCodeUserConfigDir());
21839
- pushConfigBasenames(acc, path34.join(os6.homedir(), ".opencode"));
21861
+ pushConfigBasenames(acc, root);
21862
+ pushConfigBasenames(acc, path34.join(root, ".opencode"));
21840
21863
  const managed = managedOpenCodeConfigDir();
21841
21864
  if (managed) {
21842
21865
  pushConfigBasenames(acc, managed);
@@ -21848,7 +21871,6 @@ function openCodeJsonModelFileCandidates(analysisRootAbs) {
21848
21871
  var MANDATORY_OPEN_CODE_CONFIG_REL_PATHS = ["opencode.json"];
21849
21872
  var READINESS_OPENCODE_NOT_INSTALLED = "READINESS_OPENCODE_NOT_INSTALLED";
21850
21873
  var READINESS_OPENCODE_CREDENTIALS = "READINESS_OPENCODE_CREDENTIALS";
21851
- var READINESS_OPENCODE_MODEL = "READINESS_OPENCODE_MODEL";
21852
21874
  function buildOpenCodeConfigInventory(analysisRootAbs) {
21853
21875
  return openCodeJsonModelFileCandidates(analysisRootAbs).map((p) => ({ path: p, exists: fs39.existsSync(p) }));
21854
21876
  }
@@ -21868,19 +21890,37 @@ function defaultModelFromEasyspecsConfig(cfg) {
21868
21890
  function pickString(v) {
21869
21891
  return typeof v === "string" && v.trim().length > 0 ? v.trim() : void 0;
21870
21892
  }
21893
+ function pickModelLike(v) {
21894
+ const s = pickString(v);
21895
+ if (s) {
21896
+ return s;
21897
+ }
21898
+ if (v && typeof v === "object") {
21899
+ const r = v;
21900
+ return pickString(r.id) ?? pickString(r.name) ?? pickString(r.model);
21901
+ }
21902
+ return void 0;
21903
+ }
21904
+ function modelFromEasyspecsProjectConfigOverlay(cfg) {
21905
+ const overlay = cfg.easyspecs?.openCodeRuntime?.projectConfigOverlay;
21906
+ if (!overlay || typeof overlay !== "object") {
21907
+ return void 0;
21908
+ }
21909
+ return extractModelFromOpenCodeJson(overlay);
21910
+ }
21871
21911
  function extractModelFromOpenCodeJson(data) {
21872
21912
  if (!data || typeof data !== "object") {
21873
21913
  return void 0;
21874
21914
  }
21875
21915
  const o = data;
21876
- const direct = pickString(o.model) ?? pickString(o.defaultModel);
21877
- if (direct) {
21878
- return direct;
21916
+ const top = pickModelLike(o.model) ?? pickString(o.defaultModel) ?? pickModelLike(o.small_model) ?? pickString(o.smallModel);
21917
+ if (top) {
21918
+ return top;
21879
21919
  }
21880
21920
  const models = o.models;
21881
21921
  if (models && typeof models === "object") {
21882
21922
  const m = models;
21883
- const def = pickString(m.default) ?? pickString(m.defaultModel);
21923
+ const def = pickModelLike(m.default) ?? pickString(m.defaultModel);
21884
21924
  if (def) {
21885
21925
  return def;
21886
21926
  }
@@ -21888,11 +21928,23 @@ function extractModelFromOpenCodeJson(data) {
21888
21928
  const agent = o.agent;
21889
21929
  if (agent && typeof agent === "object") {
21890
21930
  const a = agent;
21891
- const am = pickString(a.model) ?? pickString(a.defaultModel);
21931
+ const am = pickModelLike(a.model) ?? pickString(a.defaultModel);
21892
21932
  if (am) {
21893
21933
  return am;
21894
21934
  }
21895
21935
  }
21936
+ const prov = o.provider;
21937
+ if (prov && typeof prov === "object") {
21938
+ for (const v of Object.values(prov)) {
21939
+ if (v && typeof v === "object") {
21940
+ const rec = v;
21941
+ const pm = pickModelLike(rec.model);
21942
+ if (pm) {
21943
+ return pm;
21944
+ }
21945
+ }
21946
+ }
21947
+ }
21896
21948
  return void 0;
21897
21949
  }
21898
21950
  function parseOpenCodeConfigText(raw) {
@@ -21948,6 +22000,10 @@ function resolveModelFromContext(ctx) {
21948
22000
  if (fromCfg) {
21949
22001
  return { configured: true, summary: sanitizeModelSummary(fromCfg) };
21950
22002
  }
22003
+ const fromOverlay = modelFromEasyspecsProjectConfigOverlay(ctx.repoConfig);
22004
+ if (fromOverlay) {
22005
+ return { configured: true, summary: sanitizeModelSummary(fromOverlay) };
22006
+ }
21951
22007
  const fromInline = modelFromOpencodeConfigContentEnv();
21952
22008
  if (fromInline) {
21953
22009
  return { configured: true, summary: sanitizeModelSummary(fromInline) };
@@ -22018,14 +22074,6 @@ function evaluateReadinessGates(facts) {
22018
22074
  readinessReasonCode: READINESS_OPENCODE_CREDENTIALS
22019
22075
  };
22020
22076
  }
22021
- if (!facts.modelConfigured) {
22022
- return {
22023
- ok: false,
22024
- gate: "c",
22025
- exitCode: OsExit.readinessOpenCodeModel,
22026
- readinessReasonCode: READINESS_OPENCODE_MODEL
22027
- };
22028
- }
22029
22077
  return { ok: true };
22030
22078
  }
22031
22079
  function buildReadinessJsonFields(facts) {
@@ -22100,7 +22148,8 @@ var ERROR_JOIN_MAX = 900;
22100
22148
  var ADDITIONAL_APPEND_MAX = 200;
22101
22149
  var PHASE_TO_OS_EXIT = {
22102
22150
  unknown_factory_phase: OsExit.factoryUnknown,
22103
- diagnose_readiness: OsExit.readinessOpenCodeModel,
22151
+ /** Fallback when a failed row lacks an explicit exitCode; real readiness failures embed 84/85 from gates. */
22152
+ diagnose_readiness: OsExit.readinessOpenCodeNotInstalled,
22104
22153
  create_analysis_worktree: OsExit.createAnalysisWorktree,
22105
22154
  materialize_opencode_agents: OsExit.materializeOpenCodeAgents,
22106
22155
  synthesis_convergence: OsExit.synthesisConvergence,
@@ -22113,7 +22162,7 @@ var PHASE_TO_OS_EXIT = {
22113
22162
  };
22114
22163
  var TITLE_BY_PHASE = {
22115
22164
  unknown_factory_phase: "EasySpecs stopped: the failing pipeline phase could not be identified. Retry with --verbose; report this outcome if it persists.",
22116
- diagnose_readiness: "Factory readiness preflight failed: OpenCode install, credentials, default model, or mandatory `opencode.json` is not satisfied. See stderr lines above and `readinessReasonCode` in JSON.",
22165
+ diagnose_readiness: "Factory readiness preflight failed \u2014 see stderr lines above and `readinessReasonCode` / `readinessGate` in JSON.",
22117
22166
  create_analysis_worktree: "Could not prepare the analysis Git worktree (temporary checkout). Check disk space, repo permissions, and that the project is a valid Git checkout.",
22118
22167
  materialize_opencode_agents: "Could not install OpenCode agent files into the analysis worktree. Check bundled extension assets and disk permissions under the worktree path.",
22119
22168
  synthesis_convergence: "Context synthesis did not finish: required context files are still missing or invalid after retries. Inspect OpenCode errors and workstation logs for this phase.",
@@ -29036,7 +29085,7 @@ function formatCliStderrLine(line, useAnsi) {
29036
29085
  }
29037
29086
 
29038
29087
  // src/cli/main.ts
29039
- var PKG_VERSION = "0.3.0";
29088
+ var PKG_VERSION = "0.3.2";
29040
29089
  function isNonEmptyFactoryFailureArray(x) {
29041
29090
  if (!Array.isArray(x) || x.length === 0) {
29042
29091
  return false;