lagora-cli 1.1.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 (52) hide show
  1. package/README.md +138 -0
  2. package/dist/help.txt +70 -0
  3. package/dist/lagora.js +342 -0
  4. package/dist/report-help.txt +5 -0
  5. package/dist/scripts/agora_playground_harness.py +263 -0
  6. package/dist/scripts/announce.js +41 -0
  7. package/dist/scripts/check-kernel-submission.py +90 -0
  8. package/dist/scripts/chunk-2EAJVB5D.js +100 -0
  9. package/dist/scripts/chunk-2KTLCUFI.js +29 -0
  10. package/dist/scripts/chunk-AZ3EEBVD.js +137 -0
  11. package/dist/scripts/chunk-NBJMYAOA.js +2128 -0
  12. package/dist/scripts/chunk-NCJMUBTG.js +125 -0
  13. package/dist/scripts/chunk-QJPQHKIO.js +23 -0
  14. package/dist/scripts/chunk-RIR5KGHC.js +33 -0
  15. package/dist/scripts/chunk-TJZVQYBL.js +8 -0
  16. package/dist/scripts/chunk-UHJXD4TG.js +18 -0
  17. package/dist/scripts/chunk-UQ6I6VTY.js +117 -0
  18. package/dist/scripts/cli-auth.js +348 -0
  19. package/dist/scripts/cli-config-IA7EOSYD.js +7 -0
  20. package/dist/scripts/install-skill.js +199 -0
  21. package/dist/scripts/issue-local-client-DZUXZOKY.js +22 -0
  22. package/dist/scripts/issue-search.js +1823 -0
  23. package/dist/scripts/issue.js +386 -0
  24. package/dist/scripts/keycloak-provision.js +986 -0
  25. package/dist/scripts/legato-fsim-runner.py +126 -0
  26. package/dist/scripts/legato-lowering-runner.py +156 -0
  27. package/dist/scripts/legato_runner_annotations.py +235 -0
  28. package/dist/scripts/legato_runner_env.py +91 -0
  29. package/dist/scripts/legato_runner_launchers.py +287 -0
  30. package/dist/scripts/legato_runner_script_wrapper.py +193 -0
  31. package/dist/scripts/notifications-EU43SIEV.js +624 -0
  32. package/dist/scripts/playground.js +408 -0
  33. package/dist/scripts/report-bundle-sync-3U7QTP4Z.js +215 -0
  34. package/dist/scripts/report.js +104 -0
  35. package/dist/scripts/resolve-sdk-package-version.py +151 -0
  36. package/dist/scripts/sdk-runtime-JE6H2PB2.js +992 -0
  37. package/dist/scripts/sdk-runtime-kubernetes-job-KOWL4ITV.js +479 -0
  38. package/dist/scripts/sdk-runtime-smoke.py +168 -0
  39. package/dist/scripts/sdk.js +256 -0
  40. package/dist/scripts/site-feedback-CAPE5MPX.js +136 -0
  41. package/dist/scripts/site-feedback-rate-limit-5BU2WSFE.js +86 -0
  42. package/dist/scripts/site-feedback.js +117 -0
  43. package/dist/scripts/storage-234FBH54.js +67 -0
  44. package/dist/scripts/submit-issue.sh +489 -0
  45. package/dist/scripts/verification-3QCY66QW.js +772 -0
  46. package/dist/scripts/verify-issue.js +144 -0
  47. package/dist/skills/legato-agora-cli/SKILL.md +556 -0
  48. package/dist/skills/legato-agora-cli/agents/openai.yaml +7 -0
  49. package/dist/skills/legato-agora-cli/reference/kernel-with-golden.py +84 -0
  50. package/dist/skills/legato-site-feedback/SKILL.md +49 -0
  51. package/dist/skills/legato-site-feedback/agents/openai.yaml +7 -0
  52. package/package.json +16 -0
package/README.md ADDED
@@ -0,0 +1,138 @@
1
+ # lagora-cli
2
+
3
+ Lean npm distribution of the Legato Agora CLI. The npm package is `lagora-cli`
4
+ (unscoped); the executable remains `lagora`. Nothing has been published, so
5
+ installing from the public registry doesn't work yet. Until a release exists,
6
+ install from the internal GitHub release tarball or run
7
+ `./bin/lagora` from a repository checkout as described in the
8
+ [root README](../../README.md#install-the-cli-package).
9
+
10
+ After a public release:
11
+
12
+ ```sh
13
+ npm install -g lagora-cli
14
+ lagora login
15
+ lagora help
16
+ ```
17
+
18
+ `lagora login` opens the browser flow described in the root README and stores a
19
+ CLI-scoped token; nothing about login changes in the npm build.
20
+
21
+ Requires Node.js 22.16 or newer. Remote login, reports, issue commands,
22
+ Playground upload/status, SDK administration and feedback use compiled Node.js,
23
+ without Next.js, React, tsx, Bash, curl or Python runtime dependencies. Login
24
+ opens the system browser and prints the URL for manual use if opening fails.
25
+ Saved login targets and `LAGORA_CONFIG` / `XDG_CONFIG_HOME` remain supported.
26
+
27
+ `lagora report --store` retains the existing portable shell writer and requires
28
+ Bash, Python 3 and standard Unix utilities. It preserves duplicate merging,
29
+ artifact collision handling and optional `--auto-lowering`. Local reads and
30
+ mutations remain isolated from the working directory's other stores.
31
+ `playground validate` requires Python 3. Real lowering/fSIM and SDK preparation
32
+ also require the separately installed platform-specific SDK, Python and its
33
+ build tools; this package does not install them or promise Windows portability
34
+ for these optional paths. No live SDK build or production service is exercised
35
+ by the package tests. Remote reports do not query GitHub CLI identity.
36
+
37
+ ## Self-update
38
+
39
+ The installed CLI keeps itself current from the npm registry. Nothing runs in
40
+ the background: no daemon, cron entry or extra dependency.
41
+
42
+ ### Automatic
43
+
44
+ After an ordinary command finishes and prints its own output, the CLI checks
45
+ for a newer stable release and installs it if found. The original command's
46
+ exit code is preserved either way. Checks happen at most once every 24 hours
47
+ per install prefix, and a failed or offline check counts toward that window, so
48
+ a machine without network access sees at most one bounded attempt per day.
49
+ Timeouts are short: the version lookup is capped at 4 seconds and the install
50
+ at 45 seconds, with no retries.
51
+
52
+ Turn it off in one of two ways:
53
+
54
+ ```sh
55
+ lagora update --disable # persisted; lagora update --enable turns it back on
56
+ LAGORA_AUTO_UPDATE=0 lagora report ... # per process; false and off also work
57
+ ```
58
+
59
+ The persisted setting lives in `$XDG_CONFIG_HOME/lagora/update.json`
60
+ (`~/.config/lagora/update.json` by default). It's separate from the login
61
+ config, which the updater never reads or writes.
62
+
63
+ ### Manual
64
+
65
+ ```sh
66
+ lagora update # check now and apply a newer stable exact version
67
+ lagora update --help
68
+ ```
69
+
70
+ `lagora update` ignores the 24-hour throttle and the disabled setting, prints a
71
+ JSON status line, and exits 0 when it updated or was already current, 1 when
72
+ the install is unsupported, another updater holds the lock, or the update
73
+ failed. Reasons are sanitized codes; raw npm output and credentials never
74
+ appear.
75
+
76
+ ### Supported installs
77
+
78
+ Self-update, automatic or manual, only touches a canonical `npm install -g`
79
+ of `lagora-cli` on Unix where the global prefix, bin link and package
80
+ directory are owned and writable by the current non-root user and match npm's
81
+ configured global prefix. Everything else still runs every ordinary command but
82
+ never updates itself and makes no registry update requests:
83
+
84
+ - `sudo` or root installs
85
+ - Windows
86
+ - `npx`
87
+ - project-local dependencies
88
+ - `npm link` or a repository checkout
89
+ - read-only prefixes
90
+
91
+ npm itself is invoked with `--ignore-scripts`, `--engine-strict` and an exact
92
+ validated version, using your configured registry, `.npmrc` and npm-managed
93
+ auth. CLI and chat tokens are kept out of npm's environment.
94
+
95
+ ### Disk footprint and cleanup
96
+
97
+ Each applied update is staged inside the prefix and then kept as an immutable
98
+ release under `<prefix>/.lagora-update/releases/<uuid>`. Only the small global
99
+ launcher file is switched, atomically, so commands that are still running, or
100
+ suspended, keep the assets they started with. Old releases are intentionally
101
+ not garbage-collected: a paused process may still need them. Each retained
102
+ release is roughly the size of one unpacked package, about 0.6 MB at the current
103
+ version, so the directory grows by that much per update.
104
+
105
+ To reclaim the space:
106
+
107
+ 1. Make sure no `lagora` process is running or suspended.
108
+ 2. Reinstall normally: `npm install -g lagora-cli`.
109
+ 3. Remove `<prefix>/.lagora-update` (find the prefix with `npm prefix -g`).
110
+
111
+ `npm uninstall -g lagora-cli` alone leaves `.lagora-update` behind;
112
+ remove it by hand as well when uninstalling for good.
113
+
114
+ Known limits: the updater's lock doesn't coordinate with a separate `npm
115
+ install`/`uninstall` you run at the same time, and a hard kill between the
116
+ launcher switch and the manifest refresh can leave `npm ls -g` showing a stale
117
+ version while the CLI itself already runs the new release. Both are recovered
118
+ by an ordinary reinstall.
119
+
120
+ ## Build and test from this repository
121
+
122
+ ```sh
123
+ npm ci
124
+ npm run build:cli
125
+ npm run test:cli
126
+ npm run pack:cli
127
+ ```
128
+
129
+ The build reuses the repository's esbuild and compiles only the CLI dependency
130
+ graph. `dist/` and this README plus the manifest are the only shipped files.
131
+ Explicit asset allowlists exclude tests, environment files, local data and
132
+ repository evidence. There are zero runtime npm dependencies and no install
133
+ lifecycle script. The root website remains private and independently built.
134
+
135
+ The runtime test creates a real tarball with `npm pack`, installs it globally
136
+ under a temporary prefix outside the repository, then runs that installed
137
+ `lagora` with temporary HOME/config/data directories and loopback APIs only.
138
+ No npm credentials or registry publishing are needed.
package/dist/help.txt ADDED
@@ -0,0 +1,70 @@
1
+ Usage: lagora <command> [options]
2
+
3
+ Commands:
4
+ login Sign in through the browser (Keycloak + activity profile)
5
+ logout Revoke and clear CLI login
6
+ whoami Show the verified CLI identity
7
+ tokens List or revoke your active CLI tokens
8
+ report Submit a portable Legato issue bundle
9
+ search Search similar issues
10
+ fetch Fetch an issue and copy artifacts locally
11
+ comment Add an analysis/comment reply
12
+ status Update an issue status
13
+ description Rewrite the issue description
14
+ suggestion Submit or replace a kernel code suggestion
15
+ assign Assign an issue
16
+ blocker Link or sync a GitHub PR blocker
17
+ notifications List or mark remote board notifications read
18
+ announce Publish a site-wide feature announcement
19
+ sdk Inspect or update the site's prepared SDK packages
20
+ playground Upload and inspect Playground runs
21
+ feedback List, fetch, or resolve site feedback
22
+ issue Fetch or update issues
23
+ verify Run worker verification
24
+ keycloak Plan, apply, or verify safe Keycloak provisioning
25
+ skill Install the Legato Agora agent skills
26
+ help Show this help
27
+
28
+ Examples:
29
+ lagora login
30
+ lagora report --kernel kernel.py --log error.log --title "lowering failure" --reporter alice
31
+ lagora tokens list
32
+ lagora tokens revoke --token <token-id>
33
+ lagora tokens revoke --all
34
+ lagora search --query "cgdma Xfer=0 lowering"
35
+ lagora fetch --issue <issue-id> --out ./issue-work
36
+ lagora comment --issue <issue-id> --body "Root cause looks like CORE_IR lowering."
37
+ lagora status --issue <issue-id> --status investigating
38
+ lagora description --issue <issue-id> --body "Updated reproduction steps."
39
+ lagora suggestion --issue <issue-id> --file fixed_kernel.py
40
+ lagora assign --issue <issue-id> --assignee alice
41
+ lagora blocker add --issue <issue-id> --pr 1234
42
+ lagora blocker sync --issue <issue-id> --blocker-id <blocker-id>
43
+ lagora issue notifications
44
+ lagora issue notifications read --notification <notification-id>
45
+ lagora feedback list
46
+ LAGORA_ANNOUNCEMENT_TOKEN=... lagora announce create --title "Playground" --body "Playground is now available." --link /playground
47
+ LAGORA_SDK_TOKEN=... lagora sdk status
48
+ LAGORA_SDK_TOKEN=... lagora sdk list --disk
49
+ LAGORA_SDK_TOKEN=... lagora sdk update --watch
50
+ lagora playground runtimes
51
+ lagora playground validate --kernel kernel.py
52
+ lagora playground run --kernel kernel.py --sdk-name prepared-runtime
53
+ lagora playground status --run <run-id>
54
+ lagora playground report --run <run-id> --title "CORE_IR regression"
55
+ lagora feedback fetch --status open
56
+ lagora feedback resolve --id <feedback-id>
57
+ lagora fetch --store /path/to/issue-store --issue <issue-id> --out ./issue-work
58
+ lagora comment --store /path/to/issue-store --issue <issue-id> --body "Root cause looks like CORE_IR lowering."
59
+ lagora status --store /path/to/issue-store --issue <issue-id> --status investigating
60
+ lagora description --store /path/to/issue-store --issue <issue-id> --body "Updated reproduction steps."
61
+ lagora verify --store /path/to/issue-store --issue <issue-id> --kind lowering --mode real --sdk-branch main
62
+ lagora keycloak plan --state-fixture fixtures/keycloak/empty-realm.fixture.json
63
+ lagora keycloak verify --claims-fixture fixtures/keycloak/tenant-claims.fixture.json
64
+ lagora keycloak verify --live
65
+ lagora skill install
66
+
67
+ Targets:
68
+ Commands talk to https://legato-dev-agora.hyperaccel.net/legato-dev-agora by default.
69
+ Pass --api-url <url> or set LAGORA_API_URL to use another deployment, and
70
+ pass --store <path> to work against a local or mounted issue store instead.
package/dist/lagora.js ADDED
@@ -0,0 +1,342 @@
1
+ #!/usr/bin/env node
2
+
3
+ // packages/cli/src/lagora.ts
4
+ import { spawn } from "node:child_process";
5
+ import { readFile } from "node:fs/promises";
6
+ import { fileURLToPath } from "node:url";
7
+
8
+ // packages/cli/src/dispatch.ts
9
+ var aliases = {
10
+ fetch: "checkout",
11
+ comment: "comment",
12
+ status: "status",
13
+ description: "description",
14
+ suggestion: "suggestion",
15
+ assign: "assign",
16
+ blocker: "blocker",
17
+ notifications: "notifications"
18
+ };
19
+ var scripts = {
20
+ report: "report",
21
+ search: "issue-search",
22
+ issue: "issue",
23
+ verify: "verify-issue",
24
+ announce: "announce",
25
+ sdk: "sdk",
26
+ playground: "playground",
27
+ feedback: "site-feedback",
28
+ keycloak: "keycloak-provision",
29
+ skill: "install-skill"
30
+ };
31
+ var authCommands = /* @__PURE__ */ new Set(["login", "logout", "whoami", "tokens"]);
32
+ function commandTarget(command, argv) {
33
+ if (authCommands.has(command)) return { script: "cli-auth", argv: [command, ...argv] };
34
+ if (Object.hasOwn(aliases, command)) return { script: "issue", argv: [aliases[command], ...argv] };
35
+ if (Object.hasOwn(scripts, command)) return { script: scripts[command], argv: [...argv] };
36
+ throw new Error(`Unknown command: ${command}`);
37
+ }
38
+
39
+ // packages/cli/src/update.ts
40
+ import { execFile } from "node:child_process";
41
+ import { randomUUID } from "node:crypto";
42
+ import { accessSync, constants, existsSync, lstatSync, mkdirSync, mkdtempSync, readFileSync, readlinkSync, realpathSync, renameSync, rmSync, symlinkSync, unlinkSync, writeFileSync } from "node:fs";
43
+ import { homedir } from "node:os";
44
+ import path from "node:path";
45
+ import { promisify } from "node:util";
46
+ var execute = promisify(execFile);
47
+ var packageName = "lagora-cli";
48
+ var stable = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:\+[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?$/;
49
+ var interval = 24 * 60 * 60 * 1e3;
50
+ var UpdateError = class extends Error {
51
+ constructor(reason) {
52
+ super(reason);
53
+ this.reason = reason;
54
+ }
55
+ };
56
+ function isNewerStable(candidate, current) {
57
+ if (typeof candidate !== "string" || typeof current !== "string") return false;
58
+ const next = stable.exec(candidate);
59
+ const previous = stable.exec(current);
60
+ if (!next || !previous) return false;
61
+ for (const index of [1, 2, 3]) {
62
+ const a = BigInt(next[index] ?? "0");
63
+ const b = BigInt(previous[index] ?? "0");
64
+ if (a !== b) return a > b;
65
+ }
66
+ return false;
67
+ }
68
+ function code(error, expected) {
69
+ return error instanceof Error && "code" in error && error.code === expected;
70
+ }
71
+ function json(file) {
72
+ const value = JSON.parse(readFileSync(file, "utf8"));
73
+ if (!value || typeof value !== "object" || Array.isArray(value)) throw new UpdateError("invalid-metadata");
74
+ return Object.fromEntries(Object.entries(value));
75
+ }
76
+ function settingsPath(env) {
77
+ return path.join(env.XDG_CONFIG_HOME || path.join(env.HOME || homedir(), ".config"), "lagora", "update.json");
78
+ }
79
+ async function setAutoUpdate(enabled, env = process.env) {
80
+ const file = settingsPath(env);
81
+ mkdirSync(path.dirname(file), { recursive: true, mode: 448 });
82
+ const temporary = `${file}.${randomUUID()}`;
83
+ try {
84
+ writeFileSync(temporary, JSON.stringify({ enabled }), { mode: 384, flag: "wx" });
85
+ renameSync(temporary, file);
86
+ } finally {
87
+ rmSync(temporary, { force: true });
88
+ }
89
+ }
90
+ function autoEnabled(env) {
91
+ if (/^(0|false|off)$/i.test(env.LAGORA_AUTO_UPDATE ?? "")) return false;
92
+ try {
93
+ return json(settingsPath(env)).enabled !== false;
94
+ } catch (error) {
95
+ if (code(error, "ENOENT")) return true;
96
+ throw error;
97
+ }
98
+ }
99
+ function installation(packageRoot) {
100
+ if (process.platform === "win32" || process.getuid?.() === 0) return void 0;
101
+ const runtime = path.resolve(packageRoot);
102
+ const retained = path.basename(path.dirname(runtime)) === "releases" && path.basename(path.resolve(runtime, "../..")) === ".lagora-update";
103
+ const prefix = path.resolve(runtime, "../../..");
104
+ const root2 = path.join(prefix, "lib/node_modules", packageName);
105
+ if (!retained && runtime !== root2) return void 0;
106
+ try {
107
+ if (realpathSync(root2) !== root2 || realpathSync(runtime) !== runtime) return void 0;
108
+ for (let ancestor = root2; ; ancestor = path.dirname(ancestor)) {
109
+ if (existsSync(path.join(ancestor, ".git"))) return void 0;
110
+ if (ancestor === path.dirname(ancestor)) break;
111
+ }
112
+ for (const directory of [prefix, path.join(prefix, "lib/node_modules"), root2, runtime, path.join(prefix, "bin")]) {
113
+ const info = lstatSync(directory);
114
+ if (!info.isDirectory() || info.uid !== process.getuid?.() || (info.mode & 128) === 0) return void 0;
115
+ accessSync(directory, constants.W_OK);
116
+ }
117
+ const manifest = json(path.join(root2, "package.json"));
118
+ const bin = manifest.bin;
119
+ if (manifest.name !== packageName || typeof manifest.version !== "string" || !stable.test(manifest.version) || !bin || typeof bin !== "object" || Reflect.get(bin, "lagora") !== "dist/lagora.js" || realpathSync(path.join(prefix, "bin/lagora")) !== path.join(root2, "dist/lagora.js")) return void 0;
120
+ return { root: root2, prefix, version: manifest.version, state: path.join(prefix, ".lagora-update") };
121
+ } catch (error) {
122
+ if (error instanceof Error) return void 0;
123
+ throw error;
124
+ }
125
+ }
126
+ function alive(owner) {
127
+ const pid = Number(owner.split("-")[0]);
128
+ if (!Number.isSafeInteger(pid) || pid <= 0) return true;
129
+ try {
130
+ process.kill(pid, 0);
131
+ return true;
132
+ } catch (error) {
133
+ if (code(error, "ESRCH")) return false;
134
+ throw error;
135
+ }
136
+ }
137
+ function stateDirectory(install) {
138
+ mkdirSync(install.state, { recursive: true, mode: 448 });
139
+ const info = lstatSync(install.state);
140
+ if (!info.isDirectory() || info.uid !== process.getuid?.()) throw new UpdateError("unsafe-state-directory");
141
+ }
142
+ function lock(file) {
143
+ const owner = `${process.pid}-${randomUUID()}`;
144
+ try {
145
+ symlinkSync(owner, file);
146
+ } catch (error) {
147
+ if (!code(error, "EEXIST")) throw error;
148
+ let previous;
149
+ try {
150
+ previous = readlinkSync(file);
151
+ } catch (readError) {
152
+ if (code(readError, "ENOENT")) return lock(file);
153
+ throw readError;
154
+ }
155
+ if (!/^\d+-[0-9a-f-]{36}$/.test(previous) || alive(previous)) return void 0;
156
+ const releaseReaper = lock(`${file}.reap-${previous}`);
157
+ if (!releaseReaper) return void 0;
158
+ try {
159
+ try {
160
+ if (readlinkSync(file) === previous) unlinkSync(file);
161
+ } catch (readError) {
162
+ if (!code(readError, "ENOENT")) throw readError;
163
+ }
164
+ } finally {
165
+ releaseReaper();
166
+ }
167
+ return lock(file);
168
+ }
169
+ return () => {
170
+ if (readlinkSync(file) === owner) unlinkSync(file);
171
+ };
172
+ }
173
+ function npmEnvironment(env) {
174
+ return { NODE_ENV: env.NODE_ENV ?? "production", ...Object.fromEntries(Object.entries(env).filter(([key]) => /^(npm_|path$|home$|userprofile$|appdata$|localappdata$|tmpdir$|temp$|tmp$|systemroot$|comspec$|pathext$|https?_proxy$|no_proxy$|node_extra_ca_certs$|ssl_cert_file$)/i.test(key))) };
175
+ }
176
+ async function npm(args, env, timeout) {
177
+ try {
178
+ const result = await execute("npm", [...args, "--fetch-retries=0", "--fetch-timeout=2000", "--update-notifier=false", "--no-audit", "--no-fund"], {
179
+ cwd: env.HOME || homedir(),
180
+ env: npmEnvironment(env),
181
+ timeout,
182
+ killSignal: "SIGKILL",
183
+ maxBuffer: 1024 * 1024
184
+ });
185
+ return result.stdout.trim();
186
+ } catch (error) {
187
+ if (error instanceof Error) throw new UpdateError("npm-unavailable-or-failed");
188
+ throw error;
189
+ }
190
+ }
191
+ function promote(install, staged) {
192
+ const releases = path.join(install.state, "releases");
193
+ mkdirSync(releases, { recursive: true, mode: 448 });
194
+ const retained = path.join(releases, randomUUID());
195
+ renameSync(staged, retained);
196
+ const launcher = path.join(install.root, "dist/lagora.js");
197
+ const temporary = `${launcher}.${randomUUID()}`;
198
+ const manifest = path.join(install.root, "package.json");
199
+ const metadata = `${manifest}.${randomUUID()}`;
200
+ const relative = path.relative(path.dirname(launcher), path.join(retained, "dist/lagora.js"));
201
+ try {
202
+ writeFileSync(temporary, `#!/usr/bin/env node
203
+ await import(new URL(${JSON.stringify(relative)}, import.meta.url));
204
+ `, { mode: 493, flag: "wx" });
205
+ writeFileSync(metadata, readFileSync(path.join(retained, "package.json")), { mode: 420, flag: "wx" });
206
+ renameSync(temporary, launcher);
207
+ renameSync(metadata, manifest);
208
+ } finally {
209
+ rmSync(temporary, { force: true });
210
+ rmSync(metadata, { force: true });
211
+ }
212
+ }
213
+ async function runUpdate(options) {
214
+ const env = options.env ?? process.env;
215
+ let release;
216
+ let staging;
217
+ try {
218
+ if (options.mode === "auto" && !autoEnabled(env)) return { status: "disabled" };
219
+ const install = installation(options.packageRoot);
220
+ if (!install || env.npm_command === "exec") return { status: "unsupported" };
221
+ stateDirectory(install);
222
+ release = lock(path.join(install.state, "install"));
223
+ if (!release) return { status: "busy" };
224
+ const now = (options.now ?? Date.now)();
225
+ const state = path.join(install.state, "checked.json");
226
+ let last;
227
+ try {
228
+ last = json(state).at;
229
+ } catch (error) {
230
+ if (!code(error, "ENOENT") && !(error instanceof SyntaxError)) throw error;
231
+ }
232
+ if (options.mode === "auto" && typeof last === "number" && now >= last && now - last < interval) return { status: "throttled" };
233
+ writeFileSync(state, JSON.stringify({ at: now }), { mode: 384 });
234
+ if (realpathSync(await npm(["prefix", "--global"], env, 3e3)) !== install.prefix) return { status: "unsupported" };
235
+ const raw = JSON.parse(await npm(["view", `${packageName}@latest`, "name", "version", "--json"], env, 4e3));
236
+ if (!raw || typeof raw !== "object" || Reflect.get(raw, "name") !== packageName) throw new UpdateError("registry-identity-mismatch");
237
+ const version = Reflect.get(raw, "version");
238
+ if (typeof version !== "string" || !stable.test(version)) throw new UpdateError("registry-version-invalid");
239
+ if (!isNewerStable(version, install.version)) return { status: "current", version: install.version };
240
+ staging = mkdtempSync(path.join(install.state, "stage-"));
241
+ const globalConfig = await npm(["config", "get", "globalconfig"], env, 3e3);
242
+ await npm(["install", "--global", "--prefix", staging, "--globalconfig", globalConfig, "--ignore-scripts", "--engine-strict", "--install-strategy=nested", "--package-lock=false", `${packageName}@${version}`], env, 45e3);
243
+ const staged = path.join(staging, "lib/node_modules", packageName);
244
+ const manifest = json(path.join(staged, "package.json"));
245
+ if (manifest.name !== packageName || manifest.version !== version || !manifest.bin || typeof manifest.bin !== "object" || Reflect.get(manifest.bin, "lagora") !== "dist/lagora.js" || !lstatSync(path.join(staged, "dist/lagora.js")).isFile()) throw new UpdateError("installed-identity-mismatch");
246
+ promote(install, staged);
247
+ return { status: "updated", version };
248
+ } catch (error) {
249
+ if (error instanceof Error) return { status: "failed", reason: error instanceof UpdateError ? error.reason : "update-io-failed" };
250
+ throw error;
251
+ } finally {
252
+ try {
253
+ if (staging) rmSync(staging, { recursive: true, force: true });
254
+ } finally {
255
+ release?.();
256
+ }
257
+ }
258
+ }
259
+ async function beforeCommand(argv, packageRoot) {
260
+ if (argv[0] === "update") {
261
+ if (argv.length === 2 && ["--enable", "--disable"].includes(argv[1] ?? "")) {
262
+ await setAutoUpdate(argv[1] === "--enable");
263
+ console.log(`Automatic updates ${argv[1] === "--enable" ? "enabled" : "disabled"}.`);
264
+ } else if (argv.length === 2 && ["--help", "-h"].includes(argv[1] ?? "")) {
265
+ console.log("Usage: lagora update [--enable|--disable]\nUpdates a user-owned global npm install. Automatic updates run after commands, at most daily. LAGORA_AUTO_UPDATE=0 disables automatic updates.");
266
+ } else if (argv.length > 1) {
267
+ console.error("Usage: lagora update [--enable|--disable]");
268
+ process.exitCode = 1;
269
+ } else {
270
+ const result = await runUpdate({ packageRoot, mode: "manual" });
271
+ console.log(JSON.stringify(result));
272
+ if (!["updated", "current"].includes(result.status)) process.exitCode = 1;
273
+ }
274
+ return true;
275
+ }
276
+ return false;
277
+ }
278
+ async function afterCommand(packageRoot) {
279
+ try {
280
+ const result = await runUpdate({ packageRoot, mode: "auto" });
281
+ if (result.status === "updated") console.error(`lagora updated to ${result.version}; the next command uses the new version.`);
282
+ if (result.status === "failed") console.error(`lagora auto-update unavailable (${result.reason}); your command result is unchanged.`);
283
+ } catch (error) {
284
+ if (error instanceof Error) console.error("lagora auto-update cleanup failed; your command result is unchanged.");
285
+ else throw error;
286
+ }
287
+ }
288
+
289
+ // packages/cli/src/lagora.ts
290
+ var root = new URL("./", import.meta.url);
291
+ async function run(script, argv) {
292
+ const child = spawn(process.execPath, [fileURLToPath(new URL(`scripts/${script}.js`, root)), ...argv], { stdio: "inherit" });
293
+ const result = await new Promise((resolve, reject) => {
294
+ child.once("error", reject);
295
+ child.once("exit", (code2, signal) => resolve({ code: code2, signal }));
296
+ });
297
+ if (result.signal) {
298
+ process.kill(process.pid, result.signal);
299
+ return false;
300
+ }
301
+ process.exitCode = result.code ?? 1;
302
+ return result.code === 0;
303
+ }
304
+ async function main() {
305
+ const argv = process.argv.slice(2);
306
+ const packageRoot = fileURLToPath(new URL("../", root));
307
+ if (await beforeCommand(argv, packageRoot)) return;
308
+ try {
309
+ await dispatch(argv);
310
+ } finally {
311
+ await afterCommand(packageRoot);
312
+ }
313
+ }
314
+ async function dispatch(argv) {
315
+ const command = argv[0] ?? "help";
316
+ if (command === "--version" || command === "-v") {
317
+ const manifest = JSON.parse(await readFile(new URL("../package.json", root), "utf8"));
318
+ console.log(manifest.version);
319
+ return;
320
+ }
321
+ if (["help", "--help", "-h"].includes(command)) {
322
+ process.stdout.write(await readFile(new URL("help.txt", root), "utf8"));
323
+ return;
324
+ }
325
+ const args = argv.slice(1);
326
+ const target = commandTarget(command, args);
327
+ if (args.includes("--store")) process.env.AGORA_ISSUE_STORE_MODE = "isolated";
328
+ if (args.includes("--help") || args.includes("-h")) {
329
+ process.stdout.write(await readFile(new URL(command === "report" ? "report-help.txt" : "help.txt", root), "utf8"));
330
+ return;
331
+ }
332
+ if (!authCommands.has(command) && !await run("cli-auth", ["require-auth", command, ...args])) return;
333
+ if (["sdk", "announce"].includes(command) && !args.includes("--api-url")) {
334
+ const { LagoraCliConfigStore } = await import("./scripts/cli-config-IA7EOSYD.js");
335
+ target.argv.push("--api-url", (await new LagoraCliConfigStore().apiSession(void 0)).apiUrl);
336
+ }
337
+ await run(target.script, target.argv);
338
+ }
339
+ main().catch((error) => {
340
+ console.error(error instanceof Error ? error.message : String(error));
341
+ process.exitCode = 1;
342
+ });
@@ -0,0 +1,5 @@
1
+ Usage: lagora report --kernel path --title title --reporter name [--log path] [--description text | --description-file path] [--api-url url | --store path] [--idempotency-key key] [--auto-lowering] [--sdk-root path] [--python python3] [--stages MLIR,CORE_IR] [--kernel-function name]
2
+
3
+ Creates a portable issue bundle under issue-store/issues/<id>/ by default.
4
+ Pass --api-url to submit to the internal Agora server.
5
+ Pass --store to write into a local or mounted issue repository.