@staff0rd/assist 0.779.0 → 0.780.1

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/index.js CHANGED
@@ -6,7 +6,7 @@ import { Command } from "commander";
6
6
  // package.json
7
7
  var package_default = {
8
8
  name: "@staff0rd/assist",
9
- version: "0.779.0",
9
+ version: "0.780.1",
10
10
  type: "module",
11
11
  main: "dist/index.js",
12
12
  bin: {
@@ -12488,7 +12488,8 @@ function readRawConfigLayers(cwd, globalConfigPath = getGlobalConfigPath()) {
12488
12488
  project: loadRawYaml(projectConfigPathFrom(cwd)),
12489
12489
  global,
12490
12490
  repoOverride: repo.override,
12491
- ...repo.key === void 0 ? {} : { repoKey: repo.key }
12491
+ ...repo.key === void 0 ? {} : { repoKey: repo.key },
12492
+ ...repo.source === void 0 ? {} : { repoSource: repo.source }
12492
12493
  };
12493
12494
  }
12494
12495
 
@@ -12757,7 +12758,7 @@ var configConfigHelp = [
12757
12758
  {
12758
12759
  key: "repos",
12759
12760
  setter: "assist config set worktree.enabled true -g --repo",
12760
- note: "per-repo override blocks in ~/.assist.yml, keyed by repo identity; written by 'config set -g --repo [name]'"
12761
+ note: "per-repo overrides stored in the shared db, keyed by repo identity and seen by every node that uses it; written by 'config set -g --repo [name]' or the web /config repo scope, and a yml repos: entry applies only until 'config import-repos' moves it"
12761
12762
  }
12762
12763
  ];
12763
12764
 
@@ -13388,6 +13389,7 @@ function configEntryFor(leaf, { config, layers, globalConfigFile, schema: schema
13388
13389
  sources,
13389
13390
  layers: configEntryLayers(leaf.key, layers, node),
13390
13391
  ...layers.repoKey ? { repoKey: layers.repoKey } : {},
13392
+ ...layers.repoSource ? { repoSource: layers.repoSource } : {},
13391
13393
  globalConfigFile,
13392
13394
  globalOnly: isGlobalOnlyConfigKey(leaf.key),
13393
13395
  node
@@ -16819,6 +16821,12 @@ function globalOnlyRepoKeyError(key, verb) {
16819
16821
  };
16820
16822
  }
16821
16823
 
16824
+ // src/shared/db/listRepoConfigs.ts
16825
+ async function listRepoConfigs(orm) {
16826
+ const rows = await orm.select().from(repoConfigs);
16827
+ return Object.fromEntries(rows.map((row) => [row.repoKey, row.config]));
16828
+ }
16829
+
16822
16830
  // src/shared/resolveNamedRepoWriteLabel.ts
16823
16831
  var UnknownRepoConfigError = class extends Error {
16824
16832
  name = "UnknownRepoConfigError";
@@ -16841,45 +16849,74 @@ function resolveNamedRepoWriteLabel(globalRaw, name, source = "~/.assist.yml") {
16841
16849
  return matches[0];
16842
16850
  }
16843
16851
 
16844
- // src/commands/config/resolveRepoConfigBlock.ts
16845
- function resolveRepoConfigBlock(repoName, cwd, globalConfigPath) {
16846
- const globalRaw = loadGlobalConfigRaw(globalConfigPath);
16847
- const label2 = repoName === void 0 ? resolveRepoWriteLabel(globalRaw, getCurrentOrigin(cwd)) : resolveNamedRepoWriteLabel(globalRaw, repoName);
16848
- const repos2 = isPlainObject3(globalRaw.repos) ? { ...globalRaw.repos } : {};
16849
- const block = isPlainObject3(repos2[label2]) ? repos2[label2] : {};
16850
- return { globalRaw, repos: repos2, label: label2, block };
16852
+ // src/commands/config/resolveSharedRepoBlock.ts
16853
+ async function resolveSharedRepoBlock(orm, repoName, cwd) {
16854
+ const shared = { repos: await listRepoConfigs(orm) };
16855
+ const label2 = repoName === void 0 ? currentRepoLabel(shared, getCurrentOrigin(cwd)) : resolveNamedRepoWriteLabel(shared, repoName, SHARED_REPO_CONFIG_SOURCE);
16856
+ return { label: label2, block: shared.repos[label2] ?? {} };
16851
16857
  }
16852
- function isPlainObject3(value) {
16853
- return value !== null && typeof value === "object" && !Array.isArray(value);
16858
+ function currentRepoLabel(shared, origin) {
16859
+ return matchRepoConfigKey(shared, origin, SHARED_REPO_CONFIG_SOURCE) ?? origin;
16854
16860
  }
16855
16861
 
16856
- // src/commands/config/applyRepoConfigSet.ts
16857
- function applyRepoConfigSet(key, coerced, repoName, cwd = process.cwd(), globalConfigPath) {
16862
+ // src/shared/db/saveRepoConfig.ts
16863
+ import { eq as eq45 } from "drizzle-orm";
16864
+ async function saveRepoConfig(orm, repoKey, config) {
16865
+ if (Object.keys(config).length === 0) {
16866
+ await orm.delete(repoConfigs).where(eq45(repoConfigs.repoKey, repoKey));
16867
+ return;
16868
+ }
16869
+ await orm.insert(repoConfigs).values({ repoKey, config }).onConflictDoUpdate({
16870
+ target: repoConfigs.repoKey,
16871
+ set: { config, updatedAt: /* @__PURE__ */ new Date() }
16872
+ });
16873
+ }
16874
+
16875
+ // src/shared/writeRepoConfigCache.ts
16876
+ import { mkdirSync as mkdirSync12, renameSync as renameSync2, writeFileSync as writeFileSync22 } from "fs";
16877
+ import { dirname as dirname24 } from "path";
16878
+ function writeRepoConfigCache(repos2) {
16879
+ const path106 = repoConfigCachePath();
16880
+ mkdirSync12(dirname24(path106), { recursive: true });
16881
+ const cache6 = {
16882
+ refreshedAt: (/* @__PURE__ */ new Date()).toISOString(),
16883
+ repos: repos2
16884
+ };
16885
+ const tmp = `${path106}.${process.pid}.tmp`;
16886
+ writeFileSync22(tmp, JSON.stringify(cache6, null, 2));
16887
+ renameSync2(tmp, path106);
16888
+ }
16889
+
16890
+ // src/shared/refreshRepoConfigCache.ts
16891
+ async function refreshRepoConfigCache(orm) {
16892
+ const repos2 = await listRepoConfigs(orm ?? await getDb());
16893
+ writeRepoConfigCache(repos2);
16894
+ return Object.keys(repos2).length;
16895
+ }
16896
+
16897
+ // src/commands/config/saveSharedRepoBlock.ts
16898
+ async function saveSharedRepoBlock(orm, label2, block) {
16899
+ await saveRepoConfig(orm, label2, block);
16900
+ await refreshRepoConfigCache(orm);
16901
+ }
16902
+
16903
+ // src/commands/config/applySharedRepoConfigSet.ts
16904
+ async function applySharedRepoConfigSet(key, coerced, repoName, cwd = process.cwd()) {
16858
16905
  const globalOnly = globalOnlyRepoKeyError(key, "Set");
16859
16906
  if (globalOnly) return globalOnly;
16860
- const { globalRaw, repos: repos2, label: label2, block } = resolveRepoConfigBlock(
16861
- repoName,
16862
- cwd,
16863
- globalConfigPath
16864
- );
16907
+ const orm = await getDb();
16908
+ const { label: label2, block } = await resolveSharedRepoBlock(orm, repoName, cwd);
16865
16909
  const updatedBlock = setNestedValue(block, key, coerced);
16866
16910
  const validation = validateConfig(updatedBlock, key, repoConfigSchema);
16867
16911
  if (!validation.ok) return validation;
16868
- repos2[label2] = updatedBlock;
16869
- saveGlobalConfig({ ...globalRaw, repos: repos2 }, globalConfigPath);
16912
+ await saveSharedRepoBlock(orm, label2, updatedBlock);
16870
16913
  return { ok: true, target: "repo", label: label2 };
16871
16914
  }
16872
16915
 
16873
16916
  // src/commands/sessions/web/applyScopedConfigSet.ts
16874
- function applyScopedConfigSet(key, value, cwd, scope, globalConfigPath) {
16917
+ async function applyScopedConfigSet(key, value, cwd, scope, globalConfigPath) {
16875
16918
  if (scope === "repo") {
16876
- const result2 = applyRepoConfigSet(
16877
- key,
16878
- value,
16879
- void 0,
16880
- cwd,
16881
- globalConfigPath
16882
- );
16919
+ const result2 = await applySharedRepoConfigSet(key, value, void 0, cwd);
16883
16920
  return result2.ok ? { ok: true, payload: { target: result2.target, repoKey: result2.label } } : result2;
16884
16921
  }
16885
16922
  const result = applyConfigSet(
@@ -16923,7 +16960,7 @@ async function handleConfigWrite(req, res, apply) {
16923
16960
  return;
16924
16961
  }
16925
16962
  try {
16926
- const result = apply(parsed);
16963
+ const result = await apply(parsed);
16927
16964
  if (!result.ok) {
16928
16965
  respondJson(res, 400, {
16929
16966
  error: result.errors.join("\n"),
@@ -16967,11 +17004,11 @@ function isKnownConfigKey(key) {
16967
17004
  }
16968
17005
 
16969
17006
  // src/commands/config/unsetNestedValue.ts
16970
- function isPlainObject4(val) {
17007
+ function isPlainObject3(val) {
16971
17008
  return val !== null && typeof val === "object" && !Array.isArray(val);
16972
17009
  }
16973
17010
  function isContainer(val) {
16974
- return Array.isArray(val) || isPlainObject4(val);
17011
+ return Array.isArray(val) || isPlainObject3(val);
16975
17012
  }
16976
17013
  function isNumericKey2(key) {
16977
17014
  return /^\d+$/.test(key);
@@ -17007,7 +17044,7 @@ function withChild(container, key, child) {
17007
17044
  return { ...container, [key]: child };
17008
17045
  }
17009
17046
  function isPrunable(container) {
17010
- return isPlainObject4(container) && Object.keys(container).length === 0;
17047
+ return isPlainObject3(container) && Object.keys(container).length === 0;
17011
17048
  }
17012
17049
  function replaceOrPrune(container, key, child) {
17013
17050
  return isPrunable(child) ? withoutKey(container, key) : withChild(container, key, child);
@@ -17065,33 +17102,22 @@ function unsetRepoBlockKey(block, key) {
17065
17102
  return { ok: true, removed: true, block: updatedBlock };
17066
17103
  }
17067
17104
 
17068
- // src/commands/config/applyRepoConfigUnset.ts
17069
- function applyRepoConfigUnset(key, repoName, cwd = process.cwd(), globalConfigPath) {
17105
+ // src/commands/config/applySharedRepoConfigUnset.ts
17106
+ async function applySharedRepoConfigUnset(key, repoName, cwd = process.cwd()) {
17070
17107
  const globalOnly = globalOnlyRepoKeyError(key, "Unset");
17071
17108
  if (globalOnly) return globalOnly;
17072
- const { globalRaw, repos: repos2, label: label2, block } = resolveRepoConfigBlock(
17073
- repoName,
17074
- cwd,
17075
- globalConfigPath
17076
- );
17109
+ const orm = await getDb();
17110
+ const { label: label2, block } = await resolveSharedRepoBlock(orm, repoName, cwd);
17077
17111
  const unset = unsetRepoBlockKey(block, key);
17078
17112
  if (!unset.ok) return unset;
17079
- if (!unset.removed)
17080
- return { ok: true, target: "repo", label: label2, removed: false };
17081
- const updatedBlock = unset.block;
17082
- if (Object.keys(updatedBlock).length === 0) delete repos2[label2];
17083
- else repos2[label2] = updatedBlock;
17084
- const next3 = { ...globalRaw };
17085
- if (Object.keys(repos2).length === 0) delete next3.repos;
17086
- else next3.repos = repos2;
17087
- saveGlobalConfig(next3, globalConfigPath);
17088
- return { ok: true, target: "repo", label: label2, removed: true };
17113
+ if (unset.removed) await saveSharedRepoBlock(orm, label2, unset.block);
17114
+ return { ok: true, target: "repo", label: label2, removed: unset.removed };
17089
17115
  }
17090
17116
 
17091
17117
  // src/commands/sessions/web/applyScopedConfigUnset.ts
17092
- function applyScopedConfigUnset(key, cwd, scope, globalConfigPath) {
17118
+ async function applyScopedConfigUnset(key, cwd, scope, globalConfigPath) {
17093
17119
  if (scope === "repo") {
17094
- const result2 = applyRepoConfigUnset(key, void 0, cwd, globalConfigPath);
17120
+ const result2 = await applySharedRepoConfigUnset(key, void 0, cwd);
17095
17121
  return result2.ok ? {
17096
17122
  ok: true,
17097
17123
  payload: {
@@ -17435,7 +17461,7 @@ import { readFile as readFile3, stat as stat4, writeFile as writeFile3 } from "f
17435
17461
  // src/commands/sessions/web/formatWithOxfmt.ts
17436
17462
  import { execFile as execFile9 } from "child_process";
17437
17463
  import { existsSync as existsSync40 } from "fs";
17438
- import { dirname as dirname24, join as join45 } from "path";
17464
+ import { dirname as dirname25, join as join45 } from "path";
17439
17465
  import { promisify as promisify10 } from "util";
17440
17466
  var execFileAsync9 = promisify10(execFile9);
17441
17467
  var TIMEOUT_MS = 15e3;
@@ -17444,7 +17470,7 @@ function findOxfmtScript(root2) {
17444
17470
  for (; ; ) {
17445
17471
  const candidate = join45(dir, "node_modules", "oxfmt", "bin", "oxfmt");
17446
17472
  if (existsSync40(candidate)) return candidate;
17447
- const parent = dirname24(dir);
17473
+ const parent = dirname25(dir);
17448
17474
  if (parent === dir) return void 0;
17449
17475
  dir = parent;
17450
17476
  }
@@ -19088,11 +19114,11 @@ function extractGraphqlQuery(args) {
19088
19114
  }
19089
19115
 
19090
19116
  // src/shared/loadCliReads.ts
19091
- import { existsSync as existsSync42, readFileSync as readFileSync27, writeFileSync as writeFileSync22 } from "fs";
19092
- import { dirname as dirname25, resolve as resolve15 } from "path";
19117
+ import { existsSync as existsSync42, readFileSync as readFileSync27, writeFileSync as writeFileSync23 } from "fs";
19118
+ import { dirname as dirname26, resolve as resolve15 } from "path";
19093
19119
  import { fileURLToPath as fileURLToPath5 } from "url";
19094
19120
  var __filename3 = fileURLToPath5(import.meta.url);
19095
- var __dirname4 = dirname25(__filename3);
19121
+ var __dirname4 = dirname26(__filename3);
19096
19122
  function packageRoot() {
19097
19123
  return __dirname4;
19098
19124
  }
@@ -19118,7 +19144,7 @@ function loadCliReads() {
19118
19144
  return getCliReadsLines();
19119
19145
  }
19120
19146
  function saveCliReads(commands) {
19121
- writeFileSync22(
19147
+ writeFileSync23(
19122
19148
  resolve15(packageRoot(), "allowed.cli-reads"),
19123
19149
  `${commands.join("\n")}
19124
19150
  `
@@ -19373,7 +19399,7 @@ function decideCommand(toolName, rawCommand) {
19373
19399
  }
19374
19400
 
19375
19401
  // src/commands/cliHook/logDeniedToolCall.ts
19376
- import { mkdirSync as mkdirSync12 } from "fs";
19402
+ import { mkdirSync as mkdirSync13 } from "fs";
19377
19403
  import { homedir as homedir18 } from "os";
19378
19404
  import { join as join47 } from "path";
19379
19405
  import Database from "better-sqlite3";
@@ -19397,7 +19423,7 @@ function initSchema(db) {
19397
19423
  function openPromptsDb(dir) {
19398
19424
  if (_db) return _db;
19399
19425
  const dbDir = dir ?? getDbDir();
19400
- mkdirSync12(dbDir, { recursive: true });
19426
+ mkdirSync13(dbDir, { recursive: true });
19401
19427
  const db = new Database(join47(dbDir, "assist.db"));
19402
19428
  db.pragma("journal_mode = WAL");
19403
19429
  initSchema(db);
@@ -19517,7 +19543,7 @@ ${reasons.join("\n")}`);
19517
19543
  }
19518
19544
 
19519
19545
  // src/commands/permitCliReads.ts
19520
- import { existsSync as existsSync44, mkdirSync as mkdirSync13, readFileSync as readFileSync29, writeFileSync as writeFileSync23 } from "fs";
19546
+ import { existsSync as existsSync44, mkdirSync as mkdirSync14, readFileSync as readFileSync29, writeFileSync as writeFileSync24 } from "fs";
19521
19547
  import { homedir as homedir19 } from "os";
19522
19548
  import { join as join48 } from "path";
19523
19549
 
@@ -19791,8 +19817,8 @@ function readCache(cli) {
19791
19817
  }
19792
19818
  function writeCache(cli, output) {
19793
19819
  const dir = join48(homedir19(), ".assist");
19794
- mkdirSync13(dir, { recursive: true });
19795
- writeFileSync23(logPath(cli), output);
19820
+ mkdirSync14(dir, { recursive: true });
19821
+ writeFileSync24(logPath(cli), output);
19796
19822
  }
19797
19823
  async function permitCliReads(cli, options2 = { noCache: false }) {
19798
19824
  if (!cli) {
@@ -19921,7 +19947,7 @@ function registerCliHook(program2) {
19921
19947
  }
19922
19948
 
19923
19949
  // src/commands/codeComment/codeCommentConfirm.ts
19924
- import { existsSync as existsSync46, readFileSync as readFileSync31, unlinkSync as unlinkSync8, writeFileSync as writeFileSync24 } from "fs";
19950
+ import { existsSync as existsSync46, readFileSync as readFileSync31, unlinkSync as unlinkSync8, writeFileSync as writeFileSync25 } from "fs";
19925
19951
  import chalk120 from "chalk";
19926
19952
 
19927
19953
  // src/shared/isHashCommentFile.ts
@@ -20029,7 +20055,7 @@ function codeCommentConfirm(pin2) {
20029
20055
  const indentSource = lines2[index2] ?? "";
20030
20056
  const indent3 = indentSource.match(/^\s*/)?.[0] ?? "";
20031
20057
  lines2.splice(index2, 0, `${indent3}${marker2} ${state.text}`);
20032
- writeFileSync24(state.file, lines2.join("\n"));
20058
+ writeFileSync25(state.file, lines2.join("\n"));
20033
20059
  unlinkSync8(getPinStatePath(pin2));
20034
20060
  console.log(
20035
20061
  chalk120.green(
@@ -20067,7 +20093,7 @@ function validateCommentText(raw, isHash = false) {
20067
20093
  }
20068
20094
 
20069
20095
  // src/commands/codeComment/issuePin.ts
20070
- import { mkdirSync as mkdirSync14, writeFileSync as writeFileSync25 } from "fs";
20096
+ import { mkdirSync as mkdirSync15, writeFileSync as writeFileSync26 } from "fs";
20071
20097
  import { randomInt } from "crypto";
20072
20098
 
20073
20099
  // src/commands/notify/showNotification.ts
@@ -20128,9 +20154,9 @@ function showNotification(options2) {
20128
20154
  // src/commands/codeComment/issuePin.ts
20129
20155
  function issuePin(file, lineNumber, text18) {
20130
20156
  const pin2 = generatePin();
20131
- mkdirSync14(getRestrictedDir(), { recursive: true });
20157
+ mkdirSync15(getRestrictedDir(), { recursive: true });
20132
20158
  sweepRestrictedDir();
20133
- writeFileSync25(
20159
+ writeFileSync26(
20134
20160
  getPinStatePath(pin2),
20135
20161
  JSON.stringify({ pin: pin2, file, line: lineNumber, text: text18 })
20136
20162
  );
@@ -21444,47 +21470,6 @@ function unsetLines(key) {
21444
21470
  // src/commands/config/configImportRepos.ts
21445
21471
  import chalk136 from "chalk";
21446
21472
 
21447
- // src/shared/db/listRepoConfigs.ts
21448
- async function listRepoConfigs(orm) {
21449
- const rows = await orm.select().from(repoConfigs);
21450
- return Object.fromEntries(rows.map((row) => [row.repoKey, row.config]));
21451
- }
21452
-
21453
- // src/shared/db/saveRepoConfig.ts
21454
- import { eq as eq45 } from "drizzle-orm";
21455
- async function saveRepoConfig(orm, repoKey, config) {
21456
- if (Object.keys(config).length === 0) {
21457
- await orm.delete(repoConfigs).where(eq45(repoConfigs.repoKey, repoKey));
21458
- return;
21459
- }
21460
- await orm.insert(repoConfigs).values({ repoKey, config }).onConflictDoUpdate({
21461
- target: repoConfigs.repoKey,
21462
- set: { config, updatedAt: /* @__PURE__ */ new Date() }
21463
- });
21464
- }
21465
-
21466
- // src/shared/writeRepoConfigCache.ts
21467
- import { mkdirSync as mkdirSync15, renameSync as renameSync2, writeFileSync as writeFileSync26 } from "fs";
21468
- import { dirname as dirname26 } from "path";
21469
- function writeRepoConfigCache(repos2) {
21470
- const path106 = repoConfigCachePath();
21471
- mkdirSync15(dirname26(path106), { recursive: true });
21472
- const cache6 = {
21473
- refreshedAt: (/* @__PURE__ */ new Date()).toISOString(),
21474
- repos: repos2
21475
- };
21476
- const tmp = `${path106}.${process.pid}.tmp`;
21477
- writeFileSync26(tmp, JSON.stringify(cache6, null, 2));
21478
- renameSync2(tmp, path106);
21479
- }
21480
-
21481
- // src/shared/refreshRepoConfigCache.ts
21482
- async function refreshRepoConfigCache(orm) {
21483
- const repos2 = await listRepoConfigs(orm ?? await getDb());
21484
- writeRepoConfigCache(repos2);
21485
- return Object.keys(repos2).length;
21486
- }
21487
-
21488
21473
  // src/commands/config/exitWithConfigErrors.ts
21489
21474
  import chalk134 from "chalk";
21490
21475
  function exitWithConfigErrors(errors) {
@@ -21505,10 +21490,10 @@ function diffRepoConfigLeaves(current, incoming) {
21505
21490
  function leaves(node, prefix2 = "") {
21506
21491
  return Object.entries(node).flatMap(([key, value]) => {
21507
21492
  const path106 = prefix2 ? `${prefix2}.${key}` : key;
21508
- return isPlainObject5(value) && Object.keys(value).length > 0 ? leaves(value, path106) : [[path106, value]];
21493
+ return isPlainObject4(value) && Object.keys(value).length > 0 ? leaves(value, path106) : [[path106, value]];
21509
21494
  });
21510
21495
  }
21511
- function isPlainObject5(value) {
21496
+ function isPlainObject4(value) {
21512
21497
  return value !== null && typeof value === "object" && !Array.isArray(value);
21513
21498
  }
21514
21499
 
@@ -21517,7 +21502,7 @@ function planRepoConfigImport(ymlRepos, dbRepos) {
21517
21502
  return Object.entries(ymlRepos).map(([ymlKey, block]) => {
21518
21503
  const dbKey = matchDbKey(dbRepos, ymlKey) ?? ymlKey;
21519
21504
  const current = dbRepos[dbKey] ?? {};
21520
- const incoming = isPlainObject6(block) ? block : {};
21505
+ const incoming = isPlainObject5(block) ? block : {};
21521
21506
  const changes = diffRepoConfigLeaves(current, incoming);
21522
21507
  const merged = changes.reduce(
21523
21508
  (acc, change) => setNestedValue(acc, change.key, change.to),
@@ -21539,7 +21524,7 @@ function matchDbKey(dbRepos, ymlKey) {
21539
21524
  );
21540
21525
  return matches[0];
21541
21526
  }
21542
- function isPlainObject6(value) {
21527
+ function isPlainObject5(value) {
21543
21528
  return value !== null && typeof value === "object" && !Array.isArray(value);
21544
21529
  }
21545
21530
 
@@ -21568,7 +21553,7 @@ function show2(key, value) {
21568
21553
  // src/commands/config/configImportRepos.ts
21569
21554
  async function configImportRepos() {
21570
21555
  const { repos: ymlRepos, ...rest } = loadGlobalConfigRaw();
21571
- if (!isPlainObject7(ymlRepos) || Object.keys(ymlRepos).length === 0) {
21556
+ if (!isPlainObject6(ymlRepos) || Object.keys(ymlRepos).length === 0) {
21572
21557
  console.log("No repos: in ~/.assist.yml to import.");
21573
21558
  return;
21574
21559
  }
@@ -21597,7 +21582,7 @@ async function configImportRepos() {
21597
21582
  )
21598
21583
  );
21599
21584
  }
21600
- function isPlainObject7(value) {
21585
+ function isPlainObject6(value) {
21601
21586
  return value !== null && typeof value === "object" && !Array.isArray(value);
21602
21587
  }
21603
21588
 
@@ -21647,35 +21632,6 @@ function typeText(leaf) {
21647
21632
  // src/commands/config/configSet.ts
21648
21633
  import chalk138 from "chalk";
21649
21634
 
21650
- // src/commands/config/resolveSharedRepoBlock.ts
21651
- async function resolveSharedRepoBlock(orm, repoName, cwd) {
21652
- const shared = { repos: await listRepoConfigs(orm) };
21653
- const label2 = repoName === void 0 ? currentRepoLabel(shared, getCurrentOrigin(cwd)) : resolveNamedRepoWriteLabel(shared, repoName, SHARED_REPO_CONFIG_SOURCE);
21654
- return { label: label2, block: shared.repos[label2] ?? {} };
21655
- }
21656
- function currentRepoLabel(shared, origin) {
21657
- return matchRepoConfigKey(shared, origin, SHARED_REPO_CONFIG_SOURCE) ?? origin;
21658
- }
21659
-
21660
- // src/commands/config/saveSharedRepoBlock.ts
21661
- async function saveSharedRepoBlock(orm, label2, block) {
21662
- await saveRepoConfig(orm, label2, block);
21663
- await refreshRepoConfigCache(orm);
21664
- }
21665
-
21666
- // src/commands/config/applySharedRepoConfigSet.ts
21667
- async function applySharedRepoConfigSet(key, coerced, repoName, cwd = process.cwd()) {
21668
- const globalOnly = globalOnlyRepoKeyError(key, "Set");
21669
- if (globalOnly) return globalOnly;
21670
- const orm = await getDb();
21671
- const { label: label2, block } = await resolveSharedRepoBlock(orm, repoName, cwd);
21672
- const updatedBlock = setNestedValue(block, key, coerced);
21673
- const validation = validateConfig(updatedBlock, key, repoConfigSchema);
21674
- if (!validation.ok) return validation;
21675
- await saveSharedRepoBlock(orm, label2, updatedBlock);
21676
- return { ok: true, target: "repo", label: label2 };
21677
- }
21678
-
21679
21635
  // src/commands/config/coerceCliConfigValue.ts
21680
21636
  function coerceCliConfigValue(key, raw) {
21681
21637
  const leaf = describeConfigLeaves(assistConfigSchema).find(
@@ -21739,18 +21695,6 @@ async function applyRepoOrExit(key, coerced, repoName) {
21739
21695
  // src/commands/config/configUnset.ts
21740
21696
  import chalk139 from "chalk";
21741
21697
 
21742
- // src/commands/config/applySharedRepoConfigUnset.ts
21743
- async function applySharedRepoConfigUnset(key, repoName, cwd = process.cwd()) {
21744
- const globalOnly = globalOnlyRepoKeyError(key, "Unset");
21745
- if (globalOnly) return globalOnly;
21746
- const orm = await getDb();
21747
- const { label: label2, block } = await resolveSharedRepoBlock(orm, repoName, cwd);
21748
- const unset = unsetRepoBlockKey(block, key);
21749
- if (!unset.ok) return unset;
21750
- if (unset.removed) await saveSharedRepoBlock(orm, label2, unset.block);
21751
- return { ok: true, target: "repo", label: label2, removed: unset.removed };
21752
- }
21753
-
21754
21698
  // src/commands/config/resolveRepoUnsetTarget.ts
21755
21699
  function resolveRepoUnsetTarget(key, repo) {
21756
21700
  if (typeof repo === "string") {
@@ -27430,6 +27374,35 @@ function normaliseItems(items2) {
27430
27374
  return items2.map(toItem);
27431
27375
  }
27432
27376
 
27377
+ // src/commands/config/resolveRepoConfigBlock.ts
27378
+ function resolveRepoConfigBlock(repoName, cwd, globalConfigPath) {
27379
+ const globalRaw = loadGlobalConfigRaw(globalConfigPath);
27380
+ const label2 = repoName === void 0 ? resolveRepoWriteLabel(globalRaw, getCurrentOrigin(cwd)) : resolveNamedRepoWriteLabel(globalRaw, repoName);
27381
+ const repos2 = isPlainObject7(globalRaw.repos) ? { ...globalRaw.repos } : {};
27382
+ const block = isPlainObject7(repos2[label2]) ? repos2[label2] : {};
27383
+ return { globalRaw, repos: repos2, label: label2, block };
27384
+ }
27385
+ function isPlainObject7(value) {
27386
+ return value !== null && typeof value === "object" && !Array.isArray(value);
27387
+ }
27388
+
27389
+ // src/commands/config/applyRepoConfigSet.ts
27390
+ function applyRepoConfigSet(key, coerced, repoName, cwd = process.cwd(), globalConfigPath) {
27391
+ const globalOnly = globalOnlyRepoKeyError(key, "Set");
27392
+ if (globalOnly) return globalOnly;
27393
+ const { globalRaw, repos: repos2, label: label2, block } = resolveRepoConfigBlock(
27394
+ repoName,
27395
+ cwd,
27396
+ globalConfigPath
27397
+ );
27398
+ const updatedBlock = setNestedValue(block, key, coerced);
27399
+ const validation = validateConfig(updatedBlock, key, repoConfigSchema);
27400
+ if (!validation.ok) return validation;
27401
+ repos2[label2] = updatedBlock;
27402
+ saveGlobalConfig({ ...globalRaw, repos: repos2 }, globalConfigPath);
27403
+ return { ok: true, target: "repo", label: label2 };
27404
+ }
27405
+
27433
27406
  // src/commands/miro/saveMiroExtract.ts
27434
27407
  function saveToRepo(key, extract2, repo, { cwd, globalConfigPath }) {
27435
27408
  const result = applyRepoConfigSet(
@@ -41786,6 +41759,36 @@ function createAutoExit(exit, graceMs = DEFAULT_GRACE_MS) {
41786
41759
  };
41787
41760
  }
41788
41761
 
41762
+ // src/commands/sessions/daemon/pollRepoConfigCache.ts
41763
+ var POLL_MS = 6e4;
41764
+ function pollRepoConfigCache(intervalMs = POLL_MS) {
41765
+ let inFlight2 = false;
41766
+ let failing = false;
41767
+ const tick = async () => {
41768
+ if (inFlight2) return;
41769
+ inFlight2 = true;
41770
+ try {
41771
+ const before = JSON.stringify(readRepoConfigCache());
41772
+ const count8 = await refreshRepoConfigCache();
41773
+ if (failing) daemonLog("repo config cache poll recovered");
41774
+ failing = false;
41775
+ if (JSON.stringify(readRepoConfigCache()) !== before)
41776
+ daemonLog(`repo config cache updated (${count8} repos)`);
41777
+ } catch (error) {
41778
+ if (!failing)
41779
+ daemonLog(
41780
+ `repo config cache poll failed; keeping the last snapshot: ${String(error)}`
41781
+ );
41782
+ failing = true;
41783
+ } finally {
41784
+ inFlight2 = false;
41785
+ }
41786
+ };
41787
+ const timer = setInterval(() => void tick(), intervalMs);
41788
+ timer.unref();
41789
+ return () => clearInterval(timer);
41790
+ }
41791
+
41789
41792
  // src/commands/sessions/daemon/refreshRepoConfigCacheOnStart.ts
41790
41793
  async function refreshRepoConfigCacheOnStart() {
41791
41794
  try {
@@ -43251,11 +43254,11 @@ function processCwd(link3) {
43251
43254
  }
43252
43255
 
43253
43256
  // src/commands/sessions/daemon/worktree/awaitTreeVacated.ts
43254
- var POLL_MS = 500;
43257
+ var POLL_MS2 = 500;
43255
43258
  var GRACE_MS = 5e3;
43256
43259
  function awaitTreeVacated(session, treePath) {
43257
43260
  return new Promise((resolve28) => {
43258
- let ticks = GRACE_MS / POLL_MS;
43261
+ let ticks = GRACE_MS / POLL_MS2;
43259
43262
  const settle = (outcome) => {
43260
43263
  clearTimeout(timer);
43261
43264
  session.closeGrace = void 0;
@@ -43264,9 +43267,9 @@ function awaitTreeVacated(session, treePath) {
43264
43267
  const tick = () => {
43265
43268
  if (liveProcessesInTree(treePath).length === 0) settle("vacated");
43266
43269
  else if (--ticks <= 0) settle("occupied");
43267
- else timer = setTimeout(tick, POLL_MS);
43270
+ else timer = setTimeout(tick, POLL_MS2);
43268
43271
  };
43269
- let timer = setTimeout(tick, POLL_MS);
43272
+ let timer = setTimeout(tick, POLL_MS2);
43270
43273
  session.closeGrace?.cancel();
43271
43274
  session.closeGrace = { cancel: () => settle("cancelled") };
43272
43275
  });
@@ -43297,7 +43300,7 @@ async function closeBlockReason(sessionId, tree) {
43297
43300
  // src/commands/sessions/daemon/worktree/watchGitState.ts
43298
43301
  import { existsSync as existsSync90, watch } from "fs";
43299
43302
  var DEBOUNCE_MS = 500;
43300
- var POLL_MS2 = 3e4;
43303
+ var POLL_MS3 = 3e4;
43301
43304
  function watchGitState(cwd, onChange) {
43302
43305
  const common = gitCommonDir(cwd);
43303
43306
  if (!common || !existsSync90(common)) return void 0;
@@ -43328,9 +43331,9 @@ function watchGitDir(common, onChange) {
43328
43331
  }
43329
43332
  }
43330
43333
  function pollGitState(cwd, onChange) {
43331
- const timer = setInterval(onChange, POLL_MS2);
43334
+ const timer = setInterval(onChange, POLL_MS3);
43332
43335
  timer.unref?.();
43333
- daemonLog(`git-state polled every ${POLL_MS2 / 1e3}s for ${cwd}`);
43336
+ daemonLog(`git-state polled every ${POLL_MS3 / 1e3}s for ${cwd}`);
43334
43337
  return { close: () => clearInterval(timer) };
43335
43338
  }
43336
43339
 
@@ -44114,7 +44117,7 @@ async function touchedSince(file, sinceMs) {
44114
44117
  }
44115
44118
 
44116
44119
  // src/commands/sessions/daemon/bindCodexSession.ts
44117
- var POLL_MS3 = 1e3;
44120
+ var POLL_MS4 = 1e3;
44118
44121
  var MAX_ATTEMPTS = 120;
44119
44122
  var START_SLACK_MS = 5e3;
44120
44123
  function bindCodexSession(session, notify2) {
@@ -44122,7 +44125,7 @@ function bindCodexSession(session, notify2) {
44122
44125
  if (session.harness !== "codex" || !cwd || session.harnessSessionId) return;
44123
44126
  const since = session.startedAt - START_SLACK_MS;
44124
44127
  let attemptsLeft = MAX_ATTEMPTS;
44125
- const schedule = () => setTimeout(() => void poll(), POLL_MS3).unref();
44128
+ const schedule = () => setTimeout(() => void poll(), POLL_MS4).unref();
44126
44129
  const poll = async () => {
44127
44130
  if (session.harnessSessionId) return;
44128
44131
  const sessionId = await resolveCodexSessionId(cwd, since);
@@ -48345,6 +48348,7 @@ async function runDaemon() {
48345
48348
  const manager = new SessionManager(checkAutoExit);
48346
48349
  setDaemonLogSink(manager.clients.emitLog);
48347
48350
  void refreshRepoConfigCacheOnStart();
48351
+ pollRepoConfigCache();
48348
48352
  await startDaemonServer(manager, checkAutoExit);
48349
48353
  }
48350
48354
 
@@ -48621,7 +48625,7 @@ function registerLinkCommand(nodes) {
48621
48625
  }
48622
48626
 
48623
48627
  // src/commands/sessions/nodes/awaitLinkReturn.ts
48624
- var POLL_MS4 = 1e3;
48628
+ var POLL_MS5 = 1e3;
48625
48629
  var wait = (ms) => new Promise((r) => setTimeout(r, ms));
48626
48630
  async function linkStatus(name, query = queryNodes) {
48627
48631
  return (await query())?.links.find((l) => l.name === name);
@@ -48634,7 +48638,7 @@ async function awaitLinkReturn(name, options2, deps2 = {}) {
48634
48638
  const link3 = await linkStatus(name, query);
48635
48639
  if (link3?.state !== "connected") sawDown = true;
48636
48640
  else if (sawDown) return link3;
48637
- await sleep2(POLL_MS4);
48641
+ await sleep2(POLL_MS5);
48638
48642
  }
48639
48643
  return void 0;
48640
48644
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@staff0rd/assist",
3
- "version": "0.779.0",
3
+ "version": "0.780.1",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "bin": {