karajan-code 4.67.0 → 4.68.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "karajan-code",
3
- "version": "4.67.0",
3
+ "version": "4.68.0",
4
4
  "description": "Local multi-agent coding orchestrator with TDD, SonarQube, and code review pipeline",
5
5
  "type": "module",
6
6
  "license": "AGPL-3.0",
@@ -1119,7 +1119,8 @@ export function registerMeta(program, { pkgVersion }) {
1119
1119
  .option("--no-config", "Skip lint/format/commit config files (hooks only)")
1120
1120
  .option("--no-ci", "Skip CI quality workflows")
1121
1121
  .option("--no-guidelines", "Skip AI-agent guideline files (AGENTS.md/CLAUDE.md)")
1122
- .option("--no-sandbox", "Leave the host Bash sandbox alone (by default it is turned on where it can start)")
1122
+ .option("--sandbox", "Turn the host Bash sandbox on where it can start (off by default: it blocks gh, push and Sonar)")
1123
+ .option("--no-sandbox", "Leave the host Bash sandbox alone (the default; kept for existing scripts)")
1123
1124
  .option("--mutation", "Also seed an opt-in nightly/manual mutation CI job (never a PR gate)")
1124
1125
  .option("--only <dirs...>", "Harden only these language roots (e.g. frontend backend)")
1125
1126
  .option("--exclude <globs...>", "Skip language roots matching these globs (e.g. wrappers)")
@@ -1137,7 +1138,7 @@ export function registerMeta(program, { pkgVersion }) {
1137
1138
  config: flags.config !== false,
1138
1139
  ci: flags.ci !== false,
1139
1140
  guidelines: flags.guidelines !== false,
1140
- sandbox: flags.sandbox !== false,
1141
+ sandbox: flags.sandbox === true,
1141
1142
  mutation: Boolean(flags.mutation),
1142
1143
  only: flags.only ?? [],
1143
1144
  exclude: flags.exclude ?? [],
@@ -92,7 +92,7 @@ export async function hardenCommand({
92
92
  only = [],
93
93
  exclude = [],
94
94
  commitSupervisor = false,
95
- sandbox = true,
95
+ sandbox = false,
96
96
  kjVersion = null,
97
97
  // KJC-BUG-0289: the contract files already dirty before anything was generated
98
98
  // (kj init captures them before writing its own). What is dirty NOW is the person's.
@@ -162,7 +162,8 @@ export async function hardenCommand({
162
162
  // sin sello, que es como una sesión se dejaba sin herramientas.
163
163
  const sh = installSentinelHooks({ projectDir, logger, human: commitSupervisor });
164
164
  result.sentinelHooks = sh.wired ? "wired" : "script-only";
165
- // KJC-TSK-1092: the host sandbox, on by default wherever it can start here.
165
+ // KJC-TSK-1092/1241: the host sandbox, only when asked (kj harden --sandbox):
166
+ // inside it kj run cannot push, open the PR or reach Sonar on localhost.
166
167
  if (sandbox) result.sandbox = installSandbox({ projectDir, logger }).state;
167
168
  }
168
169
  } catch (err) {
@@ -8,7 +8,7 @@
8
8
  * commands depend on what the project defines). Unknown language ⇒ no commands,
9
9
  * leaving only the universal POSIX-shell checks.
10
10
  */
11
- import { existsSync } from "node:fs";
11
+ import { existsSync, readFileSync } from "node:fs";
12
12
  import { join } from "node:path";
13
13
 
14
14
  // KJC-BUG-0411 (#2563): uv and poetry keep pytest and ruff in the project's
@@ -32,6 +32,23 @@ const FORMAT_WRITE_BY_LANGUAGE = {
32
32
  php: { command: "vendor/bin/php-cs-fixer fix", extensions: [".php"] },
33
33
  };
34
34
 
35
+ // KJC-TSK-1239: JS/TS takes the formatter the project declares, from its node_modules.
36
+ // Declared both? The one its scripts call wins; else prettier, the more common.
37
+ const JS_TS = [".js", ".mjs", ".cjs", ".jsx", ".ts", ".mts", ".cts", ".tsx"];
38
+ const JS_FORMATTERS = [
39
+ { pkg: "prettier", bin: "prettier", inScripts: /\bprettier\b/, command: "node_modules/.bin/prettier --write" },
40
+ { pkg: "@biomejs/biome", bin: "biome", inScripts: /\bbiome\b/, command: "node_modules/.bin/biome format --write" },
41
+ ];
42
+ function jsFormatWrite(projectDir) {
43
+ let pkg;
44
+ try { pkg = JSON.parse(readFileSync(join(projectDir, "package.json"), "utf8")); } catch { return null; }
45
+ const deps = { ...pkg.dependencies, ...pkg.devDependencies };
46
+ const scripts = Object.values(pkg.scripts ?? {}).join("\n");
47
+ const usable = JS_FORMATTERS.filter((f) => deps[f.pkg] && existsSync(join(projectDir, "node_modules", ".bin", f.bin)));
48
+ const chosen = usable.find((f) => f.inScripts.test(scripts)) ?? usable[0];
49
+ return chosen ? { command: chosen.command, extensions: JS_TS } : null;
50
+ }
51
+
35
52
  const runnerFor = (language, projectDir) => (language === "python" && projectDir
36
53
  ? PYTHON_RUNNERS.find(([lock]) => existsSync(join(projectDir, lock)))?.[1] ?? null
37
54
  : null);
@@ -46,6 +63,7 @@ export function commandsForLanguage(language, projectDir = null) {
46
63
 
47
64
  /** The write-mode formatter of a language and the extensions it takes, or null. */
48
65
  export function formatWriteFor(language, projectDir = null) {
66
+ if (language === "javascript" || language === "typescript") return projectDir ? jsFormatWrite(projectDir) : null;
49
67
  const entry = FORMAT_WRITE_BY_LANGUAGE[language];
50
68
  if (!entry) return null;
51
69
  return { ...entry, command: [runnerFor(language, projectDir), entry.command].filter(Boolean).join(" ") };