@kici-dev/compiler 0.8.0 → 0.9.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/dist/cli.js +4 -3
- package/dist/commands/docs.js +2 -2
- package/dist/commands/feedback.d.ts +23 -1
- package/dist/commands/feedback.js +86 -9
- package/dist/commands/index.d.ts +2 -2
- package/dist/commands/index.js +2 -2
- package/dist/commands/local.d.ts +4 -3
- package/dist/commands/local.js +5 -4
- package/dist/commands/report/identity.js +1 -1
- package/dist/commands/run-banner.d.ts +1 -1
- package/dist/commands/run-banner.js +1 -1
- package/dist/commands/verify-attestation.js +1 -1
- package/dist/llm-context/llms-architecture.txt +8 -6
- package/dist/llm-context/llms-cli-remote.txt +14 -11
- package/dist/llm-context/llms-cli.txt +2 -2
- package/dist/llm-context/llms-features-execution.txt +8 -8
- package/dist/llm-context/llms-features.txt +452 -133
- package/dist/llm-context/llms-full.txt +529 -190
- package/dist/llm-context/llms-getting-started.txt +32 -15
- package/dist/llm-context/llms-providers.txt +2 -2
- package/dist/llm-context/llms-sdk-runtime.txt +5 -2
- package/dist/llm-context/llms-sdk.txt +7 -12
- package/dist/llm-context/llms.txt +6 -5
- package/dist/local-plane/orchestrator-process.d.ts +4 -5
- package/dist/local-plane/orchestrator-process.js +2 -1
- package/dist/local-plane/plane-manager.js +2 -2
- package/dist/templates/agents-md.d.ts +1 -1
- package/dist/templates/agents-md.js +9 -7
- package/dist/templates/package-json.js +1 -1
- package/dist/templates/workflows/hello-world.ts +1 -1
- package/dist/templates/workflows/pr-checks.ts +2 -2
- package/dist/test-runner/job-executor.js +3 -2
- package/dist/types.d.ts +12 -35
- package/dist/types.js +2 -12
- package/dist/types.test-d.d.ts +2 -0
- package/dist/types.test-d.js +63 -0
- package/dist/workflows/hello-world.ts +1 -1
- package/dist/workflows/pr-checks.ts +2 -2
- package/package.json +15 -15
- package/sbom.spdx.json +1303 -1483
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.
|
|
10
|
+
const version = "0.9.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
|
|
@@ -492,11 +492,12 @@ 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) => {
|
|
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").option("--draft <file>", "Build the prefilled issue-form URL from a JSON draft keyed by field id (with --open, open it)").action(async (options) => {
|
|
496
496
|
const { feedbackCommand } = await import("./commands/index.js");
|
|
497
497
|
const success = await feedbackCommand({
|
|
498
498
|
open: options.open,
|
|
499
|
-
json: options.json
|
|
499
|
+
json: options.json,
|
|
500
|
+
draft: options.draft
|
|
500
501
|
});
|
|
501
502
|
process.exit(success ? 0 : 1);
|
|
502
503
|
});
|
package/dist/commands/docs.js
CHANGED
|
@@ -3,11 +3,11 @@ import { fileURLToPath } from "node:url";
|
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import pc from "picocolors";
|
|
5
5
|
import { readFile, readdir, writeFile } from "node:fs/promises";
|
|
6
|
-
import { logger, toErrorMessage } from "@kici-dev/core";
|
|
6
|
+
import { docsUrl, logger, toErrorMessage } from "@kici-dev/core";
|
|
7
7
|
import open from "open";
|
|
8
8
|
//#region src/commands/docs.ts
|
|
9
9
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
10
|
-
const DOCS_HOME_URL = "
|
|
10
|
+
const DOCS_HOME_URL = docsUrl("");
|
|
11
11
|
function bundleFilenameForTopic(topic) {
|
|
12
12
|
if (!topic) return "llms.txt";
|
|
13
13
|
if (topic === "full") return "llms-full.txt";
|
|
@@ -5,6 +5,12 @@ export declare const FEEDBACK_TEMPLATE = "agent_report.yml";
|
|
|
5
5
|
export declare const FEEDBACK_NEW_ISSUE_URL = "https://github.com/kici-dev/kici-public/issues/new?template=agent_report.yml";
|
|
6
6
|
/** Suspected vulnerabilities go here instead, privately. */
|
|
7
7
|
export declare const FEEDBACK_SECURITY_ADVISORY_URL = "https://github.com/kici-dev/kici-public/security/advisories/new";
|
|
8
|
+
/** How an agent turns its draft into the prefilled form a person reviews and files. */
|
|
9
|
+
export declare const FEEDBACK_DRAFT_COMMAND = "kici feedback --draft <file.json> --open";
|
|
10
|
+
/** GitHub's practical URL ceiling; a longer draft violates "minimal" anyway. */
|
|
11
|
+
export declare const FEEDBACK_URL_WARN_BYTES = 6000;
|
|
12
|
+
/** A draft: the issue title plus one string per contract field, keyed by field id. */
|
|
13
|
+
export type FeedbackDraft = Record<string, string>;
|
|
8
14
|
export interface FeedbackField {
|
|
9
15
|
id: string;
|
|
10
16
|
label: string;
|
|
@@ -26,6 +32,10 @@ export interface FeedbackContract {
|
|
|
26
32
|
requiredFields: FeedbackField[];
|
|
27
33
|
prohibited: string[];
|
|
28
34
|
privateReportCommand: string;
|
|
35
|
+
/** The command that turns a JSON draft into the prefilled issue-form URL. */
|
|
36
|
+
draftCommand: string;
|
|
37
|
+
/** The keys a draft must carry: `title` plus every required field's id. */
|
|
38
|
+
draftFields: string[];
|
|
29
39
|
}
|
|
30
40
|
/**
|
|
31
41
|
* The single definition of what a reportable discrepancy is and what a report
|
|
@@ -34,11 +44,22 @@ export interface FeedbackContract {
|
|
|
34
44
|
* thing — so the CLI and the doc cannot drift apart.
|
|
35
45
|
*/
|
|
36
46
|
export declare const FEEDBACK_CONTRACT: FeedbackContract;
|
|
47
|
+
export declare function parseFeedbackDraft(raw: unknown): {
|
|
48
|
+
ok: true;
|
|
49
|
+
draft: FeedbackDraft;
|
|
50
|
+
} | {
|
|
51
|
+
ok: false;
|
|
52
|
+
problems: string[];
|
|
53
|
+
};
|
|
54
|
+
/** The form URL with every draft field prefilled — GitHub reads each query param by field id. */
|
|
55
|
+
export declare function draftIssueUrl(draft: FeedbackDraft): string;
|
|
37
56
|
export interface FeedbackOptions {
|
|
38
57
|
/** Open the prefilled issue form in the default browser. */
|
|
39
58
|
open?: boolean;
|
|
40
59
|
/** Emit the contract as JSON on stdout instead of prose. */
|
|
41
60
|
json?: boolean;
|
|
61
|
+
/** Path to a JSON draft; print (and with --open, open) the prefilled issue-form URL. */
|
|
62
|
+
draft?: string;
|
|
42
63
|
}
|
|
43
64
|
/**
|
|
44
65
|
* Print the contract for reporting a KiCI discrepancy: what qualifies, what a
|
|
@@ -47,7 +68,8 @@ export interface FeedbackOptions {
|
|
|
47
68
|
*
|
|
48
69
|
* The command reaches no network and files nothing. `--open` opens the
|
|
49
70
|
* prefilled issue form; `--json` emits the same contract for an agent to
|
|
50
|
-
* consume without parsing prose
|
|
71
|
+
* consume without parsing prose; `--draft <file>` builds the issue-form URL
|
|
72
|
+
* with every field of a JSON draft prefilled.
|
|
51
73
|
*/
|
|
52
74
|
export declare function feedbackCommand(options?: FeedbackOptions): Promise<boolean>;
|
|
53
75
|
//# sourceMappingURL=feedback.d.ts.map
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import "../rolldown-runtime-ClRpJifh.js";
|
|
2
2
|
import pc from "picocolors";
|
|
3
|
-
import {
|
|
3
|
+
import { readFile } from "node:fs/promises";
|
|
4
|
+
import { docsUrl, logger, toErrorMessage } from "@kici-dev/core";
|
|
4
5
|
import open from "open";
|
|
5
6
|
//#region src/commands/feedback.ts
|
|
6
7
|
/** The public tracker. Reports about KiCI itself go here — never customer data. */
|
|
@@ -10,6 +11,10 @@ const FEEDBACK_TEMPLATE = "agent_report.yml";
|
|
|
10
11
|
const FEEDBACK_NEW_ISSUE_URL = `${FEEDBACK_TRACKER_URL}/issues/new?template=${FEEDBACK_TEMPLATE}`;
|
|
11
12
|
/** Suspected vulnerabilities go here instead, privately. */
|
|
12
13
|
const FEEDBACK_SECURITY_ADVISORY_URL = `${FEEDBACK_TRACKER_URL}/security/advisories/new`;
|
|
14
|
+
/** How an agent turns its draft into the prefilled form a person reviews and files. */
|
|
15
|
+
const FEEDBACK_DRAFT_COMMAND = "kici feedback --draft <file.json> --open";
|
|
16
|
+
/** GitHub's practical URL ceiling; a longer draft violates "minimal" anyway. */
|
|
17
|
+
const FEEDBACK_URL_WARN_BYTES = 6e3;
|
|
13
18
|
/**
|
|
14
19
|
* The single definition of what a reportable discrepancy is and what a report
|
|
15
20
|
* must carry. `kici feedback` prints it, `--json` emits it verbatim, and
|
|
@@ -21,7 +26,7 @@ const FEEDBACK_CONTRACT = {
|
|
|
21
26
|
newIssueUrl: FEEDBACK_NEW_ISSUE_URL,
|
|
22
27
|
template: FEEDBACK_TEMPLATE,
|
|
23
28
|
securityAdvisoryUrl: FEEDBACK_SECURITY_ADVISORY_URL,
|
|
24
|
-
guideUrl: "
|
|
29
|
+
guideUrl: docsUrl("user/reporting-discrepancies/"),
|
|
25
30
|
searchCommand: "gh issue list --repo kici-dev/kici-public --search \"<terms>\" --state all",
|
|
26
31
|
approval: {
|
|
27
32
|
required: true,
|
|
@@ -59,8 +64,13 @@ const FEEDBACK_CONTRACT = {
|
|
|
59
64
|
},
|
|
60
65
|
{
|
|
61
66
|
id: "version",
|
|
62
|
-
label: "
|
|
63
|
-
description: "Output of `kici --version
|
|
67
|
+
label: "KiCI version",
|
|
68
|
+
description: "Output of `kici --version`."
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
id: "environment",
|
|
72
|
+
label: "Environment",
|
|
73
|
+
description: "Node version and OS."
|
|
64
74
|
},
|
|
65
75
|
{
|
|
66
76
|
id: "justification",
|
|
@@ -74,8 +84,48 @@ const FEEDBACK_CONTRACT = {
|
|
|
74
84
|
"No log excerpts you have not read line by line.",
|
|
75
85
|
"Reproduce with a minimal synthetic workflow, never the real one you were working on."
|
|
76
86
|
],
|
|
77
|
-
privateReportCommand: "kici report --run <run-id> --upload"
|
|
87
|
+
privateReportCommand: "kici report --run <run-id> --upload",
|
|
88
|
+
draftCommand: FEEDBACK_DRAFT_COMMAND,
|
|
89
|
+
draftFields: [
|
|
90
|
+
"title",
|
|
91
|
+
"advertised",
|
|
92
|
+
"observed",
|
|
93
|
+
"reproduction",
|
|
94
|
+
"version",
|
|
95
|
+
"environment",
|
|
96
|
+
"justification"
|
|
97
|
+
]
|
|
78
98
|
};
|
|
99
|
+
function parseFeedbackDraft(raw) {
|
|
100
|
+
const problems = [];
|
|
101
|
+
if (typeof raw !== "object" || raw === null || Array.isArray(raw)) return {
|
|
102
|
+
ok: false,
|
|
103
|
+
problems: ["draft must be a JSON object keyed by field id"]
|
|
104
|
+
};
|
|
105
|
+
const input = raw;
|
|
106
|
+
const allowed = new Set(FEEDBACK_CONTRACT.draftFields);
|
|
107
|
+
for (const key of Object.keys(input)) if (!allowed.has(key)) problems.push(`unknown field: ${key}`);
|
|
108
|
+
const draft = {};
|
|
109
|
+
for (const id of FEEDBACK_CONTRACT.draftFields) {
|
|
110
|
+
const value = input[id];
|
|
111
|
+
if (value === void 0) problems.push(`missing required field: ${id}`);
|
|
112
|
+
else if (typeof value !== "string" || value.trim() === "") problems.push(`field must be a non-empty string: ${id}`);
|
|
113
|
+
else draft[id] = value;
|
|
114
|
+
}
|
|
115
|
+
return problems.length === 0 ? {
|
|
116
|
+
ok: true,
|
|
117
|
+
draft
|
|
118
|
+
} : {
|
|
119
|
+
ok: false,
|
|
120
|
+
problems
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
/** The form URL with every draft field prefilled — GitHub reads each query param by field id. */
|
|
124
|
+
function draftIssueUrl(draft) {
|
|
125
|
+
const url = new URL(FEEDBACK_NEW_ISSUE_URL);
|
|
126
|
+
for (const id of FEEDBACK_CONTRACT.draftFields) url.searchParams.set(id, draft[id] ?? "");
|
|
127
|
+
return url.toString();
|
|
128
|
+
}
|
|
79
129
|
function printContract() {
|
|
80
130
|
const c = FEEDBACK_CONTRACT;
|
|
81
131
|
logger.info(pc.bold("Reporting a KiCI discrepancy"));
|
|
@@ -108,6 +158,7 @@ function printContract() {
|
|
|
108
158
|
logger.info(` ${c.approval.rule}`);
|
|
109
159
|
logger.info(` Form: ${c.newIssueUrl}`);
|
|
110
160
|
logger.info(pc.gray(` Or: kici feedback --open`));
|
|
161
|
+
logger.info(pc.gray(` From a draft: ${c.draftCommand} (fields: kici feedback --json → draftFields)`));
|
|
111
162
|
logger.info("");
|
|
112
163
|
logger.info(pc.gray("Machine-readable: kici feedback --json"));
|
|
113
164
|
}
|
|
@@ -118,25 +169,51 @@ function printContract() {
|
|
|
118
169
|
*
|
|
119
170
|
* The command reaches no network and files nothing. `--open` opens the
|
|
120
171
|
* prefilled issue form; `--json` emits the same contract for an agent to
|
|
121
|
-
* consume without parsing prose
|
|
172
|
+
* consume without parsing prose; `--draft <file>` builds the issue-form URL
|
|
173
|
+
* with every field of a JSON draft prefilled.
|
|
122
174
|
*/
|
|
123
175
|
async function feedbackCommand(options = {}) {
|
|
176
|
+
if (options.draft) return draftFromFile(options.draft, options.open === true);
|
|
124
177
|
if (options.json) {
|
|
125
178
|
process.stdout.write(`${JSON.stringify(FEEDBACK_CONTRACT, null, 2)}\n`);
|
|
126
179
|
return true;
|
|
127
180
|
}
|
|
128
181
|
printContract();
|
|
129
182
|
if (!options.open) return true;
|
|
183
|
+
return openOrExplain(FEEDBACK_NEW_ISSUE_URL);
|
|
184
|
+
}
|
|
185
|
+
/** Read a JSON draft, print its prefilled issue-form URL as the last stdout line, open it on request. */
|
|
186
|
+
async function draftFromFile(file, openIt) {
|
|
187
|
+
let raw;
|
|
188
|
+
try {
|
|
189
|
+
raw = JSON.parse(await readFile(file, "utf8"));
|
|
190
|
+
} catch (error) {
|
|
191
|
+
logger.error(pc.red(`Could not read the draft at ${file}: ${toErrorMessage(error)}`));
|
|
192
|
+
return false;
|
|
193
|
+
}
|
|
194
|
+
const parsed = parseFeedbackDraft(raw);
|
|
195
|
+
if (!parsed.ok) {
|
|
196
|
+
for (const problem of parsed.problems) logger.error(pc.red(problem));
|
|
197
|
+
logger.info(pc.gray(`Fields: ${FEEDBACK_CONTRACT.draftFields.join(", ")} — see kici feedback --json`));
|
|
198
|
+
return false;
|
|
199
|
+
}
|
|
200
|
+
const url = draftIssueUrl(parsed.draft);
|
|
201
|
+
if (url.length > 6e3) logger.warn(pc.yellow(`The prefilled URL is ${url.length} bytes; GitHub may truncate it. Shorten the reproduction.`));
|
|
202
|
+
process.stdout.write(`${url}\n`);
|
|
203
|
+
if (!openIt) return true;
|
|
204
|
+
return openOrExplain(url);
|
|
205
|
+
}
|
|
206
|
+
async function openOrExplain(url) {
|
|
130
207
|
try {
|
|
131
|
-
await open(
|
|
208
|
+
await open(url);
|
|
132
209
|
return true;
|
|
133
210
|
} catch (error) {
|
|
134
211
|
logger.error(pc.red(`Could not open a browser: ${toErrorMessage(error)}`));
|
|
135
|
-
logger.info(pc.gray(`Open ${
|
|
212
|
+
logger.info(pc.gray(`Open ${url} manually.`));
|
|
136
213
|
return false;
|
|
137
214
|
}
|
|
138
215
|
}
|
|
139
216
|
//#endregion
|
|
140
|
-
export { FEEDBACK_CONTRACT, FEEDBACK_NEW_ISSUE_URL, FEEDBACK_SECURITY_ADVISORY_URL, FEEDBACK_TEMPLATE, FEEDBACK_TRACKER_URL, feedbackCommand };
|
|
217
|
+
export { FEEDBACK_CONTRACT, FEEDBACK_DRAFT_COMMAND, FEEDBACK_NEW_ISSUE_URL, FEEDBACK_SECURITY_ADVISORY_URL, FEEDBACK_TEMPLATE, FEEDBACK_TRACKER_URL, FEEDBACK_URL_WARN_BYTES, draftIssueUrl, feedbackCommand, parseFeedbackDraft };
|
|
141
218
|
|
|
142
219
|
//# sourceMappingURL=feedback.js.map
|
package/dist/commands/index.d.ts
CHANGED
|
@@ -57,9 +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
|
+
export { feedbackCommand, FEEDBACK_CONTRACT, parseFeedbackDraft, draftIssueUrl, } from './feedback.js';
|
|
61
61
|
export type { DocsOptions, DocsLlmOptions } from './docs.js';
|
|
62
|
-
export type { FeedbackOptions, FeedbackContract, FeedbackField } from './feedback.js';
|
|
62
|
+
export type { FeedbackOptions, FeedbackContract, FeedbackField, FeedbackDraft, } from './feedback.js';
|
|
63
63
|
export { verifyAttestationCommand } from './verify-attestation.js';
|
|
64
64
|
export type { VerifyAttestationOptions } from './verify-attestation.js';
|
|
65
65
|
export { notificationsChannelsListCommand, notificationsChannelsAddCommand, notificationsChannelsRemoveCommand, notificationsSubscriptionsListCommand, notificationsSubscriptionsAddCommand, notificationsSubscriptionsRemoveCommand, notificationsRosterListCommand, notificationsRosterAddCommand, notificationsRosterRemoveCommand, } from './notifications.js';
|
package/dist/commands/index.js
CHANGED
|
@@ -6,7 +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
|
+
import { FEEDBACK_CONTRACT, draftIssueUrl, feedbackCommand, parseFeedbackDraft } from "./feedback.js";
|
|
10
10
|
import { fixtureCommand } from "./fixture.js";
|
|
11
11
|
import { hookInstallCommand } from "./hook.js";
|
|
12
12
|
import { watchCommand } from "./watch.js";
|
|
@@ -35,4 +35,4 @@ import { rejectCommand } from "./reject.js";
|
|
|
35
35
|
import { workflowsListCommand } from "./workflows.js";
|
|
36
36
|
import { verifyAttestationCommand } from "./verify-attestation.js";
|
|
37
37
|
import { notificationsChannelsAddCommand, notificationsChannelsListCommand, notificationsChannelsRemoveCommand, notificationsRosterAddCommand, notificationsRosterListCommand, notificationsRosterRemoveCommand, notificationsSubscriptionsAddCommand, notificationsSubscriptionsListCommand, notificationsSubscriptionsRemoveCommand } from "./notifications.js";
|
|
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 };
|
|
38
|
+
export { FEEDBACK_CONTRACT, approveCommand, compileCommand, diagnosticsCommand, docsCommand, docsLlmCommand, doctorCommand, draftIssueUrl, 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, parseFeedbackDraft, patCreateCommand, previewCommand, previewEvent, rejectCommand, reportCommand, reportListCommand, reportWithdrawCommand, runRemoteCommand, runRoutedCommand, runsArtifactsDownloadCommand, runsArtifactsListCommand, runsCancelCommand, runsListCommand, runsLogsCommand, runsRerunCommand, runsShowCommand, secretsListCommand, typesCommand, verifyAttestationCommand, watchCommand, workflowsListCommand };
|
package/dist/commands/local.d.ts
CHANGED
|
@@ -62,9 +62,10 @@ export declare function localDownCommand(): Promise<boolean>;
|
|
|
62
62
|
*/
|
|
63
63
|
export declare function localLogsCommand(): Promise<boolean>;
|
|
64
64
|
/**
|
|
65
|
-
* Attach the local dev plane to the hosted Platform so `kici run --local`
|
|
66
|
-
*
|
|
67
|
-
*
|
|
65
|
+
* Attach the local dev plane to the hosted Platform so `kici run --local` mints
|
|
66
|
+
* OIDC + attestation with the plane's own signing key under its own issuer, as
|
|
67
|
+
* a deployed orchestrator does. Mints an org-scoped orchestrator key with the
|
|
68
|
+
* logged-in PAT, then (re)boots the plane hybrid.
|
|
68
69
|
*/
|
|
69
70
|
export declare function localAttachCommand(): Promise<boolean>;
|
|
70
71
|
/** Detach the local dev plane from the Platform and reboot it offline (independent). */
|
package/dist/commands/local.js
CHANGED
|
@@ -163,9 +163,10 @@ async function localLogsCommand() {
|
|
|
163
163
|
return true;
|
|
164
164
|
}
|
|
165
165
|
/**
|
|
166
|
-
* Attach the local dev plane to the hosted Platform so `kici run --local`
|
|
167
|
-
*
|
|
168
|
-
*
|
|
166
|
+
* Attach the local dev plane to the hosted Platform so `kici run --local` mints
|
|
167
|
+
* OIDC + attestation with the plane's own signing key under its own issuer, as
|
|
168
|
+
* a deployed orchestrator does. Mints an org-scoped orchestrator key with the
|
|
169
|
+
* logged-in PAT, then (re)boots the plane hybrid.
|
|
169
170
|
*/
|
|
170
171
|
async function localAttachCommand() {
|
|
171
172
|
const config = await loadGlobalConfig();
|
|
@@ -190,7 +191,7 @@ async function localAttachCommand() {
|
|
|
190
191
|
orgId
|
|
191
192
|
});
|
|
192
193
|
console.log(pc.green("✓") + ` Local dev plane attached (hybrid) at ${pc.bold(status.url ?? "")} ` + pc.dim(`(org: ${orgId})`));
|
|
193
|
-
console.log(pc.dim("`kici run --local` now
|
|
194
|
+
console.log(pc.dim("`kici run --local` now mints OIDC + attestation with this plane's own key against the real Platform org. Detach: ") + pc.cyan("kici local detach"));
|
|
194
195
|
return true;
|
|
195
196
|
} catch (err) {
|
|
196
197
|
console.error(pc.red(`Attach failed: ${toErrorMessage(err)}`));
|
|
@@ -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.
|
|
22
|
+
kiciCliVersion: "0.9.0",
|
|
23
23
|
nodeVersion: process.version,
|
|
24
24
|
platform: process.platform,
|
|
25
25
|
arch: process.arch,
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
*
|
|
7
7
|
* Three variants:
|
|
8
8
|
* - `offline` — independent plane, local secrets, dev-signed identity.
|
|
9
|
-
* - `attached` — hybrid plane,
|
|
9
|
+
* - `attached` — hybrid plane, OIDC + attestation signed by the plane's own key.
|
|
10
10
|
* - `fallback` — wanted attached but the Platform was unreachable, so the run
|
|
11
11
|
* fell back to offline; a LOUD first line makes the degradation obvious.
|
|
12
12
|
*/
|
|
@@ -5,7 +5,7 @@ function renderRunBanner(input) {
|
|
|
5
5
|
const title = input.mode === "attached" ? "kici run --local (connected)" : "kici run --local";
|
|
6
6
|
const rows = [];
|
|
7
7
|
if (input.mode === "fallback") rows.push(["⚠", `Platform unreachable — fell back to OFFLINE${input.fallbackReason ? ` (${input.fallbackReason})` : ""}`]);
|
|
8
|
-
if (input.mode === "attached") rows.push(["plane", "local dev orchestrator (hybrid, attached)"], ["agent", "this machine (bare-metal)"], ["secrets", `REAL scoped${input.orgId ? ` (org: ${input.orgId})` : ""}`], ["identity",
|
|
8
|
+
if (input.mode === "attached") rows.push(["plane", "local dev orchestrator (hybrid, attached)"], ["agent", "this machine (bare-metal)"], ["secrets", `REAL scoped${input.orgId ? ` (org: ${input.orgId})` : ""}`], ["identity", `plane-signed OIDC + attestation (iss=${input.planeUrl})`], ["control", `kici local status | logs | detach (${input.planeUrl})`], ["force", "--offline (local plane) · --in-place (ambient)"]);
|
|
9
9
|
else rows.push(["plane", "local dev orchestrator (independent, offline)"], ["agent", "this machine (bare-metal)"], ["secrets", "LOCAL files (.kici/.secrets, .env.local, --env)"], ["identity", "DEV-SIGNED (iss=kici-local — NOT prod)"], ["control", `kici local status | logs | down (${input.planeUrl})`], ["force", "--connected (attach to Platform) · --in-place (ambient)"]);
|
|
10
10
|
if (input.trusted) rows.push(["execution", "TRUSTED — host env passthrough (NOT sandboxed)"]);
|
|
11
11
|
const labelWidth = Math.max(...rows.map(([label]) => label.length));
|
|
@@ -78,7 +78,7 @@ async function verifyAttestationCommand(artifact, options = {}) {
|
|
|
78
78
|
if (c.source_origin === "run-remote") logger.info(pc.bold(pc.yellow(" SOURCE: kici run remote (local working-tree overlay — repository/ref/sha are caller-supplied, not a triggered VCS commit)")));
|
|
79
79
|
else logger.info(pc.gray(` source: ${c.source_origin ?? "triggered"}`));
|
|
80
80
|
const origin = result.attestationOrigin ?? "live";
|
|
81
|
-
if (origin === "deferred") logger.info(pc.bold(pc.yellow(" ATTESTATION: deferred — the build facts were sealed at build time; the identity token was minted later (
|
|
81
|
+
if (origin === "deferred") logger.info(pc.bold(pc.yellow(" ATTESTATION: deferred — the build facts were sealed at build time; the identity token was minted later (once the orchestrator's signing key was available), bound to the frozen statement by hash.")));
|
|
82
82
|
else if (origin === "offline-backfill") logger.info(pc.bold(pc.yellow(" ATTESTATION: offline-backfill — the run was ingested while the Platform was down; its run/job rows were backfilled and the token minted later. The org id is the authoritative anchor; the temporal gap is disclosed.")));
|
|
83
83
|
logger.info(pc.gray(` repository=${c.repository} ref=${c.ref} sha=${c.sha} provider=${c.provider ?? "unknown"} run=${c.kici_run_id} job=${c.kici_job_id}`));
|
|
84
84
|
} else logger.error(`${pc.red("FAIL")} provenance NOT verified: ${result.failures.join(", ")}`);
|
|
@@ -411,7 +411,7 @@ Orchestrator Agent Sandbox (child pro
|
|
|
411
411
|
| | |
|
|
412
412
|
|-- job.dispatch (WS) ------------>| |
|
|
413
413
|
| (jobConfig, sourceTarUrl, | |
|
|
414
|
-
|
|
|
414
|
+
| sourceTarDigest, depsUrl, |-- Create sandbox ------->|
|
|
415
415
|
| depsHash) | (container/bare-metal/ |
|
|
416
416
|
| | firecracker) |
|
|
417
417
|
| | |-- Restore .kici/ source (tarball)
|
|
@@ -593,6 +593,8 @@ Dep cache misses alone do **not** trigger a build job. Deps are platform-specifi
|
|
|
593
593
|
|
|
594
594
|
When multiple webhooks trigger simultaneously for the same repository state, the `BuildCoordinator` coalesces concurrent build requests using a combined key (`contentHash:lockfileHash`). Only one build job runs; all waiting dispatches share the result.
|
|
595
595
|
|
|
596
|
+
The coalescing map is per coordinator. The build job itself sits on the cluster-wide dispatch queue, so an agent connected to a sibling coordinator can claim it. That sibling persists the terminal `job.status` to the shared `execution_jobs` row (`precursor_result`), and the dispatching coordinator's `PendingPrecursorDbWatcher` reads the row back and settles the pending build through `settlePendingPrecursor()`. The local agent socket goes through the same function. See [runs that span coordinators](https://docs.kici.dev/operator/orchestrator/clustering/#runs-that-span-coordinators).
|
|
597
|
+
|
|
596
598
|
### Graceful degradation
|
|
597
599
|
|
|
598
600
|
If cache storage is unavailable or a download fails:
|
|
@@ -667,7 +669,7 @@ Agent Orchestrator S3
|
|
|
667
669
|
| | for deps integrity) |
|
|
668
670
|
```
|
|
669
671
|
|
|
670
|
-
The two-phase metadata approach (`upload via PUT` then `initMeta via CopyObject`) works around the limitation that S3 pre-signed URLs cannot include custom metadata headers. For dependency tarballs, the agent also reports the SHA-256 content hash in `cache.upload.complete`; the orchestrator stores it as a companion `.hash` file alongside the tarball. When dispatching execution jobs, the orchestrator reads this hash and includes it as `depsHash` in `job.dispatch`, enabling agent-side integrity verification on download. Source tarballs
|
|
672
|
+
The two-phase metadata approach (`upload via PUT` then `initMeta via CopyObject`) works around the limitation that S3 pre-signed URLs cannot include custom metadata headers. For dependency tarballs, the agent also reports the SHA-256 content hash in `cache.upload.complete`; the orchestrator stores it as a companion `.hash` file alongside the tarball. When dispatching execution jobs, the orchestrator reads this hash and includes it as `depsHash` in `job.dispatch`, enabling agent-side integrity verification on download. Source tarballs carry their own SHA-256 as `sourceTarDigest` in `job.dispatch`, verified before extraction; the workflow `contentHash` is then re-computed against the extracted source to verify it against the lock file, which covers drift end-to-end.
|
|
671
673
|
|
|
672
674
|
### URL delivery (downloads)
|
|
673
675
|
|
|
@@ -1166,7 +1168,7 @@ The compiler processes the workflow definition:
|
|
|
1166
1168
|
|
|
1167
1169
|
When `kici run <event> --local` runs a workflow:
|
|
1168
1170
|
|
|
1169
|
-
1. **SDK module resolution:** The runner resolves `setStepOutputsMap` / `setJobOutputsMap` from the
|
|
1171
|
+
1. **SDK module resolution:** The runner resolves `setStepOutputsMap` / `setJobOutputsMap` from the `@kici-dev/sdk/internal` subpath of the same SDK copy that the workflow uses (ensures the proxy reads from the same map)
|
|
1170
1172
|
2. **Map injection:** Fresh `OutputsMap` and `StepRefMap` are created and injected via `setStepOutputsMap()` / `setStepRefMap()` before each job
|
|
1171
1173
|
3. **Step execution:** Each step runs sequentially. If the step returns a value, it is stored in the `OutputsMap` keyed by step name
|
|
1172
1174
|
4. **Bare function normalization:** Bare functions in the steps array are assigned counter names and registered in the `StepRefMap` (maps function reference to step name)
|
|
@@ -1301,7 +1303,7 @@ The Platform never processes, stores, or executes customer code, and never sees
|
|
|
1301
1303
|
|
|
1302
1304
|
The orchestrator is the execution brain. It decides what to run and dispatches work to agents.
|
|
1303
1305
|
|
|
1304
|
-
- **Trigger matching** -- Evaluates lock file triggers against webhook payloads to determine which jobs to run. Uses branch, path, and event matching
|
|
1306
|
+
- **Trigger matching** -- Evaluates lock file triggers against webhook payloads to determine which jobs to run. Uses glob-based branch, path, and event matching.
|
|
1305
1307
|
- **Lock file caching** -- Fetches `kici.lock.json` via the configured source's fetcher (GitHub API, universal-git clone for generic webhook sources backed by a git URL, or the local filesystem for `file://` sources). An LRU cache wraps the per-provider fetcher, keyed by `{provider}:{repo}:{ref}` so cross-provider fallback resolutions stay isolated.
|
|
1306
1308
|
- **Agent registry** -- Tracks connected agents with label-based routing for job dispatch.
|
|
1307
1309
|
- **Job queue** -- PostgreSQL-backed FIFO queue for reliable dispatch.
|
|
@@ -1333,7 +1335,7 @@ The agent is the execution worker. It runs on customer infrastructure and has fu
|
|
|
1333
1335
|
Shared business logic used by all three tiers. Single source of truth for cross-tier concerns. Has no internal `@kici-dev/*` dependencies -- only a handful of third-party libraries.
|
|
1334
1336
|
|
|
1335
1337
|
- Protocol message schemas (Zod-based, direction-specific unions including dashboard REST-over-WS, browser live streaming, the test-relay control plane, log pull, run events, peer-to-peer, cluster join, and source registration)
|
|
1336
|
-
- Provider interfaces (WebhookNormalizer, LockFileFetcher, ChangedFilesFetcher, FileContentsFetcher, CloneTokenProvider, RepoUrlBuilder, CheckStatusPoster)
|
|
1338
|
+
- Provider interfaces (WebhookNormalizer, LockFileFetcher, ChangedFilesFetcher, FileContentsFetcher, CloneTokenProvider, RepoUrlBuilder, CheckStatusPoster)
|
|
1337
1339
|
- Git credential vocabulary (forge names plus the credential reference, grant, request, and result shapes the SDK declares and the orchestrator's broker resolves) and the agent→orchestrator relay protocol its credential helper calls. See [Git credentials](https://docs.kici.dev/user/patterns/git-credentials/)
|
|
1338
1340
|
- Trigger matching engine (branch, path, event evaluation)
|
|
1339
1341
|
- Content-requirement matcher (the declarative `requires` filter -- pure data describing a query over the bytes of one source file at the event's ref, interpreted by the orchestrator via the `FileContentsFetcher` so no author code runs there) and the shared text-match vocabulary (`contains` / `notContains` / `matches` / `notMatches`) it shares with the commit-message trigger filter
|
|
@@ -1383,7 +1385,7 @@ It also runs the **local dev plane** -- an on-demand, fully local execution stac
|
|
|
1383
1385
|
|
|
1384
1386
|
### `@kici-dev/core`
|
|
1385
1387
|
|
|
1386
|
-
Light shared utilities with no server-side dependencies. It provides JSON-structured logging, error helpers, async-local-storage request context, and human-readable formatting (`formatBytes`/`formatDuration`/`formatUptime`). It also provides cryptographic helpers (`sha256`/`sha256File`/`deriveSharedSecret` plus symmetric encrypt/decrypt), retry-backoff computation, and the shared diagnostics-result contract. The rest of its surface ships as subpath entry points: the temp-directory allocator and its garbage collector, package-manager detection, CI-environment detection, and the idempotent-step runner (the check / confirm / apply primitive behind idempotent steps). One further subpath holds the `.kici/` source digest: the single content-hash definition the compiler writes into the lock file and the agent recomputes as its drift gate. Finally it supplies zx initialization (`initZx()`) and the TypeScript loader hook that transforms TypeScript on import. It is the dependency-light core that the SDK, compiler, and `kici` CLI consume directly so they stay free of heavier server-only dependencies. `@kici-dev/shared` re-exports it, so existing `@kici-dev/shared` import paths keep working.
|
|
1388
|
+
Light shared utilities with no server-side dependencies. It provides JSON-structured logging, error helpers, async-local-storage request context, and human-readable formatting (`formatBytes`/`formatDuration`/`formatUptime`). It also provides cryptographic helpers (`sha256`/`sha256File`/`deriveSharedSecret` plus symmetric encrypt/decrypt), retry-backoff computation, and the shared diagnostics-result contract. The rest of its surface ships as subpath entry points: the temp-directory allocator and its garbage collector, package-manager detection, CI-environment detection, and the idempotent-step runner (the check / confirm / apply primitive behind idempotent steps). One further subpath holds the `.kici/` source digest: the single content-hash definition the compiler writes into the lock file and the agent recomputes as its drift gate. It also owns the published docs host: `docsUrl()` builds every docs link a CLI prints or a template scaffolds from one `DOCS_SITE_URL` constant, so no other package spells the host. Finally it supplies zx initialization (`initZx()`) and the TypeScript loader hook that transforms TypeScript on import. It is the dependency-light core that the SDK, compiler, and `kici` CLI consume directly so they stay free of heavier server-only dependencies. `@kici-dev/shared` re-exports it, so existing `@kici-dev/shared` import paths keep working.
|
|
1387
1389
|
|
|
1388
1390
|
> Source: `packages/core/src/`
|
|
1389
1391
|
|
|
@@ -44,9 +44,7 @@ behalf). The token is printed once — save it now; it cannot be retrieved later
|
|
|
44
44
|
|
|
45
45
|
**Option B — an agent org API key.** Create one from the dashboard's
|
|
46
46
|
**Settings → API keys** tab: set the key's kind to **Agent** and give it an
|
|
47
|
-
agent name (the agent label).
|
|
48
|
-
`kici-platform-admin user api-key create --org <id> --agent --agent-label <label>`.
|
|
49
|
-
Reach for an org agent key when the agent should act as a shared service account
|
|
47
|
+
agent name (the agent label). Reach for an org agent key when the agent should act as a shared service account
|
|
50
48
|
rather than as a single user — for example, a long-lived CI bot that outlives any
|
|
51
49
|
individual's membership.
|
|
52
50
|
|
|
@@ -1198,10 +1196,11 @@ kici verify-attestation --bundle ./app.tgz.kici.json \
|
|
|
1198
1196
|
token was minted relative to the build. A normal attestation prints no marker
|
|
1199
1197
|
(the token was minted live). A **deferred** attestation prints an `ATTESTATION:
|
|
1200
1198
|
deferred` line — the build facts were sealed at build time and the token was
|
|
1201
|
-
minted later,
|
|
1202
|
-
by its hash. An **offline-backfill** attestation prints an
|
|
1203
|
-
offline-backfill` line — the run was ingested while the platform
|
|
1204
|
-
run/job
|
|
1199
|
+
minted later, once the orchestrator's signing key was available again, bound to
|
|
1200
|
+
the frozen statement by its hash. An **offline-backfill** attestation prints an
|
|
1201
|
+
`ATTESTATION: offline-backfill` line — the run was ingested while the platform
|
|
1202
|
+
was down, so its run/job records were replayed to the platform before the token
|
|
1203
|
+
was minted. Both still verify
|
|
1205
1204
|
(PASS); the marker discloses the temporal gap, and the organization id remains
|
|
1206
1205
|
the authoritative anchor.
|
|
1207
1206
|
|
|
@@ -1360,6 +1359,9 @@ kici feedback --open
|
|
|
1360
1359
|
|
|
1361
1360
|
# Read the same contract as structured data
|
|
1362
1361
|
kici feedback --json
|
|
1362
|
+
|
|
1363
|
+
# Turn a JSON draft (keys: draftFields from --json) into the prefilled form URL
|
|
1364
|
+
kici feedback --draft draft.json --open
|
|
1363
1365
|
```
|
|
1364
1366
|
|
|
1365
1367
|
`--json` exists for coding agents: KiCI is built to be driven by an LLM, and
|
|
@@ -1410,10 +1412,11 @@ Synopsis: `kici feedback [options]`
|
|
|
1410
1412
|
|
|
1411
1413
|
**Options**
|
|
1412
1414
|
|
|
1413
|
-
| Option
|
|
1414
|
-
|
|
|
1415
|
-
| `--open`
|
|
1416
|
-
| `--json`
|
|
1415
|
+
| Option | Default | Description |
|
|
1416
|
+
| ---------------- | ------- | --------------------------------------------------------------------------------------------- |
|
|
1417
|
+
| `--open` | | Open the prefilled issue form in the default browser |
|
|
1418
|
+
| `--json` | | Emit the reporting contract as JSON |
|
|
1419
|
+
| `--draft <file>` | | Build the prefilled issue-form URL from a JSON draft keyed by field id (with --open, open it) |
|
|
1417
1420
|
|
|
1418
1421
|
### `kici notifications`
|
|
1419
1422
|
|
|
@@ -1374,7 +1374,7 @@ kici local trust-root <file> # Export the dev-signed trust root fo
|
|
|
1374
1374
|
The plane runs in one of two modes:
|
|
1375
1375
|
|
|
1376
1376
|
- **Independent (offline)** — the default for a plane that has never been attached. Identity tokens and attestations are signed by a local dev key under the clearly non-production issuer `kici-local`.
|
|
1377
|
-
- **Hybrid (attached)** — `kici local attach` mints an org-scoped key with your logged-in credentials and reboots the plane connected to the Platform, so local runs get
|
|
1377
|
+
- **Hybrid (attached)** — `kici local attach` mints an org-scoped key with your logged-in credentials and reboots the plane connected to the Platform, so local runs get identity and attestation signed by the plane's own key under its own issuer, as a deployed orchestrator would. `kici local up` honors a durable attachment record: an attached plane comes back up hybrid, and falls back to offline with a warning when the Platform is unreachable.
|
|
1378
1378
|
|
|
1379
1379
|
`--offline` forces an independent boot without clearing the attachment record (only `detach` clears it); `--connected` requires an attached, reachable Platform and fails otherwise.
|
|
1380
1380
|
|
|
@@ -1542,7 +1542,7 @@ If multiple tools are detected, you are prompted to choose.
|
|
|
1542
1542
|
Open the KiCI documentation site in the default browser. With the `llm` subcommand, print the LLM-friendly documentation bundle that ships with `@kici-dev/compiler` — pipe it into a coding agent's context buffer to brief the agent on authoring conventions without an internet round-trip.
|
|
1543
1543
|
|
|
1544
1544
|
```bash
|
|
1545
|
-
kici docs # open https://kici.dev/
|
|
1545
|
+
kici docs # open https://docs.kici.dev/
|
|
1546
1546
|
kici docs --no-open # print the URL instead of opening a browser
|
|
1547
1547
|
kici docs llm # print the llms.txt index (a router over the task bundles)
|
|
1548
1548
|
kici docs llm sdk # print the SDK task bundle
|
|
@@ -977,7 +977,7 @@ The first two treat "no tier" as untrusted. The last two treat it as "no opinion
|
|
|
977
977
|
|
|
978
978
|
A subscriber that inherits a tier below `trusted` loses its install secrets. A job that installs from a private registry then fails at install time.
|
|
979
979
|
|
|
980
|
-
A `minimumTrust` context holds an `unknown` subscriber for security review
|
|
980
|
+
A `minimumTrust: 'trusted'` context holds an `unknown` subscriber for security review. Trust is a ref-based judgement with two answers, so that is the only floor a context can declare.
|
|
981
981
|
|
|
982
982
|
Both symptoms appear far from their cause. The tier belongs to the **emitting** run, so read that run's tier first.
|
|
983
983
|
|
|
@@ -1439,9 +1439,8 @@ Global workflows are gated by a **fleet-wide master switch** held by the orchest
|
|
|
1439
1439
|
| -------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------- |
|
|
1440
1440
|
| Allowed author repos | Restricts which repos can **author** (register) global workflows. Globs matched against the authoring repo identifier. When OFF, any repo in the org may author globals. | Lock authoring to `myorg/ci-*` so random product repos can't ship org-wide automation. |
|
|
1441
1441
|
| Blocked source repos | Blocks dispatch for events emitted from these **source** repos, regardless of authoring. Globs matched against the event source repo identifier. When OFF, events from any repo may trigger globals. | Protect against fork spam — e.g. `!myorg/*` via `myorg/fork-*`. |
|
|
1442
|
-
| Elevated access | **Deprecated and not enforced.** Stored and echoed back, but nothing reads it — a global workflow's job receives no secrets, so there is no access for it to grant. See _Secrets are not available_. | None. Clear the list so it does not imply a grant that is not in force. |
|
|
1443
1442
|
|
|
1444
|
-
|
|
1443
|
+
Both lists accept globs. Leading `!` inside a single pattern is not supported here; negation is via the list-is-implicit-deny semantics, so keep it simple (`myorg/ci-*`, `myorg/platform-*`).
|
|
1445
1444
|
|
|
1446
1445
|
Patterns match repo identifiers by the same rule as `repos:` on a trigger: an identifier is an owner/name pair, not a file path, so a leading dot carries no meaning of its own and a wildcard segment matches one. `myorg/*` covers `myorg/.github`, and `**` covers every repo in the org. Review any existing entry that relies on a wildcard to reach — or to spare — a dot-prefixed repo name.
|
|
1447
1446
|
|
|
@@ -1476,8 +1475,6 @@ This is about your **stored secrets**, not about repository access: the job is s
|
|
|
1476
1475
|
|
|
1477
1476
|
To run something that needs secrets on a source repo's event, put those jobs in a per-repository workflow in that repo, where the workflow's `contexts:` resolve normally.
|
|
1478
1477
|
|
|
1479
|
-
The **Elevated access** setting reads as the way to lift this, and it is not: it is **deprecated and never consulted**. Nothing in the dispatch path reads the list, and adding a repo to it does not make any secret readable. It is kept only so an existing value stays visible and clearable, and is removed at the next major version — see [Deprecations](https://docs.kici.dev/user/deprecations/).
|
|
1480
|
-
|
|
1481
1478
|
## When does it fire?
|
|
1482
1479
|
|
|
1483
1480
|
Same-repo globals (a workflow in `myorg/app` with `repos: ['myorg/app']`) fire on pushes to `myorg/app`. Cross-repo globals fire on pushes to any source repo whose identifier matches a glob on the authoring workflow's trigger. The orchestrator de-duplicates between the per-repo and cross-repo matching passes, so a single event produces at most one run per (workflow, source-repo, trigger) triple.
|
|
@@ -1530,7 +1527,7 @@ A `filter` reads the source tree, so the evaluation must be able to obtain one.
|
|
|
1530
1527
|
| Global workflow registered but never runs | Master toggle OFF, or allow-list blocks the authoring repo, or deny-list blocks the source repo | Orchestrator log: `Skipping global workflow dispatch` (dispatch time) / `Global workflows excluded from registration` (registration time) |
|
|
1531
1528
|
| A global workflow is never registered at all — it is absent from `kici-admin registration list` | The fleet-wide master switch is off, or the authoring repo does not match a populated _Allowed author repos_ list. | Orchestrator log: `Global workflows excluded from registration`, naming the organization it decided against. Check the switch first (`kici-admin cluster-settings show`), then that org's allow-list in the dashboard. An `"orgId": "__default__"` in the line is not itself the fault — that anchor carries no lists and restricts nothing. |
|
|
1532
1529
|
| `repos:` has no effect — workflow only fires on its own repo | The fleet-wide master switch is off. Without it, the orchestrator treats the workflow as per-repo-only. | Check the fleet-wide switch with `kici-admin cluster-settings show`. The dashboard → Settings → Global workflows tab shows it as a read-only badge. |
|
|
1533
|
-
| Secrets unavailable in a global job | Expected — a global workflow's job receives no secrets at all
|
|
1530
|
+
| Secrets unavailable in a global job | Expected — a global workflow's job receives no secrets at all. | Move the jobs that need credentials into a per-repository workflow in the repo that owns the secrets |
|
|
1534
1531
|
| Dashboard shows workflow twice after registering | Both a generic webhook source and a provider source (github, generic) re-registered the same repo. | Check `workflow_registrations` via `kici-admin workflow list` and confirm the right routing key owns the workflow. |
|
|
1535
1532
|
| Global workflow registered, enabled, allowed — and still no run appears | Its `filter` returned `false`. A global filter runs before the run is created, so a suppressed workflow leaves nothing behind at all. | [Reading a global workflow's filter output](https://docs.kici.dev/user/global-workflows/#reading-a-global-workflows-filter-output) — the evaluation round's own log. The orchestrator also logs `Global workflow skipped by eval round`, naming the workflow and the reason. |
|
|
1536
1533
|
| Global workflow never fires for one particular source repo | Its `repos:` patterns do not match that repo's identifier. | Orchestrator log: `Global workflows dropped by their repos filter` — one line per delivery, naming each dropped workflow, its repo and its patterns. |
|
|
@@ -1870,7 +1867,7 @@ Bind provisioning and teardown workflows to a context that carries the cloud cre
|
|
|
1870
1867
|
|
|
1871
1868
|
## The cloud-init that starts the agent
|
|
1872
1869
|
|
|
1873
|
-
`buildAgentCloudInit(creds, options)` renders the `#cloud-config` that boots the KiCI agent.
|
|
1870
|
+
`buildAgentCloudInit(creds, options)` renders the `#cloud-config` that boots the KiCI agent. It writes the single-use claim code — never a token — into a root-only env file (`0600`, owned by root). The agent exchanges that code for its own token inside the instance, so the token never transits cloud-init, the instance metadata, or any other provisioning channel. The env file holds:
|
|
1874
1871
|
|
|
1875
1872
|
- `KICI_ORCHESTRATOR_URL` — from `creds.orchestratorUrl`.
|
|
1876
1873
|
- `KICI_SCALER_CLAIM_CODE` — from `creds.claimCode`. The agent exchanges it for its own token in-instance.
|
|
@@ -1886,11 +1883,14 @@ The `0600` env file still protects the non-secret env from other users on the in
|
|
|
1886
1883
|
|
|
1887
1884
|
Pass any of these options to shape the boot:
|
|
1888
1885
|
|
|
1886
|
+
- `agentImage` — the agent image `deliveryMode: 'container'` runs. Defaults to `quay.io/kici-dev/kici-agent:latest`.
|
|
1887
|
+
- `startCommand` — an escape hatch that replaces the whole agent-start command. It ignores `deliveryMode` and `agentImage`.
|
|
1889
1888
|
- `packages` — extra apt/yum packages, merged into the cloud-init `packages:` list.
|
|
1890
1889
|
- `writeFiles` — extra `write_files` entries (path, content, permissions, owner). The reserved env-file path is rejected, so a custom file cannot overwrite the credentials.
|
|
1891
1890
|
- `runcmdBefore` / `runcmdAfter` — shell lines that run before or after the agent starts.
|
|
1892
1891
|
- `agentEnv` — extra variables appended to the agent env file. Keys must be valid env names, and a value with a newline is rejected.
|
|
1893
1892
|
- `baseCloudConfig` — a raw cloud-config document to merge everything into (users, ssh keys, apt mirrors, mounts, bootcmd). The builder unions its `packages`, `runcmd`, and `write_files` with yours.
|
|
1893
|
+
- `userDataEncoding` — `'raw'` (the default) returns the plain `#cloud-config` text that Hetzner `user_data` expects; `'base64'` returns it base64-encoded, the form AWS EC2 `UserData` and Azure `customData` expect.
|
|
1894
1894
|
|
|
1895
1895
|
## The teardown workflow
|
|
1896
1896
|
|
|
@@ -2061,7 +2061,7 @@ scalers:
|
|
|
2061
2061
|
|
|
2062
2062
|
On `kici.scaler.scale-up`, the provisioning workflow dispatches a `kici-agent.yml` workflow run in a GitHub repo. It passes the claim code, orchestrator URL, agent id, and labels as dispatch inputs. The token never appears in those inputs — only the single-use claim code, which the agent exchanges for its own token in-instance.
|
|
2063
2063
|
|
|
2064
|
-
The `kici-agent.yml` run starts the agent on the runner itself with `KICI_SCALER_CLAIM_CODE` set. `KICI_SCALER_MANAGED=1` and a zero idle timeout make the agent register, run one job, and exit. The GitHub Actions run then completes on its own. By default the run installs the published agent from npm; set `agent_bundle_release` to a release tag holding a `kici-admin agent package` tarball to pin an exact build or to serve runners that cannot reach npm.
|
|
2064
|
+
The `kici-agent.yml` run starts the agent on the runner itself with `KICI_SCALER_CLAIM_CODE` set. `KICI_SCALER_MANAGED=1` and a zero idle timeout make the agent register, run one job, and exit. The GitHub Actions run then completes on its own. The job carries `timeout-minutes: 15`. A wedged run (an agent the orchestrator refused, a job that never dispatched) then releases the runner instead of holding it for the six-hour default. Raise the limit if your jobs run longer. By default the run installs the published agent from npm; set `agent_bundle_release` to a release tag holding a `kici-admin agent package` tarball to pin an exact build or to serve runners that cannot reach npm.
|
|
2065
2065
|
|
|
2066
2066
|
Teardown is largely automatic. A GitHub Actions run self-completes when its agent exits. So the `kici.scaler.scale-down` workflow only cancels a run GitHub has not yet marked finished, and only for reasons where the agent will never do useful work (`spawn-timeout`, `heartbeat-timeout`).
|
|
2067
2067
|
|