@ainova-systems/intelligence 0.11.0-rc.11 → 0.11.0-rc.13
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 +115 -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 +17 -0
- 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 +43 -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,47 @@ 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 " Finalize repository onboarding:"
|
|
37
|
+
echo " Ask your agent to run /intelligence-learn-from-context"
|
|
38
|
+
echo " It recognizes the initial backup, recovers setup if needed, then proposes repository-specific migration after approval."
|
|
39
|
+
echo " Recommended starter package:"
|
|
40
|
+
echo " intelligence package add @ainova-systems/core"
|
|
41
|
+
fi
|
|
42
|
+
echo " Review adapters:"
|
|
43
|
+
echo " intelligence adapter list"
|
|
44
|
+
echo " intelligence adapter enable codex"
|
|
45
|
+
echo " intelligence adapter disable cursor"
|
|
46
|
+
echo " Version control:"
|
|
47
|
+
echo " Generated adapter output is gitignored by CLI-owned path."
|
|
48
|
+
echo " Commit intelligence.yaml, intelligence.lock, intelligence/, AGENTS.md, and .github/."
|
|
49
|
+
echo " Shared tool settings remain trackable; review the exact ownership policy:"
|
|
50
|
+
echo " https://github.com/ainova-systems/intelligence/blob/main/packages/sync/references/conventions.md#generated-output-and-version-control"
|
|
51
|
+
echo " Write your own:"
|
|
52
|
+
echo " create $content_dir/rules/context.md, then intelligence sync"
|
|
53
|
+
echo " Docs: https://github.com/ainova-systems/intelligence#readme"
|
|
54
|
+
}
|
|
55
|
+
|
|
15
56
|
while [ $# -gt 0 ]; do
|
|
16
57
|
case "$1" in
|
|
17
58
|
--targets) shift; targets_arg="${1:-}"; targets_set=1 ;;
|
|
@@ -68,9 +109,25 @@ case "$IP_MODE" in
|
|
|
68
109
|
ensure_project_current "$IP_ROOT"
|
|
69
110
|
fi
|
|
70
111
|
restore_project_store_if_missing "$IP_ROOT"
|
|
112
|
+
ensure_manifest_gitignore "$IP_ROOT" "$IP_ROOT/intelligence.yaml"
|
|
71
113
|
[ "$no_sync" -eq 1 ] && exit 0
|
|
72
114
|
cd "$IP_ROOT"
|
|
73
|
-
|
|
115
|
+
sync_rc=0
|
|
116
|
+
bash "$CLI_DIR/commands/sync.sh" || sync_rc=$?
|
|
117
|
+
if [ "$sync_rc" -ne 0 ]; then
|
|
118
|
+
content_dir="$(manifest_intelligence_dir "$IP_ROOT/intelligence.yaml")"
|
|
119
|
+
recovery_backup=""
|
|
120
|
+
if [ -f "$IP_ROOT/$content_dir/_backup/manifest.tsv" ]; then
|
|
121
|
+
recovery_backup="; initial backup: $content_dir/_backup/manifest.tsv"
|
|
122
|
+
fi
|
|
123
|
+
echo "" >&2
|
|
124
|
+
echo "=== Intelligence setup needs recovery ===" >&2
|
|
125
|
+
echo " No partial adapter update was kept; sync restored its pre-run outputs." >&2
|
|
126
|
+
echo " Ask your agent to read:" >&2
|
|
127
|
+
echo " $SYNC_PKG_STORE/skills/intelligence-learn-from-context/SKILL.md" >&2
|
|
128
|
+
echo " and finalize this Intelligence setup$recovery_backup." >&2
|
|
129
|
+
fi
|
|
130
|
+
exit "$sync_rc"
|
|
74
131
|
;;
|
|
75
132
|
legacy)
|
|
76
133
|
[ "$targets_set" -eq 0 ] || die "--targets applies only when creating a new project"
|
|
@@ -117,17 +174,30 @@ if [ -n "$targets_arg" ]; then
|
|
|
117
174
|
done
|
|
118
175
|
else
|
|
119
176
|
if [ -d "$root/.claude" ] || [ -f "$root/CLAUDE.md" ]; then targets="$targets claude"; fi
|
|
120
|
-
[ -d "$root/.cursor" ]
|
|
121
|
-
[ -d "$root/.codex" ]
|
|
177
|
+
if [ -d "$root/.cursor" ] || [ -f "$root/.cursorrules" ]; then targets="$targets cursor"; fi
|
|
178
|
+
if [ -d "$root/.codex" ] || [ -d "$root/.agents" ]; then targets="$targets codex"; fi
|
|
122
179
|
[ -d "$root/.pi" ] && targets="$targets pi"
|
|
123
180
|
[ -d "$root/.opencode" ] && targets="$targets opencode"
|
|
124
|
-
|
|
181
|
+
if [ -f "$root/.github/copilot-instructions.md" ] \
|
|
182
|
+
|| [ -d "$root/.github/instructions" ] \
|
|
183
|
+
|| [ -d "$root/.github/agents" ] \
|
|
184
|
+
|| [ -d "$root/.github/skills" ]; then
|
|
185
|
+
targets="$targets copilot"
|
|
186
|
+
fi
|
|
125
187
|
if [ "$targets" = "agents" ]; then
|
|
126
188
|
echo " NOTE: no tool markers found (.claude/, CLAUDE.md, .cursor/, …) — only AGENTS.md is enabled." >&2
|
|
127
189
|
echo " Name your tools explicitly: intelligence init --targets claude,cursor (or edit targets: later)" >&2
|
|
128
190
|
fi
|
|
129
191
|
fi
|
|
130
192
|
|
|
193
|
+
onboarding_count="$(onboarding_source_count "$root" "$content_dir" "$targets")"
|
|
194
|
+
onboarding_has_agents=0
|
|
195
|
+
[ -f "$root/AGENTS.md" ] && onboarding_has_agents=1
|
|
196
|
+
if [ "$preview" -eq 0 ] && [ "$onboarding_count" -gt 0 ] \
|
|
197
|
+
&& [ -e "$root/$content_dir/_backup" ]; then
|
|
198
|
+
die "onboarding backup already exists at $content_dir/_backup - review or move it before rerunning init"
|
|
199
|
+
fi
|
|
200
|
+
|
|
131
201
|
if [ "$preview" -eq 1 ]; then
|
|
132
202
|
echo "project: no Intelligence setup found"
|
|
133
203
|
echo " would create intelligence.yaml and intelligence.lock"
|
|
@@ -141,6 +211,9 @@ if [ "$preview" -eq 1 ]; then
|
|
|
141
211
|
else
|
|
142
212
|
echo " would enable adapters:$targets, then sync"
|
|
143
213
|
fi
|
|
214
|
+
if [ "$onboarding_count" -gt 0 ]; then
|
|
215
|
+
echo " would preserve $onboarding_count existing AI instruction path(s) in $content_dir/_backup before sync"
|
|
216
|
+
fi
|
|
144
217
|
exit 0
|
|
145
218
|
fi
|
|
146
219
|
|
|
@@ -175,7 +248,21 @@ manifest="$root/intelligence.yaml"
|
|
|
175
248
|
echo "# Generated output, one entry per tool. Add or drop tools freely."
|
|
176
249
|
echo "targets:"
|
|
177
250
|
for t in $targets; do
|
|
178
|
-
|
|
251
|
+
if [ "$t" = "agents" ] && [ "$onboarding_has_agents" -eq 1 ]; then
|
|
252
|
+
echo " agents:"
|
|
253
|
+
echo " enabled: true"
|
|
254
|
+
echo " output: \"AGENTS.md\""
|
|
255
|
+
echo " header: |"
|
|
256
|
+
echo " > Intelligence onboarding is pending. Before repository work, read"
|
|
257
|
+
echo " > \`$content_dir/_backup/AGENTS.md\`, which preserves the original project instructions."
|
|
258
|
+
if [ "$bare" -eq 0 ]; then
|
|
259
|
+
echo " > Run /intelligence-learn-from-context to migrate and verify them before removing the backup."
|
|
260
|
+
else
|
|
261
|
+
echo " > Review and migrate that backup before removing it."
|
|
262
|
+
fi
|
|
263
|
+
else
|
|
264
|
+
echo " $t: { enabled: true, output: \"$(default_target_output "$t")\" }"
|
|
265
|
+
fi
|
|
179
266
|
done
|
|
180
267
|
echo ""
|
|
181
268
|
echo "# Packages are managed with 'intelligence package add|search|list':"
|
|
@@ -202,13 +289,10 @@ manifest="$root/intelligence.yaml"
|
|
|
202
289
|
} > "$manifest"
|
|
203
290
|
|
|
204
291
|
# The package store is restorable state, never committed — the npm model.
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
echo ".intelligence/"
|
|
210
|
-
} >> "$root/.gitignore"
|
|
211
|
-
fi
|
|
292
|
+
ensure_base_gitignore "$root"
|
|
293
|
+
for target in $targets; do
|
|
294
|
+
ensure_target_gitignore "$root" "$manifest" "$target"
|
|
295
|
+
done
|
|
212
296
|
|
|
213
297
|
# The engine's own content (meta-skills, authoring rule, engine agents) is an
|
|
214
298
|
# ordinary package: auto-selected, opted out with --bare, removable later with
|
|
@@ -218,16 +302,27 @@ if [ "$bare" -eq 0 ]; then
|
|
|
218
302
|
sync_pkg_install "$root"
|
|
219
303
|
fi
|
|
220
304
|
|
|
305
|
+
preserve_onboarding_sources "$root" "$content_dir" "$targets"
|
|
306
|
+
|
|
221
307
|
echo "initialized: intelligence.yaml (targets:$(printf ' %s' $targets))"
|
|
222
308
|
[ "$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
309
|
if [ "$no_sync" -eq 0 ]; then
|
|
231
310
|
cd "$root"
|
|
232
|
-
|
|
311
|
+
sync_rc=0
|
|
312
|
+
bash "$CLI_DIR/commands/sync.sh" --compact || sync_rc=$?
|
|
313
|
+
if [ "$sync_rc" -ne 0 ]; then
|
|
314
|
+
echo "" >&2
|
|
315
|
+
echo "=== Intelligence setup needs recovery ===" >&2
|
|
316
|
+
echo " No partial adapter update was kept; sync restored its pre-run outputs." >&2
|
|
317
|
+
if [ "$bare" -eq 0 ]; then
|
|
318
|
+
echo " Ask your agent to read:" >&2
|
|
319
|
+
echo " $SYNC_PKG_STORE/skills/intelligence-learn-from-context/SKILL.md" >&2
|
|
320
|
+
echo " and finalize the initial Intelligence setup. The snapshot is $content_dir/_backup/manifest.tsv." >&2
|
|
321
|
+
else
|
|
322
|
+
echo " Fix the reported error, then rerun: intelligence init" >&2
|
|
323
|
+
fi
|
|
324
|
+
exit "$sync_rc"
|
|
325
|
+
fi
|
|
233
326
|
fi
|
|
327
|
+
|
|
328
|
+
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
|
+
}
|
package/cli/lib/manifest.sh
CHANGED
|
@@ -60,6 +60,23 @@ target_exists() {
|
|
|
60
60
|
' "$file"
|
|
61
61
|
}
|
|
62
62
|
|
|
63
|
+
# target_names <manifest> — declared target keys in manifest order.
|
|
64
|
+
target_names() {
|
|
65
|
+
local file="$1"
|
|
66
|
+
[ -f "$file" ] || return 0
|
|
67
|
+
awk '
|
|
68
|
+
{ sub(/\r$/, "") }
|
|
69
|
+
/^targets:[[:space:]]*$/ { in_targets = 1; next }
|
|
70
|
+
in_targets && /^[A-Za-z]/ { in_targets = 0 }
|
|
71
|
+
in_targets && /^ [a-z][a-z0-9_]*:/ {
|
|
72
|
+
line = $0
|
|
73
|
+
sub(/^ /, "", line)
|
|
74
|
+
sub(/:.*/, "", line)
|
|
75
|
+
print line
|
|
76
|
+
}
|
|
77
|
+
' "$file"
|
|
78
|
+
}
|
|
79
|
+
|
|
63
80
|
# target_set_enabled <manifest> <name> <true|false> <default-output>
|
|
64
81
|
# Transactionally update only `enabled`, preserving every other target field
|
|
65
82
|
# and comment. A missing target is added in the compact form used by init.
|