@corenel/cli 0.4.2 → 0.4.3

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 (2) hide show
  1. package/dist/cli.js +145 -67
  2. package/package.json +6 -6
package/dist/cli.js CHANGED
@@ -18931,42 +18931,58 @@ function credentialFilePath(stateDir) {
18931
18931
  }
18932
18932
  var TOKEN_ENV = "CORENEL_TOKEN";
18933
18933
  var API_BASE_ENV = "CORENEL_API_BASE";
18934
- async function writeAuthToken(token, stateDir) {
18935
- const dir = credentialDir(stateDir);
18936
- const path = tokenFilePath(stateDir);
18937
- await fs2.mkdir(dir, { recursive: true, mode: 448 });
18938
- await fs2.writeFile(path, token.trim() + "\n", { mode: 384 });
18939
- try {
18940
- await fs2.chmod(path, 384);
18941
- } catch {
18942
- }
18943
- try {
18944
- await fs2.chmod(dir, 448);
18945
- } catch {
18946
- }
18947
- }
18948
18934
  async function writeLoginCredential(token, opts = {}) {
18949
18935
  const cred = {
18950
18936
  accessToken: token.trim(),
18951
18937
  ...opts.account ? { account: opts.account } : {},
18952
18938
  ...opts.apiBase ? { apiBase: opts.apiBase } : {}
18953
18939
  };
18954
- const path = credentialFilePath(opts.stateDir);
18955
- await fs2.mkdir(credentialDir(opts.stateDir), { recursive: true, mode: 448 });
18956
- await fs2.writeFile(path, `${JSON.stringify(cred, null, 2)}
18940
+ const dir = credentialDir(opts.stateDir);
18941
+ const credPath = credentialFilePath(opts.stateDir);
18942
+ const tokPath = tokenFilePath(opts.stateDir);
18943
+ await fs2.mkdir(dir, { recursive: true, mode: 448 });
18944
+ const credTmp = `${credPath}.tmp-${process.pid.toString(36)}-${Math.random().toString(36).slice(2, 10)}`;
18945
+ const tokTmp = `${tokPath}.tmp-${process.pid.toString(36)}-${Math.random().toString(36).slice(2, 10)}`;
18946
+ await fs2.writeFile(credTmp, `${JSON.stringify(cred, null, 2)}
18947
+ `, { mode: 384 });
18948
+ await fs2.writeFile(tokTmp, `${cred.accessToken}
18957
18949
  `, { mode: 384 });
18958
18950
  try {
18959
- await fs2.chmod(path, 384);
18951
+ await fs2.chmod(credTmp, 384);
18960
18952
  } catch {
18961
18953
  }
18962
- await writeAuthToken(cred.accessToken, opts.stateDir);
18954
+ try {
18955
+ await fs2.chmod(tokTmp, 384);
18956
+ } catch {
18957
+ }
18958
+ try {
18959
+ await fs2.rename(credTmp, credPath);
18960
+ await fs2.rename(tokTmp, tokPath);
18961
+ } catch (e) {
18962
+ try {
18963
+ await fs2.rm(credTmp, { force: true });
18964
+ } catch {
18965
+ }
18966
+ try {
18967
+ await fs2.rm(tokTmp, { force: true });
18968
+ } catch {
18969
+ }
18970
+ throw e;
18971
+ }
18972
+ try {
18973
+ await fs2.chmod(dir, 448);
18974
+ } catch {
18975
+ }
18976
+ }
18977
+ function isMissing(err) {
18978
+ return typeof err === "object" && err !== null && err.code === "ENOENT";
18963
18979
  }
18964
- async function readAuthToken(stateDir) {
18980
+ async function readAuthTokenRead(stateDir) {
18965
18981
  try {
18966
18982
  const t = (await fs2.readFile(tokenFilePath(stateDir), "utf8")).trim();
18967
- return t || null;
18968
- } catch {
18969
- return null;
18983
+ return { value: t || null, unreadable: false };
18984
+ } catch (err) {
18985
+ return { value: null, unreadable: !isMissing(err) };
18970
18986
  }
18971
18987
  }
18972
18988
  async function clearAuthToken(stateDir) {
@@ -18975,27 +18991,30 @@ async function clearAuthToken(stateDir) {
18975
18991
  } catch {
18976
18992
  }
18977
18993
  }
18978
- async function readCredentialFile(stateDir) {
18994
+ async function readCredentialFileRead(stateDir) {
18979
18995
  let raw;
18980
18996
  try {
18981
18997
  raw = await fs2.readFile(credentialFilePath(stateDir), "utf8");
18982
- } catch {
18983
- return null;
18998
+ } catch (err) {
18999
+ return { value: null, unreadable: !isMissing(err) };
18984
19000
  }
18985
19001
  try {
18986
19002
  const parsed = JSON.parse(raw);
18987
- if (typeof parsed !== "object" || parsed === null) return null;
19003
+ if (typeof parsed !== "object" || parsed === null) return { value: null, unreadable: false };
18988
19004
  const c = parsed;
18989
- if (typeof c.accessToken !== "string" || !c.accessToken) return null;
19005
+ if (typeof c.accessToken !== "string" || !c.accessToken) return { value: null, unreadable: false };
18990
19006
  return {
18991
- accessToken: c.accessToken,
18992
- ...typeof c.refreshToken === "string" ? { refreshToken: c.refreshToken } : {},
18993
- ...typeof c.expiresAt === "number" ? { expiresAt: c.expiresAt } : {},
18994
- ...typeof c.account === "string" ? { account: c.account } : {},
18995
- ...typeof c.apiBase === "string" && c.apiBase ? { apiBase: c.apiBase } : {}
19007
+ value: {
19008
+ accessToken: c.accessToken,
19009
+ ...typeof c.refreshToken === "string" ? { refreshToken: c.refreshToken } : {},
19010
+ ...typeof c.expiresAt === "number" ? { expiresAt: c.expiresAt } : {},
19011
+ ...typeof c.account === "string" ? { account: c.account } : {},
19012
+ ...typeof c.apiBase === "string" && c.apiBase ? { apiBase: c.apiBase } : {}
19013
+ },
19014
+ unreadable: false
18996
19015
  };
18997
19016
  } catch {
18998
- return null;
19017
+ return { value: null, unreadable: false };
18999
19018
  }
19000
19019
  }
19001
19020
  async function clearAllCredentials(stateDir) {
@@ -19011,20 +19030,29 @@ async function resolveNodeCredential(opts = {}) {
19011
19030
  const stateDir = opts.stateDir;
19012
19031
  const fromEnv = env[TOKEN_ENV]?.trim();
19013
19032
  if (fromEnv) return { token: fromEnv, source: "env" };
19014
- const cred = await readCredentialFile(stateDir);
19015
- const fileToken = await readAuthToken(stateDir);
19033
+ const credRead = await readCredentialFileRead(stateDir);
19034
+ const tokenRead = await readAuthTokenRead(stateDir);
19035
+ const cred = credRead.value;
19036
+ const fileToken = tokenRead.value;
19037
+ const unreadable = credRead.unreadable || tokenRead.unreadable ? { unreadable: true } : {};
19016
19038
  if (fileToken) {
19017
19039
  const same = cred && cred.accessToken === fileToken ? cred : null;
19018
- return withExpiry({ token: fileToken, source: "token-file", path: tokenFilePath(stateDir) }, same, now);
19040
+ return {
19041
+ ...withExpiry({ token: fileToken, source: "token-file", path: tokenFilePath(stateDir) }, same, now),
19042
+ ...unreadable
19043
+ };
19019
19044
  }
19020
19045
  if (cred) {
19021
- return withExpiry(
19022
- { token: cred.accessToken, source: "credential-file", path: credentialFilePath(stateDir) },
19023
- cred,
19024
- now
19025
- );
19046
+ return {
19047
+ ...withExpiry(
19048
+ { token: cred.accessToken, source: "credential-file", path: credentialFilePath(stateDir) },
19049
+ cred,
19050
+ now
19051
+ ),
19052
+ ...unreadable
19053
+ };
19026
19054
  }
19027
- return { token: null, source: "none" };
19055
+ return { token: null, source: "none", ...unreadable };
19028
19056
  }
19029
19057
  function withExpiry(base, cred, now) {
19030
19058
  if (!cred) return base;
@@ -22162,24 +22190,35 @@ import { PermissionService as PermissionService4 } from "@corenel/harness/guardr
22162
22190
  import { ROOT_NODE_ID } from "@corenel/protocol";
22163
22191
  import { makeSpawn } from "@corenel/harness/core/spawn";
22164
22192
  function inMemoryMemory() {
22165
- const items = [];
22166
- let n = 0;
22193
+ const items = /* @__PURE__ */ new Map();
22167
22194
  return {
22168
- async save(text, tags = []) {
22169
- const it = { id: `m${++n}`, text, tags, createdAt: n };
22170
- items.push(it);
22195
+ async save(input) {
22196
+ const it = {
22197
+ id: input.name,
22198
+ name: input.name,
22199
+ type: input.type,
22200
+ description: input.description,
22201
+ text: input.body,
22202
+ tags: [],
22203
+ createdAt: Date.now()
22204
+ };
22205
+ items.set(input.name, it);
22171
22206
  return it;
22172
22207
  },
22208
+ async read(name) {
22209
+ return items.get(name) ?? null;
22210
+ },
22173
22211
  async recall(q) {
22174
- return items.filter((i) => i.text.includes(q));
22212
+ return [...items.values()].filter((i) => i.text.includes(q) || i.description.includes(q));
22175
22213
  },
22176
22214
  async list() {
22177
- return [...items];
22215
+ return [...items.values()];
22178
22216
  },
22179
- async forget(id) {
22180
- const i = items.findIndex((x) => x.id === id);
22181
- if (i >= 0) items.splice(i, 1);
22217
+ async forget(name) {
22218
+ items.delete(name);
22182
22219
  }
22220
+ // No core(): this stub has no tiers, and Task 9 injects nothing rather than
22221
+ // pretending it has a memory block.
22183
22222
  };
22184
22223
  }
22185
22224
  function inMemoryKv() {
@@ -22252,6 +22291,42 @@ function tokenGuard(getToken) {
22252
22291
  var sleep = (ms) => new Promise((r) => setTimeout(r, ms));
22253
22292
  var MIN_POLL_MS = 1e3;
22254
22293
  var DEFAULT_LIFETIME_S = 900;
22294
+ var ACCOUNT_LOOKUP_MS = 5e3;
22295
+ function deadlineSignal(ms, outer) {
22296
+ const ac = new AbortController();
22297
+ const onOuter = () => ac.abort();
22298
+ const timer = setTimeout(() => ac.abort(), ms);
22299
+ if (outer) {
22300
+ if (outer.aborted) ac.abort();
22301
+ else outer.addEventListener("abort", onOuter, { once: true });
22302
+ }
22303
+ return {
22304
+ signal: ac.signal,
22305
+ dispose: () => {
22306
+ clearTimeout(timer);
22307
+ outer?.removeEventListener("abort", onOuter);
22308
+ }
22309
+ };
22310
+ }
22311
+ async function whoIsThis(base, token, f, outer, deadlineMs = ACCOUNT_LOOKUP_MS) {
22312
+ const { signal, dispose } = deadlineSignal(deadlineMs, outer);
22313
+ try {
22314
+ const res = await f(`${base}/auth/me`, {
22315
+ headers: { Authorization: `Bearer ${token}` },
22316
+ signal
22317
+ });
22318
+ if (!res.ok) return void 0;
22319
+ const body = JSON.parse(await res.text());
22320
+ const email = body?.user?.email;
22321
+ if (typeof email !== "string") return void 0;
22322
+ const trimmed = email.trim();
22323
+ return trimmed ? trimmed : void 0;
22324
+ } catch {
22325
+ return void 0;
22326
+ } finally {
22327
+ dispose();
22328
+ }
22329
+ }
22255
22330
  function defaultOpen(uri, code2) {
22256
22331
  process.stdout.write(`
22257
22332
  To authorize, open: ${uri}
@@ -22300,7 +22375,9 @@ async function deviceLogin(opts) {
22300
22375
  client_id: "corenel-cli"
22301
22376
  });
22302
22377
  if (tok.access_token) {
22303
- await opts.store(tok.access_token);
22378
+ const claimed = typeof tok.account === "string" ? tok.account.trim() : "";
22379
+ const account = claimed || await whoIsThis(base, tok.access_token, f, opts.signal, opts.accountLookupMs);
22380
+ await opts.store(tok.access_token, account || void 0);
22304
22381
  return tok.access_token;
22305
22382
  }
22306
22383
  if (tok.error === "authorization_pending") continue;
@@ -22566,7 +22643,10 @@ async function loadCrewAgentAtIfExists(files, root, name, scope = "workspace") {
22566
22643
  // ../crew/runtime.ts
22567
22644
  import { saveCustomPolicy } from "@corenel/harness/guardrail";
22568
22645
  import { allTools } from "@corenel/harness/tools/builtins";
22646
+ import { registerSyncConfig, readConfigSyncRendered } from "@corenel/harness/prompts/syncConfig";
22569
22647
  import { makeCallAgentTool } from "@corenel/harness/tools/callAgent";
22648
+ var MEMORY_BLOCK = registerSyncConfig("crew/memory.md");
22649
+ var SELF_DIRECTION_BLOCK = registerSyncConfig("crew/self-direction.md");
22570
22650
  function buildSystemExtra(def, memoryLocation) {
22571
22651
  const parts = [];
22572
22652
  if (def.jobTitle?.trim()) parts.push(`--- Role ---
@@ -22580,11 +22660,7 @@ ${def.instructions.trim()}`);
22580
22660
  const location = memoryLocation ?? "memory/";
22581
22661
  const dir = location.replace(/\/+$/, "");
22582
22662
  const index = `${dir}/MEMORY.md`;
22583
- parts.push(
22584
- `--- Memory ---
22585
- You keep durable notes in your own memory folder, \`${dir}/\`, one Markdown file per note, alongside \`${index}\`, an index you maintain for yourself.
22586
- Read \`${index}\` at the start of a run to recall what you already know, and call recall_memory to look up one note by name. If you can call save_memory, use it for what is worth knowing on a later run, and keep \`${index}\` current as you do. If a file tool you have takes a \`root\` argument, you can pass \`${dir}/\` as \`root\` to read and edit those files directly.`
22587
- );
22663
+ parts.push(readConfigSyncRendered(MEMORY_BLOCK, { dir, index }));
22588
22664
  const selfDirection = selfDirectionBlock(def);
22589
22665
  if (selfDirection) parts.push(selfDirection);
22590
22666
  return parts.join("\n\n");
@@ -22595,23 +22671,21 @@ function selfDirectionBlock(def) {
22595
22671
  const raw = trigger.config?.fallbackMs;
22596
22672
  const fallbackMs = typeof raw === "number" && Number.isFinite(raw) && raw > 0 ? raw : null;
22597
22673
  const consequence = fallbackMs == null ? "If this run ends without that call, nothing will wake it again and your work stops here until someone starts you by hand." : `If this run ends without that call you will be woken anyway, about ${Math.round(fallbackMs / 6e4)} minutes from now -- but that is a backstop for a run that could not schedule itself, not a substitute for choosing when you should next run.`;
22598
- return `--- Self-direction ---
22599
- You run on your own schedule. You will not run again unless you call \`schedule_self\` with the time you should next wake, before this run ends.
22600
- ${consequence}
22601
- So decide, before you finish, whether there is more to do and when it should happen.`;
22674
+ return readConfigSyncRendered(SELF_DIRECTION_BLOCK, { consequence });
22602
22675
  }
22603
22676
 
22604
22677
  // ../crew/memory.ts
22605
- import { flattenFiles as flattenFiles4 } from "@corenel/protocol";
22606
- import { parseFact, renderFact, slugify, uniqueSlug, FACT_INDEX } from "@corenel/harness/core/factFile";
22678
+ import { makeFactStore } from "@corenel/harness/memory/store";
22607
22679
 
22608
22680
  // ../crew/room/store.ts
22609
- import { flattenFiles as flattenFiles5 } from "@corenel/protocol";
22681
+ import { flattenFiles as flattenFiles4 } from "@corenel/protocol";
22610
22682
  import { encodeLine, foldSession } from "@corenel/harness/sessions/jsonl";
22611
22683
  import { FINDINGS_FILE, encodeFindingLine, foldFindings } from "@corenel/harness/rooms/findings";
22612
22684
 
22613
22685
  // ../crew/room/prompt.ts
22686
+ import { registerSyncConfig as registerSyncConfig2, readConfigSyncRendered as readConfigSyncRendered2 } from "@corenel/harness/prompts/syncConfig";
22614
22687
  import { MAX_ROOM_FINDINGS, renderFindings } from "@corenel/harness/rooms/findings";
22688
+ var ROOM_BLOCK = registerSyncConfig2("crew/room.md");
22615
22689
 
22616
22690
  // ../crew/room/turn.ts
22617
22691
  import { readRoomOutcome } from "@corenel/harness/tools/roomTools";
@@ -24245,10 +24319,14 @@ async function main() {
24245
24319
  }
24246
24320
  case "login": {
24247
24321
  const base = await apiBase(flag(rest, "base", ""));
24248
- await deviceLogin({ base, store: (token) => writeLoginCredential(token, { apiBase: base }) });
24322
+ await deviceLogin({
24323
+ base,
24324
+ store: (token, account) => writeLoginCredential(token, { apiBase: base, ...account ? { account } : {} })
24325
+ });
24249
24326
  process.stdout.write(`
24250
24327
  Logged in. Token saved to ${authTokenPath()}
24251
24328
  `);
24329
+ process.stdout.write("If a sidecar daemon is already running, restart it to sign it in as well.\n");
24252
24330
  break;
24253
24331
  }
24254
24332
  case "auth":
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@corenel/cli",
3
- "version": "0.4.2",
3
+ "version": "0.4.3",
4
4
  "type": "module",
5
5
  "description": "Corenel CLI — runs the harness in node, in-proc, no transport. The headless proof the kernel is host-agnostic. (corenel run/ask/chat/login + start --sidecar to follow.)",
6
6
  "bin": {
@@ -9,9 +9,9 @@
9
9
  "dependencies": {
10
10
  "openai": "^4.77.0",
11
11
  "ws": "^8.18.0",
12
- "@corenel/harness": "0.6.0",
13
- "@corenel/protocol": "0.6.0",
14
- "@corenel/term": "0.2.2"
12
+ "@corenel/harness": "0.6.1",
13
+ "@corenel/term": "0.2.3",
14
+ "@corenel/protocol": "0.6.1"
15
15
  },
16
16
  "devDependencies": {
17
17
  "esbuild": "^0.21.5",
@@ -19,8 +19,8 @@
19
19
  "@types/ws": "^8.5.13",
20
20
  "tsx": "^4.19.2",
21
21
  "typescript": "^5.9.3",
22
- "@corenel/tools-node": "0.3.0",
23
- "@corenel/crew": "0.0.0"
22
+ "@corenel/crew": "0.0.0",
23
+ "@corenel/tools-node": "0.3.1"
24
24
  },
25
25
  "publishConfig": {
26
26
  "access": "public"