@ainova-systems/intelligence 0.11.0-rc.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +46 -0
  3. package/bin/intelligence.js +59 -0
  4. package/cli/commands/add.sh +133 -0
  5. package/cli/commands/doctor.sh +100 -0
  6. package/cli/commands/init.sh +96 -0
  7. package/cli/commands/install.sh +84 -0
  8. package/cli/commands/list.sh +28 -0
  9. package/cli/commands/migrate.sh +251 -0
  10. package/cli/commands/registry.sh +51 -0
  11. package/cli/commands/remove.sh +39 -0
  12. package/cli/commands/status.sh +34 -0
  13. package/cli/commands/sync.sh +22 -0
  14. package/cli/commands/update.sh +59 -0
  15. package/cli/commands/upgrade.sh +27 -0
  16. package/cli/intelligence +71 -0
  17. package/cli/lib/cli-common.sh +149 -0
  18. package/cli/lib/lockfile.sh +97 -0
  19. package/cli/lib/manifest.sh +211 -0
  20. package/cli/lib/registry.sh +141 -0
  21. package/cli/lib/semver.sh +127 -0
  22. package/engine/INIT.md +498 -0
  23. package/engine/agents/intelligence-architect.md +53 -0
  24. package/engine/agents/intelligence-operator.md +49 -0
  25. package/engine/docs/ADAPTERS.md +212 -0
  26. package/engine/docs/CLI.md +91 -0
  27. package/engine/docs/CONVENTIONS.md +440 -0
  28. package/engine/rules/intelligence-authoring.md +114 -0
  29. package/engine/scripts/VERSION +1 -0
  30. package/engine/scripts/adapters/_template.sh +86 -0
  31. package/engine/scripts/adapters/agents.sh +299 -0
  32. package/engine/scripts/adapters/claude.sh +136 -0
  33. package/engine/scripts/adapters/codex.sh +118 -0
  34. package/engine/scripts/adapters/copilot.sh +193 -0
  35. package/engine/scripts/adapters/cursor.sh +146 -0
  36. package/engine/scripts/adapters/opencode.sh +200 -0
  37. package/engine/scripts/adapters/pi.sh +256 -0
  38. package/engine/scripts/lib/common.sh +1602 -0
  39. package/engine/scripts/lib/layout.sh +51 -0
  40. package/engine/scripts/lib/migrations.sh +708 -0
  41. package/engine/scripts/sync.sh +311 -0
  42. package/engine/scripts/update.sh +237 -0
  43. package/engine/skills/intelligence-add-agent/SKILL.md +62 -0
  44. package/engine/skills/intelligence-add-rule/SKILL.md +54 -0
  45. package/engine/skills/intelligence-add-skill/SKILL.md +53 -0
  46. package/engine/skills/intelligence-extract-skill/SKILL.md +47 -0
  47. package/engine/skills/intelligence-install-adapter/SKILL.md +31 -0
  48. package/engine/skills/intelligence-learn-from-context/SKILL.md +69 -0
  49. package/engine/skills/intelligence-review-skills/SKILL.md +86 -0
  50. package/engine/skills/intelligence-sync/SKILL.md +18 -0
  51. package/engine/skills/intelligence-uninstall-adapter/SKILL.md +42 -0
  52. package/engine/skills/intelligence-update/SKILL.md +159 -0
  53. package/package.json +39 -0
  54. package/registry/index.yaml +15 -0
@@ -0,0 +1,311 @@
1
+ #!/bin/bash
2
+ # intelligence-sync: Unified sync entry point
3
+ # Reads config.yaml from the umbrella folder and syncs to all enabled targets.
4
+ #
5
+ # Usage:
6
+ # bash <umbrella>/sync/scripts/sync.sh # Sync all enabled targets
7
+ # bash <umbrella>/sync/scripts/sync.sh claude # Sync only Claude
8
+ # bash <umbrella>/sync/scripts/sync.sh cursor # Sync only Cursor
9
+ #
10
+ # Layout-agnostic: detect_layout finds the umbrella (the dir holding
11
+ # config.yaml; name not hardcoded) and migrates a pre-0.3.1 flat layout into
12
+ # the <umbrella>/sync/ module. REPO_ROOT: auto-detected from git, or via env.
13
+
14
+ set -euo pipefail
15
+
16
+ SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
17
+
18
+ source "$SCRIPT_DIR/lib/common.sh"
19
+ source "$SCRIPT_DIR/lib/layout.sh"
20
+ source "$SCRIPT_DIR/lib/migrations.sh"
21
+
22
+ # Umbrella = whatever folder holds config.yaml (name not hardcoded). The
23
+ # module is wherever this script lives — sync.sh self-locates and does NOT
24
+ # assume a folder name.
25
+ detect_layout "$SCRIPT_DIR"
26
+ INTELLIGENCE_DIR="$LS_UMBRELLA_DIR"
27
+
28
+ # sync.sh is a PURE synchronizer — it is not a migrator. Migration across a
29
+ # breaking-change gap is owned solely by the intelligence-update flow
30
+ # (update.sh + skill). sync refuses to run across an un-applied gap so a
31
+ # stale/mismatched engine can never generate against a newer layout.
32
+ if [ "${IS_CLI:-0}" != "1" ] && [ "$LS_LAYOUT" != "modular" ]; then
33
+ is_status needs-update "layout=$LS_LAYOUT"
34
+ echo "ERROR: engine is not in the modular layout (layout=$LS_LAYOUT)." >&2
35
+ echo " Run the update flow: tell your agent \"Update intelligence-sync\"." >&2
36
+ exit "$IS_RC_NEEDS_UPDATE"
37
+ fi
38
+
39
+ # CLI mode (IS_CLI=1): the engine runs from outside the repo (the npm install
40
+ # dir), so detect_layout cannot see the project — the project arrives through
41
+ # the environment instead: CONFIG_FILE names the root manifest, REPO_ROOT the
42
+ # project. The layout gate above is bypassed and the manifest is required up
43
+ # front, before the version gates read it.
44
+ if [ "${IS_CLI:-0}" = "1" ] && { [ -z "${CONFIG_FILE:-}" ] || [ ! -f "$CONFIG_FILE" ]; }; then
45
+ is_status config-missing "cli-mode"
46
+ echo "ERROR: CLI mode requires CONFIG_FILE to point at an existing manifest." >&2
47
+ exit "$IS_RC_CONFIG_MISSING"
48
+ fi
49
+
50
+ # Schema version lives in config.yaml (the frozen contract key).
51
+ _cf="${CONFIG_FILE:-$INTELLIGENCE_DIR/config.yaml}"
52
+
53
+ # Stale engine vs project schema stamped NEWER (ahead-of-engine) → refuse.
54
+ _vc_rc=0
55
+ check_version_compat "$_cf" || _vc_rc=$?
56
+ if [ "$_vc_rc" -ne 0 ]; then exit "$_vc_rc"; fi
57
+
58
+ # Schema gap → refuse; the update flow must apply the migration chain first.
59
+ # Per the contract, an ABSENT stamp means pre-0.3.1 / un-applied schema — a
60
+ # modular tree with no `sync_version` must NOT silently sync
61
+ # (that would bypass migrations). A correctly bootstrapped project always has
62
+ # the key (INIT emits it; update.sh stamps it).
63
+ _stamp="$(read_engine_stamp "$_cf")"
64
+ _eng="$(engine_version)"
65
+ if [ -z "$_stamp" ]; then
66
+ is_status needs-update "stamped= engine=$_eng (no sync_version)"
67
+ echo "ERROR: config.yaml has no sync_version — schema un-applied." >&2
68
+ echo " Run the update flow first: tell your agent \"Update intelligence-sync\"." >&2
69
+ exit "$IS_RC_NEEDS_UPDATE"
70
+ elif [ -n "$_eng" ] && _ver_gt "$_eng" "$_stamp"; then
71
+ is_status needs-update "stamped=$_stamp engine=$_eng"
72
+ echo "ERROR: project at $_stamp but engine is $_eng — pending breaking changes." >&2
73
+ echo " Run the update flow first: tell your agent \"Update intelligence-sync\"." >&2
74
+ exit "$IS_RC_NEEDS_UPDATE"
75
+ fi
76
+
77
+ # Normalize REPO_ROOT to the same `cd && pwd` style as INTELLIGENCE_DIR so
78
+ # prefix-stripping in path comparisons works (Git Bash on Windows: git
79
+ # rev-parse returns `D:/...` while cd && pwd returns `/d/...`; the styles
80
+ # do not match without normalization).
81
+ REPO_ROOT_RAW="${REPO_ROOT:-$(git rev-parse --show-toplevel 2>/dev/null || (cd "$INTELLIGENCE_DIR/.." && pwd))}"
82
+ REPO_ROOT="$(cd "$REPO_ROOT_RAW" && pwd)"
83
+ unset REPO_ROOT_RAW
84
+
85
+ # Layout tokens for generated output (see finalize_output_file in common.sh).
86
+ # Engine-shipped rules/agents cannot hardcode the umbrella's name — the project
87
+ # chooses it — so they write `<umbrella>` / `<module>` and every adapter expands
88
+ # them to these repo-relative paths on the way out. In CLI mode both values are
89
+ # part of the env contract: the umbrella is the project's content dir and the
90
+ # module is the staged engine content inside the package store.
91
+ if [ "${IS_CLI:-0}" = "1" ]; then
92
+ # Re-normalize CONFIG_FILE the same way REPO_ROOT is above — the CLI (or
93
+ # the Node shim behind it) may hand us `D:/...` while `cd && pwd` yields
94
+ # `/d/...`, and prefix comparisons downstream need one spelling.
95
+ CONFIG_FILE="$(cd "$(dirname "$CONFIG_FILE")" && pwd)/$(basename "$CONFIG_FILE")"
96
+ IS_UMBRELLA_REL="${IS_UMBRELLA_REL:-intelligence}"
97
+ IS_MODULE_REL="${IS_MODULE_REL:-.intelligence/engine}"
98
+ # Project-owned adapters keep their v1 home: <umbrella>/adapters/.
99
+ INTELLIGENCE_DIR="$REPO_ROOT/$IS_UMBRELLA_REL"
100
+ else
101
+ IS_UMBRELLA_REL="$(repo_rel_dir "$REPO_ROOT" "$LS_UMBRELLA_DIR")"
102
+ IS_MODULE_REL="$(repo_rel_dir "$REPO_ROOT" "$LS_MODULE_DIR")"
103
+ IS_UMBRELLA_REL="${IS_UMBRELLA_REL:-intelligence}"
104
+ IS_MODULE_REL="${IS_MODULE_REL:-intelligence/sync}"
105
+ fi
106
+ export IS_UMBRELLA_REL IS_MODULE_REL
107
+
108
+ # Config: explicit env > config.yaml in the umbrella folder
109
+ if [ -n "${CONFIG_FILE:-}" ]; then
110
+ CONFIG_FILE="$CONFIG_FILE"
111
+ elif [ -f "$INTELLIGENCE_DIR/config.yaml" ]; then
112
+ CONFIG_FILE="$INTELLIGENCE_DIR/config.yaml"
113
+ else
114
+ CONFIG_FILE=""
115
+ fi
116
+
117
+ if [ -z "$CONFIG_FILE" ] || [ ! -f "$CONFIG_FILE" ]; then
118
+ is_status config-missing "umbrella=$INTELLIGENCE_DIR"
119
+ echo "ERROR: Config file not found."
120
+ echo "Looked for: config.yaml (in $INTELLIGENCE_DIR)"
121
+ echo "Run INIT.md bootstrap or create config.yaml manually."
122
+ exit "$IS_RC_CONFIG_MISSING"
123
+ fi
124
+
125
+ TARGET_FILTER="${1:-}"
126
+
127
+ echo "=== intelligence-sync ==="
128
+ echo " Config: $CONFIG_FILE"
129
+ echo " Root: $REPO_ROOT"
130
+ echo ""
131
+
132
+ # Invariant: AGENTS.md is the canonical carrier of always-on rules for
133
+ # Cursor / Copilot / Codex / Pi / opencode (their adapters skip always-on
134
+ # rules to avoid duplication, since each tool reads AGENTS.md natively for
135
+ # baseline project context). If those targets are enabled, `agents` must
136
+ # also be enabled — otherwise always-on rules go nowhere for those tools.
137
+ # Skip the check when the user requested a single target via $TARGET_FILTER:
138
+ # they may be syncing only one IDE intentionally.
139
+ if [ -z "$TARGET_FILTER" ]; then
140
+ agents_enabled=$(is_target_enabled "$CONFIG_FILE" "agents")
141
+ if [ "$agents_enabled" != "1" ]; then
142
+ # AGENTS.md-dependent adapters: any tool whose adapter skips always-on
143
+ # rule emission (because the tool reads AGENTS.md natively) must be
144
+ # listed here. Add new adapters to this list when they ship.
145
+ for tool in cursor copilot codex pi opencode; do
146
+ if [ "$(is_target_enabled "$CONFIG_FILE" "$tool")" = "1" ]; then
147
+ echo "ERROR: targets.$tool is enabled but targets.agents is not." >&2
148
+ echo " $tool relies on AGENTS.md to deliver always-on rules — without it," >&2
149
+ echo " always-on rules would be invisible to $tool." >&2
150
+ echo " Either enable targets.agents in $CONFIG_FILE, or disable targets.$tool." >&2
151
+ exit 1
152
+ fi
153
+ done
154
+ fi
155
+ fi
156
+
157
+ # Remote sources (declared `packs:` reached via `@<pack>`, and inline `git+`
158
+ # specs in sources.*) are shallow-cloned on demand by resolve_source_dir. Give
159
+ # it a run-scoped cache dir so each spec is fetched at most once per sync and is
160
+ # removed on exit. Honors $TMPDIR (never hardcodes /tmp), mirroring update.sh.
161
+ IS_REMOTE_CACHE="$(mktemp -d -t intelligence-sync-remotes-XXXXXX 2>/dev/null || mktemp -d)"
162
+ export IS_REMOTE_CACHE
163
+ trap 'rm -rf "$IS_REMOTE_CACHE"' EXIT INT TERM
164
+
165
+ # A `@<pack>` token carries only the reference; its url / ref / mirror live in
166
+ # config.yaml. resolve_source_dir keeps its published two-argument contract so
167
+ # project-owned adapters written against it keep working, so the config path
168
+ # reaches it the same way the clone cache does — through the environment.
169
+ IS_CONFIG_FILE="$CONFIG_FILE"
170
+ export IS_CONFIG_FILE
171
+
172
+ # Fail closed on an undeclared pack reference or an unsafe mirror, before any
173
+ # adapter runs — see validate_pack_refs for why this cannot live in the resolver.
174
+ validate_pack_refs "$REPO_ROOT" "$CONFIG_FILE"
175
+
176
+ # A pack that declares `mirror:` is additionally materialized into a tracked
177
+ # directory in the repo, so an upstream bump is visible in `git diff` rather
178
+ # than only in the generated output. Without it, the pack stays transient.
179
+ while IFS= read -r mirror_rel; do
180
+ [ -n "$mirror_rel" ] && echo " Pack mirror: $mirror_rel"
181
+ done < <(list_pack_mirrors "$REPO_ROOT" "$CONFIG_FILE")
182
+
183
+ # Lint frontmatter across all source files (rules, agents, skills).
184
+ # Catches issues like unquoted colons that strict YAML consumers reject.
185
+ for section in rules agents skills; do
186
+ while IFS= read -r src; do
187
+ [ -z "$src" ] && continue
188
+ src_dir="$(resolve_source_dir "$REPO_ROOT" "$src")"
189
+ [ -d "$src_dir" ] || continue
190
+ if [ "$section" = "skills" ]; then
191
+ while IFS= read -r f; do
192
+ [ -n "$f" ] && lint_frontmatter "$f"
193
+ done < <(find "$src_dir" -mindepth 2 -maxdepth 2 -name 'SKILL.md' 2>/dev/null)
194
+ else
195
+ for f in "$src_dir"/*.md; do
196
+ [ -f "$f" ] && lint_frontmatter "$f"
197
+ done
198
+ fi
199
+ done < <(read_yaml_list "$CONFIG_FILE" "$section")
200
+ done
201
+
202
+ # Adapters come from two places, discovered by filename (minus `.sh`,
203
+ # `_template` excluded):
204
+ #
205
+ # 1. Built-in — <module>/scripts/adapters/ (upstream-owned; update.sh
206
+ # replaces this directory wholesale on every engine update)
207
+ # 2. Project — <umbrella>/adapters/ (project-owned; update.sh
208
+ # never touches it)
209
+ #
210
+ # A custom adapter therefore belongs in the umbrella's `adapters/` — put one in
211
+ # the engine's own adapters/ and the next update deletes it. A project adapter
212
+ # whose name matches a built-in overrides it (an escape hatch for patching a
213
+ # built-in without forking the engine — announced, never silent).
214
+ ADAPTERS=()
215
+ ADAPTER_FILES=()
216
+
217
+ register_adapter() {
218
+ local name="$1" file="$2"
219
+ local n=${#ADAPTERS[@]} i=0
220
+ while [ "$i" -lt "$n" ]; do
221
+ if [ "${ADAPTERS[$i]}" = "$name" ]; then
222
+ ADAPTER_FILES[$i]="$file"
223
+ echo " NOTE: project adapter '$name' overrides the built-in one ($(basename "$INTELLIGENCE_DIR")/adapters/$(basename "$file"))"
224
+ return 0
225
+ fi
226
+ i=$((i + 1))
227
+ done
228
+ ADAPTERS+=("$name")
229
+ ADAPTER_FILES+=("$file")
230
+ }
231
+
232
+ for adapters_dir in "$SCRIPT_DIR/adapters" "$INTELLIGENCE_DIR/adapters"; do
233
+ [ -d "$adapters_dir" ] || continue
234
+ for adapter_file in "$adapters_dir"/*.sh; do
235
+ [ -f "$adapter_file" ] || continue
236
+ adapter_name="$(basename "$adapter_file" .sh)"
237
+ [ "$adapter_name" = "_template" ] && continue
238
+ register_adapter "$adapter_name" "$adapter_file"
239
+ done
240
+ done
241
+
242
+ synced=0
243
+ adapter_count=${#ADAPTERS[@]}
244
+ adapter_idx=0
245
+
246
+ while [ "$adapter_idx" -lt "$adapter_count" ]; do
247
+ adapter="${ADAPTERS[$adapter_idx]}"
248
+ adapter_file="${ADAPTER_FILES[$adapter_idx]}"
249
+ adapter_idx=$((adapter_idx + 1))
250
+
251
+ # Skip if user requested specific target and this isn't it
252
+ if [ -n "$TARGET_FILTER" ] && [ "$adapter" != "$TARGET_FILTER" ]; then
253
+ continue
254
+ fi
255
+
256
+ # Check if target is enabled in config
257
+ enabled=$(is_target_enabled "$CONFIG_FILE" "$adapter")
258
+ if [ "$enabled" != "1" ] && [ -z "$TARGET_FILTER" ]; then
259
+ continue
260
+ fi
261
+
262
+ # Get output directory
263
+ output=$(get_target_output "$CONFIG_FILE" "$adapter")
264
+ if [ -z "$output" ]; then
265
+ output=".$adapter"
266
+ fi
267
+ output_dir="$REPO_ROOT/$output"
268
+
269
+ # Refuse to run if the output would clobber content — `output: "."`,
270
+ # `output: "intelligence"`, or a `../` path that escapes the repo. Applies
271
+ # to EVERY adapter, `agents` included: dir-writing adapters `rm -rf` their
272
+ # output, and `agents` overwrites whatever single file it is handed. Both
273
+ # turn a bad config line into a destructive write.
274
+ validate_output_path "$REPO_ROOT" "$CONFIG_FILE" "$adapter" "$output_dir"
275
+
276
+ # Source adapter and run.
277
+ # shellcheck source=/dev/null
278
+ source "$adapter_file"
279
+ "sync_to_$adapter" "$REPO_ROOT" "$CONFIG_FILE" "$output_dir"
280
+ echo ""
281
+ synced=$((synced + 1))
282
+ done
283
+
284
+ if [ $synced -eq 0 ]; then
285
+ if [ -n "$TARGET_FILTER" ]; then
286
+ echo "ERROR: Adapter '$TARGET_FILTER' not found."
287
+ echo "Available: ${ADAPTERS[*]}"
288
+ else
289
+ echo "WARNING: No targets enabled in $CONFIG_FILE"
290
+ fi
291
+ exit 1
292
+ fi
293
+
294
+ # Warn about unsynced directories
295
+ warn_unsynced "$REPO_ROOT" "$CONFIG_FILE"
296
+
297
+ # Report model overrides that drift from intelligence-sync defaults
298
+ # (helpful when defaults move forward — e.g., gpt-5.5 -> gpt-5.6).
299
+ report_model_drift "$CONFIG_FILE"
300
+
301
+ # The intelligence CLI is the recommended setup for new projects. Recommend it
302
+ # to vendored setups — stderr only, so IS_STATUS stdout parsing (skills, CI)
303
+ # is untouched, and suppressible for pipelines.
304
+ if [ "${IS_CLI:-0}" != "1" ] && [ -z "${IS_SUPPRESS_CLI_NOTE:-}" ]; then
305
+ echo "NOTE: the intelligence CLI is now the recommended setup — 'npm i -g @ainova-systems/intelligence', then 'intelligence migrate'. This vendored flow keeps working." >&2
306
+ fi
307
+
308
+ echo ""
309
+ # sync.sh never migrates (the update flow owns that), so success is always ok.
310
+ is_status ok "synced=$synced"
311
+ echo "=== Done: $synced target(s) synced ==="
@@ -0,0 +1,237 @@
1
+ #!/bin/bash
2
+ # intelligence-sync: self-update
3
+ # Pulls the latest upstream-owned content into the local vendored module:
4
+ # <umbrella>/sync/scripts/ sync engine + adapters
5
+ # <umbrella>/sync/INIT.md bootstrap prompt
6
+ # <umbrella>/sync/skills/intelligence-* meta-skills (by reserved prefix)
7
+ # <umbrella>/sync/docs/ vendored docs
8
+ # Project content (config.yaml, rules/, agents/, non-meta skills/) is never
9
+ # touched — except an idempotent additive line in config.yaml sources.skills
10
+ # when migrating a pre-0.3.1 flat project.
11
+ #
12
+ # The umbrella folder name is not hardcoded (intelligence/, Intelligence/, …).
13
+ # Pre-0.3.1 projects laid the engine out flat under the umbrella; this script
14
+ # transparently migrates them into the <umbrella>/sync/ module.
15
+ #
16
+ # Usage:
17
+ # bash <umbrella>/sync/scripts/update.sh # interactive
18
+ # bash <umbrella>/sync/scripts/update.sh --yes # apply without prompt
19
+ # REPO_URL=<url> bash .../update.sh # custom upstream
20
+ #
21
+ # Cross-platform: uses `mktemp -d` (Linux/macOS/Windows Git Bash).
22
+ # Honors $TMPDIR / $TMP / $TEMP — never hardcodes /tmp.
23
+
24
+ set -euo pipefail
25
+
26
+ REPO_URL="${REPO_URL:-https://github.com/ainova-systems/intelligence-sync.git}"
27
+ SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
28
+ AUTO_YES=0
29
+ [ "${1:-}" = "--yes" ] && AUTO_YES=1
30
+
31
+ source "$SCRIPT_DIR/lib/layout.sh"
32
+ source "$SCRIPT_DIR/lib/migrations.sh"
33
+
34
+ detect_layout "$SCRIPT_DIR"
35
+ UMBRELLA="$LS_UMBRELLA_DIR"
36
+ CONFIG_FILE_PATH="$UMBRELLA/config.yaml"
37
+
38
+ # Local module dir = wherever this engine lives (self-located, any name) when
39
+ # already modular; for a pre-0.3.1 flat project the module does not exist yet,
40
+ # so it is created under the conventional name `sync`. MODULE_NAME is only the
41
+ # creation convention — not a rename feature, not used to find the upstream.
42
+ if [ "$LS_LAYOUT" = "modular" ]; then
43
+ MODULE_DIR="$LS_MODULE_DIR"
44
+ MODULE_NAME="$LS_MODULE_NAME"
45
+ else
46
+ MODULE_NAME="sync"
47
+ MODULE_DIR="$UMBRELLA/$MODULE_NAME"
48
+ fi
49
+ # The upstream repo's module is always `sync/` by convention, independent of
50
+ # whatever the local module is named.
51
+ UPSTREAM_MODULE="sync"
52
+
53
+ WORK_DIR=$(mktemp -d -t intelligence-sync-update-XXXXXX 2>/dev/null || mktemp -d)
54
+ trap 'rm -rf "$WORK_DIR"' EXIT INT TERM
55
+
56
+ echo "=== intelligence-sync: self-update ==="
57
+ echo " Upstream: $REPO_URL"
58
+ echo " Umbrella: $UMBRELLA (layout: $LS_LAYOUT)"
59
+ echo " Module: $MODULE_DIR"
60
+ echo " Work dir: $WORK_DIR"
61
+ echo ""
62
+
63
+ if ! command -v git >/dev/null 2>&1; then
64
+ echo "ERROR: git is required."
65
+ exit 1
66
+ fi
67
+
68
+ echo " Cloning latest..."
69
+ # LF regardless of the host's core.autocrlf: this checkout is copied verbatim
70
+ # into the project, so a CRLF one on Windows would install CRLF shell scripts.
71
+ git -c core.autocrlf=false -c core.eol=lf clone --depth=1 --quiet "$REPO_URL" "$WORK_DIR"
72
+
73
+ # Normalize the upstream into a single module-shaped staging dir so the rest
74
+ # of this script is layout-agnostic. Accept either upstream shape:
75
+ # modular: $WORK_DIR/intelligence/sync/{scripts,INIT.md,docs,skills}
76
+ # legacy : $WORK_DIR/intelligence/{scripts,INIT.md,skills} + $WORK_DIR/docs
77
+ UPMOD="$WORK_DIR/_module"
78
+ mkdir -p "$UPMOD/skills"
79
+ if [ -d "$WORK_DIR/intelligence/$UPSTREAM_MODULE/scripts" ]; then
80
+ _SRC="$WORK_DIR/intelligence/$UPSTREAM_MODULE"
81
+ cp -r "$_SRC/scripts" "$UPMOD/scripts"
82
+ [ -f "$_SRC/INIT.md" ] && cp "$_SRC/INIT.md" "$UPMOD/INIT.md"
83
+ [ -d "$_SRC/docs" ] && cp -r "$_SRC/docs" "$UPMOD/docs"
84
+ # Engine-owned rule + agent (0.7.0+). Absent in older upstreams — optional.
85
+ [ -d "$_SRC/rules" ] && cp -r "$_SRC/rules" "$UPMOD/rules"
86
+ [ -d "$_SRC/agents" ] && cp -r "$_SRC/agents" "$UPMOD/agents"
87
+ for s in "$_SRC"/skills/intelligence-*; do
88
+ [ -d "$s" ] && cp -r "$s" "$UPMOD/skills/"
89
+ done
90
+ elif [ -d "$WORK_DIR/intelligence/scripts" ]; then
91
+ cp -r "$WORK_DIR/intelligence/scripts" "$UPMOD/scripts"
92
+ [ -f "$WORK_DIR/intelligence/INIT.md" ] && cp "$WORK_DIR/intelligence/INIT.md" "$UPMOD/INIT.md"
93
+ [ -d "$WORK_DIR/docs" ] && cp -r "$WORK_DIR/docs" "$UPMOD/docs"
94
+ for s in "$WORK_DIR/intelligence"/skills/intelligence-*; do
95
+ [ -d "$s" ] && cp -r "$s" "$UPMOD/skills/"
96
+ done
97
+ else
98
+ is_status error "upstream-layout-unrecognized"
99
+ echo "ERROR: upstream layout unrecognized — no intelligence/$UPSTREAM_MODULE/scripts/ or intelligence/scripts/."
100
+ exit "$IS_RC_ERROR"
101
+ fi
102
+
103
+ # Local module dir to diff against: the existing module, or (pre-migration)
104
+ # the flat legacy locations.
105
+ if [ -d "$MODULE_DIR/scripts" ]; then
106
+ _LOCAL="$MODULE_DIR"
107
+ else
108
+ _LOCAL="$UMBRELLA" # legacy flat
109
+ fi
110
+
111
+ echo ""
112
+ echo " Diff (scripts/):"
113
+ diff -ruN "$_LOCAL/scripts" "$UPMOD/scripts" || true
114
+ echo ""
115
+ echo " Diff (INIT.md):"
116
+ diff -uN "$_LOCAL/INIT.md" "$UPMOD/INIT.md" 2>/dev/null || true
117
+ echo ""
118
+ echo " Diff (meta-skills intelligence-*):"
119
+ for up in "$UPMOD"/skills/intelligence-*; do
120
+ [ -d "$up" ] || continue
121
+ name=$(basename "$up")
122
+ diff -ruN "$_LOCAL/skills/$name" "$up" 2>/dev/null || true
123
+ done
124
+ if [ -d "$UPMOD/docs" ]; then
125
+ echo ""
126
+ echo " Diff (docs/):"
127
+ diff -ruN "$_LOCAL/docs" "$UPMOD/docs" 2>/dev/null || true
128
+ fi
129
+ # Engine-owned rule + agent (0.7.0+): upstream-owned like the meta-skills, and
130
+ # distinct from the project's own <umbrella>/rules and <umbrella>/agents.
131
+ for _d in rules agents; do
132
+ [ -d "$UPMOD/$_d" ] || continue
133
+ echo ""
134
+ echo " Diff (engine $_d/):"
135
+ diff -ruN "$_LOCAL/$_d" "$UPMOD/$_d" 2>/dev/null || true
136
+ done
137
+
138
+ if [ $AUTO_YES -ne 1 ]; then
139
+ echo ""
140
+ if [ "$LS_LAYOUT" = "legacy" ]; then
141
+ echo " NOTE: pre-0.3.1 flat layout — the engine will be MIGRATED into '$MODULE_NAME/'."
142
+ echo " Legacy scripts/, INIT.md, docs/, and intelligence-* skills move there;"
143
+ echo " a single additive line is added to config.yaml sources.skills."
144
+ fi
145
+ read -r -p "Apply update? Engine/INIT/meta-skills/docs + engine rule/agent overwritten; YOUR rules/agents/skills NOT touched. [y/N] " confirm
146
+ case "$confirm" in
147
+ y|Y|yes|YES) ;;
148
+ *) echo " Cancelled."; exit 0 ;;
149
+ esac
150
+ fi
151
+
152
+ # CRITICAL: run the DESTINATION engine's migration chain, not the stale local
153
+ # one. A breaking migration shipped in the new version is defined only in the
154
+ # upstream migrations.sh; re-source it so MIGRATIONS / migrate_to_* /
155
+ # run_migrations / engine_version all reflect the version we are applying.
156
+ # Otherwise a new breaking change would be silently skipped while the version
157
+ # still advances — the exact corruption this architecture exists to prevent.
158
+ if [ -f "$UPMOD/scripts/lib/migrations.sh" ]; then
159
+ # shellcheck source=/dev/null
160
+ source "$UPMOD/scripts/lib/migrations.sh"
161
+ fi
162
+
163
+ # Migrate via the upstream chain (authoritative content from UPMOD).
164
+ # Idempotent: a no-op on already-current projects. Fail-closed: on a state
165
+ # bash will not resolve it emits IS_STATUS + a stable code and we stop so the
166
+ # intelligence-update skill can take over (never partially destroys).
167
+ _mig_rc=0
168
+ run_migrations "$UMBRELLA" "$MODULE_NAME" "$UPMOD" || _mig_rc=$?
169
+ if [ "$_mig_rc" -ne 0 ]; then exit "$_mig_rc"; fi
170
+
171
+ # In-place refresh of the module (covers already-modular projects, and
172
+ # re-asserts content post-migration). Idempotent.
173
+ mkdir -p "$MODULE_DIR/skills"
174
+ if command -v rsync >/dev/null 2>&1; then
175
+ rsync -a --delete "$UPMOD/scripts/" "$MODULE_DIR/scripts/"
176
+ else
177
+ rm -rf "$MODULE_DIR/scripts"; cp -r "$UPMOD/scripts" "$MODULE_DIR/scripts"
178
+ fi
179
+ [ -f "$UPMOD/INIT.md" ] && cp "$UPMOD/INIT.md" "$MODULE_DIR/INIT.md"
180
+ for _d in rules agents; do
181
+ [ -d "$UPMOD/$_d" ] || continue
182
+ if command -v rsync >/dev/null 2>&1; then
183
+ mkdir -p "$MODULE_DIR/$_d"
184
+ rsync -a --delete "$UPMOD/$_d/" "$MODULE_DIR/$_d/"
185
+ else
186
+ # `:?` so an empty MODULE_DIR/_d can never expand this into `rm -rf /`.
187
+ rm -rf "${MODULE_DIR:?}/${_d:?}"; cp -r "$UPMOD/$_d" "$MODULE_DIR/$_d"
188
+ fi
189
+ done
190
+ if [ -d "$UPMOD/docs" ]; then
191
+ if command -v rsync >/dev/null 2>&1; then
192
+ rsync -a --delete "$UPMOD/docs/" "$MODULE_DIR/docs/"
193
+ else
194
+ rm -rf "$MODULE_DIR/docs"; cp -r "$UPMOD/docs" "$MODULE_DIR/docs"
195
+ fi
196
+ fi
197
+ for up in "$UPMOD"/skills/intelligence-*; do
198
+ [ -d "$up" ] || continue
199
+ name=$(basename "$up")
200
+ if command -v rsync >/dev/null 2>&1; then
201
+ rsync -a --delete "$up/" "$MODULE_DIR/skills/$name/"
202
+ else
203
+ rm -rf "$MODULE_DIR/skills/$name"; cp -r "$up" "$MODULE_DIR/skills/$name"
204
+ fi
205
+ done
206
+ # Prune local meta-skills no longer upstream (deprecated ones disappear; no
207
+ # duplicates, project skills untouched).
208
+ for local_skill in "$MODULE_DIR"/skills/intelligence-*; do
209
+ [ -d "$local_skill" ] || continue
210
+ name=$(basename "$local_skill")
211
+ [ -d "$UPMOD/skills/$name" ] || { echo " Removing meta-skill no longer upstream: $name"; rm -rf "$local_skill"; }
212
+ done
213
+
214
+ # Stamp the applied schema version into config.yaml (the frozen contract
215
+ # key). Covers the already-modular in-place path where no migration ran.
216
+ _ver="0.3.1"
217
+ [ -f "$UPMOD/scripts/VERSION" ] && _ver="$(tr -d ' \r\n' < "$UPMOD/scripts/VERSION")"
218
+ stamp_version "$CONFIG_FILE_PATH" "$_ver"
219
+
220
+ find "$MODULE_DIR/scripts" -name '*.sh' -exec chmod +x {} \; 2>/dev/null || true
221
+
222
+ echo ""
223
+ if [ "${IS_MIGRATED:-0}" -eq 1 ]; then
224
+ is_status migrated "version=$_ver"
225
+ else
226
+ is_status ok "version=$_ver"
227
+ fi
228
+ echo " Updated: $MODULE_NAME/{scripts,INIT.md,docs}, $MODULE_NAME/skills/intelligence-*, $MODULE_NAME/{rules,agents} (version $_ver)"
229
+ echo " Untouched: your <umbrella>/rules, <umbrella>/agents, project skills, <umbrella>/adapters."
230
+ echo " config.yaml only gains the engine's managed keys (sync_version, module sources)."
231
+ echo " Next: bash $MODULE_NAME/scripts/sync.sh"
232
+
233
+ # The intelligence CLI is the recommended setup for new projects. stderr only,
234
+ # so IS_STATUS stdout parsing (skills, CI) is untouched; suppressible for CI.
235
+ if [ -z "${IS_SUPPRESS_CLI_NOTE:-}" ]; then
236
+ echo "NOTE: the intelligence CLI is now the recommended setup — 'npm i -g @ainova-systems/intelligence', then 'intelligence migrate'. This vendored flow keeps working." >&2
237
+ fi
@@ -0,0 +1,62 @@
1
+ ---
2
+ name: intelligence-add-agent
3
+ description: "Create new specialized agent"
4
+ argument-hint: <domain> [description]
5
+ ---
6
+
7
+ # Add Agent
8
+
9
+ ## Steps
10
+
11
+ 1. **Determine domain prefix** (the scope is required):
12
+ - **Reuse the existing domain when one fits**: list `intelligence/agents/` and `intelligence/skills/`. If a domain prefix is already established for the target area (`backend-`, `frontend-`, `devops-`), use it. Introduce a new domain only when the scope is materially different from all existing ones.
13
+ - **When no existing domain fits**, derive from repo structure:
14
+ - Single / root project → use the project codename from `intelligence/config.yaml` → `project.name`
15
+ - Backend service / API component → `backend-`
16
+ - Frontend / web / UI component → `frontend-`
17
+ - Infrastructure, IaC, CI/CD, deployment → `devops-`
18
+ - Shared library / common / cross-cutting code → `core-`
19
+ - Test suites (e2e, integration) → `tests-`
20
+ - Tool-internal (intelligence-sync itself) → `intelligence-`
21
+ - If the repo is a monorepo with named components (e.g., `apps/billing`, `services/auth`), prefer the component name as the domain (`billing-`, `auth-`).
22
+ - **Every agent needs a domain prefix.** If the scope is unclear, ask the user before proceeding.
23
+
24
+ 2. **Check existing agents**: Read `intelligence/agents/` to avoid duplicates. If an agent for this domain exists, ask user whether to update it instead.
25
+
26
+ 3. **Determine tier and access**:
27
+ - Developer agents: `tier: heavy`, `access: full`
28
+ - Reviewer/validator agents: `tier: standard`, `access: readonly`
29
+ - Simple lookup agents: `tier: light`, `access: readonly`
30
+ - Caveat: `readonly`'s closed tools list also removes MCP and tool-search access. A reviewer
31
+ that needs MCP reads takes `access: full` with a read-only boundary stated in its body.
32
+
33
+ 4. **Analyze codebase**: Read source files in the domain's directory to determine:
34
+ - Technology stack and frameworks
35
+ - Architecture patterns
36
+ - Build and test commands
37
+ - Key conventions and forbidden patterns
38
+
39
+ 5. **Create agent**: Write `intelligence/agents/<domain>-<role>.md` with frontmatter:
40
+ ```yaml
41
+ ---
42
+ name: <domain>-<role>
43
+ description: "<when to use this agent - IDEs use this to suggest the agent>"
44
+ tier: heavy|standard|light
45
+ access: full|readonly
46
+ skills:
47
+ - <existing-skills-for-this-domain>
48
+ ---
49
+ ```
50
+
51
+ **YAML safety (required):** **always wrap `description` (and any other free-text string field) in double quotes**, regardless of content. Codex CLI uses strict YAML — an unquoted colon, leading hyphen, or word that parses as boolean (`yes`, `no`, `true`) silently breaks the agent. Quoting unconditionally prevents the entire class of bug. If the value itself contains a double quote, escape it as `\"` or wrap it in single quotes so an inner quote does not terminate the scalar early.
52
+
53
+ 6. **Write body** with sections: **Expertise** -> **Boundaries** -> **Build & Verify**
54
+ - An agent is **thin**: who it is, where it stops, how it verifies. Everything else already reaches it.
55
+ - **Do not tell the agent to read the rules.** Rules load on their own: Claude Code loads `.claude/rules/` into every custom subagent's startup context alongside `CLAUDE.md` (*Subagents → What loads at startup*), and Cursor / Copilot / Codex / Pi / opencode receive always-on rules inlined in `AGENTS.md`. A `Read intelligence/rules/<domain>.md before starting` line duplicates content the agent already has — double the tokens, and a second copy that drifts from the rule it copied.
56
+ - **Point at a rule, never restate it.** If you want to copy a rule into the agent, the rule is in the wrong place — move it, do not clone it.
57
+ - **Do carry** what is genuinely the agent's own: its boundaries ("if the app is not running, stop — do not hand-write the output"), its verification commands, its definition of done.
58
+ - All content must come from actual codebase analysis.
59
+
60
+ 7. **Link existing skills**: Find skills in `intelligence/skills/` matching this domain prefix and add them to the agent's `skills:` frontmatter.
61
+
62
+ 8. **Run `/intelligence-sync`** to distribute to all enabled IDE targets.
@@ -0,0 +1,54 @@
1
+ ---
2
+ name: intelligence-add-rule
3
+ description: "Create new intelligence rule"
4
+ argument-hint: <name> [paths-glob]
5
+ ---
6
+
7
+ # Add Rule
8
+
9
+ ## Steps
10
+
11
+ 1. **Determine rule name from domain** (the scope is required):
12
+ - **Reuse the existing domain when one fits**: list `intelligence/rules/`. If a rule file covers the target area (e.g., `backend.md`, `frontend.md`), extend it. Introduce a new domain only when the scope is materially different from all existing rules.
13
+ - **When no existing rule fits**, derive the filename from repo structure:
14
+ - Single / root project → use the project codename from `intelligence/config.yaml` → `project.name` (e.g., `<codename>.md`)
15
+ - Backend service / API component → `backend.md`
16
+ - Frontend / web / UI component → `frontend.md`
17
+ - Infrastructure, IaC, CI/CD, deployment → `devops.md`
18
+ - Shared library / common / cross-cutting code → `core.md`
19
+ - Test suites (e2e, integration) → `tests.md`
20
+ - Always-loaded global context → `context.md`
21
+ - If the repo is a monorepo with named components (e.g., `apps/billing`, `services/auth`), prefer the component name as the rule name (`billing.md`, `auth.md`).
22
+ - **Rule filenames match the domain used by skills/agents.** If the scope is unclear, ask the user before proceeding.
23
+
24
+ 2. **Check existing rules**: Read `intelligence/rules/` to detect overlapping scope — favor extending an existing rule over creating a new one.
25
+
26
+ 3. **Determine scope**:
27
+ - If paths glob provided — scoped rule with `paths:` frontmatter
28
+ - If no paths — always-loaded rule (no `paths:` in frontmatter)
29
+
30
+ 4. **Analyze codebase**: Read source files matching the scope to extract:
31
+ - REQUIRED patterns (conventions consistently followed across the codebase — judgment calls expressed as positive defaults)
32
+ - Invariants (true must-nots — safety, output format, security; not judgment calls)
33
+ - Architecture patterns (layer dependencies, module structure)
34
+ - Build and test commands specific to this scope
35
+ - Anti-patterns observed in code, each paired with the positive replacement that should adopt instead
36
+
37
+ 5. **Create rule**: Write `intelligence/rules/<name>.md`:
38
+ ```yaml
39
+ ---
40
+ paths:
41
+ - "<glob-pattern>"
42
+ ---
43
+ ```
44
+
45
+ 6. **Write body** with sections: **REQUIRED** → **Invariants** → **Architecture** → **Build & Test** → **Examples** → **Patterns to recognize and replace** (optional)
46
+ - Lead with REQUIRED (positive defaults) — the LLM follows the positive instruction first
47
+ - Reserve **Invariants** for true must-nots — security, safety, output format. Use absolute language (MUST / NEVER) only here, never for judgment calls
48
+ - **Patterns to recognize and replace** is reference documentation of anti-patterns paired with positive replacements — readers recognize the pattern, apply the replacement
49
+ - Examples come from the actual codebase — reference real files
50
+ - Every REQUIRED / Invariant / Pattern is backed by observed code
51
+
52
+ 7. **Update config.yaml** if needed: Add source path to `sources.rules` if rule is in a new directory not yet listed.
53
+
54
+ 8. **Run `/intelligence-sync`** to distribute to all enabled IDE targets.