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/src/init.js
CHANGED
|
@@ -7,6 +7,8 @@ import { compareBytes } from "./compare.js";
|
|
|
7
7
|
import { isIndexableSourcePath } from "./engine/source-policy.js";
|
|
8
8
|
import { lookupMirror } from "./engine/state-paths.js";
|
|
9
9
|
import { inspectLefthookIntegration, installHookManagerIntegration, isActiveLefthookHook, } from "./hook-manager-integration.js";
|
|
10
|
+
import { acquireRepairLease } from "./repair-lease.js";
|
|
11
|
+
import { installKnodinSkills, removeKnodinSkills } from "./skill-management.js";
|
|
10
12
|
import { registerInitializedWorktree } from "./worktree-lifecycle.js";
|
|
11
13
|
const MANAGED_MARKER = "KNODIN MANAGED HOOK";
|
|
12
14
|
const HOOK_NAMES = ["post-commit", "post-checkout", "post-merge", "post-rewrite"];
|
|
@@ -152,7 +154,10 @@ function configureMutationAuditTargets(repo) {
|
|
|
152
154
|
});
|
|
153
155
|
}
|
|
154
156
|
for (const hookName of HOOK_NAMES) {
|
|
155
|
-
add({
|
|
157
|
+
add({
|
|
158
|
+
absolute: path.join(effectiveHooks, hookName),
|
|
159
|
+
label: `${effectiveLabel}/${hookName}`,
|
|
160
|
+
});
|
|
156
161
|
add({
|
|
157
162
|
absolute: path.join(effectiveHooks, `${hookName}.knodin-original`),
|
|
158
163
|
label: `${effectiveLabel}/${hookName}.knodin-original`,
|
|
@@ -384,11 +389,11 @@ while :; do
|
|
|
384
389
|
ARG1="$(sed -n '2p' "$EVENT")"
|
|
385
390
|
ARG2="$(sed -n '3p' "$EVENT")"
|
|
386
391
|
if [ "$KIND" = "commit" ]; then
|
|
387
|
-
${invocation} --repo "$REPO_ROOT" hook-refresh commit --json >> "$LOG_PATH" 2
|
|
392
|
+
${invocation} --repo "$REPO_ROOT" hook-refresh commit --json >> "$LOG_PATH" 2>> "$LOG_PATH.stderr"
|
|
388
393
|
elif [ "$KIND" = "checkout" ] || [ "$KIND" = "merge" ]; then
|
|
389
|
-
${invocation} --repo "$REPO_ROOT" hook-refresh "$KIND" "$ARG1" "$ARG2" --json >> "$LOG_PATH" 2
|
|
394
|
+
${invocation} --repo "$REPO_ROOT" hook-refresh "$KIND" "$ARG1" "$ARG2" --json >> "$LOG_PATH" 2>> "$LOG_PATH.stderr"
|
|
390
395
|
elif [ "$KIND" = "rewrite" ]; then
|
|
391
|
-
${invocation} --repo "$REPO_ROOT" hook-refresh rewrite "$ARG1" --json >> "$LOG_PATH" 2
|
|
396
|
+
${invocation} --repo "$REPO_ROOT" hook-refresh rewrite "$ARG1" --json >> "$LOG_PATH" 2>> "$LOG_PATH.stderr"
|
|
392
397
|
else
|
|
393
398
|
printf 'knodin background refresh: invalid queued event %s\n' "$KIND" >> "$LOG_PATH"
|
|
394
399
|
false
|
|
@@ -700,6 +705,7 @@ This repository is indexed locally by knodin. Start with \`knodin status\`; if i
|
|
|
700
705
|
- Use gateway operations \`explain\`, \`review\`, and \`query\` for source-evidenced context. CLI fallbacks are \`knodin explain\`, \`knodin review --scope compare\`, and \`knodin rename\`.
|
|
701
706
|
- Direct reads are appropriate for files just authored in the current session; do not force a graph round trip when the agent already has fresh source context.
|
|
702
707
|
- Run \`knodin index <changed-files>\` while working when you need immediately fresh graph evidence. Managed Git hooks installed by \`knodin init\` refresh the graph after commits, checkouts, merges, and rewrites.
|
|
708
|
+
- When indexing is active, run \`knodin wait --fresh\` and recheck status before falling back to direct traversal.
|
|
703
709
|
- Keep output truthful: local graph evidence can be stale or ambiguous; say so and repair/reindex instead of claiming certainty.
|
|
704
710
|
|
|
705
711
|
<!-- knodin:end -->
|
|
@@ -959,9 +965,17 @@ export function inspectRepositoryIntegrationStatus(repo) {
|
|
|
959
965
|
const receipt = readRepositoryIntegrationConfig(repo);
|
|
960
966
|
const candidates = [
|
|
961
967
|
{ agent: "claude", path: ".mcp.json", marker: '"knodin"' },
|
|
962
|
-
{
|
|
968
|
+
{
|
|
969
|
+
agent: "codex",
|
|
970
|
+
path: ".codex/config.toml",
|
|
971
|
+
marker: 'mcp_servers."knodin"',
|
|
972
|
+
},
|
|
963
973
|
{ agent: "gemini", path: ".gemini/settings.json", marker: '"knodin"' },
|
|
964
|
-
{
|
|
974
|
+
{
|
|
975
|
+
agent: "antigravity",
|
|
976
|
+
path: ".agents/mcp_config.json",
|
|
977
|
+
marker: '"knodin"',
|
|
978
|
+
},
|
|
965
979
|
{
|
|
966
980
|
agent: "codex",
|
|
967
981
|
path: "AGENTS.md",
|
|
@@ -1046,6 +1060,7 @@ export function detectTrackedTeamIntegration(repo) {
|
|
|
1046
1060
|
export async function initializeRepository(repo, options) {
|
|
1047
1061
|
const resolvedRepo = path.resolve(repo);
|
|
1048
1062
|
const scope = options.scope ?? "personal";
|
|
1063
|
+
const configureIntegration = options.configureIntegration ?? true;
|
|
1049
1064
|
const priorIntegration = readRepositoryIntegrationConfig(resolvedRepo);
|
|
1050
1065
|
if (runGit(resolvedRepo, ["rev-parse", "--is-inside-work-tree"]).trim() !== "true") {
|
|
1051
1066
|
throw new Error(`knodin init: not a Git worktree: ${resolvedRepo}`);
|
|
@@ -1064,173 +1079,217 @@ export async function initializeRepository(repo, options) {
|
|
|
1064
1079
|
if (!path.isAbsolute(options.command[0])) {
|
|
1065
1080
|
throw new Error("knodin init: packaged runtime command must be an absolute path");
|
|
1066
1081
|
}
|
|
1067
|
-
const
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
const hooksDir = hookInstallation.hooksDir;
|
|
1079
|
-
await Promise.all([
|
|
1080
|
-
fs.promises.mkdir(knodinHooksDir, { recursive: true }),
|
|
1081
|
-
fs.promises.mkdir(hooksDir, { recursive: true }),
|
|
1082
|
-
]);
|
|
1083
|
-
const backgroundPath = path.join(knodinHooksDir, "background-index.sh");
|
|
1084
|
-
await fs.promises.writeFile(backgroundPath, backgroundScript(options.command), {
|
|
1085
|
-
encoding: "utf-8",
|
|
1086
|
-
mode: 0o755,
|
|
1087
|
-
});
|
|
1088
|
-
await fs.promises.chmod(backgroundPath, 0o755);
|
|
1089
|
-
const hookManagerIntegration = installHookManagerIntegration(resolvedRepo);
|
|
1090
|
-
for (const hookName of HOOK_NAMES) {
|
|
1091
|
-
let preservedOriginal;
|
|
1092
|
-
if (hookInstallation.trackedHooksDir) {
|
|
1093
|
-
const relativeHook = `${hookInstallation.trackedHooksDir}/${hookName}`;
|
|
1094
|
-
const sourceHook = path.join(resolvedRepo, relativeHook);
|
|
1095
|
-
try {
|
|
1096
|
-
const stat = await fs.promises.stat(sourceHook);
|
|
1097
|
-
preservedOriginal =
|
|
1098
|
-
stat.isFile() && (stat.mode & 0o111) !== 0 ? `repo:${relativeHook}` : null;
|
|
1099
|
-
}
|
|
1100
|
-
catch {
|
|
1101
|
-
preservedOriginal = null;
|
|
1102
|
-
}
|
|
1082
|
+
const lifecycleLease = acquireRepairLease(resolvedRepo, options.configureIntegration ? "configure" : "init");
|
|
1083
|
+
try {
|
|
1084
|
+
const mutationTargets = options.auditConfigurationChanges
|
|
1085
|
+
? configureMutationAuditTargets(resolvedRepo)
|
|
1086
|
+
: [];
|
|
1087
|
+
const beforeMutation = mutationSnapshot(mutationTargets);
|
|
1088
|
+
if (configureIntegration &&
|
|
1089
|
+
scope !== "team" &&
|
|
1090
|
+
!options.allowTrackedTransition &&
|
|
1091
|
+
detectTrackedTeamIntegration(resolvedRepo)) {
|
|
1092
|
+
throw new Error("knodin init: tracked team integration is active; use `knodin configure --scope personal` or `--scope cli-only` for an explicit commit-ready transition");
|
|
1103
1093
|
}
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
await preventLefthookAutoInstall(path.join(hooksDir, entry.name));
|
|
1111
|
-
}
|
|
1112
|
-
const indexResult = await options.index(resolvedRepo, {
|
|
1113
|
-
onProgress: options.onProgress,
|
|
1114
|
-
});
|
|
1115
|
-
if (isIndexResult(indexResult) && indexResult.verification.status !== "healthy") {
|
|
1116
|
-
throw new InitializationHealthError(indexResult);
|
|
1117
|
-
}
|
|
1118
|
-
const lifecycleRefresh = drainQueuedLifecycleEvents(resolvedRepo, backgroundPath);
|
|
1119
|
-
await fs.promises.rm(path.join(knodinHooksDir, HOOK_FAILURE_FILE), { force: true });
|
|
1120
|
-
let agentInstructionChanges = [];
|
|
1121
|
-
if (scope === "team") {
|
|
1122
|
-
const installed = await Promise.all([
|
|
1123
|
-
installManagedAgentInstructions(resolvedRepo, "AGENTS.md"),
|
|
1124
|
-
installManagedAgentInstructions(resolvedRepo, "GEMINI.md"),
|
|
1094
|
+
const knodinHooksDir = path.join(resolvedRepo, ".knodin", "hooks");
|
|
1095
|
+
const hookInstallation = await prepareHookInstallation(resolvedRepo);
|
|
1096
|
+
const hooksDir = hookInstallation.hooksDir;
|
|
1097
|
+
await Promise.all([
|
|
1098
|
+
fs.promises.mkdir(knodinHooksDir, { recursive: true }),
|
|
1099
|
+
fs.promises.mkdir(hooksDir, { recursive: true }),
|
|
1125
1100
|
]);
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
}
|
|
1131
|
-
const requestedAgents = options.agents ?? [];
|
|
1132
|
-
const projectPathByAgent = {
|
|
1133
|
-
codex: ".codex/config.toml",
|
|
1134
|
-
gemini: ".gemini/settings.json",
|
|
1135
|
-
copilot: ".vscode/mcp.json",
|
|
1136
|
-
antigravity: ".agents/mcp_config.json",
|
|
1137
|
-
};
|
|
1138
|
-
const blockedAgents = [];
|
|
1139
|
-
const externalConfigurationOutcomes = [];
|
|
1140
|
-
if (scope === "personal" &&
|
|
1141
|
-
options.allowTrackedTransition &&
|
|
1142
|
-
priorIntegration?.scope === "team") {
|
|
1143
|
-
const cleanup = configureProjectAgents({
|
|
1144
|
-
repo: resolvedRepo,
|
|
1145
|
-
scope: "cli-only",
|
|
1146
|
-
agents: ["claude", "codex", "gemini", "copilot", "antigravity"],
|
|
1147
|
-
run: options.runAgentCommand,
|
|
1101
|
+
const backgroundPath = path.join(knodinHooksDir, "background-index.sh");
|
|
1102
|
+
await fs.promises.writeFile(backgroundPath, backgroundScript(options.command), {
|
|
1103
|
+
encoding: "utf-8",
|
|
1104
|
+
mode: 0o755,
|
|
1148
1105
|
});
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1106
|
+
await fs.promises.chmod(backgroundPath, 0o755);
|
|
1107
|
+
const hookManagerIntegration = installHookManagerIntegration(resolvedRepo);
|
|
1108
|
+
for (const hookName of HOOK_NAMES) {
|
|
1109
|
+
let preservedOriginal;
|
|
1110
|
+
if (hookInstallation.trackedHooksDir) {
|
|
1111
|
+
const relativeHook = `${hookInstallation.trackedHooksDir}/${hookName}`;
|
|
1112
|
+
const sourceHook = path.join(resolvedRepo, relativeHook);
|
|
1113
|
+
try {
|
|
1114
|
+
const stat = await fs.promises.stat(sourceHook);
|
|
1115
|
+
preservedOriginal =
|
|
1116
|
+
stat.isFile() && (stat.mode & 0o111) !== 0 ? `repo:${relativeHook}` : null;
|
|
1117
|
+
}
|
|
1118
|
+
catch {
|
|
1119
|
+
preservedOriginal = null;
|
|
1120
|
+
}
|
|
1121
|
+
}
|
|
1122
|
+
await installManagedHook(hooksDir, hookName, preservedOriginal);
|
|
1123
|
+
}
|
|
1124
|
+
for (const entry of await fs.promises.readdir(hooksDir, {
|
|
1125
|
+
withFileTypes: true,
|
|
1126
|
+
})) {
|
|
1127
|
+
if (entry.isFile())
|
|
1128
|
+
await preventLefthookAutoInstall(path.join(hooksDir, entry.name));
|
|
1129
|
+
}
|
|
1130
|
+
let agentInstructionChanges = [];
|
|
1131
|
+
let agentIntegration = {
|
|
1132
|
+
configured: [],
|
|
1133
|
+
removed: [],
|
|
1134
|
+
failed: [],
|
|
1135
|
+
projectFiles: [],
|
|
1136
|
+
};
|
|
1137
|
+
const externalConfigurationOutcomes = [];
|
|
1138
|
+
let excluded = [];
|
|
1139
|
+
if (configureIntegration && scope === "team") {
|
|
1140
|
+
const installed = await Promise.all([
|
|
1141
|
+
installManagedAgentInstructions(resolvedRepo, "AGENTS.md"),
|
|
1142
|
+
installManagedAgentInstructions(resolvedRepo, "GEMINI.md"),
|
|
1143
|
+
]);
|
|
1144
|
+
agentInstructionChanges = installed.filter((change) => change !== null);
|
|
1145
|
+
}
|
|
1146
|
+
else if (configureIntegration) {
|
|
1147
|
+
agentInstructionChanges = await removeManagedPersonalArtifacts(resolvedRepo, options.allowTrackedTransition);
|
|
1148
|
+
}
|
|
1149
|
+
const requestedAgents = options.agents ?? [];
|
|
1150
|
+
const projectPathByAgent = {
|
|
1151
|
+
codex: ".codex/config.toml",
|
|
1152
|
+
gemini: ".gemini/settings.json",
|
|
1153
|
+
copilot: ".vscode/mcp.json",
|
|
1154
|
+
antigravity: ".agents/mcp_config.json",
|
|
1155
|
+
};
|
|
1156
|
+
const blockedAgents = [];
|
|
1157
|
+
if (configureIntegration) {
|
|
1158
|
+
if (scope === "personal" &&
|
|
1159
|
+
options.allowTrackedTransition &&
|
|
1160
|
+
priorIntegration?.scope === "team") {
|
|
1161
|
+
const cleanup = configureProjectAgents({
|
|
1162
|
+
repo: resolvedRepo,
|
|
1163
|
+
scope: "cli-only",
|
|
1164
|
+
agents: ["claude", "codex", "gemini", "copilot", "antigravity"],
|
|
1165
|
+
run: options.runAgentCommand,
|
|
1166
|
+
});
|
|
1167
|
+
if (cleanup.failed.length > 0)
|
|
1168
|
+
throw new Error(`knodin configure: could not remove tracked team integration: ${cleanup.failed[0]?.message}`);
|
|
1169
|
+
if (cleanup.removed.includes("claude"))
|
|
1170
|
+
externalConfigurationOutcomes.push({
|
|
1171
|
+
system: "claude-local-mcp",
|
|
1172
|
+
state: "removal-attempted",
|
|
1173
|
+
});
|
|
1174
|
+
}
|
|
1175
|
+
const eligibleAgents = scope === "team"
|
|
1176
|
+
? requestedAgents
|
|
1177
|
+
: requestedAgents.filter((agent) => {
|
|
1178
|
+
const projectPath = agent === "claude" ? ".mcp.json" : projectPathByAgent[agent];
|
|
1179
|
+
if (!projectPath ||
|
|
1180
|
+
!isTracked(resolvedRepo, projectPath) ||
|
|
1181
|
+
(scope === "cli-only" && options.allowTrackedTransition))
|
|
1182
|
+
return true;
|
|
1183
|
+
if (options.allowTrackedTransition && priorIntegration?.scope === "team")
|
|
1184
|
+
return false;
|
|
1185
|
+
blockedAgents.push({
|
|
1186
|
+
agent,
|
|
1187
|
+
message: `${projectPath} is tracked; personal mode left it unchanged and did not exclude it`,
|
|
1188
|
+
});
|
|
1189
|
+
return false;
|
|
1190
|
+
});
|
|
1191
|
+
agentIntegration = configureProjectAgents({
|
|
1192
|
+
repo: resolvedRepo,
|
|
1193
|
+
scope,
|
|
1194
|
+
agents: eligibleAgents,
|
|
1195
|
+
run: options.runAgentCommand,
|
|
1155
1196
|
});
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1197
|
+
const skillClients = (scope === "team"
|
|
1198
|
+
? ["codex", "claude", "gemini"]
|
|
1199
|
+
: agentIntegration.configured.filter((agent) => ["codex", "claude", "gemini"].includes(agent)));
|
|
1200
|
+
const skillIntegration = scope === "cli-only"
|
|
1201
|
+
? removeKnodinSkills({
|
|
1202
|
+
repo: resolvedRepo,
|
|
1203
|
+
scope: "team",
|
|
1204
|
+
clients: ["codex", "claude", "gemini"],
|
|
1205
|
+
})
|
|
1206
|
+
: installKnodinSkills({
|
|
1207
|
+
repo: resolvedRepo,
|
|
1208
|
+
scope,
|
|
1209
|
+
clients: skillClients,
|
|
1210
|
+
});
|
|
1211
|
+
for (const issue of skillIntegration.issues)
|
|
1212
|
+
agentIntegration.failed.push({
|
|
1213
|
+
agent: skillClients.find((client) => issue.path.includes(`.${client}`)) ?? "codex",
|
|
1214
|
+
message: `${issue.path}: ${issue.message}`,
|
|
1215
|
+
});
|
|
1216
|
+
if (scope === "personal" && agentIntegration.configured.includes("claude"))
|
|
1217
|
+
externalConfigurationOutcomes.push({
|
|
1218
|
+
system: "claude-local-mcp",
|
|
1219
|
+
state: "configured-or-present",
|
|
1220
|
+
});
|
|
1221
|
+
if (scope === "cli-only" &&
|
|
1222
|
+
agentIntegration.removed.includes("claude") &&
|
|
1223
|
+
!externalConfigurationOutcomes.some(({ system, state }) => system === "claude-local-mcp" && state === "removal-attempted"))
|
|
1224
|
+
externalConfigurationOutcomes.push({
|
|
1225
|
+
system: "claude-local-mcp",
|
|
1226
|
+
state: "removal-attempted",
|
|
1227
|
+
});
|
|
1228
|
+
agentIntegration.failed.push(...blockedAgents);
|
|
1229
|
+
await writeRepositoryIntegrationConfig(resolvedRepo, {
|
|
1230
|
+
scope,
|
|
1231
|
+
agents: agentIntegration.configured,
|
|
1170
1232
|
});
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1233
|
+
if (scope === "team") {
|
|
1234
|
+
await ensureTeamGitIgnore(resolvedRepo);
|
|
1235
|
+
await removeManagedExcludes(resolvedRepo);
|
|
1236
|
+
}
|
|
1237
|
+
else if (scope === "cli-only") {
|
|
1238
|
+
await removeManagedExcludes(resolvedRepo);
|
|
1239
|
+
}
|
|
1240
|
+
excluded =
|
|
1241
|
+
scope === "team"
|
|
1242
|
+
? []
|
|
1243
|
+
: await excludeUntrackedPaths(resolvedRepo, [
|
|
1244
|
+
...(isTracked(resolvedRepo, ".knodin") ? [] : [".knodin/"]),
|
|
1245
|
+
...agentIntegration.projectFiles,
|
|
1246
|
+
]);
|
|
1247
|
+
}
|
|
1248
|
+
if (!configureIntegration && !isTracked(resolvedRepo, ".knodin")) {
|
|
1249
|
+
excluded = await excludeUntrackedPaths(resolvedRepo, [".knodin/"]);
|
|
1250
|
+
}
|
|
1251
|
+
if (hookManagerIntegration) {
|
|
1252
|
+
const managerExcludes = await excludeUntrackedPaths(resolvedRepo, [
|
|
1253
|
+
hookManagerIntegration.localConfig,
|
|
1254
|
+
]);
|
|
1255
|
+
excluded = [...new Set([...excluded, ...managerExcludes])].sort(compareBytes);
|
|
1256
|
+
}
|
|
1257
|
+
registerInitializedWorktree(resolvedRepo);
|
|
1258
|
+
// Configuration is graph-visible, so explicit configuration must complete
|
|
1259
|
+
// before the final index and health verification. Plain init reaches this
|
|
1260
|
+
// point without touching agent instructions, MCP files, skills, or receipts.
|
|
1261
|
+
const indexResult = await options.index(resolvedRepo, {
|
|
1262
|
+
onProgress: options.onProgress,
|
|
1183
1263
|
});
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1264
|
+
if (isIndexResult(indexResult) && indexResult.verification.status !== "healthy") {
|
|
1265
|
+
throw new InitializationHealthError(indexResult);
|
|
1266
|
+
}
|
|
1267
|
+
const lifecycleRefresh = drainQueuedLifecycleEvents(resolvedRepo, backgroundPath);
|
|
1268
|
+
await fs.promises.rm(path.join(knodinHooksDir, HOOK_FAILURE_FILE), {
|
|
1269
|
+
force: true,
|
|
1190
1270
|
});
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1271
|
+
const detectedFilesystemChanges = filesystemChanges(beforeMutation, mutationSnapshot(mutationTargets, true));
|
|
1272
|
+
return {
|
|
1273
|
+
scope,
|
|
1274
|
+
knodin: ".knodin",
|
|
1275
|
+
database: ".knodin/db.sqlite",
|
|
1276
|
+
backgroundIndexer: ".knodin/hooks/background-index.sh",
|
|
1277
|
+
hooksDirectory: path.relative(resolvedRepo, hooksDir) || ".",
|
|
1278
|
+
gitHooks: [...HOOK_NAMES],
|
|
1279
|
+
claudeSettings: null,
|
|
1280
|
+
agentInstructions: scope === "team" ? "AGENTS.md" : null,
|
|
1281
|
+
agentIntegration,
|
|
1282
|
+
agentInstructionChanges,
|
|
1283
|
+
filesystemChanges: detectedFilesystemChanges,
|
|
1284
|
+
externalConfigurationOutcomes,
|
|
1285
|
+
excluded,
|
|
1286
|
+
lifecycleRefresh,
|
|
1287
|
+
hookManagerIntegration,
|
|
1288
|
+
};
|
|
1202
1289
|
}
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
: await excludeUntrackedPaths(resolvedRepo, [
|
|
1206
|
-
...(isTracked(resolvedRepo, ".knodin") ? [] : [".knodin/"]),
|
|
1207
|
-
...agentIntegration.projectFiles,
|
|
1208
|
-
]);
|
|
1209
|
-
if (hookManagerIntegration) {
|
|
1210
|
-
const managerExcludes = await excludeUntrackedPaths(resolvedRepo, [
|
|
1211
|
-
hookManagerIntegration.localConfig,
|
|
1212
|
-
]);
|
|
1213
|
-
excluded = [...new Set([...excluded, ...managerExcludes])].sort(compareBytes);
|
|
1290
|
+
finally {
|
|
1291
|
+
lifecycleLease.release();
|
|
1214
1292
|
}
|
|
1215
|
-
registerInitializedWorktree(resolvedRepo);
|
|
1216
|
-
const detectedFilesystemChanges = filesystemChanges(beforeMutation, mutationSnapshot(mutationTargets, true));
|
|
1217
|
-
return {
|
|
1218
|
-
scope,
|
|
1219
|
-
knodin: ".knodin",
|
|
1220
|
-
database: ".knodin/db.sqlite",
|
|
1221
|
-
backgroundIndexer: ".knodin/hooks/background-index.sh",
|
|
1222
|
-
hooksDirectory: path.relative(resolvedRepo, hooksDir) || ".",
|
|
1223
|
-
gitHooks: [...HOOK_NAMES],
|
|
1224
|
-
claudeSettings: null,
|
|
1225
|
-
agentInstructions: scope === "team" ? "AGENTS.md" : null,
|
|
1226
|
-
agentIntegration,
|
|
1227
|
-
agentInstructionChanges,
|
|
1228
|
-
filesystemChanges: detectedFilesystemChanges,
|
|
1229
|
-
externalConfigurationOutcomes,
|
|
1230
|
-
excluded,
|
|
1231
|
-
lifecycleRefresh,
|
|
1232
|
-
hookManagerIntegration,
|
|
1233
|
-
};
|
|
1234
1293
|
}
|
|
1235
1294
|
async function matchesManagedFile(filePath, expected, executable) {
|
|
1236
1295
|
try {
|