@ainova-systems/intelligence 0.11.0-rc.11 → 0.11.0-rc.14
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/cli/commands/adapter.sh +32 -2
- package/cli/commands/init.sh +120 -20
- package/cli/commands/sync.sh +76 -23
- package/cli/intelligence +16 -1
- package/cli/internal/check.sh +40 -0
- package/cli/internal/convert-legacy.sh +2 -8
- package/cli/internal/target-state.sh +24 -17
- package/cli/lib/adapter-lifecycle.sh +33 -0
- package/cli/lib/cli-common.sh +4 -0
- package/cli/lib/gitignore.sh +53 -0
- package/cli/lib/manifest.sh +35 -1
- package/cli/lib/onboarding.sh +63 -0
- package/engine/ENGINE_SHA +1 -1
- package/engine/adapters/_template.sh +19 -2
- package/engine/adapters/agents.sh +14 -3
- package/engine/adapters/claude.sh +15 -0
- package/engine/adapters/codex.sh +11 -1
- package/engine/adapters/copilot.sh +11 -0
- package/engine/adapters/cursor.sh +15 -0
- package/engine/adapters/opencode.sh +11 -0
- package/engine/adapters/pi.sh +18 -5
- package/engine/lib/adapter-contract.sh +100 -0
- package/engine/sync.sh +87 -25
- package/package.json +1 -1
- package/packages/sync/agents/intelligence-architect.md +1 -1
- package/packages/sync/references/adapters.md +44 -5
- package/packages/sync/references/conventions.md +33 -16
- package/packages/sync/references/onboarding-migration.md +74 -0
- package/packages/sync/skills/intelligence-install-adapter/SKILL.md +12 -5
- package/packages/sync/skills/intelligence-learn-from-context/SKILL.md +44 -3
- package/packages/sync/skills/intelligence-learn-from-repository/SKILL.md +47 -10
- package/packages/sync/skills/intelligence-review-skills/SKILL.md +1 -1
package/cli/commands/adapter.sh
CHANGED
|
@@ -137,10 +137,32 @@ case "$action" in
|
|
|
137
137
|
assert_valid_target_name "$name"
|
|
138
138
|
require_cli_project
|
|
139
139
|
ensure_project_current "$IP_ROOT"
|
|
140
|
-
bash "$CLI_DIR/internal/target-state.sh" "$action" "$name"
|
|
141
140
|
if [ "$action" = "enable" ]; then
|
|
142
|
-
|
|
141
|
+
state_stage="$(mktemp -d -t intelligence-adapter-state-XXXXXX)"
|
|
142
|
+
cp "$IP_ROOT/intelligence.yaml" "$state_stage/intelligence.yaml"
|
|
143
|
+
gitignore_existed=0
|
|
144
|
+
if [ -f "$IP_ROOT/.gitignore" ]; then
|
|
145
|
+
gitignore_existed=1
|
|
146
|
+
cp "$IP_ROOT/.gitignore" "$state_stage/gitignore"
|
|
147
|
+
fi
|
|
148
|
+
enable_rc=0
|
|
149
|
+
bash "$CLI_DIR/internal/target-state.sh" "$action" "$name" || enable_rc=$?
|
|
150
|
+
if [ "$enable_rc" -eq 0 ]; then
|
|
151
|
+
bash "$CLI_DIR/commands/sync.sh" || enable_rc=$?
|
|
152
|
+
fi
|
|
153
|
+
if [ "$enable_rc" -ne 0 ]; then
|
|
154
|
+
cp "$state_stage/intelligence.yaml" "$IP_ROOT/intelligence.yaml"
|
|
155
|
+
if [ "$gitignore_existed" -eq 1 ]; then
|
|
156
|
+
cp "$state_stage/gitignore" "$IP_ROOT/.gitignore"
|
|
157
|
+
else
|
|
158
|
+
rm -f "$IP_ROOT/.gitignore"
|
|
159
|
+
fi
|
|
160
|
+
echo "ERROR: adapter enable failed; manifest and Git policy were restored." >&2
|
|
161
|
+
fi
|
|
162
|
+
rm -rf "$state_stage"
|
|
163
|
+
exit "$enable_rc"
|
|
143
164
|
fi
|
|
165
|
+
bash "$CLI_DIR/internal/target-state.sh" "$action" "$name"
|
|
144
166
|
;;
|
|
145
167
|
remove)
|
|
146
168
|
[ -n "$name" ] || die "usage: intelligence adapter remove <name> [--apply]"
|
|
@@ -148,6 +170,14 @@ case "$action" in
|
|
|
148
170
|
adapter_remove "$@"
|
|
149
171
|
;;
|
|
150
172
|
*)
|
|
173
|
+
case "$name" in
|
|
174
|
+
list)
|
|
175
|
+
die "adapter action comes first - run: intelligence adapter list"
|
|
176
|
+
;;
|
|
177
|
+
create|enable|disable|remove)
|
|
178
|
+
die "adapter action comes first - run: intelligence adapter $name $action"
|
|
179
|
+
;;
|
|
180
|
+
esac
|
|
151
181
|
die "usage: intelligence adapter <list|create|enable|disable|remove> [name]"
|
|
152
182
|
;;
|
|
153
183
|
esac
|
package/cli/commands/init.sh
CHANGED
|
@@ -12,6 +12,48 @@ source "$CLI_DIR/lib/cli-common.sh"
|
|
|
12
12
|
|
|
13
13
|
targets_arg="" no_sync=0 content_dir="intelligence" bare=0
|
|
14
14
|
targets_set=0 dir_set=0 bare_set=0 preview=0 apply=0 force=0
|
|
15
|
+
|
|
16
|
+
print_new_project_onboarding() {
|
|
17
|
+
local heading="Intelligence ready"
|
|
18
|
+
[ "$no_sync" -eq 0 ] || heading="Next steps"
|
|
19
|
+
|
|
20
|
+
echo ""
|
|
21
|
+
echo "=== $heading ==="
|
|
22
|
+
if [ -n "${ONBOARDING_BACKUP_REL:-}" ]; then
|
|
23
|
+
echo " Existing AI instructions preserved:"
|
|
24
|
+
echo " $ONBOARDING_BACKUP_REL ($ONBOARDING_BACKUP_COUNT path(s))"
|
|
25
|
+
if [ "$bare" -eq 0 ]; then
|
|
26
|
+
echo " The learn skill will migrate them before proposing backup removal."
|
|
27
|
+
else
|
|
28
|
+
echo " Review and migrate them before removing this backup."
|
|
29
|
+
fi
|
|
30
|
+
fi
|
|
31
|
+
if [ "$no_sync" -eq 1 ]; then
|
|
32
|
+
echo " Run first:"
|
|
33
|
+
echo " intelligence sync"
|
|
34
|
+
fi
|
|
35
|
+
if [ "$bare" -eq 0 ]; then
|
|
36
|
+
echo " Recommended starter package:"
|
|
37
|
+
echo " intelligence package add @ainova-systems/core"
|
|
38
|
+
echo " Install it before learning so package/project duplicates can be detected."
|
|
39
|
+
echo " Finalize repository onboarding:"
|
|
40
|
+
echo " Ask your agent to run /intelligence-learn-from-context"
|
|
41
|
+
echo " It recognizes the initial backup, recovers setup if needed, then proposes repository-specific migration after approval."
|
|
42
|
+
fi
|
|
43
|
+
echo " Review adapters:"
|
|
44
|
+
echo " intelligence adapter list"
|
|
45
|
+
echo " intelligence adapter enable codex"
|
|
46
|
+
echo " intelligence adapter disable cursor"
|
|
47
|
+
echo " Version control:"
|
|
48
|
+
echo " Generated adapter output is gitignored by CLI-owned path."
|
|
49
|
+
echo " Commit intelligence.yaml, intelligence.lock, intelligence/, AGENTS.md, and .github/."
|
|
50
|
+
echo " Shared tool settings remain trackable; review the exact ownership policy:"
|
|
51
|
+
echo " https://github.com/ainova-systems/intelligence/blob/main/packages/sync/references/conventions.md#generated-output-and-version-control"
|
|
52
|
+
echo " Write your own:"
|
|
53
|
+
echo " create $content_dir/rules/context.md, then intelligence sync"
|
|
54
|
+
echo " Docs: https://github.com/ainova-systems/intelligence#readme"
|
|
55
|
+
}
|
|
56
|
+
|
|
15
57
|
while [ $# -gt 0 ]; do
|
|
16
58
|
case "$1" in
|
|
17
59
|
--targets) shift; targets_arg="${1:-}"; targets_set=1 ;;
|
|
@@ -68,9 +110,25 @@ case "$IP_MODE" in
|
|
|
68
110
|
ensure_project_current "$IP_ROOT"
|
|
69
111
|
fi
|
|
70
112
|
restore_project_store_if_missing "$IP_ROOT"
|
|
113
|
+
ensure_manifest_gitignore "$IP_ROOT" "$IP_ROOT/intelligence.yaml"
|
|
71
114
|
[ "$no_sync" -eq 1 ] && exit 0
|
|
72
115
|
cd "$IP_ROOT"
|
|
73
|
-
|
|
116
|
+
sync_rc=0
|
|
117
|
+
bash "$CLI_DIR/commands/sync.sh" || sync_rc=$?
|
|
118
|
+
if [ "$sync_rc" -ne 0 ]; then
|
|
119
|
+
content_dir="$(manifest_intelligence_dir "$IP_ROOT/intelligence.yaml")"
|
|
120
|
+
recovery_backup=""
|
|
121
|
+
if [ -f "$IP_ROOT/$content_dir/_backup/manifest.tsv" ]; then
|
|
122
|
+
recovery_backup="; initial backup: $content_dir/_backup/manifest.tsv"
|
|
123
|
+
fi
|
|
124
|
+
echo "" >&2
|
|
125
|
+
echo "=== Intelligence setup needs recovery ===" >&2
|
|
126
|
+
echo " No partial adapter update was kept; sync restored its pre-run outputs." >&2
|
|
127
|
+
echo " Ask your agent to read:" >&2
|
|
128
|
+
echo " $SYNC_PKG_STORE/skills/intelligence-learn-from-context/SKILL.md" >&2
|
|
129
|
+
echo " and finalize this Intelligence setup$recovery_backup." >&2
|
|
130
|
+
fi
|
|
131
|
+
exit "$sync_rc"
|
|
74
132
|
;;
|
|
75
133
|
legacy)
|
|
76
134
|
[ "$targets_set" -eq 0 ] || die "--targets applies only when creating a new project"
|
|
@@ -117,17 +175,30 @@ if [ -n "$targets_arg" ]; then
|
|
|
117
175
|
done
|
|
118
176
|
else
|
|
119
177
|
if [ -d "$root/.claude" ] || [ -f "$root/CLAUDE.md" ]; then targets="$targets claude"; fi
|
|
120
|
-
[ -d "$root/.cursor" ]
|
|
121
|
-
[ -d "$root/.codex" ]
|
|
178
|
+
if [ -d "$root/.cursor" ] || [ -f "$root/.cursorrules" ]; then targets="$targets cursor"; fi
|
|
179
|
+
if [ -d "$root/.codex" ] || [ -d "$root/.agents" ]; then targets="$targets codex"; fi
|
|
122
180
|
[ -d "$root/.pi" ] && targets="$targets pi"
|
|
123
181
|
[ -d "$root/.opencode" ] && targets="$targets opencode"
|
|
124
|
-
|
|
182
|
+
if [ -f "$root/.github/copilot-instructions.md" ] \
|
|
183
|
+
|| [ -d "$root/.github/instructions" ] \
|
|
184
|
+
|| [ -d "$root/.github/agents" ] \
|
|
185
|
+
|| [ -d "$root/.github/skills" ]; then
|
|
186
|
+
targets="$targets copilot"
|
|
187
|
+
fi
|
|
125
188
|
if [ "$targets" = "agents" ]; then
|
|
126
189
|
echo " NOTE: no tool markers found (.claude/, CLAUDE.md, .cursor/, …) — only AGENTS.md is enabled." >&2
|
|
127
190
|
echo " Name your tools explicitly: intelligence init --targets claude,cursor (or edit targets: later)" >&2
|
|
128
191
|
fi
|
|
129
192
|
fi
|
|
130
193
|
|
|
194
|
+
onboarding_count="$(onboarding_source_count "$root" "$content_dir" "$targets")"
|
|
195
|
+
onboarding_has_agents=0
|
|
196
|
+
[ -f "$root/AGENTS.md" ] && onboarding_has_agents=1
|
|
197
|
+
if [ "$preview" -eq 0 ] && [ "$onboarding_count" -gt 0 ] \
|
|
198
|
+
&& [ -e "$root/$content_dir/_backup" ]; then
|
|
199
|
+
die "onboarding backup already exists at $content_dir/_backup - review or move it before rerunning init"
|
|
200
|
+
fi
|
|
201
|
+
|
|
131
202
|
if [ "$preview" -eq 1 ]; then
|
|
132
203
|
echo "project: no Intelligence setup found"
|
|
133
204
|
echo " would create intelligence.yaml and intelligence.lock"
|
|
@@ -141,6 +212,9 @@ if [ "$preview" -eq 1 ]; then
|
|
|
141
212
|
else
|
|
142
213
|
echo " would enable adapters:$targets, then sync"
|
|
143
214
|
fi
|
|
215
|
+
if [ "$onboarding_count" -gt 0 ]; then
|
|
216
|
+
echo " would preserve $onboarding_count existing AI instruction path(s) in $content_dir/_backup before sync"
|
|
217
|
+
fi
|
|
144
218
|
exit 0
|
|
145
219
|
fi
|
|
146
220
|
|
|
@@ -175,7 +249,21 @@ manifest="$root/intelligence.yaml"
|
|
|
175
249
|
echo "# Generated output, one entry per tool. Add or drop tools freely."
|
|
176
250
|
echo "targets:"
|
|
177
251
|
for t in $targets; do
|
|
178
|
-
|
|
252
|
+
if [ "$t" = "agents" ] && [ "$onboarding_has_agents" -eq 1 ]; then
|
|
253
|
+
echo " agents:"
|
|
254
|
+
echo " enabled: true"
|
|
255
|
+
echo " output: \"AGENTS.md\""
|
|
256
|
+
echo " header: |"
|
|
257
|
+
echo " > Intelligence onboarding is pending. Before repository work, read"
|
|
258
|
+
echo " > \`$content_dir/_backup/AGENTS.md\`, which preserves the original project instructions."
|
|
259
|
+
if [ "$bare" -eq 0 ]; then
|
|
260
|
+
echo " > Run /intelligence-learn-from-context to migrate and verify them before removing the backup."
|
|
261
|
+
else
|
|
262
|
+
echo " > Review and migrate that backup before removing it."
|
|
263
|
+
fi
|
|
264
|
+
else
|
|
265
|
+
echo " $t: { enabled: true, output: \"$(default_target_output "$t")\" }"
|
|
266
|
+
fi
|
|
179
267
|
done
|
|
180
268
|
echo ""
|
|
181
269
|
echo "# Packages are managed with 'intelligence package add|search|list':"
|
|
@@ -202,13 +290,10 @@ manifest="$root/intelligence.yaml"
|
|
|
202
290
|
} > "$manifest"
|
|
203
291
|
|
|
204
292
|
# The package store is restorable state, never committed — the npm model.
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
echo ".intelligence/"
|
|
210
|
-
} >> "$root/.gitignore"
|
|
211
|
-
fi
|
|
293
|
+
ensure_base_gitignore "$root"
|
|
294
|
+
for target in $targets; do
|
|
295
|
+
ensure_target_gitignore "$root" "$manifest" "$target"
|
|
296
|
+
done
|
|
212
297
|
|
|
213
298
|
# The engine's own content (meta-skills, authoring rule, engine agents) is an
|
|
214
299
|
# ordinary package: auto-selected, opted out with --bare, removable later with
|
|
@@ -218,16 +303,31 @@ if [ "$bare" -eq 0 ]; then
|
|
|
218
303
|
sync_pkg_install "$root"
|
|
219
304
|
fi
|
|
220
305
|
|
|
306
|
+
preserve_onboarding_sources "$root" "$content_dir" "$targets"
|
|
307
|
+
|
|
221
308
|
echo "initialized: intelligence.yaml (targets:$(printf ' %s' $targets))"
|
|
222
309
|
[ "$bare" -eq 1 ] && echo " bare setup: no packages — engine meta-skills not installed"
|
|
223
|
-
echo " add packages: intelligence package add @ainova-systems/core (browse: intelligence package search)"
|
|
224
|
-
echo " write your own: create $content_dir/rules/context.md, then intelligence sync"
|
|
225
|
-
if [ "$bare" -eq 0 ]; then
|
|
226
|
-
echo " tailor this repository: ask your agent to run /intelligence-learn-from-repository after sync"
|
|
227
|
-
fi
|
|
228
|
-
echo " docs: https://github.com/ainova-systems/intelligence#readme"
|
|
229
|
-
|
|
230
310
|
if [ "$no_sync" -eq 0 ]; then
|
|
231
311
|
cd "$root"
|
|
232
|
-
|
|
312
|
+
sync_rc=0
|
|
313
|
+
echo ""
|
|
314
|
+
echo "=== Sync started ==="
|
|
315
|
+
echo " Rendering enabled adapters in compact mode..."
|
|
316
|
+
bash "$CLI_DIR/commands/sync.sh" --compact || sync_rc=$?
|
|
317
|
+
if [ "$sync_rc" -ne 0 ]; then
|
|
318
|
+
echo "" >&2
|
|
319
|
+
echo "=== Intelligence setup needs recovery ===" >&2
|
|
320
|
+
echo " No partial adapter update was kept; sync restored its pre-run outputs." >&2
|
|
321
|
+
if [ "$bare" -eq 0 ]; then
|
|
322
|
+
echo " Ask your agent to read:" >&2
|
|
323
|
+
echo " $SYNC_PKG_STORE/skills/intelligence-learn-from-context/SKILL.md" >&2
|
|
324
|
+
echo " and finalize the initial Intelligence setup. The snapshot is $content_dir/_backup/manifest.tsv." >&2
|
|
325
|
+
else
|
|
326
|
+
echo " Fix the reported error, then rerun: intelligence init" >&2
|
|
327
|
+
fi
|
|
328
|
+
exit "$sync_rc"
|
|
329
|
+
fi
|
|
330
|
+
echo "=== Sync completed ==="
|
|
233
331
|
fi
|
|
332
|
+
|
|
333
|
+
print_new_project_onboarding
|
package/cli/commands/sync.sh
CHANGED
|
@@ -1,27 +1,80 @@
|
|
|
1
1
|
#!/bin/bash
|
|
2
|
-
# intelligence sync [target]
|
|
2
|
+
# intelligence sync [target] [--compact] - render intelligence to enabled tools.
|
|
3
3
|
set -euo pipefail
|
|
4
4
|
source "$CLI_DIR/lib/cli-common.sh"
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
6
|
+
compact=0
|
|
7
|
+
target=""
|
|
8
|
+
while [ $# -gt 0 ]; do
|
|
9
|
+
case "$1" in
|
|
10
|
+
--compact) compact=1 ;;
|
|
11
|
+
-*) die "unknown option '$1'" ;;
|
|
12
|
+
*)
|
|
13
|
+
[ -z "$target" ] || die "usage: intelligence sync [adapter] [--compact]"
|
|
14
|
+
target="$1"
|
|
15
|
+
;;
|
|
16
|
+
esac
|
|
17
|
+
shift
|
|
18
|
+
done
|
|
19
|
+
|
|
20
|
+
run_sync() {
|
|
21
|
+
detect_project || return $?
|
|
22
|
+
case "$IP_MODE" in
|
|
23
|
+
cli)
|
|
24
|
+
# `sync` is the normal fresh-clone command. A newer globally installed
|
|
25
|
+
# CLI aligns the current Intelligence project first (except in CI, where a
|
|
26
|
+
# tracked migration must be reviewed and committed locally), and a
|
|
27
|
+
# missing ignored store is restored strictly from the committed lock.
|
|
28
|
+
ensure_project_current "$IP_ROOT" || return $?
|
|
29
|
+
restore_project_store_if_missing "$IP_ROOT" || return $?
|
|
30
|
+
export_engine_env "$IP_ROOT" || return $?
|
|
31
|
+
if [ -n "$target" ]; then
|
|
32
|
+
bash "$IS_ENGINE_DIR/sync.sh" "$target" || return $?
|
|
33
|
+
else
|
|
34
|
+
bash "$IS_ENGINE_DIR/sync.sh" || return $?
|
|
35
|
+
fi
|
|
36
|
+
;;
|
|
37
|
+
legacy)
|
|
38
|
+
[ "$compact" -eq 0 ] || die "--compact is unavailable for a legacy Intelligence Sync project - run 'intelligence init' to convert it first"
|
|
39
|
+
# A vendored project syncs with its own engine: its pin is the
|
|
40
|
+
# contract, and a newer bundled engine must not generate against an
|
|
41
|
+
# older schema.
|
|
42
|
+
echo "NOTE: legacy Intelligence Sync project - delegating to $IP_MODULE_DIR/scripts/sync.sh. 'intelligence init' converts it into an Intelligence project." >&2
|
|
43
|
+
if [ -n "$target" ]; then
|
|
44
|
+
bash "$IP_MODULE_DIR/scripts/sync.sh" "$target" || return $?
|
|
45
|
+
else
|
|
46
|
+
bash "$IP_MODULE_DIR/scripts/sync.sh" || return $?
|
|
47
|
+
fi
|
|
48
|
+
;;
|
|
49
|
+
*)
|
|
50
|
+
die "no intelligence project found here - run 'intelligence init'"
|
|
51
|
+
;;
|
|
52
|
+
esac
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if [ "$compact" -eq 0 ]; then
|
|
56
|
+
run_sync
|
|
57
|
+
exit $?
|
|
58
|
+
fi
|
|
59
|
+
|
|
60
|
+
# Compact mode is intentionally quiet only on success. Buffering the complete
|
|
61
|
+
# combined stream means a failure still returns every diagnostic emitted by
|
|
62
|
+
# lifecycle preflight, locked restore or the engine, together with its real rc.
|
|
63
|
+
compact_output="$(mktemp -t intelligence-sync-XXXXXX)"
|
|
64
|
+
trap 'rm -f "$compact_output"' EXIT
|
|
65
|
+
rc=0
|
|
66
|
+
(run_sync) > "$compact_output" 2>&1 || rc=$?
|
|
67
|
+
if [ "$rc" -ne 0 ]; then
|
|
68
|
+
cat "$compact_output" >&2
|
|
69
|
+
exit "$rc"
|
|
70
|
+
fi
|
|
71
|
+
|
|
72
|
+
status_line="$(grep '^IS_STATUS=ok\($\| \)' "$compact_output" | tail -1 || true)"
|
|
73
|
+
done_line="$(grep '^=== Done:' "$compact_output" | tail -1 || true)"
|
|
74
|
+
if [ -z "$status_line" ] || [ -z "$done_line" ]; then
|
|
75
|
+
cat "$compact_output" >&2
|
|
76
|
+
echo "ERROR: sync succeeded without its final status contract" >&2
|
|
77
|
+
exit 1
|
|
78
|
+
fi
|
|
79
|
+
echo "$status_line"
|
|
80
|
+
echo "$done_line"
|
package/cli/intelligence
CHANGED
|
@@ -46,7 +46,8 @@ Usage: intelligence <command> [args]
|
|
|
46
46
|
init [--preview|--apply] Initialize, convert, restore or align this project
|
|
47
47
|
--targets a,b --dir name --bare --no-sync New-project options
|
|
48
48
|
--force Accept a dirty worktree during legacy project conversion
|
|
49
|
-
sync [adapter]
|
|
49
|
+
sync [adapter] [--compact] Restore locked content, then render enabled adapters
|
|
50
|
+
--compact On success show only final status; on failure show diagnostics
|
|
50
51
|
update [@scope/name] Show an update plan; ask before applying it
|
|
51
52
|
--preview Show the plan without asking or writing
|
|
52
53
|
--apply Apply the plan without asking
|
|
@@ -76,6 +77,20 @@ case "$cmd" in
|
|
|
76
77
|
esac
|
|
77
78
|
cmd_file="$CLI_DIR/commands/$cmd.sh"
|
|
78
79
|
if [ ! -f "$cmd_file" ]; then
|
|
80
|
+
case "$cmd" in
|
|
81
|
+
adapters)
|
|
82
|
+
echo "ERROR: unknown command 'adapters'. Use the singular command: intelligence adapter list" >&2
|
|
83
|
+
exit 1
|
|
84
|
+
;;
|
|
85
|
+
packages)
|
|
86
|
+
echo "ERROR: unknown command 'packages'. Use the singular command: intelligence package list" >&2
|
|
87
|
+
exit 1
|
|
88
|
+
;;
|
|
89
|
+
registries)
|
|
90
|
+
echo "ERROR: unknown command 'registries'. Use the singular command: intelligence registry list" >&2
|
|
91
|
+
exit 1
|
|
92
|
+
;;
|
|
93
|
+
esac
|
|
79
94
|
echo "ERROR: unknown command '$cmd'. Run 'intelligence help'." >&2
|
|
80
95
|
exit 1
|
|
81
96
|
fi
|
package/cli/internal/check.sh
CHANGED
|
@@ -86,6 +86,46 @@ while IFS= read -r name; do
|
|
|
86
86
|
fi
|
|
87
87
|
done < <(qmap_keys "$manifest" "packages")
|
|
88
88
|
|
|
89
|
+
# Adapter contracts are the shared source of truth for dependencies, rollback,
|
|
90
|
+
# onboarding backup and Git policy. Validate every declared target, including
|
|
91
|
+
# disabled ones, so a later enable cannot reveal a stale custom adapter.
|
|
92
|
+
content_dir="$(manifest_intelligence_dir "$manifest")"
|
|
93
|
+
while IFS= read -r target; do
|
|
94
|
+
[ -n "$target" ] || continue
|
|
95
|
+
output="$(get_target_output "$manifest" "$target")"
|
|
96
|
+
[ -n "$output" ] || output="$(default_target_output "$target")"
|
|
97
|
+
adapter_file="$(adapter_file_for "$IP_ROOT" "$content_dir" "$target" 2>/dev/null || true)"
|
|
98
|
+
if [ -z "$adapter_file" ]; then
|
|
99
|
+
warn "adapter '$target' is declared but its implementation is missing"
|
|
100
|
+
continue
|
|
101
|
+
fi
|
|
102
|
+
records="$(adapter_contract_records "$target" "$adapter_file" "$output" 2>/dev/null || true)"
|
|
103
|
+
if ! printf '%s\n' "$records" | grep -Fqx $'version\t1'; then
|
|
104
|
+
warn "adapter '$target' has an invalid ownership contract"
|
|
105
|
+
continue
|
|
106
|
+
fi
|
|
107
|
+
while IFS=$'\t' read -r kind value; do
|
|
108
|
+
if [ "$kind" = "requires" ] \
|
|
109
|
+
&& [ "$(is_target_enabled "$manifest" "$target")" = "1" ] \
|
|
110
|
+
&& [ "$(is_target_enabled "$manifest" "$value")" != "1" ]; then
|
|
111
|
+
warn "enabled adapter '$target' requires enabled adapter '$value'"
|
|
112
|
+
fi
|
|
113
|
+
if [ "$(is_target_enabled "$manifest" "$target")" = "1" ]; then
|
|
114
|
+
case "$kind" in
|
|
115
|
+
ignore)
|
|
116
|
+
grep -Fqx -- "$value" "$IP_ROOT/.gitignore" 2>/dev/null \
|
|
117
|
+
|| warn "adapter '$target' Git policy is missing '$value'"
|
|
118
|
+
;;
|
|
119
|
+
include)
|
|
120
|
+
grep -Fqx -- "!$value" "$IP_ROOT/.gitignore" 2>/dev/null \
|
|
121
|
+
|| warn "adapter '$target' Git policy is missing '!$value'"
|
|
122
|
+
;;
|
|
123
|
+
esac
|
|
124
|
+
fi
|
|
125
|
+
done <<< "$records"
|
|
126
|
+
ok "adapter $target contract v1"
|
|
127
|
+
done < <(target_names "$manifest")
|
|
128
|
+
|
|
89
129
|
# Lock orphans.
|
|
90
130
|
if [ -f "$lock" ]; then
|
|
91
131
|
while IFS= read -r name; do
|
|
@@ -348,16 +348,10 @@ rollback_on_exit() {
|
|
|
348
348
|
# plain set -e/EXIT failure rather than only an explicit sync refusal.
|
|
349
349
|
trap rollback_on_exit EXIT
|
|
350
350
|
trap 'rollback; exit 130' INT TERM
|
|
351
|
-
if [ ! -f "$root/.gitignore" ] || ! grep -q '^\.intelligence/' "$root/.gitignore"; then
|
|
352
|
-
{
|
|
353
|
-
[ -f "$root/.gitignore" ] && [ -n "$(tail -c 1 "$root/.gitignore" 2>/dev/null)" ] && echo ""
|
|
354
|
-
echo "# intelligence CLI package store (restored automatically by 'intelligence sync')"
|
|
355
|
-
echo ".intelligence/"
|
|
356
|
-
} >> "$root/.gitignore"
|
|
357
|
-
fi
|
|
358
351
|
mv "$stage/.intelligence" "$root/.intelligence"
|
|
359
352
|
cp "$manifest_stage" "$root/intelligence.yaml"
|
|
360
353
|
lock_write_from_tsv "$root/intelligence.lock" "$lock_rows"
|
|
354
|
+
ensure_manifest_gitignore "$root" "$root/intelligence.yaml"
|
|
361
355
|
|
|
362
356
|
sync_out="$(cd "$root" && IS_SUPPRESS_CLI_NOTE=1 bash "$CLI_DIR/commands/sync.sh" 2>&1)" || {
|
|
363
357
|
echo "$sync_out"
|
|
@@ -397,4 +391,4 @@ rmdir "$umbrella" 2>/dev/null || true
|
|
|
397
391
|
echo ""
|
|
398
392
|
echo "converted. Review the diff, then commit. The old config.yaml is kept at .intelligence/backup/config.yaml."
|
|
399
393
|
echo "From now on: intelligence sync | package | update | status."
|
|
400
|
-
echo "Next: ask your agent to run /intelligence-learn-from-
|
|
394
|
+
echo "Next: ask your agent to run /intelligence-learn-from-context to verify setup and review the converted project context."
|
|
@@ -25,31 +25,38 @@ if [ "$action" = "enable" ]; then
|
|
|
25
25
|
die "adapter '$name' not found — create it first: intelligence adapter create $name"
|
|
26
26
|
fi
|
|
27
27
|
|
|
28
|
-
# These adapters intentionally omit always-on rules because their tools
|
|
29
|
-
# read AGENTS.md. Do not create a manifest that full sync must refuse.
|
|
30
|
-
case "$name" in
|
|
31
|
-
cursor|copilot|codex|pi|opencode)
|
|
32
|
-
if [ "$(is_target_enabled "$manifest" "agents")" != "1" ]; then
|
|
33
|
-
die "target '$name' requires target 'agents' — enable it first"
|
|
34
|
-
fi
|
|
35
|
-
;;
|
|
36
|
-
esac
|
|
37
|
-
|
|
38
28
|
output="$(get_target_output "$manifest" "$name")"
|
|
39
29
|
[ -n "$output" ] || output="$(default_target_output "$name")"
|
|
30
|
+
validate_adapter_contract_for "$IP_ROOT" "$content_dir" "$name" "$output" \
|
|
31
|
+
|| die "adapter '$name' has an invalid ownership contract"
|
|
32
|
+
while IFS= read -r required; do
|
|
33
|
+
[ -n "$required" ] || continue
|
|
34
|
+
if [ "$(is_target_enabled "$manifest" "$required")" != "1" ]; then
|
|
35
|
+
die "target '$name' requires target '$required' — enable it first"
|
|
36
|
+
fi
|
|
37
|
+
done < <(adapter_records_for "$IP_ROOT" "$content_dir" "$name" "$output" \
|
|
38
|
+
| awk -F '\t' '$1 == "requires" { print $2 }')
|
|
40
39
|
target_set_enabled "$manifest" "$name" true "$output"
|
|
40
|
+
ensure_target_gitignore "$IP_ROOT" "$manifest" "$name"
|
|
41
41
|
echo "enabled: $name (output: $output)"
|
|
42
42
|
exit 0
|
|
43
43
|
fi
|
|
44
44
|
|
|
45
45
|
target_exists "$manifest" "$name" || die "target '$name' is not in the manifest"
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
46
|
+
while IFS= read -r dependent; do
|
|
47
|
+
[ -n "$dependent" ] || continue
|
|
48
|
+
[ "$dependent" = "$name" ] && continue
|
|
49
|
+
[ "$(is_target_enabled "$manifest" "$dependent")" = "1" ] || continue
|
|
50
|
+
dependent_output="$(get_target_output "$manifest" "$dependent")"
|
|
51
|
+
[ -n "$dependent_output" ] || dependent_output="$(default_target_output "$dependent")"
|
|
52
|
+
dependent_records="$(adapter_records_for "$IP_ROOT" "$content_dir" "$dependent" "$dependent_output")" \
|
|
53
|
+
|| die "adapter '$dependent' has an invalid ownership contract"
|
|
54
|
+
if awk -F '\t' -v required="$name" \
|
|
55
|
+
'$1 == "requires" && $2 == required { found=1 } END { exit(found ? 0 : 1) }' \
|
|
56
|
+
<<< "$dependent_records"; then
|
|
57
|
+
die "target '$name' is required by enabled target '$dependent' — disable '$dependent' first"
|
|
58
|
+
fi
|
|
59
|
+
done < <(target_names "$manifest")
|
|
53
60
|
output="$(get_target_output "$manifest" "$name")"
|
|
54
61
|
[ -n "$output" ] || output="$(default_target_output "$name")"
|
|
55
62
|
target_set_enabled "$manifest" "$name" false "$output"
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# CLI consumers of the engine's declarative adapter contract.
|
|
3
|
+
|
|
4
|
+
adapter_file_for() {
|
|
5
|
+
local root="$1" content_dir="$2" name="$3"
|
|
6
|
+
if [ -f "$root/$content_dir/adapters/$name.sh" ]; then
|
|
7
|
+
printf '%s\n' "$root/$content_dir/adapters/$name.sh"
|
|
8
|
+
elif [ -f "$IS_ENGINE_DIR/adapters/$name.sh" ]; then
|
|
9
|
+
printf '%s\n' "$IS_ENGINE_DIR/adapters/$name.sh"
|
|
10
|
+
else
|
|
11
|
+
return 1
|
|
12
|
+
fi
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
adapter_records_for() {
|
|
16
|
+
local root="$1" content_dir="$2" name="$3" output="$4" file
|
|
17
|
+
file="$(adapter_file_for "$root" "$content_dir" "$name")" || {
|
|
18
|
+
echo "ERROR: adapter '$name' not found" >&2
|
|
19
|
+
return 1
|
|
20
|
+
}
|
|
21
|
+
adapter_contract_records "$name" "$file" "$output"
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
validate_adapter_contract_for() {
|
|
25
|
+
local root="$1" content_dir="$2" name="$3" output="$4"
|
|
26
|
+
adapter_records_for "$root" "$content_dir" "$name" "$output" >/dev/null
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
adapter_contract_paths() {
|
|
30
|
+
local root="$1" content_dir="$2" name="$3" output="$4"
|
|
31
|
+
adapter_records_for "$root" "$content_dir" "$name" "$output" \
|
|
32
|
+
| awk -F '\t' '$1 == "owned" || $1 == "managed" || $1 == "legacy" || $1 == "preserve" { print $2 }'
|
|
33
|
+
}
|
package/cli/lib/cli-common.sh
CHANGED
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
# IS_ENGINE_DIR come exported from the dispatcher.
|
|
12
12
|
source "$IS_ENGINE_DIR/lib/common.sh"
|
|
13
13
|
source "$IS_ENGINE_DIR/lib/contract.sh"
|
|
14
|
+
source "$IS_ENGINE_DIR/lib/adapter-contract.sh"
|
|
14
15
|
|
|
15
16
|
die() {
|
|
16
17
|
echo "ERROR: $*" >&2
|
|
@@ -50,6 +51,9 @@ source "$CLI_DIR/lib/manifest.sh"
|
|
|
50
51
|
source "$CLI_DIR/lib/semver.sh"
|
|
51
52
|
source "$CLI_DIR/lib/registry.sh"
|
|
52
53
|
source "$CLI_DIR/lib/lockfile.sh"
|
|
54
|
+
source "$CLI_DIR/lib/adapter-lifecycle.sh"
|
|
55
|
+
source "$CLI_DIR/lib/gitignore.sh"
|
|
56
|
+
source "$CLI_DIR/lib/onboarding.sh"
|
|
53
57
|
|
|
54
58
|
# The engine-content package: OPTIONAL but auto-selected at init. Package by
|
|
55
59
|
# UX (manifest entry, lockfile row, list/search/remove), bundle by mechanics —
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Generated-output policy derived from each adapter's ownership contract.
|
|
3
|
+
|
|
4
|
+
gitignore_add_line() {
|
|
5
|
+
local root="$1" line="$2" file="$1/.gitignore"
|
|
6
|
+
if [ -f "$file" ] && grep -Fqx -- "$line" "$file"; then
|
|
7
|
+
return 0
|
|
8
|
+
fi
|
|
9
|
+
printf '%s\n' "$line" >> "$file"
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
ensure_gitignore_header() {
|
|
13
|
+
local root="$1" file="$1/.gitignore"
|
|
14
|
+
if [ ! -f "$file" ] || ! grep -Fqx '# Intelligence generated state and tool output' "$file"; then
|
|
15
|
+
if [ -f "$file" ] && [ -s "$file" ] && [ -n "$(tail -c 1 "$file" 2>/dev/null)" ]; then
|
|
16
|
+
printf '\n' >> "$file"
|
|
17
|
+
fi
|
|
18
|
+
printf '%s\n' '# Intelligence generated state and tool output' >> "$file"
|
|
19
|
+
fi
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
ensure_base_gitignore() {
|
|
23
|
+
local root="$1"
|
|
24
|
+
ensure_gitignore_header "$root"
|
|
25
|
+
gitignore_add_line "$root" '.intelligence/'
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
ensure_target_gitignore() {
|
|
29
|
+
local root="$1" manifest="$2" target="$3" content_dir output kind value records
|
|
30
|
+
ensure_gitignore_header "$root"
|
|
31
|
+
content_dir="$(manifest_intelligence_dir "$manifest")"
|
|
32
|
+
output="$(get_target_output "$manifest" "$target")"
|
|
33
|
+
[ -n "$output" ] || output="$(default_target_output "$target")"
|
|
34
|
+
records="$(adapter_records_for "$root" "$content_dir" "$target" "$output")" \
|
|
35
|
+
|| die "adapter '$target' has an invalid ownership contract"
|
|
36
|
+
while IFS=$'\t' read -r kind value; do
|
|
37
|
+
case "$kind" in
|
|
38
|
+
ignore) gitignore_add_line "$root" "$value" ;;
|
|
39
|
+
include) gitignore_add_line "$root" "!$value" ;;
|
|
40
|
+
esac
|
|
41
|
+
done <<< "$records"
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
ensure_manifest_gitignore() {
|
|
45
|
+
local root="$1" manifest="$2" target
|
|
46
|
+
ensure_base_gitignore "$root"
|
|
47
|
+
while IFS= read -r target; do
|
|
48
|
+
[ -n "$target" ] || continue
|
|
49
|
+
if [ "$(is_target_enabled "$manifest" "$target")" = "1" ]; then
|
|
50
|
+
ensure_target_gitignore "$root" "$manifest" "$target"
|
|
51
|
+
fi
|
|
52
|
+
done < <(target_names "$manifest")
|
|
53
|
+
}
|