@ze-norm/cli 0.13.0 → 0.14.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.
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/api/client.ts"],"names":[],"mappings":"AAyBA,kFAAkF;AAClF,wBAAgB,qBAAqB,IAAI,IAAI,CAE5C;AAED,MAAM,WAAW,gBAAgB;IAC/B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AA0BD,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,qBAAa,YAAY;IACvB,OAAO,CAAC,OAAO,CAAS;IAIxB,OAAO,CAAC,aAAa,CAAgB;gBAEzB,IAAI,CAAC,EAAE,gBAAgB;IAKnC,wEAAwE;YAC1D,mBAAmB;IAMjC,OAAO,CAAC,YAAY;IA0BpB,OAAO,CAAC,cAAc;IAStB,2EAA2E;IAC3E,gBAAgB,IAAI,OAAO;IAI3B,uEAAuE;IACvE,qBAAqB,IAAI,OAAO;IAQhC,OAAO,CAAC,2BAA2B;YAIrB,QAAQ;YAqBR,OAAO;IAqEf,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC;IAIhC,IAAI,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,CAAC,CAAC;IAIjD,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,CAAC,CAAC;IAIhD,KAAK,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,CAAC,CAAC;IAIlD,MAAM,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC;IAIzC;;OAEG;IACG,cAAc,IAAI,OAAO,CAAC,WAAW,CAAC;CAG7C"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/api/client.ts"],"names":[],"mappings":"AA0BA,kFAAkF;AAClF,wBAAgB,qBAAqB,IAAI,IAAI,CAE5C;AAED,MAAM,WAAW,gBAAgB;IAC/B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAiCD,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,qBAAa,YAAY;IACvB,OAAO,CAAC,OAAO,CAAS;IAIxB,OAAO,CAAC,aAAa,CAAgB;gBAEzB,IAAI,CAAC,EAAE,gBAAgB;IAKnC,wEAAwE;YAC1D,mBAAmB;IAMjC,OAAO,CAAC,YAAY;IA0BpB,OAAO,CAAC,cAAc;IAStB,2EAA2E;IAC3E,gBAAgB,IAAI,OAAO;IAI3B,uEAAuE;IACvE,qBAAqB,IAAI,OAAO;IAYhC,OAAO,CAAC,2BAA2B;YAIrB,QAAQ;YAqBR,OAAO;IAqEf,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC;IAIhC,IAAI,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,CAAC,CAAC;IAIjD,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,CAAC,CAAC;IAIhD,KAAK,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,CAAC,CAAC;IAIlD,MAAM,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC;IAIzC;;OAEG;IACG,cAAc,IAAI,OAAO,CAAC,WAAW,CAAC;CAG7C"}
@@ -3,6 +3,7 @@ import { join } from "node:path";
3
3
  import { ApiError, AuthError, UpgradeRequiredError } from "../util/errors.js";
4
4
  import { forceRefreshToken, hasRefreshableCredentials, resolveValidToken, } from "../auth/store.js";
5
5
  import { PRODUCTION_API_URL } from "../config/defaults.js";
6
+ import { resolveEnvironment, ZENORM_CLI_ENV_VAR } from "../config/environments.js";
6
7
  import { getCliVersion } from "../util/package.js";
7
8
  import { log } from "../util/logger.js";
8
9
  const UPGRADE_COMMAND = "npm install -g @ze-norm/cli@latest";
@@ -23,11 +24,17 @@ function resolveBaseUrl(explicit) {
23
24
  // 1. Explicit option
24
25
  if (explicit)
25
26
  return explicit;
26
- // 2. Environment variable
27
+ // 2. Named environment via ZENORM_CLI. A selected environment is an explicit
28
+ // "talk to this stack" intent, so its API URL wins over a stray
29
+ // ZENORM_API_URL / .zenorm.json left over from another workflow.
30
+ if (process.env[ZENORM_CLI_ENV_VAR]) {
31
+ return resolveEnvironment().apiUrl;
32
+ }
33
+ // 3. Environment variable
27
34
  const envUrl = process.env["ZENORM_API_URL"];
28
35
  if (envUrl)
29
36
  return envUrl;
30
- // 3. .zenorm.json config file in cwd
37
+ // 4. .zenorm.json config file in cwd
31
38
  const configPath = join(process.cwd(), ".zenorm.json");
32
39
  if (existsSync(configPath)) {
33
40
  const raw = readFileSync(configPath, "utf-8");
@@ -35,7 +42,7 @@ function resolveBaseUrl(explicit) {
35
42
  if (config.apiUrl)
36
43
  return config.apiUrl;
37
44
  }
38
- // 4. Public CLI default
45
+ // 5. Public CLI default
39
46
  return PRODUCTION_API_URL;
40
47
  }
41
48
  export class ZenormClient {
@@ -95,9 +102,12 @@ export class ZenormClient {
95
102
  }
96
103
  /** True when requests will intentionally ignore stored credentials. */
97
104
  isUsingLocalDevBypass() {
98
- return (this.isLocalBaseUrl() &&
99
- process.env["ZENORM_LOCAL_DEV_BYPASS_AUTH"] === "true" &&
100
- !process.env["ZENORM_API_TOKEN"]);
105
+ // Selecting the `local` environment implies dev-bypass — that is what the
106
+ // local stack is (no real Clerk sign-in, dev-bypass headers). An explicit
107
+ // ZENORM_LOCAL_DEV_BYPASS_AUTH still enables it for a raw localhost URL.
108
+ const bypassEnabled = process.env["ZENORM_LOCAL_DEV_BYPASS_AUTH"] === "true" ||
109
+ resolveEnvironment().name === "local";
110
+ return (this.isLocalBaseUrl() && bypassEnabled && !process.env["ZENORM_API_TOKEN"]);
101
111
  }
102
112
  shouldBypassAuthForLocalDev() {
103
113
  return this.isUsingLocalDevBypass();
@@ -1 +1 @@
1
- {"version":3,"file":"device-flow.d.ts","sourceRoot":"","sources":["../../src/auth/device-flow.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAkUpD;;;;;;;;GAQG;AACH,wBAAsB,kBAAkB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC;IACtE,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC,CAuBD;AAED;;;;;;;;;GASG;AACH,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,iBAAiB,CAAC,CAkDpE"}
1
+ {"version":3,"file":"device-flow.d.ts","sourceRoot":"","sources":["../../src/auth/device-flow.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AA6UpD;;;;;;;;GAQG;AACH,wBAAsB,kBAAkB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC;IACtE,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC,CAuBD;AAED;;;;;;;;;GASG;AACH,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,iBAAiB,CAAC,CAkDpE"}
@@ -5,6 +5,7 @@ import { platform } from "node:os";
5
5
  import { URL, URLSearchParams } from "node:url";
6
6
  import { log } from "../util/logger.js";
7
7
  import { CLI_CALLBACK_PORTS, PRODUCTION_CLERK_CLIENT_ID, PRODUCTION_CLERK_ISSUER, } from "../config/defaults.js";
8
+ import { resolveEnvironment, ZENORM_CLI_ENV_VAR } from "../config/environments.js";
8
9
  /**
9
10
  * Find the first pre-registered callback port that is free to bind. Clerk
10
11
  * matches redirect_uris exactly, so the local listener must use one of the
@@ -26,6 +27,11 @@ async function pickFreeCallbackPort() {
26
27
  `Free one of them and run \`zenorm login\` again.`);
27
28
  }
28
29
  function getClerkIssuer() {
30
+ // A named environment (ZENORM_CLI) selects the whole Clerk instance, so it
31
+ // wins over a stray ZENORM_CLERK_ISSUER from another workflow.
32
+ if (process.env[ZENORM_CLI_ENV_VAR]) {
33
+ return resolveEnvironment().clerkIssuer;
34
+ }
29
35
  return process.env["ZENORM_CLERK_ISSUER"] ?? PRODUCTION_CLERK_ISSUER;
30
36
  }
31
37
  /** Escape user-influenced text before interpolating into the result page HTML. */
@@ -38,6 +44,11 @@ function escapeHtml(value) {
38
44
  .replace(/'/g, "'");
39
45
  }
40
46
  function getClerkClientId() {
47
+ // A named environment (ZENORM_CLI) selects the whole Clerk instance, so it
48
+ // wins over stray ZENORM_CLERK_CLIENT_ID / VITE_CLERK_PUBLISHABLE_KEY vars.
49
+ if (process.env[ZENORM_CLI_ENV_VAR]) {
50
+ return resolveEnvironment().clerkClientId;
51
+ }
41
52
  return (process.env["ZENORM_CLERK_CLIENT_ID"] ??
42
53
  process.env["VITE_CLERK_PUBLISHABLE_KEY"] ??
43
54
  PRODUCTION_CLERK_CLIENT_ID);
@@ -1 +1 @@
1
- {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/auth/store.ts"],"names":[],"mappings":"AAUA,MAAM,WAAW,iBAAiB;IAChC,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB;AAaD,wBAAgB,eAAe,IAAI,iBAAiB,GAAG,IAAI,CAO1D;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,iBAAiB,GAAG,IAAI,CAM9D;AAED,wBAAgB,iBAAiB,IAAI,OAAO,CAO3C;AAED;;;;;;;GAOG;AACH,wBAAgB,YAAY,IAAI,MAAM,GAAG,IAAI,CAU5C;AAWD;;;;;;;;;;GAUG;AACH,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAwBhE;AAED;;;;GAIG;AACH,wBAAgB,yBAAyB,IAAI,OAAO,CAInD;AAED;;;;;;GAMG;AACH,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,MAAM,CAAC,CAezD"}
1
+ {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/auth/store.ts"],"names":[],"mappings":"AAWA,MAAM,WAAW,iBAAiB;IAChC,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB;AAmBD,wBAAgB,eAAe,IAAI,iBAAiB,GAAG,IAAI,CAO1D;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,iBAAiB,GAAG,IAAI,CAM9D;AAED,wBAAgB,iBAAiB,IAAI,OAAO,CAO3C;AAED;;;;;;;GAOG;AACH,wBAAgB,YAAY,IAAI,MAAM,GAAG,IAAI,CAU5C;AAWD;;;;;;;;;;GAUG;AACH,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAwBhE;AAED;;;;GAIG;AACH,wBAAgB,yBAAyB,IAAI,OAAO,CAInD;AAED;;;;;;GAMG;AACH,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,MAAM,CAAC,CAezD"}
@@ -2,12 +2,18 @@ import { existsSync, mkdirSync, readFileSync, unlinkSync, writeFileSync } from "
2
2
  import { homedir } from "node:os";
3
3
  import { join } from "node:path";
4
4
  import { refreshAccessToken } from "./device-flow.js";
5
+ import { resolveEnvironment } from "../config/environments.js";
5
6
  import { log } from "../util/logger.js";
6
7
  // Refresh the access token this many ms before it actually expires, so an
7
8
  // in-flight request never races the expiry boundary.
8
9
  const EXPIRY_SKEW_MS = 60_000;
10
+ // Credentials are scoped per environment so a prod login and a dev login can
11
+ // coexist instead of overwriting each other. Prod keeps the historical
12
+ // `credentials.json` filename for back-compat; other stacks get a suffix.
9
13
  function getCredentialsPath() {
10
- return join(homedir(), ".zenorm", "credentials.json");
14
+ const env = resolveEnvironment();
15
+ const filename = env.name === "prod" ? "credentials.json" : `credentials.${env.name}.json`;
16
+ return join(homedir(), ".zenorm", filename);
11
17
  }
12
18
  function ensureDir() {
13
19
  const dir = join(homedir(), ".zenorm");
@@ -6,7 +6,7 @@ import type { ChildProcess, SpawnOptions } from "node:child_process";
6
6
  * the daemon does NOT run the agent headlessly. Instead it launches the active
7
7
  * coding agent — Claude Code by default, or Codex when the user runs with
8
8
  * `--agent codex` — as a *live interactive session*, seeded with the
9
- * `/zenorm <specId>` handoff. The agent owns the terminal directly (inherited
9
+ * harness-native ZeNorm skill handoff. The agent owns the terminal directly (inherited
10
10
  * stdio), so the operator works with it interactively until they close it; when
11
11
  * the agent exits, the daemon releases the worker and moves on to the next task.
12
12
  *
@@ -1 +1 @@
1
- {"version":3,"file":"pull.d.ts","sourceRoot":"","sources":["../../src/commands/pull.ts"],"names":[],"mappings":"AAcA,wBAAsB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CA4F/D"}
1
+ {"version":3,"file":"pull.d.ts","sourceRoot":"","sources":["../../src/commands/pull.ts"],"names":[],"mappings":"AAcA,wBAAsB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CA8F/D"}
@@ -39,9 +39,11 @@ export async function pullCommand(argv) {
39
39
  log.debug("Listing specs to resolve by key", { specRef });
40
40
  const { specs } = await client.get("/v1/specs");
41
41
  spec = specs.find((s) => s.key === specRef);
42
- }
43
- if (!spec) {
44
- throw new CliError(`Spec "${specRef}" not found by key or id. Run \`zenorm list\` to see available specs.`);
42
+ if (!spec) {
43
+ const available = specs.map((s) => s.key).join(", ");
44
+ throw new CliError(`Spec "${specRef}" not found by key or id.` +
45
+ (available ? ` Available spec keys: ${available}` : " The workspace has no specs."));
46
+ }
45
47
  }
46
48
  // Fetch grilled blocks (goals, constraints, acceptance criteria, tasks).
47
49
  let blocksMd = "";
@@ -1 +1 @@
1
- {"version":3,"file":"task.d.ts","sourceRoot":"","sources":["../../src/commands/task.ts"],"names":[],"mappings":"AAyOA,wBAAsB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAqB/D"}
1
+ {"version":3,"file":"task.d.ts","sourceRoot":"","sources":["../../src/commands/task.ts"],"names":[],"mappings":"AA2OA,wBAAsB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAqB/D"}
@@ -33,7 +33,9 @@ async function resolveSpecId(client, specRef) {
33
33
  const { specs } = await client.get("/v1/specs");
34
34
  const spec = specs.find((s) => s.key === specRef);
35
35
  if (!spec) {
36
- throw new CliError(`Spec "${specRef}" not found by key or id. Run \`zenorm list\` to see available specs.`);
36
+ const available = specs.map((s) => s.key).join(", ");
37
+ throw new CliError(`Spec "${specRef}" not found by key or id.` +
38
+ (available ? ` Available spec keys: ${available}` : " The workspace has no specs."));
37
39
  }
38
40
  return spec.id;
39
41
  }
@@ -23,8 +23,9 @@ export interface TaskRunner {
23
23
  * Build the handoff prompt that hands the agent the WHOLE SPEC the claimed task
24
24
  * belongs to, so a single agent session implements every available task for that
25
25
  * spec with shared context — instead of one fresh session per task. The
26
- * `/zenorm <specId>` trigger is what the `zenorm` dispatcher SKILL.md keys on
27
- * (spec mode `execute-task` walks every `planned`/`todo` task in order).
26
+ * harness-native ZeNorm invocation (`/zenorm` for Claude Code, `$zenorm`
27
+ * for Codex) triggers the dispatcher in spec mode, where `execute-task` walks
28
+ * every `planned`/`todo` task in order.
28
29
  *
29
30
  * The claim only flips THIS one task to `active` server-side (the lease that
30
31
  * proves there is work for this repo and guards against a second daemon). The
@@ -35,14 +36,14 @@ export interface TaskRunner {
35
36
  *
36
37
  * Exported for unit testing.
37
38
  */
38
- export declare function buildHandoffPrompt(task: SpecTaskRecord): string;
39
+ export declare function buildHandoffPrompt(task: SpecTaskRecord, agent: SupportedAgent): string;
39
40
  /**
40
41
  * The interactive (coding-agent mode) handoff prompt. Same spec-mode handoff as
41
42
  * the headless prompt, MINUS the "work non-interactively" instruction: in this
42
43
  * mode the agent runs as a live session the operator drives, so it SHOULD pause
43
44
  * for input. Exported for unit testing.
44
45
  */
45
- export declare function buildInteractiveHandoffPrompt(task: SpecTaskRecord): string;
46
+ export declare function buildInteractiveHandoffPrompt(task: SpecTaskRecord, agent: SupportedAgent): string;
46
47
  /**
47
48
  * The headless subprocess invocation for a given agent + task. Pure (no
48
49
  * side effects) so it can be unit-tested directly without spawning anything.
@@ -1 +1 @@
1
- {"version":3,"file":"work.d.ts","sourceRoot":"","sources":["../../src/commands/work.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"work.d.ts","sourceRoot":"","sources":["../../src/commands/work.ts"],"names":[],"mappings":"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"}
@@ -61,8 +61,9 @@ const AGENT_INSTALL_HINT = {
61
61
  * Build the handoff prompt that hands the agent the WHOLE SPEC the claimed task
62
62
  * belongs to, so a single agent session implements every available task for that
63
63
  * spec with shared context — instead of one fresh session per task. The
64
- * `/zenorm <specId>` trigger is what the `zenorm` dispatcher SKILL.md keys on
65
- * (spec mode `execute-task` walks every `planned`/`todo` task in order).
64
+ * harness-native ZeNorm invocation (`/zenorm` for Claude Code, `$zenorm`
65
+ * for Codex) triggers the dispatcher in spec mode, where `execute-task` walks
66
+ * every `planned`/`todo` task in order.
66
67
  *
67
68
  * The claim only flips THIS one task to `active` server-side (the lease that
68
69
  * proves there is work for this repo and guards against a second daemon). The
@@ -73,10 +74,10 @@ const AGENT_INSTALL_HINT = {
73
74
  *
74
75
  * Exported for unit testing.
75
76
  */
76
- export function buildHandoffPrompt(task) {
77
+ export function buildHandoffPrompt(task, agent) {
77
78
  const zenormCli = process.env["ZENORM_CLI"]?.trim() || "zenorm";
78
79
  return [
79
- ...handoffPromptBody(task, zenormCli),
80
+ ...handoffPromptBody(task, zenormCli, agent),
80
81
  // Headless runs have no operator to wait on — tell the agent to drive
81
82
  // straight through without pausing for input. The interactive variant
82
83
  // (buildInteractiveHandoffPrompt) deliberately omits this line.
@@ -89,14 +90,14 @@ export function buildHandoffPrompt(task) {
89
90
  * mode the agent runs as a live session the operator drives, so it SHOULD pause
90
91
  * for input. Exported for unit testing.
91
92
  */
92
- export function buildInteractiveHandoffPrompt(task) {
93
+ export function buildInteractiveHandoffPrompt(task, agent) {
93
94
  const zenormCli = process.env["ZENORM_CLI"]?.trim() || "zenorm";
94
- return handoffPromptBody(task, zenormCli).join("\n");
95
+ return handoffPromptBody(task, zenormCli, agent).join("\n");
95
96
  }
96
97
  /** Shared spec-mode handoff lines for both the headless and interactive prompts. */
97
- function handoffPromptBody(task, zenormCli) {
98
+ function handoffPromptBody(task, zenormCli, agent) {
98
99
  return [
99
- `/zenorm ${task.specId}`,
100
+ buildSkillInvocation(agent, task.specId),
100
101
  "",
101
102
  `Execute ALL available tasks for ZeNorm spec ${task.specId} in THIS one`,
102
103
  "session (spec mode — walk every `planned`/`todo` task in list order). Do not",
@@ -112,6 +113,19 @@ function handoffPromptBody(task, zenormCli) {
112
113
  `\`${zenormCli} task complete <task-id>\` flow as you finish it.`,
113
114
  ];
114
115
  }
116
+ /** Build the explicit skill invocation understood by the selected harness. */
117
+ function buildSkillInvocation(agent, specId) {
118
+ switch (agent) {
119
+ case "claude":
120
+ return `/zenorm ${specId}`;
121
+ case "codex":
122
+ return `$zenorm ${specId}`;
123
+ default: {
124
+ const never = agent;
125
+ throw new CliError(`No ZeNorm skill invocation defined for agent "${String(never)}".`);
126
+ }
127
+ }
128
+ }
115
129
  /**
116
130
  * The headless subprocess invocation for a given agent + task. Pure (no
117
131
  * side effects) so it can be unit-tested directly without spawning anything.
@@ -125,7 +139,7 @@ function handoffPromptBody(task, zenormCli) {
125
139
  * Exported for unit testing.
126
140
  */
127
141
  export function buildAgentCommand(agent, task, model) {
128
- const prompt = buildHandoffPrompt(task);
142
+ const prompt = buildHandoffPrompt(task, agent);
129
143
  switch (agent) {
130
144
  case "claude":
131
145
  // stream-json requires --verbose; it does NOT make the transcript verbose
@@ -208,7 +222,7 @@ export function buildAgentCommand(agent, task, model) {
208
222
  * Exported for unit testing.
209
223
  */
210
224
  export function buildInteractiveAgentCommand(agent, task, model) {
211
- const prompt = buildInteractiveHandoffPrompt(task);
225
+ const prompt = buildInteractiveHandoffPrompt(task, agent);
212
226
  switch (agent) {
213
227
  case "claude":
214
228
  return {
@@ -0,0 +1,31 @@
1
+ /**
2
+ * A named CLI environment: the full bundle of endpoints the CLI talks to.
3
+ * Selecting one via the `ZENORM_CLI` env var switches API + Clerk together, so
4
+ * you never have to keep `ZENORM_API_URL`, `ZENORM_CLERK_ISSUER`, and
5
+ * `ZENORM_CLERK_CLIENT_ID` in sync by hand.
6
+ *
7
+ * IMPORTANT: only the **prod** preset is baked into this (published) module.
8
+ * The non-prod stacks point at an internal Clerk instance whose identifiers
9
+ * must NOT ship in the public npm tarball (the publish pipeline greps the
10
+ * package for them and blocks the release). Those stacks are launched by the
11
+ * non-shipped source entries (`local.ts` / `dev.ts`, run via their repo shims),
12
+ * which inject `ZENORM_API_URL` + `ZENORM_CLERK_*` before importing the CLI.
13
+ * When `ZENORM_CLI` selects a non-prod stack, this resolver reads those
14
+ * injected vars instead of baking the endpoints in.
15
+ */
16
+ export interface CliEnvironment {
17
+ readonly name: "prod" | "dev" | "local";
18
+ readonly apiUrl: string;
19
+ readonly clerkIssuer: string;
20
+ readonly clerkClientId: string;
21
+ }
22
+ export declare const ZENORM_CLI_ENV_VAR = "ZENORM_CLI";
23
+ /**
24
+ * Resolve the active CLI environment from `ZENORM_CLI`.
25
+ *
26
+ * Unset → production (the public default). A set-but-unrecognized value is a
27
+ * loud error rather than a silent fallback: a typo like `ZENORM_CLI=prd` must
28
+ * not quietly send `zenorm` commands at the wrong stack.
29
+ */
30
+ export declare function resolveEnvironment(): CliEnvironment;
31
+ //# sourceMappingURL=environments.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"environments.d.ts","sourceRoot":"","sources":["../../src/config/environments.ts"],"names":[],"mappings":"AAOA;;;;;;;;;;;;;;GAcG;AACH,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,KAAK,GAAG,OAAO,CAAC;IACxC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;CAChC;AASD,eAAO,MAAM,kBAAkB,eAAe,CAAC;AAyC/C;;;;;;GAMG;AACH,wBAAgB,kBAAkB,IAAI,cAAc,CAiBnD"}
@@ -0,0 +1,65 @@
1
+ import { CliError } from "../util/errors.js";
2
+ import { PRODUCTION_API_URL, PRODUCTION_CLERK_CLIENT_ID, PRODUCTION_CLERK_ISSUER, } from "./defaults.js";
3
+ const PROD_ENVIRONMENT = {
4
+ name: "prod",
5
+ apiUrl: PRODUCTION_API_URL,
6
+ clerkIssuer: PRODUCTION_CLERK_ISSUER,
7
+ clerkClientId: PRODUCTION_CLERK_CLIENT_ID,
8
+ };
9
+ export const ZENORM_CLI_ENV_VAR = "ZENORM_CLI";
10
+ const ENV_NAMES = ["prod", "dev", "local"];
11
+ /**
12
+ * Normalize a raw `ZENORM_CLI` value to a canonical env name. Accepts the bare
13
+ * name (`prod`/`dev`/`local`), `production`, and each name with a `-zenorm`
14
+ * suffix (constructed here so the suffixed literal is never a static token).
15
+ */
16
+ function parseEnvName(raw) {
17
+ const key = raw.trim().toLowerCase();
18
+ if (key === "production")
19
+ return "prod";
20
+ for (const name of ENV_NAMES) {
21
+ if (key === name || key === `${name}-zenorm`)
22
+ return name;
23
+ }
24
+ return null;
25
+ }
26
+ /**
27
+ * Build a non-prod environment from the endpoint env vars injected by the
28
+ * repo launchers. Fails loud if they are missing — that means the public
29
+ * `zenorm` was pointed at an internal stack without the launcher that carries
30
+ * its (non-shipped) endpoints, and we must not silently fall back to prod.
31
+ */
32
+ function environmentFromInjectedVars(name) {
33
+ const apiUrl = process.env["ZENORM_API_URL"];
34
+ const clerkIssuer = process.env["ZENORM_CLERK_ISSUER"];
35
+ const clerkClientId = process.env["ZENORM_CLERK_CLIENT_ID"];
36
+ if (!apiUrl || !clerkIssuer || !clerkClientId) {
37
+ const shim = `${name}${"-zenorm"}`;
38
+ throw new CliError(`${ZENORM_CLI_ENV_VAR}=${name} needs the ${name} endpoints, which are not ` +
39
+ `bundled in the public CLI. Launch it with \`${shim}\` (from the repo), ` +
40
+ `or set ZENORM_API_URL, ZENORM_CLERK_ISSUER, and ZENORM_CLERK_CLIENT_ID.`);
41
+ }
42
+ return { name, apiUrl, clerkIssuer, clerkClientId };
43
+ }
44
+ /**
45
+ * Resolve the active CLI environment from `ZENORM_CLI`.
46
+ *
47
+ * Unset → production (the public default). A set-but-unrecognized value is a
48
+ * loud error rather than a silent fallback: a typo like `ZENORM_CLI=prd` must
49
+ * not quietly send `zenorm` commands at the wrong stack.
50
+ */
51
+ export function resolveEnvironment() {
52
+ const raw = process.env[ZENORM_CLI_ENV_VAR];
53
+ if (raw === undefined || raw.trim() === "") {
54
+ return PROD_ENVIRONMENT;
55
+ }
56
+ const name = parseEnvName(raw);
57
+ if (!name) {
58
+ const allowed = ENV_NAMES.join(", ");
59
+ throw new CliError(`Invalid ${ZENORM_CLI_ENV_VAR}=${JSON.stringify(raw)}. ` +
60
+ `Expected one of: ${allowed} (or a "-zenorm" suffixed form).`);
61
+ }
62
+ if (name === "prod")
63
+ return PROD_ENVIRONMENT;
64
+ return environmentFromInjectedVars(name);
65
+ }
@@ -2,9 +2,11 @@
2
2
  name: zenorm
3
3
  description: >-
4
4
  Dispatcher for explicit ZeNorm spec-driven work. Use when the user invokes
5
- `/zenorm ...`, or explicitly asks to execute, implement, run, continue, or
6
- sync a ZeNorm spec or task e.g. "implement spec AUTH-123", "run this
7
- ZeNorm spec", "continue spec Z-9", "do ZeNorm task <uuid>", "sync zenorm",
5
+ the harness-native ZeNorm skill command (`/zenorm ...` in Claude Code,
6
+ `$zenorm ...` in Codex, or `@zenorm ...` in Cursor), or explicitly asks to
7
+ execute, implement, run, continue, or sync a ZeNorm spec or task e.g.
8
+ "implement spec AUTH-123", "run this ZeNorm spec", "continue spec Z-9",
9
+ "do ZeNorm task UUID", "sync zenorm",
8
10
  "wrap up the ZeNorm session". It routes to the right focused skill:
9
11
  full-spec execution, single-task execution, or session sync-back, and owns
10
12
  the session id and the final outcome flush. Do NOT trigger merely because a
@@ -20,7 +22,8 @@ child skills rely on: the **session id** and the **single final sync**.
20
22
 
21
23
  ## Routing
22
24
 
23
- `$ARGUMENTS` is everything after `/zenorm`. Run the resolver it strips
25
+ `$ARGUMENTS` is everything after the harness-native skill invocation
26
+ (`/zenorm`, `$zenorm`, or `@zenorm`). Run the resolver — it strips
24
27
  verbs, classifies the target, and resolves spec keys of ANY shape (code,
25
28
  slug, or UUID) against the CLI so you do not guess:
26
29
 
@@ -42,7 +45,7 @@ for looking unfamiliar. The resolver already checked it against the CLI.
42
45
 
43
46
  The `--dispatched` flag tells `execute-task` that *you* (the dispatcher) own
44
47
  the final `zenorm-sync`, so it will not run its own. This keeps sync
45
- single-owner: exactly one sync per `/zenorm` invocation, no double posts. (If
48
+ single-owner: exactly one sync per ZeNorm skill invocation, no double posts. (If
46
49
  a user runs `execute-task` directly without going through you, it has no
47
50
  `--dispatched` flag and syncs itself — that path stays correct too.)
48
51
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@ze-norm/cli",
3
3
  "private": false,
4
- "version": "0.13.0",
4
+ "version": "0.14.2",
5
5
  "license": "SEE LICENSE IN README.md",
6
6
  "type": "module",
7
7
  "repository": {