agent-knowledge-cli 0.1.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (88) hide show
  1. agent_knowledge/__init__.py +3 -0
  2. agent_knowledge/__main__.py +3 -0
  3. agent_knowledge/assets/__init__.py +0 -0
  4. agent_knowledge/assets/claude/global.md +44 -0
  5. agent_knowledge/assets/claude/project-template.md +46 -0
  6. agent_knowledge/assets/claude/scripts/install.sh +85 -0
  7. agent_knowledge/assets/commands/doctor.md +21 -0
  8. agent_knowledge/assets/commands/global-knowledge-sync.md +27 -0
  9. agent_knowledge/assets/commands/graphify-sync.md +26 -0
  10. agent_knowledge/assets/commands/knowledge-sync.md +26 -0
  11. agent_knowledge/assets/commands/ship.md +29 -0
  12. agent_knowledge/assets/rules/generate-architecture-doc.mdc +87 -0
  13. agent_knowledge/assets/rules/history-backfill.mdc +67 -0
  14. agent_knowledge/assets/rules/memory-bootstrap.mdc +53 -0
  15. agent_knowledge/assets/rules/memory-writeback.mdc +90 -0
  16. agent_knowledge/assets/rules/shared-memory.mdc +102 -0
  17. agent_knowledge/assets/rules/workflow-orchestration.mdc +93 -0
  18. agent_knowledge/assets/rules-global/action-first.mdc +26 -0
  19. agent_knowledge/assets/rules-global/no-icons-emojis.mdc +16 -0
  20. agent_knowledge/assets/rules-global/no-unsolicited-docs.mdc +20 -0
  21. agent_knowledge/assets/scripts/bootstrap-memory-tree.sh +389 -0
  22. agent_knowledge/assets/scripts/compact-memory.sh +191 -0
  23. agent_knowledge/assets/scripts/doctor.sh +137 -0
  24. agent_knowledge/assets/scripts/global-knowledge-sync.sh +372 -0
  25. agent_knowledge/assets/scripts/graphify-sync.sh +397 -0
  26. agent_knowledge/assets/scripts/import-agent-history.sh +706 -0
  27. agent_knowledge/assets/scripts/install-project-links.sh +258 -0
  28. agent_knowledge/assets/scripts/lib/knowledge-common.sh +875 -0
  29. agent_knowledge/assets/scripts/measure-token-savings.py +540 -0
  30. agent_knowledge/assets/scripts/ship.sh +256 -0
  31. agent_knowledge/assets/scripts/update-knowledge.sh +341 -0
  32. agent_knowledge/assets/scripts/validate-knowledge.sh +265 -0
  33. agent_knowledge/assets/skills/decision-recording/SKILL.md +124 -0
  34. agent_knowledge/assets/skills/history-backfill/SKILL.md +115 -0
  35. agent_knowledge/assets/skills/memory-compaction/SKILL.md +115 -0
  36. agent_knowledge/assets/skills/memory-management/SKILL.md +134 -0
  37. agent_knowledge/assets/skills/project-ontology-bootstrap/SKILL.md +173 -0
  38. agent_knowledge/assets/skills/session-management/SKILL.md +116 -0
  39. agent_knowledge/assets/skills-cursor/create-rule/SKILL.md +164 -0
  40. agent_knowledge/assets/skills-cursor/create-skill/SKILL.md +498 -0
  41. agent_knowledge/assets/skills-cursor/create-subagent/SKILL.md +225 -0
  42. agent_knowledge/assets/skills-cursor/migrate-to-skills/SKILL.md +134 -0
  43. agent_knowledge/assets/skills-cursor/shell/SKILL.md +24 -0
  44. agent_knowledge/assets/skills-cursor/update-cursor-settings/SKILL.md +122 -0
  45. agent_knowledge/assets/templates/dashboards/project-overview.template.md +24 -0
  46. agent_knowledge/assets/templates/dashboards/session-rollup.template.md +23 -0
  47. agent_knowledge/assets/templates/hooks/hooks.json.template +11 -0
  48. agent_knowledge/assets/templates/integrations/claude/CLAUDE.md +7 -0
  49. agent_knowledge/assets/templates/integrations/codex/AGENTS.md +7 -0
  50. agent_knowledge/assets/templates/integrations/cursor/agent-knowledge.mdc +11 -0
  51. agent_knowledge/assets/templates/integrations/cursor/hooks.json +11 -0
  52. agent_knowledge/assets/templates/memory/MEMORY.root.template.md +36 -0
  53. agent_knowledge/assets/templates/memory/branch.template.md +33 -0
  54. agent_knowledge/assets/templates/memory/decision.template.md +33 -0
  55. agent_knowledge/assets/templates/memory/profile.hybrid.yaml +16 -0
  56. agent_knowledge/assets/templates/memory/profile.ml-platform.yaml +18 -0
  57. agent_knowledge/assets/templates/memory/profile.robotics.yaml +19 -0
  58. agent_knowledge/assets/templates/memory/profile.web-app.yaml +16 -0
  59. agent_knowledge/assets/templates/portfolio/.obsidian/README.md +21 -0
  60. agent_knowledge/assets/templates/portfolio/.obsidian/app.json +5 -0
  61. agent_knowledge/assets/templates/portfolio/.obsidian/core-plugins.json +7 -0
  62. agent_knowledge/assets/templates/project/.agent-project.yaml +36 -0
  63. agent_knowledge/assets/templates/project/.agentknowledgeignore +10 -0
  64. agent_knowledge/assets/templates/project/AGENTS.md +87 -0
  65. agent_knowledge/assets/templates/project/agent-knowledge/.obsidian/README.md +23 -0
  66. agent_knowledge/assets/templates/project/agent-knowledge/.obsidian/app.json +5 -0
  67. agent_knowledge/assets/templates/project/agent-knowledge/.obsidian/core-plugins.json +7 -0
  68. agent_knowledge/assets/templates/project/agent-knowledge/Evidence/README.md +34 -0
  69. agent_knowledge/assets/templates/project/agent-knowledge/Evidence/imports/README.md +29 -0
  70. agent_knowledge/assets/templates/project/agent-knowledge/Evidence/raw/README.md +25 -0
  71. agent_knowledge/assets/templates/project/agent-knowledge/Memory/MEMORY.md +37 -0
  72. agent_knowledge/assets/templates/project/agent-knowledge/Memory/decisions/decisions.md +31 -0
  73. agent_knowledge/assets/templates/project/agent-knowledge/Outputs/README.md +24 -0
  74. agent_knowledge/assets/templates/project/agent-knowledge/STATUS.md +43 -0
  75. agent_knowledge/assets/templates/project/agent-knowledge/Sessions/README.md +21 -0
  76. agent_knowledge/assets/templates/project/agent-knowledge/Templates/README.md +19 -0
  77. agent_knowledge/assets/templates/project/gitignore.agent-knowledge +13 -0
  78. agent_knowledge/cli.py +457 -0
  79. agent_knowledge/runtime/__init__.py +0 -0
  80. agent_knowledge/runtime/integrations.py +154 -0
  81. agent_knowledge/runtime/paths.py +46 -0
  82. agent_knowledge/runtime/shell.py +22 -0
  83. agent_knowledge/runtime/sync.py +255 -0
  84. agent_knowledge_cli-0.1.2.dist-info/METADATA +155 -0
  85. agent_knowledge_cli-0.1.2.dist-info/RECORD +88 -0
  86. agent_knowledge_cli-0.1.2.dist-info/WHEEL +4 -0
  87. agent_knowledge_cli-0.1.2.dist-info/entry_points.txt +2 -0
  88. agent_knowledge_cli-0.1.2.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,256 @@
1
+ #!/bin/bash
2
+ #
3
+ # Project ship flow: validate, sync knowledge, commit, push, optionally open a PR.
4
+ #
5
+
6
+ set -euo pipefail
7
+
8
+ SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
9
+ # shellcheck source=/dev/null
10
+ . "$SCRIPT_DIR/lib/knowledge-common.sh"
11
+
12
+ usage() {
13
+ cat <<'EOF'
14
+ Usage:
15
+ scripts/ship.sh [project-dir]
16
+ scripts/ship.sh --project <dir> [--message <commit-message>] [--open-pr] [--open-pr=auto] [--dry-run] [--json] [--summary-file <file>]
17
+ EOF
18
+ }
19
+
20
+ TARGET_PROJECT_ARG="."
21
+ POSITIONAL=()
22
+ COMMIT_MESSAGE=""
23
+ OPEN_PR_MODE="no"
24
+ VALIDATION_LABELS=()
25
+ VALIDATION_RESULTS=()
26
+ WARNINGS=()
27
+
28
+ while [ "$#" -gt 0 ]; do
29
+ if kc_parse_common_flag "$@" ; then
30
+ shift
31
+ continue
32
+ fi
33
+ flag_status=$?
34
+ if [ "$flag_status" -eq 2 ]; then
35
+ shift 2
36
+ continue
37
+ fi
38
+
39
+ case "$1" in
40
+ --project)
41
+ TARGET_PROJECT_ARG="${2:-.}"
42
+ shift 2
43
+ ;;
44
+ --message)
45
+ COMMIT_MESSAGE="${2:-}"
46
+ shift 2
47
+ ;;
48
+ --open-pr)
49
+ OPEN_PR_MODE="yes"
50
+ shift
51
+ ;;
52
+ --open-pr=auto)
53
+ OPEN_PR_MODE="auto"
54
+ shift
55
+ ;;
56
+ *)
57
+ POSITIONAL+=("$1")
58
+ shift
59
+ ;;
60
+ esac
61
+ done
62
+
63
+ if [ "$SHOW_HELP" -eq 1 ]; then
64
+ usage
65
+ exit 0
66
+ fi
67
+
68
+ if [ ${#POSITIONAL[@]} -ge 1 ]; then
69
+ TARGET_PROJECT_ARG="${POSITIONAL[0]}"
70
+ fi
71
+
72
+ kc_load_project_context "$TARGET_PROJECT_ARG"
73
+ kc_git_available || kc_fail "Ship requires a git repo."
74
+
75
+ branch="$(git -C "$TARGET_PROJECT" rev-parse --abbrev-ref HEAD)"
76
+ [ "$branch" != "HEAD" ] || kc_fail "Refusing to ship from a detached HEAD."
77
+
78
+ if [ -n "$(git -C "$TARGET_PROJECT" ls-files -u)" ]; then
79
+ kc_fail "Refusing to ship with unresolved merge conflicts."
80
+ fi
81
+
82
+ detect_validation_commands() {
83
+ if [ -f "$TARGET_PROJECT/Makefile" ] && grep -qE '^(test|check):' "$TARGET_PROJECT/Makefile" 2>/dev/null; then
84
+ if grep -q '^test:' "$TARGET_PROJECT/Makefile" 2>/dev/null; then
85
+ printf '%s\n' "make test"
86
+ else
87
+ printf '%s\n' "make check"
88
+ fi
89
+ fi
90
+
91
+ if [ -f "$TARGET_PROJECT/package.json" ]; then
92
+ if grep -q '"lint"' "$TARGET_PROJECT/package.json" 2>/dev/null; then
93
+ if [ -f "$TARGET_PROJECT/pnpm-lock.yaml" ]; then
94
+ printf '%s\n' "pnpm run lint"
95
+ elif [ -f "$TARGET_PROJECT/yarn.lock" ]; then
96
+ printf '%s\n' "yarn lint"
97
+ else
98
+ printf '%s\n' "npm run lint --if-present"
99
+ fi
100
+ fi
101
+ if grep -q '"test"' "$TARGET_PROJECT/package.json" 2>/dev/null; then
102
+ if [ -f "$TARGET_PROJECT/pnpm-lock.yaml" ]; then
103
+ printf '%s\n' "pnpm test"
104
+ elif [ -f "$TARGET_PROJECT/yarn.lock" ]; then
105
+ printf '%s\n' "yarn test"
106
+ else
107
+ printf '%s\n' "npm test --if-present"
108
+ fi
109
+ fi
110
+ fi
111
+
112
+ if [ -f "$TARGET_PROJECT/Cargo.toml" ]; then
113
+ printf '%s\n' "cargo test"
114
+ fi
115
+
116
+ if [ -f "$TARGET_PROJECT/go.mod" ]; then
117
+ printf '%s\n' "go test ./..."
118
+ fi
119
+
120
+ if [ -f "$TARGET_PROJECT/pyproject.toml" ] || [ -f "$TARGET_PROJECT/requirements.txt" ]; then
121
+ if [ -d "$TARGET_PROJECT/tests" ] || [ -f "$TARGET_PROJECT/pytest.ini" ]; then
122
+ printf '%s\n' "python -m pytest -q"
123
+ fi
124
+ fi
125
+ }
126
+
127
+ run_validation() {
128
+ local label="$1"
129
+ local command="$2"
130
+
131
+ VALIDATION_LABELS+=("$label")
132
+ kc_run_shell_command "$label" "$command" "$TARGET_PROJECT"
133
+ VALIDATION_RESULTS+=("$label:$KC_COMMAND_STATUS")
134
+ if [ "$KC_COMMAND_STATUS" = "failed" ]; then
135
+ kc_err "$KC_COMMAND_OUTPUT"
136
+ kc_fail "Validation failed: $label"
137
+ fi
138
+ }
139
+
140
+ validation_commands="$(detect_validation_commands | awk 'NF && !seen[$0]++ { print $0 }')"
141
+ if [ -n "$validation_commands" ]; then
142
+ while IFS= read -r command; do
143
+ [ -n "$command" ] || continue
144
+ run_validation "$command" "$command"
145
+ done <<EOF
146
+ $validation_commands
147
+ EOF
148
+ else
149
+ WARNINGS+=("No standard validation commands were detected.")
150
+ fi
151
+
152
+ validate_args=(--project "$TARGET_PROJECT")
153
+ if [ "$DRY_RUN" -eq 1 ]; then
154
+ validate_args+=(--dry-run)
155
+ fi
156
+ kc_run_child_script "$SCRIPT_DIR/validate-knowledge.sh" "${validate_args[@]}"
157
+
158
+ sync_args=(--project "$TARGET_PROJECT" --compact)
159
+ if [ "$DRY_RUN" -eq 1 ]; then
160
+ sync_args+=(--dry-run)
161
+ fi
162
+ kc_run_child_script "$SCRIPT_DIR/update-knowledge.sh" "${sync_args[@]}"
163
+
164
+ status_lines="$(git -C "$TARGET_PROJECT" status --short)"
165
+ changed_files="$(kc_git_changed_files || true)"
166
+
167
+ if [ -z "$status_lines" ]; then
168
+ WARNINGS+=("No repo changes to commit after validation and knowledge sync.")
169
+ fi
170
+
171
+ if [ -z "$COMMIT_MESSAGE" ]; then
172
+ scope="$(printf '%s\n' "$changed_files" | awk -F/ 'NF { print $1 }' | grep -v '^agent-knowledge$' | awk '!seen[$0]++' | head -3 | paste -sd ', ' -)"
173
+ if [ -n "$scope" ]; then
174
+ COMMIT_MESSAGE="chore: ship $scope updates"
175
+ else
176
+ COMMIT_MESSAGE="chore: sync project knowledge"
177
+ fi
178
+ fi
179
+
180
+ knowledge_external=0
181
+ case "$KNOWLEDGE_REAL_DIR" in
182
+ "$TARGET_PROJECT"/*)
183
+ knowledge_external=0
184
+ ;;
185
+ *)
186
+ knowledge_external=1
187
+ WARNINGS+=("Knowledge source of truth lives outside the repo and is not staged here: $KNOWLEDGE_REAL_DIR")
188
+ ;;
189
+ esac
190
+
191
+ if [ -n "$status_lines" ]; then
192
+ kc_run_shell_command "git add" "git add -A" "$TARGET_PROJECT"
193
+ [ "$KC_COMMAND_STATUS" != "failed" ] || kc_fail "git add failed."
194
+
195
+ kc_run_shell_command "git commit" "git commit -m \"$(printf '%s' "$COMMIT_MESSAGE" | sed 's/"/\\"/g')\"" "$TARGET_PROJECT"
196
+ if [ "$KC_COMMAND_STATUS" = "failed" ]; then
197
+ if printf '%s' "$KC_COMMAND_OUTPUT" | grep -qi 'nothing to commit'; then
198
+ WARNINGS+=("git commit reported nothing to commit.")
199
+ else
200
+ kc_err "$KC_COMMAND_OUTPUT"
201
+ kc_fail "git commit failed."
202
+ fi
203
+ fi
204
+ fi
205
+
206
+ if git -C "$TARGET_PROJECT" remote get-url origin >/dev/null 2>&1; then
207
+ upstream="$(git -C "$TARGET_PROJECT" rev-parse --abbrev-ref --symbolic-full-name '@{u}' 2>/dev/null || true)"
208
+ if [ -n "$upstream" ]; then
209
+ kc_run_shell_command "git push" "git push" "$TARGET_PROJECT"
210
+ else
211
+ kc_run_shell_command "git push -u" "git push -u origin $branch" "$TARGET_PROJECT"
212
+ fi
213
+ else
214
+ WARNINGS+=("No origin remote configured; push skipped.")
215
+ fi
216
+
217
+ should_open_pr=0
218
+ if [ "$OPEN_PR_MODE" = "yes" ]; then
219
+ should_open_pr=1
220
+ elif [ "$OPEN_PR_MODE" = "auto" ] && command -v gh >/dev/null 2>&1 && [ "$branch" != "main" ] && [ "$branch" != "master" ]; then
221
+ should_open_pr=1
222
+ fi
223
+
224
+ if [ "$should_open_pr" -eq 1 ]; then
225
+ if command -v gh >/dev/null 2>&1; then
226
+ kc_run_shell_command "gh pr create" "gh pr create --fill" "$TARGET_PROJECT"
227
+ else
228
+ WARNINGS+=("GitHub CLI is unavailable; PR creation skipped.")
229
+ fi
230
+ fi
231
+
232
+ json_summary="{"
233
+ json_summary="$json_summary\"script\":\"ship\","
234
+ json_summary="$json_summary\"project_root\":\"$(kc_json_escape "$TARGET_PROJECT")\","
235
+ json_summary="$json_summary\"branch\":\"$(kc_json_escape "$branch")\","
236
+ json_summary="$json_summary\"commit_message\":\"$(kc_json_escape "$COMMIT_MESSAGE")\","
237
+ json_summary="$json_summary\"dry_run\":$(kc_json_bool "$DRY_RUN"),"
238
+ json_summary="$json_summary\"knowledge_external\":$(kc_json_bool "$knowledge_external"),"
239
+ json_summary="$json_summary\"validations\":$(kc_json_array "${VALIDATION_RESULTS[@]+"${VALIDATION_RESULTS[@]}"}"),"
240
+ json_summary="$json_summary\"warnings\":$(kc_json_array "${WARNINGS[@]+"${WARNINGS[@]}"}")"
241
+ json_summary="$json_summary}"
242
+ kc_write_json_output "$json_summary"
243
+
244
+ if [ "$JSON_MODE" -ne 1 ]; then
245
+ kc_log "Ship summary: $TARGET_PROJECT"
246
+ kc_log " branch: $branch"
247
+ kc_log " commit message: $COMMIT_MESSAGE"
248
+ if [ ${#VALIDATION_RESULTS[@]} -gt 0 ]; then
249
+ kc_log " validations:"
250
+ printf ' %s\n' "${VALIDATION_RESULTS[@]+"${VALIDATION_RESULTS[@]}"}"
251
+ fi
252
+ if [ ${#WARNINGS[@]} -gt 0 ]; then
253
+ kc_log " warnings:"
254
+ printf ' %s\n' "${WARNINGS[@]+"${WARNINGS[@]}"}"
255
+ fi
256
+ fi
@@ -0,0 +1,341 @@
1
+ #!/bin/bash
2
+ #
3
+ # Project-level knowledge refresh.
4
+ #
5
+
6
+ set -euo pipefail
7
+
8
+ SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
9
+ AGENTS_RULES_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
10
+ DECISION_TEMPLATE="$AGENTS_RULES_DIR/templates/memory/decision.template.md"
11
+ # shellcheck source=/dev/null
12
+ . "$SCRIPT_DIR/lib/knowledge-common.sh"
13
+
14
+ usage() {
15
+ cat <<'EOF'
16
+ Usage:
17
+ scripts/update-knowledge.sh [project-dir]
18
+ scripts/update-knowledge.sh --project <dir> [--decision-title <title>] [--decision-why <text>] [--compact] [--dry-run] [--json] [--summary-file <file>]
19
+ EOF
20
+ }
21
+
22
+ TARGET_PROJECT_ARG="."
23
+ POSITIONAL=()
24
+ DECISION_TITLE=""
25
+ DECISION_WHY=""
26
+ DECISION_SLUG=""
27
+ RUN_COMPACTION=0
28
+ UPDATED_NOTES=()
29
+ SKIPPED=()
30
+ WARNINGS=()
31
+
32
+ while [ "$#" -gt 0 ]; do
33
+ if kc_parse_common_flag "$@" ; then
34
+ shift
35
+ continue
36
+ fi
37
+ flag_status=$?
38
+ if [ "$flag_status" -eq 2 ]; then
39
+ shift 2
40
+ continue
41
+ fi
42
+
43
+ case "$1" in
44
+ --project)
45
+ TARGET_PROJECT_ARG="${2:-.}"
46
+ shift 2
47
+ ;;
48
+ --decision-title)
49
+ DECISION_TITLE="${2:-}"
50
+ shift 2
51
+ ;;
52
+ --decision-why)
53
+ DECISION_WHY="${2:-}"
54
+ shift 2
55
+ ;;
56
+ --decision-slug)
57
+ DECISION_SLUG="${2:-}"
58
+ shift 2
59
+ ;;
60
+ --compact)
61
+ RUN_COMPACTION=1
62
+ shift
63
+ ;;
64
+ *)
65
+ POSITIONAL+=("$1")
66
+ shift
67
+ ;;
68
+ esac
69
+ done
70
+
71
+ if [ "$SHOW_HELP" -eq 1 ]; then
72
+ usage
73
+ exit 0
74
+ fi
75
+
76
+ if [ ${#POSITIONAL[@]} -ge 1 ]; then
77
+ TARGET_PROJECT_ARG="${POSITIONAL[0]}"
78
+ fi
79
+
80
+ kc_load_project_context "$TARGET_PROJECT_ARG"
81
+
82
+ if [ ! -e "$KNOWLEDGE_POINTER_PATH" ]; then
83
+ kc_fail "Missing ./agent-knowledge pointer. Run: agent-knowledge init"
84
+ fi
85
+
86
+ kc_require_knowledge_pointer
87
+
88
+ if [ ! -f "$MEMORY_ROOT" ] || [ ! -f "$STATUS_FILE" ]; then
89
+ bootstrap_args=(--project "$TARGET_PROJECT")
90
+ if [ "$DRY_RUN" -eq 1 ]; then
91
+ bootstrap_args+=(--dry-run)
92
+ fi
93
+ "$SCRIPT_DIR/bootstrap-memory-tree.sh" "${bootstrap_args[@]}"
94
+ kc_load_project_context "$TARGET_PROJECT"
95
+ kc_require_knowledge_pointer
96
+ fi
97
+
98
+ changed_files="$(kc_git_changed_files || true)"
99
+
100
+ format_paths_inline() {
101
+ local paths_text="$1"
102
+ local limit="$2"
103
+ local count=0
104
+ local line=""
105
+ local output=""
106
+
107
+ while IFS= read -r line; do
108
+ [ -n "$line" ] || continue
109
+ count=$((count + 1))
110
+ if [ "$count" -le "$limit" ]; then
111
+ if [ -n "$output" ]; then
112
+ output="$output, "
113
+ fi
114
+ output="$output\`$line\`"
115
+ fi
116
+ done <<EOF
117
+ $paths_text
118
+ EOF
119
+
120
+ if [ "$count" -gt "$limit" ]; then
121
+ output="$output, ..."
122
+ fi
123
+ printf '%s' "$output"
124
+ }
125
+
126
+ classify_path() {
127
+ local path="$1"
128
+ local candidates=""
129
+ local existing=""
130
+
131
+ case "$path" in
132
+ agent-knowledge/*)
133
+ return 0
134
+ ;;
135
+ .github/workflows/*|deploy/*|deployment/*|infra/*)
136
+ candidates="deployments architecture"
137
+ ;;
138
+ package.json|package-lock.json|pnpm-lock.yaml|yarn.lock|pnpm-workspace.yaml|nx.json|turbo.json|pyproject.toml|requirements.txt|Cargo.toml|go.mod|CMakeLists.txt|package.xml|Makefile)
139
+ candidates="stack"
140
+ ;;
141
+ *.eslintrc|*.eslintrc.js|*.eslintrc.cjs|eslint.config.js|eslint.config.mjs|eslint.config.cjs|.editorconfig|.prettierrc|.prettierrc.json|.prettierrc.yaml|tsconfig.json|tsconfig.base.json|pytest.ini|mypy.ini|ruff.toml|.clang-format|.clang-tidy|.pre-commit-config.yaml)
142
+ candidates="conventions"
143
+ ;;
144
+ README.md|README.rst|AGENTS.md|CLAUDE.md|docs/*|src/*|app/*|apps/*|services/*|packages/*)
145
+ candidates="architecture"
146
+ ;;
147
+ *)
148
+ candidates="architecture"
149
+ ;;
150
+ esac
151
+
152
+ # Check each candidate against actually existing branch notes.
153
+ # A branch exists as either Memory/<name>.md or Memory/<name>/<name>.md.
154
+ for existing in $candidates; do
155
+ if [ -f "$MEMORY_DIR/$existing.md" ] || [ -f "$MEMORY_DIR/$existing/$existing.md" ]; then
156
+ printf '%s\n' "$existing"
157
+ fi
158
+ done
159
+ }
160
+
161
+ append_note_change() {
162
+ local file="$1"
163
+ local bullet="$2"
164
+ local rel
165
+ rel="$(kc_rel_knowledge_path "$file")"
166
+ kc_append_unique_bullet "$file" "Recent Changes" "$bullet" "$rel"
167
+ case "$KC_LAST_ACTION" in
168
+ updated|would-update)
169
+ UPDATED_NOTES+=("$rel")
170
+ ;;
171
+ esac
172
+ }
173
+
174
+ render_decision_note() {
175
+ local title="$1"
176
+ local why="$2"
177
+ local slug="$3"
178
+ local dst="$DECISIONS_DIR/$slug.md"
179
+ local tmp_file
180
+
181
+ tmp_file="$(mktemp)"
182
+ TEMPLATE_PROJECT_NAME="$PROJECT_NAME" \
183
+ TEMPLATE_PROFILE="$PROJECT_PROFILE" \
184
+ TEMPLATE_DATE="$(kc_today)" \
185
+ TEMPLATE_DECISION_SLUG="$slug" \
186
+ TEMPLATE_SHORT_TITLE="$title" \
187
+ TEMPLATE_WHAT_LINES="- Triggered by project knowledge sync for changed files." \
188
+ TEMPLATE_WHY_LINES="- ${why:-Durable understanding changed enough to justify a recorded note.}" \
189
+ TEMPLATE_ALTERNATIVES_LINES="- Record the change only in recent-change bullets." \
190
+ TEMPLATE_CONSEQUENCES_LINES="- Future sessions can link a concrete decision instead of inferring intent from evidence alone." \
191
+ TEMPLATE_SUPERSEDED_LINES="- None." \
192
+ awk '
193
+ BEGIN {
194
+ project = ENVIRON["TEMPLATE_PROJECT_NAME"]
195
+ profile = ENVIRON["TEMPLATE_PROFILE"]
196
+ date = ENVIRON["TEMPLATE_DATE"]
197
+ decision_slug = ENVIRON["TEMPLATE_DECISION_SLUG"]
198
+ short_title = ENVIRON["TEMPLATE_SHORT_TITLE"]
199
+ what_lines = ENVIRON["TEMPLATE_WHAT_LINES"]
200
+ why_lines = ENVIRON["TEMPLATE_WHY_LINES"]
201
+ alternatives_lines = ENVIRON["TEMPLATE_ALTERNATIVES_LINES"]
202
+ consequences_lines = ENVIRON["TEMPLATE_CONSEQUENCES_LINES"]
203
+ superseded_lines = ENVIRON["TEMPLATE_SUPERSEDED_LINES"]
204
+ }
205
+ {
206
+ gsub(/<project-name>/, project)
207
+ gsub(/<profile-type>/, profile)
208
+ gsub(/<date>/, date)
209
+ gsub(/<decision-slug>/, decision_slug)
210
+ gsub(/<short-title>/, short_title)
211
+ if ($0 == "<what-lines>") { print what_lines; next }
212
+ if ($0 == "<why-lines>") { print why_lines; next }
213
+ if ($0 == "<alternatives-lines>") { print alternatives_lines; next }
214
+ if ($0 == "<consequences-lines>") { print consequences_lines; next }
215
+ if ($0 == "<superseded-lines>") { print superseded_lines; next }
216
+ print
217
+ }
218
+ ' "$DECISION_TEMPLATE" > "$tmp_file"
219
+
220
+ kc_apply_temp_file "$tmp_file" "$dst" "Memory/decisions/$slug.md"
221
+ case "$KC_LAST_ACTION" in
222
+ created|updated|would-create|would-update)
223
+ UPDATED_NOTES+=("Memory/decisions/$slug.md")
224
+ ;;
225
+ esac
226
+
227
+ # Update decisions log (decisions.md, with fallback to legacy INDEX.md)
228
+ local decisions_log="$DECISIONS_DIR/decisions.md"
229
+ [ -f "$decisions_log" ] || decisions_log="$DECISIONS_DIR/INDEX.md"
230
+ local decisions_label="Memory/decisions/$(basename "$decisions_log")"
231
+ kc_append_unique_bullet "$decisions_log" "Current State" "- [$title]($slug.md) - Recorded from project sync." "$decisions_label"
232
+ kc_append_unique_bullet "$decisions_log" "Recent Changes" "- $(kc_today) - Updated decision note [$title]($slug.md)." "$decisions_label"
233
+ }
234
+
235
+ affected_areas_raw=""
236
+ if [ -n "$changed_files" ]; then
237
+ while IFS= read -r path; do
238
+ [ -n "$path" ] || continue
239
+ area_lines="$(classify_path "$path")"
240
+ if [ -n "$area_lines" ]; then
241
+ affected_areas_raw="${affected_areas_raw}${area_lines}"$'\n'
242
+ else
243
+ SKIPPED+=("$path")
244
+ fi
245
+ done <<EOF
246
+ $changed_files
247
+ EOF
248
+ else
249
+ WARNINGS+=("No git-tracked project changes detected; evidence refresh still ran.")
250
+ fi
251
+
252
+ affected_areas="$(printf '%s\n' "$affected_areas_raw" | awk 'NF && !seen[$0]++ { print $0 }')"
253
+ changed_paths_summary="$(format_paths_inline "$changed_files" 5)"
254
+
255
+ if [ -n "$affected_areas" ]; then
256
+ while IFS= read -r area; do
257
+ [ -n "$area" ] || continue
258
+ note_path="$MEMORY_DIR/$area.md"
259
+ if [ -f "$note_path" ]; then
260
+ append_note_change "$note_path" "- $(kc_today) - Synced after changes in $changed_paths_summary."
261
+ else
262
+ WARNINGS+=("Skipped missing area note for $area")
263
+ fi
264
+ done <<EOF
265
+ $affected_areas
266
+ EOF
267
+
268
+ areas_summary="$(printf '%s\n' "$affected_areas" | awk 'NF { items[++count]=$0 } END { for (i=1;i<=count;i++) { printf "`%s`", items[i]; if (i < count) printf ", " } }')"
269
+ append_note_change "$MEMORY_ROOT" "- $(kc_today) - Knowledge sync touched $areas_summary from $changed_paths_summary."
270
+ else
271
+ append_note_change "$MEMORY_ROOT" "- $(kc_today) - Knowledge sync ran with no new durable branch updates."
272
+ fi
273
+
274
+ if [ -n "$DECISION_TITLE" ]; then
275
+ if [ -z "$DECISION_SLUG" ]; then
276
+ DECISION_SLUG="$(kc_slugify "$DECISION_TITLE")"
277
+ fi
278
+ render_decision_note "$DECISION_TITLE" "$DECISION_WHY" "$DECISION_SLUG"
279
+ else
280
+ WARNINGS+=("No decision note update requested.")
281
+ fi
282
+
283
+ import_args=(--project "$TARGET_PROJECT")
284
+ if [ "$DRY_RUN" -eq 1 ]; then
285
+ import_args+=(--dry-run)
286
+ fi
287
+ kc_run_child_script "$SCRIPT_DIR/import-agent-history.sh" "${import_args[@]}"
288
+
289
+ if [ "$RUN_COMPACTION" -eq 1 ]; then
290
+ compact_args=(--project "$TARGET_PROJECT")
291
+ if [ "$DRY_RUN" -eq 1 ]; then
292
+ compact_args+=(--dry-run)
293
+ fi
294
+ kc_run_child_script "$SCRIPT_DIR/compact-memory.sh" "${compact_args[@]}"
295
+ fi
296
+
297
+ kc_status_load
298
+ if [ "${DRY_RUN:-0}" -eq 0 ]; then
299
+ STATUS_LAST_PROJECT_SYNC="$(kc_now_utc)"
300
+ fi
301
+ STATUS_WARNING_LINES="$(printf '%s\n' "${WARNINGS[@]+"${WARNINGS[@]}"}")"
302
+ kc_status_write "$STATUS_WARNING_LINES"
303
+
304
+ json_summary="{"
305
+ json_summary="$json_summary\"script\":\"update-knowledge\","
306
+ json_summary="$json_summary\"project_root\":\"$(kc_json_escape "$TARGET_PROJECT")\","
307
+ json_summary="$json_summary\"dry_run\":$(kc_json_bool "$DRY_RUN"),"
308
+ json_summary="$json_summary\"changed_files\":$(kc_json_array_from_lines "$changed_files"),"
309
+ json_summary="$json_summary\"affected_areas\":$(kc_json_array_from_lines "$affected_areas"),"
310
+ json_summary="$json_summary\"updated_notes\":$(kc_json_array "${UPDATED_NOTES[@]+"${UPDATED_NOTES[@]}"}"),"
311
+ json_summary="$json_summary\"skipped\":$(kc_json_array "${SKIPPED[@]+"${SKIPPED[@]}"}"),"
312
+ json_summary="$json_summary\"warnings\":$(kc_json_array "${WARNINGS[@]+"${WARNINGS[@]}"}")"
313
+ json_summary="$json_summary}"
314
+ kc_write_json_output "$json_summary"
315
+
316
+ if [ "$JSON_MODE" -ne 1 ]; then
317
+ kc_log "Knowledge sync: $TARGET_PROJECT"
318
+ if [ -n "$changed_files" ]; then
319
+ kc_log "Changed files:"
320
+ while IFS= read -r path; do
321
+ [ -n "$path" ] || continue
322
+ kc_log " $path"
323
+ done <<EOF
324
+ $changed_files
325
+ EOF
326
+ fi
327
+
328
+ kc_log ""
329
+ if [ ${#UPDATED_NOTES[@]} -gt 0 ]; then
330
+ kc_log "Updated memory notes:"
331
+ printf ' %s\n' "${UPDATED_NOTES[@]+"${UPDATED_NOTES[@]}"}"
332
+ else
333
+ kc_log "No durable memory note changes were required."
334
+ fi
335
+
336
+ if [ ${#SKIPPED[@]} -gt 0 ]; then
337
+ kc_log ""
338
+ kc_log "Skipped:"
339
+ printf ' %s\n' "${SKIPPED[@]+"${SKIPPED[@]}"}"
340
+ fi
341
+ fi