@kici-dev/compiler 0.6.0 → 0.7.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.
Files changed (45) hide show
  1. package/dist/cli.js +10 -2
  2. package/dist/commands/compile.js +5 -1
  3. package/dist/commands/doctor.js +8 -2
  4. package/dist/commands/feedback.d.ts +53 -0
  5. package/dist/commands/feedback.js +142 -0
  6. package/dist/commands/index.d.ts +2 -0
  7. package/dist/commands/index.js +2 -1
  8. package/dist/commands/init.d.ts +9 -0
  9. package/dist/commands/init.js +77 -12
  10. package/dist/commands/preview.js +1 -1
  11. package/dist/commands/report/identity.d.ts +11 -0
  12. package/dist/commands/report/identity.js +7 -2
  13. package/dist/commands/run-routed.js +1 -0
  14. package/dist/commands/types.d.ts +6 -1
  15. package/dist/commands/types.js +2 -1
  16. package/dist/execution/executor.js +7 -1
  17. package/dist/llm-context/llms-architecture.txt +72 -86
  18. package/dist/llm-context/llms-cli-remote.txt +2380 -0
  19. package/dist/llm-context/llms-cli.txt +348 -2615
  20. package/dist/llm-context/llms-features-execution.txt +80 -23
  21. package/dist/llm-context/llms-features.txt +137 -6
  22. package/dist/llm-context/llms-full.txt +2582 -2025
  23. package/dist/llm-context/llms-getting-started.txt +152 -5
  24. package/dist/llm-context/llms-patterns.txt +81 -5
  25. package/dist/llm-context/llms-providers.txt +6 -2
  26. package/dist/llm-context/llms-sdk-runtime.txt +22 -18
  27. package/dist/llm-context/llms-sdk.txt +47 -7
  28. package/dist/llm-context/llms.txt +20 -13
  29. package/dist/local-plane/orchestrator-process.d.ts +0 -8
  30. package/dist/local-plane/orchestrator-process.js +3 -14
  31. package/dist/local-plane/plane-manager.js +2 -2
  32. package/dist/lockfile/generator.js +25 -9
  33. package/dist/lockfile/hasher.d.ts +5 -13
  34. package/dist/lockfile/hasher.js +1 -15
  35. package/dist/lockfile/workspace-siblings.d.ts +46 -0
  36. package/dist/lockfile/workspace-siblings.js +197 -0
  37. package/dist/templates/package-json.js +1 -1
  38. package/dist/test-runner/job-executor.js +1 -1
  39. package/dist/test-runner/rule-evaluator.js +1 -1
  40. package/dist/types.d.ts +6 -1
  41. package/package.json +7 -9
  42. package/sbom.spdx.json +123 -123
  43. package/dist/postinstall.d.ts +0 -9
  44. package/dist/postinstall.js +0 -62
  45. package/hack/postinstall.mjs +0 -105
package/dist/cli.js CHANGED
@@ -7,7 +7,7 @@ import { realpathSync } from "node:fs";
7
7
  import { Argument, Command } from "commander";
8
8
  import pc from "picocolors";
9
9
  //#region src/cli.ts
10
- const version = "0.6.0";
10
+ const version = "0.7.0";
11
11
  /**
12
12
  * Top-level commands that were removed, mapped to their current equivalent.
13
13
  * Consulted when the CLI hits an unknown command so the user gets a precise
@@ -484,7 +484,7 @@ Environment variables:
484
484
  const { docsCommand } = await import("./commands/index.js");
485
485
  const success = await docsCommand({ open: options.open });
486
486
  process.exit(success ? 0 : 1);
487
- }).command("llm [topic]").description("Print KiCI LLM docs bundles. No topic prints the llms.txt index; <topic> prints a task bundle (e.g. sdk, cli, patterns, features, providers, architecture, getting-started); \"full\" prints the complete bundle.").option("--out <path>", "Write the bundle to a file instead of stdout").action(async (topic, options) => {
487
+ }).command("llm [topic]").description("Print KiCI LLM docs bundles. No topic prints the llms.txt index; <topic> prints a task bundle (e.g. sdk, cli, cli-remote, patterns, features, providers, architecture, getting-started); \"full\" prints the complete bundle.").option("--out <path>", "Write the bundle to a file instead of stdout").action(async (topic, options) => {
488
488
  const { docsLlmCommand } = await import("./commands/index.js");
489
489
  const success = await docsLlmCommand({
490
490
  topic,
@@ -492,6 +492,14 @@ Environment variables:
492
492
  });
493
493
  process.exit(success ? 0 : 1);
494
494
  });
495
+ program.command("feedback").description("Print how to report a discrepancy between what KiCI advertises and what it does. Files nothing.").option("--open", "Open the prefilled issue form in the default browser").option("--json", "Emit the reporting contract as JSON").action(async (options) => {
496
+ const { feedbackCommand } = await import("./commands/index.js");
497
+ const success = await feedbackCommand({
498
+ open: options.open,
499
+ json: options.json
500
+ });
501
+ process.exit(success ? 0 : 1);
502
+ });
495
503
  program.command("admin").description("Operator-facing commands for running instances").command("drain-worker").description("Trigger graceful drain on a worker instance").requiredOption("--url <url>", "Worker URL (e.g., http://worker-host:<port>)").action(async (options) => {
496
504
  const { drainWorkerCommand } = await import("./commands/index.js");
497
505
  const success = await drainWorkerCommand({ url: options.url });
@@ -13,6 +13,7 @@ import path from "node:path";
13
13
  import { existsSync } from "node:fs";
14
14
  import pc from "picocolors";
15
15
  import fs$1 from "node:fs/promises";
16
+ import { findDigestReproducibilityWarnings, loadKiciIgnoreRules } from "@kici-dev/core/kici-source-digest";
16
17
  import { logger, toErrorMessage } from "@kici-dev/core";
17
18
  import { PackageManager, detectPackageManagerSync } from "@kici-dev/core/package-manager";
18
19
  import { execSync } from "node:child_process";
@@ -80,6 +81,9 @@ async function compileCommand(options) {
80
81
  const lockJson = serializeLockFile(lockFile);
81
82
  const windowWarning = schemaWindowWarning(BREAKING_FLOOR, SCHEMA_VERSION);
82
83
  if (windowWarning) logger.warn(pc.yellow(windowWarning));
84
+ const ignoreRules = await loadKiciIgnoreRules(absoluteKiciDir);
85
+ for (const warning of ignoreRules.warnings) logger.warn(pc.yellow(warning));
86
+ for (const warning of await findDigestReproducibilityWarnings(absoluteKiciDir, ignoreRules)) logger.warn(pc.yellow(warning));
83
87
  if (!options.check) {
84
88
  await fs$1.writeFile(lockPath, lockJson, "utf-8");
85
89
  if (!options.quiet) logger.info(pc.green("✓") + ` Compiled workflows → .kici/kici.lock.json` + pc.dim(` (${workflowsWithSource.length} workflow${workflowsWithSource.length !== 1 ? "s" : ""})`));
@@ -91,7 +95,7 @@ async function compileCommand(options) {
91
95
  if (hasToken && hasEndpoint && config.activeOrgId) {
92
96
  const { typesCommand } = await import("./types.js");
93
97
  await typesCommand({
94
- kiciDir,
98
+ kiciDir: absoluteKiciDir,
95
99
  quiet: options.quiet
96
100
  });
97
101
  }
@@ -8,7 +8,7 @@ import path from "node:path";
8
8
  import pc from "picocolors";
9
9
  import fs from "node:fs/promises";
10
10
  import { deriveDiagnoseOverall, diagnoseExitCode, toErrorMessage } from "@kici-dev/core";
11
- import { matcherSatisfiedBy } from "@kici-dev/engine";
11
+ import { canonicalizeLabelSet, canonicalizeMatcher, matcherSatisfiedBy } from "@kici-dev/engine";
12
12
  import { execFile } from "node:child_process";
13
13
  import { promisify } from "node:util";
14
14
  //#region src/commands/doctor.ts
@@ -157,9 +157,15 @@ function checkLockFile(state) {
157
157
  * A label group satisfies a requirement only when it matches EVERY runsOn
158
158
  * matcher AND matches NONE of the excludeLabels — the same authority the
159
159
  * orchestrator's job queue applies (`runsOn.every` && `!exclude.some`).
160
+ *
161
+ * Both sides are folded first, and both arms of the check get the fold: the
162
+ * probe reports canonical agent labels while lock matchers carry whatever case
163
+ * the workflow author wrote, so comparing them raw would report a dispatchable
164
+ * job unreachable and would let an excluded label slip past on case alone.
160
165
  */
161
166
  function requirementSatisfiedBy(req, labels) {
162
- return req.runsOn.every((m) => matcherSatisfiedBy(m, labels)) && !req.exclude.some((m) => matcherSatisfiedBy(m, labels));
167
+ const canonical = canonicalizeLabelSet([...labels]);
168
+ return req.runsOn.every((m) => matcherSatisfiedBy(canonicalizeMatcher(m), canonical)) && !req.exclude.some((m) => matcherSatisfiedBy(canonicalizeMatcher(m), canonical));
163
169
  }
164
170
  function describeMatcher(m) {
165
171
  return m.kind === "regex" ? `/${m.source}/${m.flags}` : m.value;
@@ -0,0 +1,53 @@
1
+ /** The public tracker. Reports about KiCI itself go here — never customer data. */
2
+ export declare const FEEDBACK_TRACKER_URL = "https://github.com/kici-dev/kici-public";
3
+ /** The issue form tuned for an advertised-versus-actual report. */
4
+ export declare const FEEDBACK_TEMPLATE = "agent_report.yml";
5
+ export declare const FEEDBACK_NEW_ISSUE_URL = "https://github.com/kici-dev/kici-public/issues/new?template=agent_report.yml";
6
+ /** Suspected vulnerabilities go here instead, privately. */
7
+ export declare const FEEDBACK_SECURITY_ADVISORY_URL = "https://github.com/kici-dev/kici-public/security/advisories/new";
8
+ export interface FeedbackField {
9
+ id: string;
10
+ label: string;
11
+ description: string;
12
+ }
13
+ export interface FeedbackContract {
14
+ tracker: string;
15
+ newIssueUrl: string;
16
+ template: string;
17
+ securityAdvisoryUrl: string;
18
+ guideUrl: string;
19
+ searchCommand: string;
20
+ approval: {
21
+ required: boolean;
22
+ rule: string;
23
+ };
24
+ qualifies: string[];
25
+ doesNotQualify: string[];
26
+ requiredFields: FeedbackField[];
27
+ prohibited: string[];
28
+ privateReportCommand: string;
29
+ }
30
+ /**
31
+ * The single definition of what a reportable discrepancy is and what a report
32
+ * must carry. `kici feedback` prints it, `--json` emits it verbatim, and
33
+ * hack/feedback-contract.test.ts asserts the published guide says the same
34
+ * thing — so the CLI and the doc cannot drift apart.
35
+ */
36
+ export declare const FEEDBACK_CONTRACT: FeedbackContract;
37
+ export interface FeedbackOptions {
38
+ /** Open the prefilled issue form in the default browser. */
39
+ open?: boolean;
40
+ /** Emit the contract as JSON on stdout instead of prose. */
41
+ json?: boolean;
42
+ }
43
+ /**
44
+ * Print the contract for reporting a KiCI discrepancy: what qualifies, what a
45
+ * report must carry, what must never appear in a public issue, and the rule
46
+ * that an agent drafts a report but a human decides to file it.
47
+ *
48
+ * The command reaches no network and files nothing. `--open` opens the
49
+ * prefilled issue form; `--json` emits the same contract for an agent to
50
+ * consume without parsing prose.
51
+ */
52
+ export declare function feedbackCommand(options?: FeedbackOptions): Promise<boolean>;
53
+ //# sourceMappingURL=feedback.d.ts.map
@@ -0,0 +1,142 @@
1
+ import "../rolldown-runtime-ClRpJifh.js";
2
+ import pc from "picocolors";
3
+ import { logger, toErrorMessage } from "@kici-dev/core";
4
+ import open from "open";
5
+ //#region src/commands/feedback.ts
6
+ /** The public tracker. Reports about KiCI itself go here — never customer data. */
7
+ const FEEDBACK_TRACKER_URL = "https://github.com/kici-dev/kici-public";
8
+ /** The issue form tuned for an advertised-versus-actual report. */
9
+ const FEEDBACK_TEMPLATE = "agent_report.yml";
10
+ const FEEDBACK_NEW_ISSUE_URL = `${FEEDBACK_TRACKER_URL}/issues/new?template=${FEEDBACK_TEMPLATE}`;
11
+ /** Suspected vulnerabilities go here instead, privately. */
12
+ const FEEDBACK_SECURITY_ADVISORY_URL = `${FEEDBACK_TRACKER_URL}/security/advisories/new`;
13
+ /**
14
+ * The single definition of what a reportable discrepancy is and what a report
15
+ * must carry. `kici feedback` prints it, `--json` emits it verbatim, and
16
+ * hack/feedback-contract.test.ts asserts the published guide says the same
17
+ * thing — so the CLI and the doc cannot drift apart.
18
+ */
19
+ const FEEDBACK_CONTRACT = {
20
+ tracker: FEEDBACK_TRACKER_URL,
21
+ newIssueUrl: FEEDBACK_NEW_ISSUE_URL,
22
+ template: FEEDBACK_TEMPLATE,
23
+ securityAdvisoryUrl: FEEDBACK_SECURITY_ADVISORY_URL,
24
+ guideUrl: "https://kici.dev/docs/user/reporting-discrepancies/",
25
+ searchCommand: "gh issue list --repo kici-dev/kici-public --search \"<terms>\" --state all",
26
+ approval: {
27
+ required: true,
28
+ rule: "Draft the issue, show the full body to the person you are working with, and file it only after they say yes."
29
+ },
30
+ qualifies: [
31
+ "A documented flag, command, or option that does not exist in the version you ran.",
32
+ "Documented output — a shape, a field, an exit code — that differs from what the command produced.",
33
+ "A CLI --help description that contradicts the published docs.",
34
+ "A documented behaviour that does not happen, or a documented guarantee that does not hold.",
35
+ "A documented error or limit that the tool does not actually enforce."
36
+ ],
37
+ doesNotQualify: [
38
+ "Usage questions, or behaviour you find surprising but that the docs describe correctly.",
39
+ "Feature requests and design preferences.",
40
+ "Anything you inferred from reading docs without running the command.",
41
+ "Anything reproduced only on a locally built or unreleased version.",
42
+ "A failure that is your workflow, your credentials, or your environment."
43
+ ],
44
+ requiredFields: [
45
+ {
46
+ id: "advertised",
47
+ label: "What the docs or CLI advertise",
48
+ description: "The exact claim, quoted, plus its source: a docs URL or the command whose --help says it."
49
+ },
50
+ {
51
+ id: "observed",
52
+ label: "What actually happened",
53
+ description: "The real output or behaviour, quoted, with any error text."
54
+ },
55
+ {
56
+ id: "reproduction",
57
+ label: "Minimal reproduction, including setup",
58
+ description: "Every step from an empty directory: the setup commands, a minimal synthetic workflow, and the exact command you ran."
59
+ },
60
+ {
61
+ id: "version",
62
+ label: "Version and environment",
63
+ description: "Output of `kici --version`, plus Node version and OS."
64
+ },
65
+ {
66
+ id: "justification",
67
+ label: "Why this is a discrepancy",
68
+ description: "One or two sentences ruling out the likely misreads — why the docs cannot be read to match what you observed."
69
+ }
70
+ ],
71
+ prohibited: [
72
+ "No secrets, tokens, or credentials — not even redacted-looking ones.",
73
+ "No private repository names, internal hostnames, organization ids, or run ids.",
74
+ "No log excerpts you have not read line by line.",
75
+ "Reproduce with a minimal synthetic workflow, never the real one you were working on."
76
+ ],
77
+ privateReportCommand: "kici report --run <run-id> --upload"
78
+ };
79
+ function printContract() {
80
+ const c = FEEDBACK_CONTRACT;
81
+ logger.info(pc.bold("Reporting a KiCI discrepancy"));
82
+ logger.info("");
83
+ logger.info("Use this when the published docs or the CLI advertise one behaviour and KiCI does another.");
84
+ logger.info(`Tracker: ${c.tracker}`);
85
+ logger.info(`Full guide: ${c.guideUrl}`);
86
+ logger.info("");
87
+ logger.info(pc.bold("1. Search first"));
88
+ logger.info("Comment on an existing report rather than opening a second one.");
89
+ logger.info(` ${c.searchCommand}`);
90
+ logger.info("");
91
+ logger.info(pc.bold("2. Check it qualifies"));
92
+ for (const item of c.qualifies) logger.info(` ${pc.green("+")} ${item}`);
93
+ logger.info(" Not a discrepancy:");
94
+ for (const item of c.doesNotQualify) logger.info(` ${pc.gray("-")} ${item}`);
95
+ logger.info("");
96
+ logger.info(pc.bold("3. Never file these publicly"));
97
+ logger.info(` A suspected vulnerability is never a public issue — open a private advisory instead:\n ${c.securityAdvisoryUrl}`);
98
+ logger.info(` A problem with your own runs is not a tracker issue — send it privately instead:\n ${c.privateReportCommand}`);
99
+ for (const rule of c.prohibited) logger.info(` ${pc.yellow("!")} ${rule}`);
100
+ logger.info("");
101
+ logger.info(pc.bold("4. Draft the report"));
102
+ for (const field of c.requiredFields) {
103
+ logger.info(` ${field.label}`);
104
+ logger.info(pc.gray(` ${field.description}`));
105
+ }
106
+ logger.info("");
107
+ logger.info(pc.bold("5. Get approval, then file"));
108
+ logger.info(` ${c.approval.rule}`);
109
+ logger.info(` Form: ${c.newIssueUrl}`);
110
+ logger.info(pc.gray(` Or: kici feedback --open`));
111
+ logger.info("");
112
+ logger.info(pc.gray("Machine-readable: kici feedback --json"));
113
+ }
114
+ /**
115
+ * Print the contract for reporting a KiCI discrepancy: what qualifies, what a
116
+ * report must carry, what must never appear in a public issue, and the rule
117
+ * that an agent drafts a report but a human decides to file it.
118
+ *
119
+ * The command reaches no network and files nothing. `--open` opens the
120
+ * prefilled issue form; `--json` emits the same contract for an agent to
121
+ * consume without parsing prose.
122
+ */
123
+ async function feedbackCommand(options = {}) {
124
+ if (options.json) {
125
+ process.stdout.write(`${JSON.stringify(FEEDBACK_CONTRACT, null, 2)}\n`);
126
+ return true;
127
+ }
128
+ printContract();
129
+ if (!options.open) return true;
130
+ try {
131
+ await open(FEEDBACK_NEW_ISSUE_URL);
132
+ return true;
133
+ } catch (error) {
134
+ logger.error(pc.red(`Could not open a browser: ${toErrorMessage(error)}`));
135
+ logger.info(pc.gray(`Open ${FEEDBACK_NEW_ISSUE_URL} manually.`));
136
+ return false;
137
+ }
138
+ }
139
+ //#endregion
140
+ export { FEEDBACK_CONTRACT, FEEDBACK_NEW_ISSUE_URL, FEEDBACK_SECURITY_ADVISORY_URL, FEEDBACK_TEMPLATE, FEEDBACK_TRACKER_URL, feedbackCommand };
141
+
142
+ //# sourceMappingURL=feedback.js.map
@@ -57,7 +57,9 @@ export type { WorkflowsListOptions } from './workflows.js';
57
57
  export { drainWorkerCommand } from './drain-worker.js';
58
58
  export type { DrainWorkerOptions } from './drain-worker.js';
59
59
  export { docsCommand, docsLlmCommand } from './docs.js';
60
+ export { feedbackCommand, FEEDBACK_CONTRACT } from './feedback.js';
60
61
  export type { DocsOptions, DocsLlmOptions } from './docs.js';
62
+ export type { FeedbackOptions, FeedbackContract, FeedbackField } from './feedback.js';
61
63
  export { verifyAttestationCommand } from './verify-attestation.js';
62
64
  export type { VerifyAttestationOptions } from './verify-attestation.js';
63
65
  export { notificationsChannelsListCommand, notificationsChannelsAddCommand, notificationsChannelsRemoveCommand, notificationsSubscriptionsListCommand, notificationsSubscriptionsAddCommand, notificationsSubscriptionsRemoveCommand, notificationsRosterListCommand, notificationsRosterAddCommand, notificationsRosterRemoveCommand, } from './notifications.js';
@@ -6,6 +6,7 @@ import { docsCommand, docsLlmCommand } from "./docs.js";
6
6
  import { doctorCommand } from "./doctor.js";
7
7
  import { drainWorkerCommand } from "./drain-worker.js";
8
8
  import { endpointsCommand } from "./endpoints.js";
9
+ import { FEEDBACK_CONTRACT, feedbackCommand } from "./feedback.js";
9
10
  import { fixtureCommand } from "./fixture.js";
10
11
  import { hookInstallCommand } from "./hook.js";
11
12
  import { watchCommand } from "./watch.js";
@@ -34,4 +35,4 @@ import { rejectCommand } from "./reject.js";
34
35
  import { workflowsListCommand } from "./workflows.js";
35
36
  import { verifyAttestationCommand } from "./verify-attestation.js";
36
37
  import { notificationsChannelsAddCommand, notificationsChannelsListCommand, notificationsChannelsRemoveCommand, notificationsRosterAddCommand, notificationsRosterListCommand, notificationsRosterRemoveCommand, notificationsSubscriptionsAddCommand, notificationsSubscriptionsListCommand, notificationsSubscriptionsRemoveCommand } from "./notifications.js";
37
- export { approveCommand, compileCommand, diagnosticsCommand, docsCommand, docsLlmCommand, doctorCommand, drainWorkerCommand, endpointsCommand, fixtureCommand, hookInstallCommand, initCommand, localAttachCommand, localDetachCommand, localDownCommand, localLogsCommand, localStatusCommand, localTrustRootCommand, localUpCommand, loginCommand, logoutCommand, notificationsChannelsAddCommand, notificationsChannelsListCommand, notificationsChannelsRemoveCommand, notificationsRosterAddCommand, notificationsRosterListCommand, notificationsRosterRemoveCommand, notificationsSubscriptionsAddCommand, notificationsSubscriptionsListCommand, notificationsSubscriptionsRemoveCommand, orchestratorsListCommand, orchestratorsUseCommand, orgCurrentCommand, orgListCommand, orgUseCommand, patCreateCommand, previewCommand, previewEvent, rejectCommand, reportCommand, reportListCommand, reportWithdrawCommand, runRemoteCommand, runRoutedCommand, runsArtifactsDownloadCommand, runsArtifactsListCommand, runsCancelCommand, runsListCommand, runsLogsCommand, runsRerunCommand, runsShowCommand, secretsListCommand, typesCommand, verifyAttestationCommand, watchCommand, workflowsListCommand };
38
+ export { FEEDBACK_CONTRACT, approveCommand, compileCommand, diagnosticsCommand, docsCommand, docsLlmCommand, doctorCommand, drainWorkerCommand, endpointsCommand, feedbackCommand, fixtureCommand, hookInstallCommand, initCommand, localAttachCommand, localDetachCommand, localDownCommand, localLogsCommand, localStatusCommand, localTrustRootCommand, localUpCommand, loginCommand, logoutCommand, notificationsChannelsAddCommand, notificationsChannelsListCommand, notificationsChannelsRemoveCommand, notificationsRosterAddCommand, notificationsRosterListCommand, notificationsRosterRemoveCommand, notificationsSubscriptionsAddCommand, notificationsSubscriptionsListCommand, notificationsSubscriptionsRemoveCommand, orchestratorsListCommand, orchestratorsUseCommand, orgCurrentCommand, orgListCommand, orgUseCommand, patCreateCommand, previewCommand, previewEvent, rejectCommand, reportCommand, reportListCommand, reportWithdrawCommand, runRemoteCommand, runRoutedCommand, runsArtifactsDownloadCommand, runsArtifactsListCommand, runsCancelCommand, runsListCommand, runsLogsCommand, runsRerunCommand, runsShowCommand, secretsListCommand, typesCommand, verifyAttestationCommand, watchCommand, workflowsListCommand };
@@ -48,4 +48,13 @@ export declare function initCommand(options?: InitOptions): Promise<boolean>;
48
48
  * @param kiciDir - The resolved `.kici` directory path.
49
49
  */
50
50
  export declare function writeKiciGitignore(kiciDir: string): Promise<void>;
51
+ /**
52
+ * Scaffold `.kici/.kiciignore` with the default exclusion set. Never overwrites
53
+ * an existing file — the customer may have tuned it — and never runs from
54
+ * `kici compile`: a compile that wrote into the tree it is hashing is the exact
55
+ * hazard the exclusion set exists to close.
56
+ *
57
+ * @param kiciDir - The resolved `.kici` directory path.
58
+ */
59
+ export declare function writeKiciIgnore(kiciDir: string): Promise<void>;
51
60
  //# sourceMappingURL=init.d.ts.map
@@ -11,12 +11,13 @@ import { rewriteRunsOnForHost, shouldOfferFirstRun } from "./init-host-os.js";
11
11
  import path from "node:path";
12
12
  import pc from "picocolors";
13
13
  import { access, mkdir, readFile, rm, writeFile } from "node:fs/promises";
14
+ import { KICI_DIGEST_DEFAULT_EXCLUSIONS, KICI_IGNORE_FILENAME } from "@kici-dev/core/kici-source-digest";
14
15
  import { $ } from "zx";
15
16
  import { initZx, logger, toErrorMessage } from "@kici-dev/core";
16
17
  import { detectPackageManager, detectWorkspaceRoot, installBuildPolicyArgs, installCommand, parsePackageManager } from "@kici-dev/core/package-manager";
18
+ import os from "node:os";
17
19
  import { checkbox, confirm, select } from "@inquirer/prompts";
18
20
  import { isCiEnvironment } from "@kici-dev/core/ci-env";
19
- import os from "node:os";
20
21
  //#region src/commands/init.ts
21
22
  /**
22
23
  * kici init command
@@ -77,6 +78,7 @@ async function initCommand(options = {}) {
77
78
  await writeFile(kiciIgnorePath, kiciIgnoreTemplate, "utf-8");
78
79
  }
79
80
  await writeKiciGitignore(kiciDir);
81
+ await writeKiciIgnore(kiciDir);
80
82
  const devMode = await detectDevelopmentMode();
81
83
  const mode = await resolveScaffoldMode(options);
82
84
  const useVerdaccio = devMode;
@@ -230,8 +232,21 @@ async function resolvePackageManager(override, dir = process.cwd()) {
230
232
  }
231
233
  return detectPackageManager(dir);
232
234
  }
233
- /** The @kici-dev scope → local Verdaccio registry line written in dev mode. */
234
- const VERDACCIO_NPMRC = "@kici-dev:registry=http://verdaccio.local:4873\n";
235
+ /**
236
+ * The `@kici-dev` scope → local registry line written in dev mode, or `null`
237
+ * when no dev registry is configured.
238
+ *
239
+ * The registry URL comes from `KICI_DEV_REGISTRY` rather than a literal in this
240
+ * file. `init.ts` ships in the published `@kici-dev/compiler` source and
241
+ * bundle, so a hard-coded internal hostname is published to every customer who
242
+ * unpacks the tarball — a disclosure, not a reachable path (every write site is
243
+ * behind the dev-mode gate), but an avoidable one. With dev mode on and the
244
+ * variable unset there is nothing to point at, so no `.npmrc` is written.
245
+ */
246
+ function devRegistryNpmrc() {
247
+ const registry = process.env.KICI_DEV_REGISTRY?.trim();
248
+ return registry ? `@kici-dev:registry=${registry}\n` : null;
249
+ }
235
250
  /** Write .kici/tsconfig.json + the empty types/ dir (TypeScript mode only). */
236
251
  async function writeTsConfigAndTypesDir(kiciDir) {
237
252
  logger.info(pc.gray("Writing .kici/tsconfig.json"));
@@ -254,13 +269,15 @@ async function runInstall(pm, dir) {
254
269
  async function wireStandaloneDeps(kiciDir, devMode, options) {
255
270
  logger.info(pc.gray("Writing .kici/package.json"));
256
271
  await writeFile(path.join(kiciDir, "package.json"), generatePackageJson(devMode), "utf-8");
257
- if (devMode) {
258
- logger.info(pc.yellow("Pointing @kici-dev to local Verdaccio registry."));
259
- await writeFile(path.join(kiciDir, ".npmrc"), VERDACCIO_NPMRC, "utf-8");
272
+ const devNpmrc = devMode ? devRegistryNpmrc() : null;
273
+ if (devMode && !devNpmrc) logger.info(pc.yellow("Dev mode: KICI_DEV_REGISTRY is unset, writing no .npmrc."));
274
+ if (devNpmrc) {
275
+ logger.info(pc.yellow("Pointing @kici-dev to the dev registry."));
276
+ await writeFile(path.join(kiciDir, ".npmrc"), devNpmrc, "utf-8");
260
277
  const rootNpmrc = path.resolve(".npmrc");
261
278
  if (!await checkExists(rootNpmrc)) {
262
- logger.info(pc.gray("Writing .npmrc (Verdaccio scope)"));
263
- await writeFile(rootNpmrc, VERDACCIO_NPMRC, "utf-8");
279
+ logger.info(pc.gray("Writing .npmrc (dev registry scope)"));
280
+ await writeFile(rootNpmrc, devNpmrc, "utf-8");
264
281
  }
265
282
  }
266
283
  if (!options.mjs) {
@@ -276,11 +293,13 @@ async function wireStandaloneDeps(kiciDir, devMode, options) {
276
293
  */
277
294
  async function wireIntegrateDeps(kiciDir, workspaceRoot, devMode, options) {
278
295
  await addSdkToRootManifest(workspaceRoot, devMode);
279
- if (devMode) {
296
+ const devNpmrc = devMode ? devRegistryNpmrc() : null;
297
+ if (devMode && !devNpmrc) logger.info(pc.yellow("Dev mode: KICI_DEV_REGISTRY is unset, writing no .npmrc."));
298
+ if (devNpmrc) {
280
299
  const rootNpmrc = path.join(workspaceRoot, ".npmrc");
281
300
  if (!await checkExists(rootNpmrc)) {
282
- logger.info(pc.gray("Writing workspace-root .npmrc (Verdaccio scope)"));
283
- await writeFile(rootNpmrc, VERDACCIO_NPMRC, "utf-8");
301
+ logger.info(pc.gray("Writing workspace-root .npmrc (dev registry scope)"));
302
+ await writeFile(rootNpmrc, devNpmrc, "utf-8");
284
303
  }
285
304
  }
286
305
  if (!options.mjs) await writeTsConfigAndTypesDir(kiciDir);
@@ -389,6 +408,52 @@ async function writeKiciGitignore(kiciDir) {
389
408
  await writeFile(gitignorePath, KICI_GITIGNORE_TEMPLATE, "utf-8");
390
409
  }
391
410
  /**
411
+ * Build the `.kici/.kiciignore` scaffold: the default exclusion set, annotated.
412
+ *
413
+ * Rendered from `KICI_DIGEST_DEFAULT_EXCLUSIONS` rather than a hand-typed list,
414
+ * so a new default cannot ship with the seeded file silently short of it — the
415
+ * file replaces the defaults rather than merging with them, which makes a stale
416
+ * template an unstable hash rather than a cosmetic drift.
417
+ */
418
+ function buildKiciIgnoreTemplate() {
419
+ return [
420
+ "# Paths the workflow source digest does NOT cover.",
421
+ "#",
422
+ "# This file IS the exclusion list: it replaces the built-in defaults rather",
423
+ "# than adding to them. The entries below are those defaults. Removing one",
424
+ "# re-includes that path in the hash — and node_modules/, .npmrc and",
425
+ "# package-lock.json are rewritten during a run, so dropping one makes the",
426
+ "# hash change on every run and the drift gate reject it. `kici compile`",
427
+ "# warns when that happens.",
428
+ "#",
429
+ "# Patterns are gitignore-style, relative to .kici/. Unrelated to the",
430
+ "# repo-root .kiciignore, which selects what `kici run --remote` uploads.",
431
+ "#",
432
+ "# This file is itself hashed: which files define a workflow identity is",
433
+ "# part of that identity, so editing it forces a recompile.",
434
+ "",
435
+ ...KICI_DIGEST_DEFAULT_EXCLUSIONS,
436
+ ""
437
+ ].join("\n");
438
+ }
439
+ /**
440
+ * Scaffold `.kici/.kiciignore` with the default exclusion set. Never overwrites
441
+ * an existing file — the customer may have tuned it — and never runs from
442
+ * `kici compile`: a compile that wrote into the tree it is hashing is the exact
443
+ * hazard the exclusion set exists to close.
444
+ *
445
+ * @param kiciDir - The resolved `.kici` directory path.
446
+ */
447
+ async function writeKiciIgnore(kiciDir) {
448
+ const kiciIgnorePath = path.join(kiciDir, KICI_IGNORE_FILENAME);
449
+ if (await checkExists(kiciIgnorePath)) {
450
+ logger.info(pc.gray(`Skipping .kici/${KICI_IGNORE_FILENAME} (already exists)`));
451
+ return;
452
+ }
453
+ logger.info(pc.gray(`Writing .kici/${KICI_IGNORE_FILENAME}`));
454
+ await writeFile(kiciIgnorePath, buildKiciIgnoreTemplate(), "utf-8");
455
+ }
456
+ /**
392
457
  * Update .gitignore with .kici/ entries
393
458
  *
394
459
  * Safely appends to .gitignore, checking for existing entries to avoid duplicates.
@@ -560,6 +625,6 @@ async function offerHookInstallation(useVerdaccio) {
560
625
  } else logger.warn(pc.yellow(`Warning: ${result.message}`));
561
626
  }
562
627
  //#endregion
563
- export { initCommand, writeKiciGitignore };
628
+ export { initCommand, writeKiciGitignore, writeKiciIgnore };
564
629
 
565
630
  //# sourceMappingURL=init.js.map
@@ -9,10 +9,10 @@ import { loadSecretsFile } from "../test-runner/secrets-file.js";
9
9
  import path from "node:path";
10
10
  import pc from "picocolors";
11
11
  import { readFile } from "node:fs/promises";
12
- import { flattenStepInputs } from "@kici-dev/sdk";
13
12
  import { logger, toErrorMessage } from "@kici-dev/core";
14
13
  import { matchAllWorkflows } from "@kici-dev/engine";
15
14
  import { normalizeRunsOnToMatchers } from "@kici-dev/engine/labels/compile";
15
+ import { flattenStepInputs } from "@kici-dev/sdk/internal";
16
16
  //#region src/commands/preview.ts
17
17
  /**
18
18
  * Main preview command entry point.
@@ -13,6 +13,17 @@ export interface OrchestratorIdentity {
13
13
  version: string | null;
14
14
  mode: string | null;
15
15
  connected: boolean;
16
+ /**
17
+ * Where this orchestrator's config files live on its host. Recorded so a
18
+ * support bundle names the files whoever reads it should ask for. Paths
19
+ * only — the bundle never carries their contents. Each is null when the
20
+ * orchestrator did not report it.
21
+ */
22
+ configPaths: {
23
+ envFile: string | null;
24
+ scalerConfig: string | null;
25
+ composeFile: string | null;
26
+ };
16
27
  }
17
28
  export interface ReportIdentity {
18
29
  kiciCliVersion: string;
@@ -19,7 +19,7 @@ import { PROTOCOL_VERSION } from "@kici-dev/engine";
19
19
  */
20
20
  function collectIdentity(probe) {
21
21
  const identity = {
22
- kiciCliVersion: "0.6.0",
22
+ kiciCliVersion: "0.7.0",
23
23
  nodeVersion: process.version,
24
24
  platform: process.platform,
25
25
  arch: process.arch,
@@ -38,7 +38,12 @@ function collectIdentity(probe) {
38
38
  clusterName: o.clusterName ?? "(unnamed)",
39
39
  version: o.version ?? null,
40
40
  mode: o.mode ?? null,
41
- connected: o.connected
41
+ connected: o.connected,
42
+ configPaths: {
43
+ envFile: o.configPaths?.envFile ?? null,
44
+ scalerConfig: o.configPaths?.scalerConfig ?? null,
45
+ composeFile: o.configPaths?.composeFile ?? null
46
+ }
42
47
  }));
43
48
  if (probe.infra.latestVersion) identity.latestKnownVersion = probe.infra.latestVersion;
44
49
  return identity;
@@ -129,6 +129,7 @@ async function runRouted(options) {
129
129
  }
130
130
  const seeded = await ensureLocalSource(plane.url, plane.adminToken, {
131
131
  repoDir: workdir.dir,
132
+ ...resolved.kind === "attached" && { orgId: resolved.orgId },
132
133
  inPlace: Boolean(options.inPlace)
133
134
  });
134
135
  const seededSecrets = await seedLocalSecrets(plane.url, plane.adminToken, {
@@ -1,5 +1,10 @@
1
1
  export interface TypesOptions {
2
- /** Path to .kici directory (defaults to .kici) */
2
+ /**
3
+ * Path to the `.kici` directory (defaults to `.kici`). Resolved through
4
+ * `resolveKiciDir`, the same resolver every other command uses, so a
5
+ * relative value is interpreted against the project rather than against
6
+ * whatever directory the CLI happened to be invoked from.
7
+ */
3
8
  kiciDir?: string;
4
9
  /** Suppress the success line on stdout (so machine-readable output stays pure). */
5
10
  quiet?: boolean;
@@ -1,4 +1,5 @@
1
1
  import "../rolldown-runtime-ClRpJifh.js";
2
+ import { resolveKiciDir } from "../execution/executor.js";
2
3
  import { loadGlobalConfig } from "../remote/config.js";
3
4
  import { DashboardClient, DashboardClientError } from "../remote/dashboard-client.js";
4
5
  import { generateSecretsDts } from "../generators/secrets-dts.js";
@@ -44,7 +45,7 @@ async function fileExists(p) {
44
45
  * @returns true on success, false on error
45
46
  */
46
47
  async function typesCommand(options = {}) {
47
- const kiciDir = options.kiciDir ?? ".kici";
48
+ const kiciDir = resolveKiciDir(options.kiciDir);
48
49
  const typesDir = path.join(kiciDir, "types");
49
50
  const outputPath = path.join(typesDir, "secrets.d.ts");
50
51
  try {
@@ -6,6 +6,7 @@ import { pathToFileURL } from "node:url";
6
6
  import path from "node:path";
7
7
  import { existsSync } from "node:fs";
8
8
  import fs$1 from "node:fs/promises";
9
+ import { findKiciDir, hashKiciSourceTree } from "@kici-dev/core/kici-source-digest";
9
10
  //#region src/execution/executor.ts
10
11
  /**
11
12
  * Map a caught runtime error's stack to a `SourceLocation` in the entry file.
@@ -46,7 +47,12 @@ function locateInEntry(stack, entryPoint) {
46
47
  */
47
48
  async function loadModule(entryPoint, errorContext) {
48
49
  let hashBundleSource;
49
- try {
50
+ const kiciDir = findKiciDir(entryPoint);
51
+ if (kiciDir) {
52
+ const digest = await hashKiciSourceTree(kiciDir);
53
+ if (digest) hashBundleSource = digest;
54
+ }
55
+ if (hashBundleSource === void 0) try {
50
56
  hashBundleSource = await fs$1.readFile(entryPoint, "utf-8");
51
57
  } catch {}
52
58
  try {