knodin 0.8.6 → 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/README.md +6 -0
- package/dist/bin/cli.js +459 -95
- package/dist/bin/launcher.js +0 -0
- package/dist/fixtures/update-verification/config/application.xml +4 -0
- package/dist/fixtures/update-verification/dbt/manifest.json +17 -0
- package/dist/fixtures/update-verification/dbt/models/accounts.sql +1 -0
- package/dist/fixtures/update-verification/dbt/models/contacts.sql +1 -0
- package/dist/fixtures/update-verification/fixture.json +147 -0
- package/dist/fixtures/update-verification/force-app/main/default/classes/UpdateFixture.cls +14 -0
- package/dist/fixtures/update-verification/force-app/main/default/flows/Update_Verification.flow-meta.xml +9 -0
- package/dist/fixtures/update-verification/package.json +5 -0
- package/dist/fixtures/update-verification/prisma/schema.prisma +10 -0
- package/dist/fixtures/update-verification/sql/functions.sql +16 -0
- package/dist/fixtures/update-verification/src/CsharpFixture.cs +6 -0
- package/dist/fixtures/update-verification/src/JavaFixture.java +9 -0
- package/dist/fixtures/update-verification/src/javascript.js +7 -0
- package/dist/fixtures/update-verification/src/python_fixture.py +6 -0
- package/dist/fixtures/update-verification/src/typescript.ts +7 -0
- package/dist/fixtures/update-verification/terraform/main.tf +7 -0
- package/dist/fixtures/update-verification/terraform/modules/verified-child/main.tf +3 -0
- package/dist/src/agent-integration.js +26 -3
- package/dist/src/backup-retention.js +811 -0
- package/dist/src/cli-model.js +66 -9
- package/dist/src/docs-sections.js +1 -0
- package/dist/src/doctor.js +142 -12
- package/dist/src/engine/embeddings.js +8 -1
- package/dist/src/engine/index.js +355 -292
- package/dist/src/init.js +223 -164
- package/dist/src/manager-update.js +455 -0
- package/dist/src/release-preflight.js +106 -95
- package/dist/src/repair-lease.js +77 -8
- package/dist/src/repository-management.js +219 -3
- package/dist/src/response-budget.js +5 -1
- package/dist/src/server.js +18 -5
- package/dist/src/shared-index/compatibility.js +4 -2
- package/dist/src/skill-management.js +149 -0
- package/dist/src/system-config.js +176 -16
- package/dist/src/system-management.js +508 -0
- package/dist/src/tools/knodin-tools.js +174 -22
- package/dist/src/update-ceremony.js +20 -24
- package/dist/src/update-coordination.js +158 -0
- package/dist/src/update-executor.js +336 -0
- package/dist/src/update-verifier.js +358 -0
- package/docs/BACKUP-RETENTION.md +54 -0
- package/docs/CLI.md +13 -0
- package/docs/DOCTOR-AND-UPDATES.md +44 -12
- package/docs/SIGNED-UPDATES.md +29 -22
- package/docs/SYSTEMS-AND-RELATIONSHIPS.md +27 -6
- package/docs/prompts/declare-multi-repository-system.md +18 -0
- package/docs/releases/0.8.7.md +27 -0
- package/docs/releases/0.9.0.md +43 -0
- package/package.json +11 -2
- package/roadmap/competitive-roadmap.md +8 -0
- package/skills/knodin-debug/SKILL.md +12 -0
- package/skills/knodin-debug/agents/openai.yaml +4 -0
- package/skills/knodin-explore/SKILL.md +11 -0
- package/skills/knodin-explore/agents/openai.yaml +4 -0
- package/skills/knodin-impact/SKILL.md +11 -0
- package/skills/knodin-impact/agents/openai.yaml +4 -0
- package/skills/knodin-lifecycle/SKILL.md +12 -0
- package/skills/knodin-lifecycle/agents/openai.yaml +4 -0
- package/skills/knodin-refactor/SKILL.md +12 -0
- package/skills/knodin-refactor/agents/openai.yaml +4 -0
- package/skills/knodin-review/SKILL.md +11 -0
- package/skills/knodin-review/agents/openai.yaml +4 -0
- package/skills/knodin-systems/SKILL.md +14 -0
- package/skills/knodin-systems/agents/openai.yaml +4 -0
package/dist/bin/cli.js
CHANGED
|
@@ -14,12 +14,12 @@
|
|
|
14
14
|
import { spawn, spawnSync } from "node:child_process";
|
|
15
15
|
import fs from "node:fs";
|
|
16
16
|
import path from "node:path";
|
|
17
|
-
import readline from "node:readline/promises";
|
|
18
17
|
import { fileURLToPath } from "node:url";
|
|
19
18
|
import { canUseSessionContextCache, parseClaudeHookPayload, readSessionContextCache, recordClaudeLifecycleEvent, renderSessionContext, SESSION_CONTEXT_BUDGET_LINE, sessionStartHookOutput, writeSessionContextCache, } from "../src/agent-events.js";
|
|
20
19
|
import { inspectClaudeAgentHooks, installClaudeAgentHooks, uninstallClaudeAgentHooks, } from "../src/agent-hooks.js";
|
|
21
20
|
import { detectSupportedAgents, parseInitScope, } from "../src/agent-integration.js";
|
|
22
21
|
import { refreshExternalGraphArtifacts, writeArtifactRefreshRecord, } from "../src/artifact-refresh.js";
|
|
22
|
+
import { formatBackupHuman, installBackupRetention, listBackups, maybeRunOpportunisticRetention, pruneBackups, removeBackupRetention, retentionDoctor, retentionStatus, runInstalledRetention, } from "../src/backup-retention.js";
|
|
23
23
|
import { checkIndexed, extractPositionals, extractRepoFlag, parseReviewArgs, planIndex, resolveCliRuntimeCommand, resolveRepo, } from "../src/cli-args.js";
|
|
24
24
|
import { helpCommandPath, parseCliInvocation, renderCliHelp } from "../src/cli-model.js";
|
|
25
25
|
import { buildKnodinContext } from "../src/context.js";
|
|
@@ -33,20 +33,26 @@ import { diagnoseFailure, } from "../src/failure-diagnosis.js";
|
|
|
33
33
|
import { gitExecutable } from "../src/git-executable.js";
|
|
34
34
|
import { decorateGraphQueryResult, inspectGraphQueryHealth } from "../src/graph-query-health.js";
|
|
35
35
|
import { createIndexActivityReporter } from "../src/index-activity.js";
|
|
36
|
-
import {
|
|
36
|
+
import { InitializationHealthError, initializeRepository, inspectRepositoryIntegrationStatus, readRepositoryIntegrationConfig, refreshFromGitEvent, } from "../src/init.js";
|
|
37
37
|
import { createInitProgressRenderer } from "../src/init-progress.js";
|
|
38
38
|
import { attachLifecycleHealth, attachRepairLifecycle } from "../src/lifecycle-health.js";
|
|
39
|
+
import { acknowledgeUpdateFailure, queryOwnerAvailability, readManagerUpdateState, readUpdateJournal, resolveManagerOwnership, setManualPin, unpinUpdate, updateAttention, writeManagerUpdateState, } from "../src/manager-update.js";
|
|
39
40
|
import { addMirror, listMirrors, refreshMirror, removeMirror } from "../src/mirror.js";
|
|
40
41
|
import { compressOutput, compressOutputFile, deleteOutputArtifact, readOutputArtifact, } from "../src/output-compression.js";
|
|
41
42
|
import { clearTelemetry, exportTelemetry, readTelemetryRecords, telemetryStatus, writeTelemetryReport, } from "../src/output-telemetry.js";
|
|
42
43
|
import { auditPullRequests } from "../src/pr-triage.js";
|
|
43
44
|
import { deliverProgressiveEvidence, } from "../src/progressive-evidence.js";
|
|
45
|
+
import { acquireRepairLease } from "../src/repair-lease.js";
|
|
44
46
|
import { createRepairPlan, createRepairProgressRenderer, parseRepairCliArgs, resolveRepairProgressMode, serializeRepairJsonlRecord, } from "../src/repair-progress.js";
|
|
45
47
|
import { runRepositoryInitializationProcess } from "../src/repository-init-process.js";
|
|
46
48
|
import { detectRepositorySignals, discoverRepositories, formatRepositoryHuman, initializeRepositories, inventoryRepository, parseFleetInitArgs, parseRepositoryCommandArgs, repositorySignalInspectionLimit, searchRepositories, withRepositorySignals, } from "../src/repository-management.js";
|
|
47
49
|
import { applyResponseBudget } from "../src/response-budget.js";
|
|
48
50
|
import { appendSessionEvent, clearSessionTelemetry, disableSessionTelemetry, enableSessionTelemetry, readSessionEvents, sessionTelemetryStatus, } from "../src/session-telemetry.js";
|
|
51
|
+
import { inspectKnodinSkills, installKnodinSkills, KNODIN_SKILLS, removeKnodinSkills, } from "../src/skill-management.js";
|
|
49
52
|
import { configuredRepositoryInitMemoryLimitBytes, enrichSystemRelationships, incorporateSystemQueryEvidence, indexModeForPath, loadSystemConfiguration, queryConfiguredSystem, systemMembershipsForPath, validateSystemHealth, } from "../src/system-config.js";
|
|
53
|
+
import { applySystemPlan, planSystemImport, planSystemLink, planSystemRelate, planSystemUnlink, planSystemUnrelate, } from "../src/system-management.js";
|
|
54
|
+
import { coordinationStatus } from "../src/update-coordination.js";
|
|
55
|
+
import { certifyAutomaticUpdates, executeManagerUpdate, recoverInterruptedUpdate, } from "../src/update-executor.js";
|
|
50
56
|
import { applyTrustedUpdate, checkTrustedUpdate, claimScheduledUpdateCheck, detectUpdateInstallMethod, explainTrustedUpdate, releaseScheduledUpdateCheck, rollbackTrustedUpdate, trustedUpdateStatus, } from "../src/update-policy.js";
|
|
51
57
|
import { KNODIN_VERSION } from "../src/version.js";
|
|
52
58
|
import { writeVisualization, } from "../src/visualization.js";
|
|
@@ -63,44 +69,6 @@ function explicitScope(args) {
|
|
|
63
69
|
const equals = args.find((argument) => argument.startsWith("--scope="));
|
|
64
70
|
return equals ? parseInitScope(equals.slice("--scope=".length)) : null;
|
|
65
71
|
}
|
|
66
|
-
async function chooseInitScope(args, repo) {
|
|
67
|
-
const selected = explicitScope(args);
|
|
68
|
-
if (selected)
|
|
69
|
-
return selected;
|
|
70
|
-
if (detectTrackedTeamIntegration(repo)) {
|
|
71
|
-
process.stderr.write("[init:scope] Detected tracked knodin team integration; preserving team scope\n");
|
|
72
|
-
return "team";
|
|
73
|
-
}
|
|
74
|
-
if (!process.stdin.isTTY || !process.stderr.isTTY)
|
|
75
|
-
return "personal";
|
|
76
|
-
const prompt = readline.createInterface({
|
|
77
|
-
input: process.stdin,
|
|
78
|
-
output: process.stderr,
|
|
79
|
-
});
|
|
80
|
-
try {
|
|
81
|
-
const answer = await prompt.question([
|
|
82
|
-
"How should knodin integrate with coding agents?",
|
|
83
|
-
" 1. Personal (recommended) — all detected agents; Git stays clean",
|
|
84
|
-
" 2. Team — create commit-ready shared configuration",
|
|
85
|
-
" 3. CLI-only — agents will not discover or invoke knodin automatically",
|
|
86
|
-
"Select [1]: ",
|
|
87
|
-
].join("\n"));
|
|
88
|
-
if (!answer.trim() || answer.trim() === "1")
|
|
89
|
-
return "personal";
|
|
90
|
-
if (answer.trim() === "2")
|
|
91
|
-
return "team";
|
|
92
|
-
if (answer.trim() === "3") {
|
|
93
|
-
const confirmation = await prompt.question("CLI-only requires manual knodin commands. Continue? [y/N] ");
|
|
94
|
-
if (!/^y(?:es)?$/i.test(confirmation.trim()))
|
|
95
|
-
throw new Error("knodin init: CLI-only selection cancelled");
|
|
96
|
-
return "cli-only";
|
|
97
|
-
}
|
|
98
|
-
return parseInitScope(answer.trim());
|
|
99
|
-
}
|
|
100
|
-
finally {
|
|
101
|
-
prompt.close();
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
72
|
function integrationAgents(repo) {
|
|
105
73
|
const previous = readRepositoryIntegrationConfig(repo)?.agents ?? [];
|
|
106
74
|
const repositoryDetected = inspectRepositoryIntegrationStatus(repo)?.agents ?? [];
|
|
@@ -149,7 +117,7 @@ function formatConfigureHuman(result) {
|
|
|
149
117
|
const externalOutcomeLines = result.paths.externalConfigurationOutcomes
|
|
150
118
|
.map(({ system, state }) => `\nExternal configuration outcome: ${system} ${state} (external mutation not locally observable)`)
|
|
151
119
|
.join("");
|
|
152
|
-
return `${result.message}\nAgent integration: ${result.paths.scope} — ${configured}${failures}${filesystemMutationLines}${externalOutcomeLines}\nGraph initialization:
|
|
120
|
+
return `${result.message}\nAgent integration: ${result.paths.scope} — ${configured}${failures}${filesystemMutationLines}${externalOutcomeLines}\nGraph initialization: refreshed and verified\nLifecycle refresh: ${refresh}\nNext: ${result.nextAction}\n`;
|
|
153
121
|
}
|
|
154
122
|
function formatRepairHuman(result) {
|
|
155
123
|
const coverage = result.after.coverage;
|
|
@@ -643,7 +611,6 @@ async function main() {
|
|
|
643
611
|
process.send?.({ type: "rss", rssBytes: process.memoryUsage().rss });
|
|
644
612
|
const engine = createEngine({ watcher: "disabled" });
|
|
645
613
|
try {
|
|
646
|
-
const systemConfig = loadSystemConfiguration(repository);
|
|
647
614
|
const summary = await initializeRepositories([repository], {
|
|
648
615
|
// A portfolio worker owns exactly one already-discovered worktree.
|
|
649
616
|
// Do not recursively initialize nested repositories inside the same
|
|
@@ -654,7 +621,7 @@ async function main() {
|
|
|
654
621
|
index: (target) => engine.index(target),
|
|
655
622
|
status: (target) => engine.status(target),
|
|
656
623
|
agents: detectSupportedAgents(),
|
|
657
|
-
indexMode: (target) => indexModeForPath(
|
|
624
|
+
indexMode: (target) => indexModeForPath(loadSystemConfiguration(target), target),
|
|
658
625
|
});
|
|
659
626
|
const result = summary.results.find(({ repository: target }) => target === repository);
|
|
660
627
|
if (!result)
|
|
@@ -704,6 +671,26 @@ async function main() {
|
|
|
704
671
|
// `--json` is a shared output flag. Repair owns its richer --json/--jsonl
|
|
705
672
|
// parser; all other commands receive their original arguments minus it.
|
|
706
673
|
const rest = cmd === "repair" ? rawRest : rawRest.filter((argument) => argument !== "--json");
|
|
674
|
+
let recoveryJournal = readUpdateJournal();
|
|
675
|
+
const recoverySafeStates = new Set(["planned", "candidate-verified", "rollback-verified"]);
|
|
676
|
+
if (recoveryJournal && !recoverySafeStates.has(recoveryJournal.state) && cmd !== "doctor") {
|
|
677
|
+
const recovery = await recoverInterruptedUpdate({ runtimeCommand, env: process.env });
|
|
678
|
+
recoveryJournal = readUpdateJournal();
|
|
679
|
+
if (recovery?.status === "terminal-unhealthy" && cmd !== "update") {
|
|
680
|
+
throw new Error(`knodin update recovery is terminal-unhealthy: ${recovery.reason ?? "candidate and rollback verification failed"}`);
|
|
681
|
+
}
|
|
682
|
+
}
|
|
683
|
+
if (recoveryJournal &&
|
|
684
|
+
!recoverySafeStates.has(recoveryJournal.state) &&
|
|
685
|
+
cmd !== "update" &&
|
|
686
|
+
cmd !== "doctor") {
|
|
687
|
+
throw new Error(`knodin is in unverified update state ${recoveryJournal.state}; run \`knodin update status\` for recovery guidance`);
|
|
688
|
+
}
|
|
689
|
+
if (!jsonOutput && cmd !== "update") {
|
|
690
|
+
const attention = updateAttention(readManagerUpdateState());
|
|
691
|
+
if (attention)
|
|
692
|
+
process.stderr.write(`${attention}\n`);
|
|
693
|
+
}
|
|
707
694
|
const selector = {
|
|
708
695
|
identity: selectorValue("--identity"),
|
|
709
696
|
file: selectorValue("--file"),
|
|
@@ -805,7 +792,6 @@ async function main() {
|
|
|
805
792
|
linkedWorktrees: plan.linkedWorktrees,
|
|
806
793
|
});
|
|
807
794
|
const engine = createEngine({ watcher: "disabled" });
|
|
808
|
-
const systemConfig = loadSystemConfiguration(plan.roots[0] ?? process.cwd());
|
|
809
795
|
const repositories = [];
|
|
810
796
|
const discoveryRecords = plan.signals
|
|
811
797
|
? discovery.repositories.slice(0, repositorySignalInspectionLimit(plan))
|
|
@@ -813,7 +799,7 @@ async function main() {
|
|
|
813
799
|
for (const record of discoveryRecords) {
|
|
814
800
|
const inventory = await inventoryRepository(record, {
|
|
815
801
|
status: async (target) => attachLifecycleHealth(target, await engine.status(target, { audit: "cached" })),
|
|
816
|
-
systemMemberships: (target) => systemMembershipsForPath(
|
|
802
|
+
systemMemberships: (target) => systemMembershipsForPath(loadSystemConfiguration(target), target),
|
|
817
803
|
});
|
|
818
804
|
repositories.push(withRepositorySignals(inventory, plan.signals, plan.signals ? await detectRepositorySignals(record.path) : {}));
|
|
819
805
|
}
|
|
@@ -826,7 +812,11 @@ async function main() {
|
|
|
826
812
|
repositories,
|
|
827
813
|
};
|
|
828
814
|
const boundedOutput = plan.signals
|
|
829
|
-
? applyResponseBudget(output, "repositories:discover", {
|
|
815
|
+
? applyResponseBudget(output, "repositories:discover", {
|
|
816
|
+
bytes: plan.byteBudget,
|
|
817
|
+
tokens: plan.tokenBudget,
|
|
818
|
+
items: plan.itemBudget,
|
|
819
|
+
}, { bytes: 65_536, tokens: 16_384, items: 100 })
|
|
830
820
|
: output;
|
|
831
821
|
process.stdout.write(`${JSON.stringify(boundedOutput, null, plan.json ? 0 : 2)}\n`);
|
|
832
822
|
process.exitCode = discovery.issues.length > 0 ? 1 : 0;
|
|
@@ -903,14 +893,18 @@ async function main() {
|
|
|
903
893
|
}));
|
|
904
894
|
}
|
|
905
895
|
await engine.close();
|
|
906
|
-
const output = {
|
|
896
|
+
const output = {
|
|
897
|
+
schemaVersion: 1,
|
|
898
|
+
command: "init",
|
|
899
|
+
...summary,
|
|
900
|
+
repositories,
|
|
901
|
+
};
|
|
907
902
|
process.stdout.write(plan.json ? `${JSON.stringify(output)}\n` : formatRepositoryHuman(summary));
|
|
908
903
|
process.exitCode = summary.exitCode;
|
|
909
904
|
return;
|
|
910
905
|
}
|
|
911
906
|
if (plan.command === "search") {
|
|
912
907
|
const engine = createEngine({ watcher: "disabled" });
|
|
913
|
-
const systemConfig = loadSystemConfiguration(plan.roots[0] ?? process.cwd());
|
|
914
908
|
const output = await searchRepositories(plan.roots, plan.query ?? "", {
|
|
915
909
|
depth: plan.depth,
|
|
916
910
|
linkedWorktrees: plan.linkedWorktrees,
|
|
@@ -927,7 +921,7 @@ async function main() {
|
|
|
927
921
|
includeSource: true,
|
|
928
922
|
federate: false,
|
|
929
923
|
}),
|
|
930
|
-
systemMemberships: (target) => systemMembershipsForPath(
|
|
924
|
+
systemMemberships: (target) => systemMembershipsForPath(loadSystemConfiguration(target), target),
|
|
931
925
|
});
|
|
932
926
|
await engine.close();
|
|
933
927
|
process.stdout.write(`${JSON.stringify(output, null, plan.json ? 0 : 2)}\n`);
|
|
@@ -1011,13 +1005,15 @@ async function main() {
|
|
|
1011
1005
|
if (cmd === "update") {
|
|
1012
1006
|
if (repoFlag !== undefined)
|
|
1013
1007
|
throw new Error("knodin update does not accept --repo");
|
|
1014
|
-
const [action, ...
|
|
1015
|
-
if (!action
|
|
1016
|
-
throw new Error("knodin update requires
|
|
1017
|
-
}
|
|
1018
|
-
if (unsupported.length > 0)
|
|
1019
|
-
throw new Error(`knodin update ${action}: unknown argument ${unsupported[0]}`);
|
|
1008
|
+
const [action, ...actionArguments] = rest;
|
|
1009
|
+
if (!action)
|
|
1010
|
+
throw new Error("knodin update requires an action");
|
|
1020
1011
|
const method = detectUpdateInstallMethod(runtimeCommand);
|
|
1012
|
+
const owner = resolveManagerOwnership({
|
|
1013
|
+
runtimeCommand,
|
|
1014
|
+
executablePath: runtimeCommand.at(-1),
|
|
1015
|
+
env: process.env,
|
|
1016
|
+
});
|
|
1021
1017
|
const runManager = async (argv) => {
|
|
1022
1018
|
const [executable, ...arguments_] = argv;
|
|
1023
1019
|
if (!executable)
|
|
@@ -1053,8 +1049,16 @@ async function main() {
|
|
|
1053
1049
|
healthCheck,
|
|
1054
1050
|
};
|
|
1055
1051
|
let output;
|
|
1056
|
-
if (action === "status")
|
|
1057
|
-
output =
|
|
1052
|
+
if (action === "status") {
|
|
1053
|
+
output = {
|
|
1054
|
+
...trustedUpdateStatus(options),
|
|
1055
|
+
owner,
|
|
1056
|
+
managerState: readManagerUpdateState(),
|
|
1057
|
+
journal: readUpdateJournal(),
|
|
1058
|
+
coordination: coordinationStatus(),
|
|
1059
|
+
attention: updateAttention(readManagerUpdateState()),
|
|
1060
|
+
};
|
|
1061
|
+
}
|
|
1058
1062
|
else if (action === "check") {
|
|
1059
1063
|
try {
|
|
1060
1064
|
output = await checkTrustedUpdate(options);
|
|
@@ -1068,11 +1072,178 @@ async function main() {
|
|
|
1068
1072
|
output = explainTrustedUpdate(options);
|
|
1069
1073
|
else if (action === "apply")
|
|
1070
1074
|
output = await applyTrustedUpdate(options);
|
|
1071
|
-
else
|
|
1075
|
+
else if (action === "rollback")
|
|
1072
1076
|
output = await rollbackTrustedUpdate(options);
|
|
1077
|
+
else if (action === "available") {
|
|
1078
|
+
output = await queryOwnerAvailability({ installedVersion: KNODIN_VERSION, owner });
|
|
1079
|
+
const availability = output;
|
|
1080
|
+
const state = readManagerUpdateState();
|
|
1081
|
+
if (availability.latestVersion &&
|
|
1082
|
+
state.pin?.kind === "automatic-rollback" &&
|
|
1083
|
+
state.pin.acknowledgedFailedVersion === state.pin.failedVersion &&
|
|
1084
|
+
availability.latestVersion !== state.pin.failedVersion) {
|
|
1085
|
+
writeManagerUpdateState({
|
|
1086
|
+
...state,
|
|
1087
|
+
lastAvailableVersion: availability.latestVersion,
|
|
1088
|
+
pin: { ...state.pin, newerAvailableVersion: availability.latestVersion },
|
|
1089
|
+
});
|
|
1090
|
+
}
|
|
1091
|
+
}
|
|
1092
|
+
else if (action === "upgrade") {
|
|
1093
|
+
const apply = actionArguments.includes("--apply");
|
|
1094
|
+
const explicitVersion = actionArguments.find((argument) => argument !== "--apply");
|
|
1095
|
+
let targetVersion = explicitVersion;
|
|
1096
|
+
if (!targetVersion) {
|
|
1097
|
+
const availability = await queryOwnerAvailability({
|
|
1098
|
+
installedVersion: KNODIN_VERSION,
|
|
1099
|
+
owner,
|
|
1100
|
+
});
|
|
1101
|
+
if (!availability.latestVersion)
|
|
1102
|
+
output = availability;
|
|
1103
|
+
else
|
|
1104
|
+
targetVersion = availability.latestVersion;
|
|
1105
|
+
}
|
|
1106
|
+
if (targetVersion)
|
|
1107
|
+
output = await executeManagerUpdate({
|
|
1108
|
+
currentVersion: KNODIN_VERSION,
|
|
1109
|
+
targetVersion,
|
|
1110
|
+
runtimeCommand,
|
|
1111
|
+
env: process.env,
|
|
1112
|
+
apply,
|
|
1113
|
+
});
|
|
1114
|
+
}
|
|
1115
|
+
else if (action === "pin") {
|
|
1116
|
+
const apply = actionArguments.includes("--apply");
|
|
1117
|
+
const version = actionArguments.find((argument) => argument !== "--apply");
|
|
1118
|
+
if (!version)
|
|
1119
|
+
throw new Error("knodin update pin requires a version");
|
|
1120
|
+
output = apply
|
|
1121
|
+
? await executeManagerUpdate({
|
|
1122
|
+
currentVersion: KNODIN_VERSION,
|
|
1123
|
+
targetVersion: version,
|
|
1124
|
+
runtimeCommand,
|
|
1125
|
+
env: process.env,
|
|
1126
|
+
apply: true,
|
|
1127
|
+
pinKind: "manual",
|
|
1128
|
+
})
|
|
1129
|
+
: setManualPin(version);
|
|
1130
|
+
}
|
|
1131
|
+
else if (action === "unpin")
|
|
1132
|
+
output = unpinUpdate();
|
|
1133
|
+
else if (action === "acknowledge")
|
|
1134
|
+
output = acknowledgeUpdateFailure();
|
|
1135
|
+
else if (action === "auto") {
|
|
1136
|
+
const subaction = actionArguments[0];
|
|
1137
|
+
if (!subaction || !["status", "enable", "disable", "run"].includes(subaction))
|
|
1138
|
+
throw new Error("knodin update auto requires status, enable, disable, or run");
|
|
1139
|
+
const state = readManagerUpdateState();
|
|
1140
|
+
if (subaction === "status")
|
|
1141
|
+
output = state;
|
|
1142
|
+
else if (subaction === "disable") {
|
|
1143
|
+
output = { ...state, autoEnabled: false };
|
|
1144
|
+
writeManagerUpdateState(output);
|
|
1145
|
+
}
|
|
1146
|
+
else if (subaction === "enable") {
|
|
1147
|
+
if (state.platformAutoEligible) {
|
|
1148
|
+
output = { ...state, autoEnabled: true };
|
|
1149
|
+
writeManagerUpdateState(output);
|
|
1150
|
+
}
|
|
1151
|
+
else
|
|
1152
|
+
output = await certifyAutomaticUpdates({
|
|
1153
|
+
currentVersion: KNODIN_VERSION,
|
|
1154
|
+
runtimeCommand,
|
|
1155
|
+
env: process.env,
|
|
1156
|
+
});
|
|
1157
|
+
}
|
|
1158
|
+
else if (!state.autoEnabled || !state.platformAutoEligible) {
|
|
1159
|
+
output = { ...state, status: "disabled" };
|
|
1160
|
+
}
|
|
1161
|
+
else {
|
|
1162
|
+
const availability = await queryOwnerAvailability({
|
|
1163
|
+
installedVersion: KNODIN_VERSION,
|
|
1164
|
+
owner,
|
|
1165
|
+
});
|
|
1166
|
+
output =
|
|
1167
|
+
availability.status === "available" &&
|
|
1168
|
+
availability.autoEligible &&
|
|
1169
|
+
availability.latestVersion
|
|
1170
|
+
? await executeManagerUpdate({
|
|
1171
|
+
currentVersion: KNODIN_VERSION,
|
|
1172
|
+
targetVersion: availability.latestVersion,
|
|
1173
|
+
runtimeCommand,
|
|
1174
|
+
env: process.env,
|
|
1175
|
+
apply: true,
|
|
1176
|
+
})
|
|
1177
|
+
: availability;
|
|
1178
|
+
}
|
|
1179
|
+
}
|
|
1180
|
+
else
|
|
1181
|
+
throw new Error(`knodin update: unknown action ${action}`);
|
|
1073
1182
|
process.stdout.write(jsonOutput ? `${JSON.stringify(output)}\n` : formatGenericHuman("update", output));
|
|
1074
1183
|
return;
|
|
1075
1184
|
}
|
|
1185
|
+
if (cmd === "backups") {
|
|
1186
|
+
const action = invocation.commandPath[1];
|
|
1187
|
+
const retentionAction = invocation.commandPath[2];
|
|
1188
|
+
const roots = invocation.positionals;
|
|
1189
|
+
const defaultRoots = () => {
|
|
1190
|
+
if (roots.length > 0)
|
|
1191
|
+
return roots;
|
|
1192
|
+
const target = resolveRepo(repoFlag, process.cwd());
|
|
1193
|
+
if (!target.ok)
|
|
1194
|
+
throw new Error(target.error);
|
|
1195
|
+
return [target.repo];
|
|
1196
|
+
};
|
|
1197
|
+
const depth = invocation.options.depth;
|
|
1198
|
+
const retentionDays = invocation.options.retentionDays;
|
|
1199
|
+
const keepNewest = invocation.options.keepNewest;
|
|
1200
|
+
let output;
|
|
1201
|
+
if (action === "list")
|
|
1202
|
+
output = listBackups(defaultRoots(), { depth });
|
|
1203
|
+
else if (action === "prune") {
|
|
1204
|
+
output = pruneBackups(defaultRoots(), {
|
|
1205
|
+
depth,
|
|
1206
|
+
retentionDays,
|
|
1207
|
+
keepNewest,
|
|
1208
|
+
apply: invocation.options.apply === true,
|
|
1209
|
+
});
|
|
1210
|
+
}
|
|
1211
|
+
else if (action === "retention" && retentionAction === "install") {
|
|
1212
|
+
output = installBackupRetention(roots, {
|
|
1213
|
+
depth,
|
|
1214
|
+
retentionDays,
|
|
1215
|
+
keepNewest,
|
|
1216
|
+
schedule: invocation.options.schedule,
|
|
1217
|
+
dryRun: invocation.options.dryRun === true,
|
|
1218
|
+
launcher: runtimeCommand,
|
|
1219
|
+
});
|
|
1220
|
+
}
|
|
1221
|
+
else if (action === "retention" && retentionAction === "status") {
|
|
1222
|
+
output = retentionStatus();
|
|
1223
|
+
}
|
|
1224
|
+
else if (action === "retention" && retentionAction === "doctor") {
|
|
1225
|
+
output = retentionDoctor();
|
|
1226
|
+
}
|
|
1227
|
+
else if (action === "retention" && retentionAction === "remove") {
|
|
1228
|
+
output = removeBackupRetention();
|
|
1229
|
+
}
|
|
1230
|
+
else if (action === "retention" && retentionAction === "run") {
|
|
1231
|
+
output = runInstalledRetention();
|
|
1232
|
+
}
|
|
1233
|
+
else {
|
|
1234
|
+
throw new Error("knodin backups requires list, prune, or retention install|status|doctor|remove");
|
|
1235
|
+
}
|
|
1236
|
+
if (invocation.options.jsonl === true) {
|
|
1237
|
+
const records = output.backups ??
|
|
1238
|
+
output.candidates ?? [output];
|
|
1239
|
+
for (const record of records)
|
|
1240
|
+
process.stdout.write(`${JSON.stringify(record)}\n`);
|
|
1241
|
+
}
|
|
1242
|
+
else {
|
|
1243
|
+
process.stdout.write(jsonOutput ? `${JSON.stringify(output)}\n` : formatBackupHuman("backups", output));
|
|
1244
|
+
}
|
|
1245
|
+
return;
|
|
1246
|
+
}
|
|
1076
1247
|
if (process.stdout.isTTY &&
|
|
1077
1248
|
claimScheduledUpdateCheck({
|
|
1078
1249
|
currentVersion: KNODIN_VERSION,
|
|
@@ -1124,6 +1295,14 @@ async function main() {
|
|
|
1124
1295
|
process.exit(1);
|
|
1125
1296
|
}
|
|
1126
1297
|
const repo = resolved.repo;
|
|
1298
|
+
if (cmd !== "doctor") {
|
|
1299
|
+
try {
|
|
1300
|
+
maybeRunOpportunisticRetention(repo);
|
|
1301
|
+
}
|
|
1302
|
+
catch {
|
|
1303
|
+
// Best-effort cleanup must never make an ordinary command fail.
|
|
1304
|
+
}
|
|
1305
|
+
}
|
|
1127
1306
|
if (cmd === "agent-event" && !fs.existsSync(resolveDbPath(repo)))
|
|
1128
1307
|
return;
|
|
1129
1308
|
if (cmd === "doctor") {
|
|
@@ -1247,7 +1426,10 @@ async function main() {
|
|
|
1247
1426
|
const input = positionals[0] === "create" ? (positionals[1] ?? "-") : (positionals[0] ?? "-");
|
|
1248
1427
|
compressionResult =
|
|
1249
1428
|
input === "-"
|
|
1250
|
-
? compressOutput(repo, {
|
|
1429
|
+
? compressOutput(repo, {
|
|
1430
|
+
...request,
|
|
1431
|
+
text: await readBoundedStdin(maxInputBytes),
|
|
1432
|
+
})
|
|
1251
1433
|
: compressOutputFile(repo, input, request);
|
|
1252
1434
|
}
|
|
1253
1435
|
if (action === "diagnose" &&
|
|
@@ -1326,7 +1508,10 @@ async function main() {
|
|
|
1326
1508
|
if (existing.state !== "configured")
|
|
1327
1509
|
throw new Error("knodin shared configure --disable requires a valid existing configuration");
|
|
1328
1510
|
writeSharedIndexConfig(repo, { ...existing.config, enabled: false });
|
|
1329
|
-
result = {
|
|
1511
|
+
result = {
|
|
1512
|
+
state: "configured",
|
|
1513
|
+
config: { ...existing.config, enabled: false },
|
|
1514
|
+
};
|
|
1330
1515
|
break;
|
|
1331
1516
|
}
|
|
1332
1517
|
const required = (name) => {
|
|
@@ -1361,7 +1546,11 @@ async function main() {
|
|
|
1361
1546
|
},
|
|
1362
1547
|
};
|
|
1363
1548
|
const target = writeSharedIndexConfig(repo, config);
|
|
1364
|
-
result = {
|
|
1549
|
+
result = {
|
|
1550
|
+
state: "configured",
|
|
1551
|
+
path: target,
|
|
1552
|
+
config: loadSharedIndexConfig(repo),
|
|
1553
|
+
};
|
|
1365
1554
|
break;
|
|
1366
1555
|
}
|
|
1367
1556
|
if (action === "publisher-metadata") {
|
|
@@ -1395,7 +1584,10 @@ async function main() {
|
|
|
1395
1584
|
if (!bundlePath)
|
|
1396
1585
|
throw new Error("knodin shared publisher-finalize requires <bundle>");
|
|
1397
1586
|
const bundle = JSON.parse(fs.readFileSync(path.resolve(process.cwd(), bundlePath), "utf8"));
|
|
1398
|
-
const pointer = finalizeSharedPublisherBundle({
|
|
1587
|
+
const pointer = finalizeSharedPublisherBundle({
|
|
1588
|
+
config: configuration.config,
|
|
1589
|
+
bundle,
|
|
1590
|
+
});
|
|
1399
1591
|
result = { bundle, pointer: JSON.parse(pointer.toString("utf8")) };
|
|
1400
1592
|
break;
|
|
1401
1593
|
}
|
|
@@ -1422,12 +1614,19 @@ async function main() {
|
|
|
1422
1614
|
let credentialProbe = "not-requested";
|
|
1423
1615
|
if (invocation.options.probe === true) {
|
|
1424
1616
|
if (configuration.state !== "configured" || !configuration.config.enabled) {
|
|
1425
|
-
credentialProbe = {
|
|
1617
|
+
credentialProbe = {
|
|
1618
|
+
state: "unavailable",
|
|
1619
|
+
category: "configuration",
|
|
1620
|
+
};
|
|
1426
1621
|
}
|
|
1427
1622
|
else {
|
|
1428
1623
|
const store = createSharedObjectStore(configuration.config);
|
|
1429
1624
|
try {
|
|
1430
|
-
const current = spawnSync(gitExecutable(), ["symbolic-ref", "--quiet", "--short", "HEAD"], {
|
|
1625
|
+
const current = spawnSync(gitExecutable(), ["symbolic-ref", "--quiet", "--short", "HEAD"], {
|
|
1626
|
+
cwd: repo,
|
|
1627
|
+
encoding: "utf8",
|
|
1628
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
1629
|
+
}).stdout.trim();
|
|
1431
1630
|
const branch = configuredBranchCandidates(configuration.config, current || undefined)[0];
|
|
1432
1631
|
if (!store || !branch)
|
|
1433
1632
|
throw new SharedIndexError("configuration", "shared-index probe has no configured local branch candidate");
|
|
@@ -1628,13 +1827,123 @@ async function main() {
|
|
|
1628
1827
|
break;
|
|
1629
1828
|
}
|
|
1630
1829
|
case "system": {
|
|
1631
|
-
const
|
|
1632
|
-
|
|
1830
|
+
const requestedAction = invocation.commandPath[1];
|
|
1831
|
+
if (requestedAction === "link") {
|
|
1832
|
+
const [systemId, ...repositories] = invocation.positionals;
|
|
1833
|
+
if (!systemId)
|
|
1834
|
+
throw new Error("knodin system link requires <system-id>");
|
|
1835
|
+
const overrides = Object.fromEntries((Array.isArray(invocation.options.repositoryId) ? invocation.options.repositoryId : [])
|
|
1836
|
+
.map(String)
|
|
1837
|
+
.map((value) => {
|
|
1838
|
+
const at = value.lastIndexOf("=");
|
|
1839
|
+
if (at < 1)
|
|
1840
|
+
throw new Error("--repository-id must be <path>=<id>");
|
|
1841
|
+
return [value.slice(0, at), value.slice(at + 1)];
|
|
1842
|
+
}));
|
|
1843
|
+
const componentOverrides = Object.fromEntries((Array.isArray(invocation.options.component) ? invocation.options.component : [])
|
|
1844
|
+
.map(String)
|
|
1845
|
+
.map((value) => {
|
|
1846
|
+
const at = value.indexOf("=");
|
|
1847
|
+
if (at < 1)
|
|
1848
|
+
throw new Error("--component must be <repo-id>=<component-id>[:type]");
|
|
1849
|
+
const repositoryId = value.slice(0, at);
|
|
1850
|
+
const [id, componentType] = value.slice(at + 1).split(":");
|
|
1851
|
+
if (!id)
|
|
1852
|
+
throw new Error("--component requires a component id");
|
|
1853
|
+
if (componentType &&
|
|
1854
|
+
!["component", "api", "resource", "artifact"].includes(componentType))
|
|
1855
|
+
throw new Error(`--component: unsupported type ${componentType}`);
|
|
1856
|
+
return [
|
|
1857
|
+
repositoryId,
|
|
1858
|
+
{
|
|
1859
|
+
id,
|
|
1860
|
+
type: componentType,
|
|
1861
|
+
},
|
|
1862
|
+
];
|
|
1863
|
+
}));
|
|
1864
|
+
if (invocation.options.initMissing === true && invocation.options.dryRun !== true) {
|
|
1865
|
+
for (const checkout of repositories.map((value) => path.resolve(repo, value))) {
|
|
1866
|
+
if (fs.existsSync(path.join(checkout, ".knodin")))
|
|
1867
|
+
continue;
|
|
1868
|
+
await initializeRepository(checkout, {
|
|
1869
|
+
command: runtimeCommand,
|
|
1870
|
+
index: (target, indexOptions) => engine.index(target, undefined, false, indexOptions),
|
|
1871
|
+
scope: "personal",
|
|
1872
|
+
agents: [],
|
|
1873
|
+
});
|
|
1874
|
+
}
|
|
1875
|
+
}
|
|
1876
|
+
const plan = planSystemLink({
|
|
1877
|
+
systemId,
|
|
1878
|
+
repositories,
|
|
1879
|
+
scope: invocation.options.scope === "team" ? "team" : "personal",
|
|
1880
|
+
distributed: invocation.options.distributed === true,
|
|
1881
|
+
repositoryIds: overrides,
|
|
1882
|
+
components: componentOverrides,
|
|
1883
|
+
});
|
|
1884
|
+
result = invocation.options.dryRun === true ? plan : applySystemPlan(plan);
|
|
1885
|
+
break;
|
|
1886
|
+
}
|
|
1887
|
+
if (requestedAction === "relate") {
|
|
1888
|
+
const [systemId] = invocation.positionals;
|
|
1889
|
+
if (!systemId)
|
|
1890
|
+
throw new Error("knodin system relate requires <system-id>");
|
|
1891
|
+
const plan = planSystemRelate({
|
|
1892
|
+
systemId,
|
|
1893
|
+
type: String(invocation.options.type),
|
|
1894
|
+
from: String(invocation.options.from),
|
|
1895
|
+
to: String(invocation.options.to),
|
|
1896
|
+
evidence: String(invocation.options.evidence),
|
|
1897
|
+
repoPath: repo,
|
|
1898
|
+
});
|
|
1899
|
+
result = invocation.options.dryRun === true ? plan : applySystemPlan(plan);
|
|
1900
|
+
break;
|
|
1901
|
+
}
|
|
1902
|
+
if (requestedAction === "unlink") {
|
|
1903
|
+
const [systemId, ...repositories] = invocation.positionals;
|
|
1904
|
+
if (!systemId)
|
|
1905
|
+
throw new Error("knodin system unlink requires <system-id>");
|
|
1906
|
+
const plan = planSystemUnlink({
|
|
1907
|
+
systemId,
|
|
1908
|
+
repositories,
|
|
1909
|
+
repoPath: repo,
|
|
1910
|
+
});
|
|
1911
|
+
result = invocation.options.dryRun === true ? plan : applySystemPlan(plan);
|
|
1912
|
+
break;
|
|
1913
|
+
}
|
|
1914
|
+
if (requestedAction === "unrelate") {
|
|
1915
|
+
const [systemId] = invocation.positionals;
|
|
1916
|
+
if (!systemId)
|
|
1917
|
+
throw new Error("knodin system unrelate requires <system-id>");
|
|
1918
|
+
const plan = planSystemUnrelate({
|
|
1919
|
+
systemId,
|
|
1920
|
+
type: String(invocation.options.type),
|
|
1921
|
+
from: String(invocation.options.from),
|
|
1922
|
+
to: String(invocation.options.to),
|
|
1923
|
+
repoPath: repo,
|
|
1924
|
+
});
|
|
1925
|
+
result = invocation.options.dryRun === true ? plan : applySystemPlan(plan);
|
|
1926
|
+
break;
|
|
1927
|
+
}
|
|
1928
|
+
if (requestedAction === "import") {
|
|
1929
|
+
const [manifestPath] = invocation.positionals;
|
|
1930
|
+
if (!manifestPath)
|
|
1931
|
+
throw new Error("knodin system import requires <path>");
|
|
1932
|
+
const plan = planSystemImport({
|
|
1933
|
+
manifestPath,
|
|
1934
|
+
scope: invocation.options.scope === "team" ? "team" : "personal",
|
|
1935
|
+
repoPath: repo,
|
|
1936
|
+
});
|
|
1937
|
+
result = invocation.options.dryRun === true ? plan : applySystemPlan(plan);
|
|
1938
|
+
break;
|
|
1939
|
+
}
|
|
1940
|
+
const requireComplete = rest.includes("--require-complete");
|
|
1941
|
+
const [action, systemId, ...unsupported] = rest.filter((argument) => argument !== "--allow-partial" && argument !== "--require-complete");
|
|
1633
1942
|
if (!action || !["list", "show", "validate", "query"].includes(action)) {
|
|
1634
1943
|
throw new Error("knodin system requires list, show, validate, or query");
|
|
1635
1944
|
}
|
|
1636
|
-
if (
|
|
1637
|
-
throw new Error(`knodin system ${action}: --
|
|
1945
|
+
if (requireComplete && action !== "query")
|
|
1946
|
+
throw new Error(`knodin system ${action}: --require-complete applies only to query`);
|
|
1638
1947
|
if (unsupported.length > 0)
|
|
1639
1948
|
throw new Error(`knodin system ${action}: unknown argument ${unsupported[0]}`);
|
|
1640
1949
|
const config = await enrichSystemRelationships(loadSystemConfiguration(repo));
|
|
@@ -1673,39 +1982,83 @@ async function main() {
|
|
|
1673
1982
|
}
|
|
1674
1983
|
else {
|
|
1675
1984
|
const validation = await validateSystemHealth(config, systemId, async (target) => attachLifecycleHealth(target, await engine.status(target, { audit: "cached" })), repo);
|
|
1676
|
-
result = queryConfiguredSystem(config, systemId,
|
|
1985
|
+
result = queryConfiguredSystem(config, systemId, requireComplete, validation);
|
|
1677
1986
|
if (result.status === "unavailable")
|
|
1678
1987
|
process.exitCode = 1;
|
|
1679
1988
|
}
|
|
1680
1989
|
break;
|
|
1681
1990
|
}
|
|
1682
|
-
case "
|
|
1683
|
-
const
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1991
|
+
case "skills": {
|
|
1992
|
+
const action = invocation.commandPath[1];
|
|
1993
|
+
const requested = Array.isArray(invocation.options.client)
|
|
1994
|
+
? invocation.options.client.map(String)
|
|
1995
|
+
: [];
|
|
1996
|
+
const supported = new Set(["codex", "claude", "gemini"]);
|
|
1997
|
+
for (const client of requested)
|
|
1998
|
+
if (!supported.has(client))
|
|
1999
|
+
throw new Error(`knodin skills: unsupported client ${client}`);
|
|
2000
|
+
const clients = (requested.length ? requested : ["codex", "claude", "gemini"]);
|
|
2001
|
+
const scope = typeof invocation.options.scope === "string"
|
|
2002
|
+
? parseInitScope(invocation.options.scope)
|
|
2003
|
+
: "personal";
|
|
2004
|
+
if (action === "list") {
|
|
2005
|
+
result = { skills: KNODIN_SKILLS, clients, scope };
|
|
2006
|
+
break;
|
|
1692
2007
|
}
|
|
1693
|
-
|
|
1694
|
-
|
|
2008
|
+
if (action === "install")
|
|
2009
|
+
result = installKnodinSkills({
|
|
2010
|
+
repo,
|
|
2011
|
+
scope,
|
|
2012
|
+
clients,
|
|
2013
|
+
dryRun: invocation.options.dryRun === true,
|
|
2014
|
+
});
|
|
2015
|
+
else if (action === "remove")
|
|
2016
|
+
result = removeKnodinSkills({
|
|
2017
|
+
repo,
|
|
2018
|
+
scope,
|
|
2019
|
+
clients,
|
|
2020
|
+
dryRun: invocation.options.dryRun === true,
|
|
2021
|
+
});
|
|
2022
|
+
else if (action === "doctor")
|
|
2023
|
+
result = inspectKnodinSkills({ repo, scope, clients });
|
|
2024
|
+
else
|
|
2025
|
+
throw new Error("knodin skills requires list, install, remove, or doctor");
|
|
2026
|
+
break;
|
|
2027
|
+
}
|
|
2028
|
+
case "hook-refresh": {
|
|
2029
|
+
const lifecycleLease = acquireRepairLease(repo, "lifecycle-hook");
|
|
2030
|
+
try {
|
|
2031
|
+
const [kind, first, second] = rest;
|
|
2032
|
+
let event;
|
|
2033
|
+
if (kind === "commit")
|
|
2034
|
+
event = { kind };
|
|
2035
|
+
else if (kind === "checkout" && first && second) {
|
|
2036
|
+
event = { kind, before: first, after: second };
|
|
2037
|
+
}
|
|
2038
|
+
else if (kind === "merge" && first && second) {
|
|
2039
|
+
event = { kind, before: first, after: second };
|
|
2040
|
+
}
|
|
2041
|
+
else if (kind === "rewrite" && first) {
|
|
2042
|
+
event = { kind, inputPath: first };
|
|
2043
|
+
}
|
|
2044
|
+
else {
|
|
2045
|
+
throw new Error("knodin hook-refresh: invalid lifecycle event");
|
|
2046
|
+
}
|
|
2047
|
+
const shared = await opportunisticSharedRestore();
|
|
2048
|
+
const indexed = shared?.restored
|
|
2049
|
+
? []
|
|
2050
|
+
: await refreshFromGitEvent(repo, event, (target, files) => engine.index(target, files));
|
|
2051
|
+
result = { indexed, ...(shared ? { sharedRestore: shared } : {}) };
|
|
1695
2052
|
}
|
|
1696
|
-
|
|
1697
|
-
|
|
2053
|
+
finally {
|
|
2054
|
+
lifecycleLease.release();
|
|
1698
2055
|
}
|
|
1699
|
-
const shared = await opportunisticSharedRestore();
|
|
1700
|
-
const indexed = shared?.restored
|
|
1701
|
-
? []
|
|
1702
|
-
: await refreshFromGitEvent(repo, event, (target, files) => engine.index(target, files));
|
|
1703
|
-
result = { indexed, ...(shared ? { sharedRestore: shared } : {}) };
|
|
1704
2056
|
break;
|
|
1705
2057
|
}
|
|
1706
2058
|
case "init": {
|
|
1707
|
-
const
|
|
1708
|
-
const
|
|
2059
|
+
const requestedScope = explicitScope(rawRest);
|
|
2060
|
+
const scope = requestedScope ?? readRepositoryIntegrationConfig(repo)?.scope ?? "cli-only";
|
|
2061
|
+
const agents = requestedScope && scope !== "team" ? integrationAgents(repo) : [];
|
|
1709
2062
|
const renderer = createInitRenderer();
|
|
1710
2063
|
const activity = createIndexActivityReporter(repo);
|
|
1711
2064
|
activity.start();
|
|
@@ -1723,6 +2076,7 @@ async function main() {
|
|
|
1723
2076
|
index: (target, options) => engine.index(target, undefined, false, options),
|
|
1724
2077
|
scope,
|
|
1725
2078
|
agents,
|
|
2079
|
+
configureIntegration: requestedScope !== null,
|
|
1726
2080
|
onProgress: (event) => {
|
|
1727
2081
|
activity.update(event);
|
|
1728
2082
|
renderer.onProgress(event);
|
|
@@ -1767,16 +2121,17 @@ async function main() {
|
|
|
1767
2121
|
const agents = scope === "team" ? [] : integrationAgents(repo);
|
|
1768
2122
|
const paths = await initializeRepository(repo, {
|
|
1769
2123
|
command: runtimeCommand,
|
|
1770
|
-
index:
|
|
2124
|
+
index: (target, options) => engine.index(target, undefined, false, options),
|
|
1771
2125
|
scope,
|
|
1772
2126
|
agents,
|
|
1773
2127
|
allowTrackedTransition: true,
|
|
1774
2128
|
auditConfigurationChanges: true,
|
|
2129
|
+
configureIntegration: true,
|
|
1775
2130
|
});
|
|
1776
2131
|
result = {
|
|
1777
2132
|
status: "success",
|
|
1778
2133
|
message: `knodin agent integration changed to ${scope}.`,
|
|
1779
|
-
graphInitialization: "
|
|
2134
|
+
graphInitialization: "refreshed",
|
|
1780
2135
|
nextAction: "run `knodin status` and reload the configured client",
|
|
1781
2136
|
paths,
|
|
1782
2137
|
};
|
|
@@ -1926,7 +2281,9 @@ async function main() {
|
|
|
1926
2281
|
}
|
|
1927
2282
|
const progressMode = resolveRepairProgressMode(options, process.env, process.stderr.isTTY);
|
|
1928
2283
|
const renderer = progressMode === "tty"
|
|
1929
|
-
? createProgressWorkerRenderer("repair-progress-worker", {
|
|
2284
|
+
? createProgressWorkerRenderer("repair-progress-worker", {
|
|
2285
|
+
type: "start",
|
|
2286
|
+
})
|
|
1930
2287
|
: (() => {
|
|
1931
2288
|
const direct = createRepairProgressRenderer({
|
|
1932
2289
|
mode: progressMode,
|
|
@@ -2367,7 +2724,10 @@ async function main() {
|
|
|
2367
2724
|
else if (action === "export")
|
|
2368
2725
|
result = exportTelemetry(repo, readTelemetryRecords(repo, input, retentionDays), selectorValue("--output"), readSessionEvents(repo, retentionDays));
|
|
2369
2726
|
else if (action === "clear")
|
|
2370
|
-
result = {
|
|
2727
|
+
result = {
|
|
2728
|
+
...clearTelemetry(repo, input),
|
|
2729
|
+
session: clearSessionTelemetry(repo),
|
|
2730
|
+
};
|
|
2371
2731
|
else
|
|
2372
2732
|
throw new Error("knodin telemetry requires enable, disable, status, report, export, or clear");
|
|
2373
2733
|
break;
|
|
@@ -2439,7 +2799,11 @@ async function main() {
|
|
|
2439
2799
|
result =
|
|
2440
2800
|
action === "preview"
|
|
2441
2801
|
? persistDiagnosticsPreview(repo, options)
|
|
2442
|
-
: collectDiagnostics(repo, {
|
|
2802
|
+
: collectDiagnostics(repo, {
|
|
2803
|
+
...options,
|
|
2804
|
+
outputPath: outputOption,
|
|
2805
|
+
previewId,
|
|
2806
|
+
});
|
|
2443
2807
|
}
|
|
2444
2808
|
else {
|
|
2445
2809
|
throw new Error("knodin diagnostics requires enable, status, preview, archive, inspect, clear, or disable");
|