pilotswarm-sdk 0.5.63 → 0.5.64

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 (81) hide show
  1. package/api/src/admin-diagnostics.d.ts +12 -0
  2. package/api/src/admin-diagnostics.js +38 -1
  3. package/api/src/http-api-transport.js +26 -0
  4. package/api/src/protocol.js +15 -0
  5. package/dist/cms-migrations.d.ts.map +1 -1
  6. package/dist/cms-migrations.js +4 -0
  7. package/dist/cms-migrations.js.map +1 -1
  8. package/dist/cms.d.ts +3 -0
  9. package/dist/cms.d.ts.map +1 -1
  10. package/dist/cms.js +7 -0
  11. package/dist/cms.js.map +1 -1
  12. package/dist/feature-flag-cache.d.ts +40 -0
  13. package/dist/feature-flag-cache.d.ts.map +1 -0
  14. package/dist/feature-flag-cache.js +125 -0
  15. package/dist/feature-flag-cache.js.map +1 -0
  16. package/dist/feature-flags.d.ts +68 -0
  17. package/dist/feature-flags.d.ts.map +1 -0
  18. package/dist/feature-flags.js +45 -0
  19. package/dist/feature-flags.js.map +1 -0
  20. package/dist/feature-store.d.ts +55 -0
  21. package/dist/feature-store.d.ts.map +1 -0
  22. package/dist/feature-store.js +106 -0
  23. package/dist/feature-store.js.map +1 -0
  24. package/dist/feature-tools.d.ts +94 -0
  25. package/dist/feature-tools.d.ts.map +1 -0
  26. package/dist/feature-tools.js +60 -0
  27. package/dist/feature-tools.js.map +1 -0
  28. package/dist/index.d.ts +6 -0
  29. package/dist/index.d.ts.map +1 -1
  30. package/dist/index.js +4 -0
  31. package/dist/index.js.map +1 -1
  32. package/dist/managed-session.d.ts +4 -0
  33. package/dist/managed-session.d.ts.map +1 -1
  34. package/dist/managed-session.js +99 -10
  35. package/dist/managed-session.js.map +1 -1
  36. package/dist/management-client.d.ts +18 -0
  37. package/dist/management-client.d.ts.map +1 -1
  38. package/dist/management-client.js +19 -0
  39. package/dist/management-client.js.map +1 -1
  40. package/dist/migrations/feature-flags-0077.d.ts +3 -0
  41. package/dist/migrations/feature-flags-0077.d.ts.map +1 -0
  42. package/dist/migrations/feature-flags-0077.js +271 -0
  43. package/dist/migrations/feature-flags-0077.js.map +1 -0
  44. package/dist/migrations/native-tasks-default-policy-0078.d.ts +3 -0
  45. package/dist/migrations/native-tasks-default-policy-0078.d.ts.map +1 -0
  46. package/dist/migrations/native-tasks-default-policy-0078.js +21 -0
  47. package/dist/migrations/native-tasks-default-policy-0078.js.map +1 -0
  48. package/dist/native-subagents.d.ts +25 -0
  49. package/dist/native-subagents.d.ts.map +1 -0
  50. package/dist/native-subagents.js +186 -0
  51. package/dist/native-subagents.js.map +1 -0
  52. package/dist/native-task-observer.d.ts +87 -0
  53. package/dist/native-task-observer.d.ts.map +1 -0
  54. package/dist/native-task-observer.js +268 -0
  55. package/dist/native-task-observer.js.map +1 -0
  56. package/dist/session-manager.d.ts +6 -0
  57. package/dist/session-manager.d.ts.map +1 -1
  58. package/dist/session-manager.js +68 -9
  59. package/dist/session-manager.js.map +1 -1
  60. package/dist/session-proxy.d.ts.map +1 -1
  61. package/dist/session-proxy.js +18 -1
  62. package/dist/session-proxy.js.map +1 -1
  63. package/dist/types.d.ts +8 -0
  64. package/dist/types.d.ts.map +1 -1
  65. package/dist/types.js.map +1 -1
  66. package/dist/web/generated-op-methods.d.ts +96 -0
  67. package/dist/web/generated-op-methods.d.ts.map +1 -1
  68. package/dist/web/generated-op-methods.js +24 -0
  69. package/dist/web/generated-op-methods.js.map +1 -1
  70. package/dist/web/web-management-client.d.ts +13 -0
  71. package/dist/web/web-management-client.d.ts.map +1 -1
  72. package/dist/web/web-management-client.js +12 -0
  73. package/dist/web/web-management-client.js.map +1 -1
  74. package/dist/worker.d.ts +4 -0
  75. package/dist/worker.d.ts.map +1 -1
  76. package/dist/worker.js +40 -11
  77. package/dist/worker.js.map +1 -1
  78. package/package.json +3 -3
  79. package/plugins/mgmt/agents/pilotswarm.agent.md +18 -1
  80. package/plugins/mgmt/agents/resourcemgr.agent.md +18 -1
  81. package/plugins/system/agents/default.agent.md +15 -7
@@ -0,0 +1,3 @@
1
+ /** Frozen catalog publication. 0076 preserves upstream MoA dashboards. */
2
+ export declare function featureFlagsMigration(schema: string): string;
3
+ //# sourceMappingURL=feature-flags-0077.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"feature-flags-0077.d.ts","sourceRoot":"","sources":["../../src/migrations/feature-flags-0077.ts"],"names":[],"mappings":"AAAA,0EAA0E;AAC1E,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CA4Q5D"}
@@ -0,0 +1,271 @@
1
+ /** Frozen catalog publication. 0076 preserves upstream MoA dashboards. */
2
+ export function featureFlagsMigration(schema) {
3
+ const s = `"${schema.replace(/"/g, '""')}"`;
4
+ return `
5
+ CREATE TABLE IF NOT EXISTS ${s}.feature_flags (
6
+ feature_key TEXT PRIMARY KEY, display_name TEXT NOT NULL, description TEXT NOT NULL,
7
+ default_enabled BOOLEAN NOT NULL, default_allow_user_override BOOLEAN NOT NULL,
8
+ required_capability TEXT, revision BIGINT NOT NULL DEFAULT 1 CHECK (revision > 0)
9
+ );
10
+ CREATE TABLE IF NOT EXISTS ${s}.feature_flag_settings (
11
+ setting_id BIGSERIAL PRIMARY KEY,
12
+ feature_key TEXT NOT NULL REFERENCES ${s}.feature_flags(feature_key),
13
+ scope TEXT NOT NULL CHECK (scope IN ('cluster', 'user')),
14
+ user_id BIGINT REFERENCES ${s}.users(user_id), enabled BOOLEAN NOT NULL,
15
+ allow_user_override BOOLEAN, revision BIGINT NOT NULL CHECK (revision > 0),
16
+ updated_by TEXT NOT NULL, updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
17
+ CHECK ((scope = 'cluster' AND user_id IS NULL AND allow_user_override IS NOT NULL)
18
+ OR (scope = 'user' AND user_id IS NOT NULL AND allow_user_override IS NULL))
19
+ );
20
+ CREATE UNIQUE INDEX IF NOT EXISTS feature_flag_settings_cluster ON ${s}.feature_flag_settings(feature_key) WHERE scope = 'cluster';
21
+ CREATE UNIQUE INDEX IF NOT EXISTS feature_flag_settings_user ON ${s}.feature_flag_settings(feature_key, user_id) WHERE scope = 'user';
22
+ CREATE INDEX IF NOT EXISTS feature_flag_settings_by_user ON ${s}.feature_flag_settings(user_id) WHERE scope = 'user';
23
+ CREATE UNIQUE INDEX IF NOT EXISTS feature_flag_audit_request ON ${s}.authz_audit
24
+ ((details->>'actorKey'), (details->>'requestId'))
25
+ WHERE action IN ('feature_flag.set', 'feature_flag.unset') AND decision = 'allow';
26
+ INSERT INTO ${s}.feature_flags(feature_key, display_name, description, default_enabled, default_allow_user_override, required_capability)
27
+ VALUES ('copilot.native_tasks', 'Native Copilot tasks',
28
+ 'Allow Copilot to delegate local work to native tasks on the same worker.', false, false, 'copilot.native_tasks')
29
+ ON CONFLICT (feature_key) DO NOTHING;
30
+
31
+ CREATE OR REPLACE FUNCTION ${s}.cms_feature_definition_json(f ${s}.feature_flags) RETURNS JSONB LANGUAGE sql IMMUTABLE AS $$
32
+ SELECT jsonb_build_object('featureKey', f.feature_key, 'displayName', f.display_name,
33
+ 'description', f.description, 'defaultEnabled', f.default_enabled,
34
+ 'defaultAllowUserOverride', f.default_allow_user_override,
35
+ 'requiredCapability', f.required_capability, 'revision', f.revision::TEXT);
36
+ $$;
37
+ CREATE OR REPLACE FUNCTION ${s}.cms_feature_setting_json(r ${s}.feature_flag_settings) RETURNS JSONB LANGUAGE sql IMMUTABLE AS $$
38
+ SELECT jsonb_build_object('settingId', r.setting_id::TEXT, 'featureKey', r.feature_key,
39
+ 'scope', r.scope, 'userId', r.user_id, 'enabled', r.enabled, 'allowUserOverride', r.allow_user_override,
40
+ 'revision', r.revision::TEXT, 'updatedBy', r.updated_by, 'updatedAt', r.updated_at);
41
+ $$;
42
+ CREATE OR REPLACE FUNCTION ${s}.cms_feature_revisions() RETURNS TABLE(feature_key TEXT, revision TEXT) LANGUAGE sql STABLE AS $$
43
+ SELECT f.feature_key, f.revision::TEXT FROM ${s}.feature_flags f ORDER BY f.feature_key;
44
+ $$;
45
+ -- Internal worker read: one statement snapshot, complete settings for each requested key.
46
+ CREATE OR REPLACE FUNCTION ${s}.cms_feature_snapshot(p_keys TEXT[]) RETURNS JSONB LANGUAGE sql STABLE AS $$
47
+ SELECT jsonb_build_object(
48
+ 'definitions', COALESCE((SELECT jsonb_agg(${s}.cms_feature_definition_json(f) ORDER BY f.feature_key)
49
+ FROM ${s}.feature_flags f WHERE f.feature_key = ANY(p_keys)), '[]'::JSONB),
50
+ 'settings', COALESCE((SELECT jsonb_agg(${s}.cms_feature_setting_json(r) ||
51
+ CASE WHEN u.user_id IS NOT NULL THEN jsonb_build_object('owner', jsonb_build_object('provider', u.provider, 'subject', u.subject)) ELSE '{}'::JSONB END)
52
+ FROM ${s}.feature_flag_settings r LEFT JOIN ${s}.users u ON u.user_id = r.user_id
53
+ WHERE r.feature_key = ANY(p_keys)), '[]'::JSONB));
54
+ $$;
55
+ -- Authenticated surfaces supply the actor; never accept it from request JSON.
56
+ CREATE OR REPLACE FUNCTION ${s}.cms_feature_target(p_provider TEXT, p_subject TEXT, p_admin BOOLEAN, p_scope TEXT, p_user BIGINT, p_write BOOLEAN)
57
+ RETURNS BIGINT LANGUAGE plpgsql STABLE AS $$
58
+ DECLARE v_actor BIGINT; v_target BIGINT;
59
+ BEGIN
60
+ IF COALESCE(p_provider, '') = '' OR COALESCE(p_subject, '') = '' THEN
61
+ RAISE EXCEPTION 'FEATURE_FORBIDDEN: An authenticated actor is required';
62
+ END IF;
63
+ SELECT u.user_id INTO v_actor FROM ${s}.users u WHERE u.provider = p_provider AND u.subject = p_subject;
64
+ IF p_scope = 'cluster' THEN
65
+ IF p_user IS NOT NULL THEN RAISE EXCEPTION 'FEATURE_INVALID: Cluster scope cannot name a user'; END IF;
66
+ IF p_write AND NOT COALESCE(p_admin, false) THEN RAISE EXCEPTION 'FEATURE_FORBIDDEN: Cluster changes require admin'; END IF;
67
+ RETURN NULL;
68
+ END IF;
69
+ IF p_scope IS DISTINCT FROM 'user' THEN RAISE EXCEPTION 'FEATURE_INVALID: Invalid feature scope'; END IF;
70
+ v_target := COALESCE(p_user, v_actor);
71
+ IF v_target IS NULL OR (NOT COALESCE(p_admin, false) AND v_target IS DISTINCT FROM v_actor) THEN
72
+ RAISE EXCEPTION 'FEATURE_FORBIDDEN: Only admins can access another user';
73
+ END IF;
74
+ IF NOT EXISTS (SELECT 1 FROM ${s}.users WHERE user_id = v_target) THEN RAISE EXCEPTION 'FEATURE_NOT_FOUND: User not found'; END IF;
75
+ RETURN v_target;
76
+ END;
77
+ $$;
78
+ CREATE OR REPLACE FUNCTION ${s}.cms_feature_read(p_provider TEXT, p_subject TEXT, p_admin BOOLEAN, p_scope TEXT, p_user BIGINT)
79
+ RETURNS JSONB LANGUAGE plpgsql STABLE AS $$
80
+ DECLARE v_user BIGINT; v_result JSONB;
81
+ BEGIN
82
+ v_user := ${s}.cms_feature_target(p_provider, p_subject, p_admin, p_scope, p_user, false);
83
+ SELECT jsonb_build_object('userId', v_user,
84
+ 'definitions', COALESCE((SELECT jsonb_agg(${s}.cms_feature_definition_json(f) ORDER BY f.feature_key) FROM ${s}.feature_flags f), '[]'::JSONB),
85
+ 'settings', COALESCE((SELECT jsonb_agg(${s}.cms_feature_setting_json(r)) FROM ${s}.feature_flag_settings r
86
+ WHERE r.scope = 'cluster' OR r.user_id = v_user), '[]'::JSONB)) INTO v_result;
87
+ RETURN v_result;
88
+ END;
89
+ $$;
90
+ CREATE OR REPLACE FUNCTION ${s}.cms_feature_mutate(
91
+ p_provider TEXT, p_subject TEXT, p_admin BOOLEAN, p_scope TEXT, p_user BIGINT,
92
+ p_key TEXT, p_enabled BOOLEAN, p_override BOOLEAN, p_unset BOOLEAN, p_expected BIGINT, p_request TEXT)
93
+ RETURNS JSONB LANGUAGE plpgsql AS $$
94
+ DECLARE v_user BIGINT; v_actor TEXT; v_hash TEXT; v_before JSONB; v_after JSONB;
95
+ v_revision BIGINT; v_result JSONB; v_receipt JSONB;
96
+ BEGIN
97
+ v_user := ${s}.cms_feature_target(p_provider, p_subject, p_admin, p_scope, p_user, true);
98
+ -- Registration locks ghost users before moving their preferences. Take the
99
+ -- same user -> feature lock order, and keep this FK target alive until commit.
100
+ IF v_user IS NOT NULL THEN
101
+ PERFORM 1 FROM ${s}.users WHERE user_id = v_user FOR KEY SHARE;
102
+ IF NOT FOUND THEN RAISE EXCEPTION 'FEATURE_NOT_FOUND: User not found'; END IF;
103
+ END IF;
104
+ IF p_expected IS NULL OR p_expected < 1 OR COALESCE(length(p_request), 0) NOT BETWEEN 1 AND 128 OR p_unset IS NULL THEN
105
+ RAISE EXCEPTION 'FEATURE_INVALID: Positive expectedRevision and requestId are required';
106
+ END IF;
107
+ IF (NOT p_unset AND (p_enabled IS NULL OR (p_scope = 'cluster' AND p_override IS NULL)))
108
+ OR (p_scope = 'user' AND p_override IS NOT NULL)
109
+ OR (p_unset AND (p_enabled IS NOT NULL OR p_override IS NOT NULL)) THEN
110
+ RAISE EXCEPTION 'FEATURE_INVALID: Invalid setting values for scope';
111
+ END IF;
112
+ v_actor := jsonb_build_array(p_provider, p_subject)::TEXT;
113
+ v_hash := md5(jsonb_build_array(p_scope, v_user, p_key, p_enabled, p_override, p_unset, p_expected)::TEXT);
114
+ -- Serialize receipts across different feature keys using the same actor/request ID.
115
+ PERFORM pg_advisory_xact_lock(hashtextextended(v_actor || ':' || p_request, 7731));
116
+ SELECT a.details INTO v_receipt FROM ${s}.authz_audit a WHERE a.action IN ('feature_flag.set', 'feature_flag.unset')
117
+ AND a.decision = 'allow' AND a.details->>'actorKey' = v_actor AND a.details->>'requestId' = p_request;
118
+ IF v_receipt IS NOT NULL THEN
119
+ IF v_receipt->>'requestHash' IS DISTINCT FROM v_hash THEN RAISE EXCEPTION 'FEATURE_CONFLICT: Request ID was used for different input'; END IF;
120
+ RETURN v_receipt->'result';
121
+ END IF;
122
+ SELECT f.revision INTO v_revision FROM ${s}.feature_flags f WHERE f.feature_key = p_key FOR UPDATE;
123
+ IF NOT FOUND THEN RAISE EXCEPTION 'FEATURE_NOT_FOUND: Feature not found'; END IF;
124
+ IF v_revision <> p_expected THEN RAISE EXCEPTION 'FEATURE_CONFLICT: Feature changed; reload before saving'; END IF;
125
+ SELECT ${s}.cms_feature_setting_json(r) INTO v_before FROM ${s}.feature_flag_settings r
126
+ WHERE r.feature_key = p_key AND r.scope = p_scope AND r.user_id IS NOT DISTINCT FROM v_user;
127
+ UPDATE ${s}.feature_flags SET revision = revision + 1 WHERE feature_key = p_key RETURNING revision INTO v_revision;
128
+ IF p_unset THEN
129
+ DELETE FROM ${s}.feature_flag_settings WHERE feature_key = p_key AND scope = p_scope AND user_id IS NOT DISTINCT FROM v_user;
130
+ ELSE
131
+ UPDATE ${s}.feature_flag_settings SET enabled = p_enabled, allow_user_override = p_override,
132
+ revision = v_revision, updated_by = v_actor, updated_at = now()
133
+ WHERE feature_key = p_key AND scope = p_scope AND user_id IS NOT DISTINCT FROM v_user
134
+ RETURNING ${s}.cms_feature_setting_json(feature_flag_settings) INTO v_after;
135
+ IF NOT FOUND THEN
136
+ INSERT INTO ${s}.feature_flag_settings (feature_key, scope, user_id, enabled, allow_user_override, revision, updated_by)
137
+ VALUES (p_key, p_scope, v_user, p_enabled, p_override, v_revision, v_actor)
138
+ RETURNING ${s}.cms_feature_setting_json(feature_flag_settings) INTO v_after;
139
+ END IF;
140
+ END IF;
141
+ v_result := jsonb_build_object('featureKey', p_key, 'scope', p_scope, 'userId', v_user, 'revision', v_revision::TEXT, 'setting', v_after);
142
+ INSERT INTO ${s}.authz_audit(actor_provider, actor_subject, action, target, decision, details)
143
+ VALUES (p_provider, p_subject, CASE WHEN p_unset THEN 'feature_flag.unset' ELSE 'feature_flag.set' END,
144
+ p_key, 'allow', jsonb_build_object('actorKey', v_actor, 'requestId', p_request, 'requestHash', v_hash,
145
+ 'scope', p_scope, 'userId', v_user, 'featureKey', p_key, 'before', v_before, 'after', v_after,
146
+ 'revision', v_revision::TEXT, 'result', v_result));
147
+ RETURN v_result;
148
+ END;
149
+ $$;
150
+ CREATE OR REPLACE FUNCTION ${s}.cms_feature_changes(p_provider TEXT, p_subject TEXT, p_admin BOOLEAN, p_limit INT)
151
+ RETURNS JSONB LANGUAGE plpgsql STABLE AS $$
152
+ BEGIN
153
+ PERFORM ${s}.cms_feature_target(p_provider, p_subject, p_admin, 'cluster', NULL, true);
154
+ RETURN COALESCE((SELECT jsonb_agg(to_jsonb(a)) FROM (SELECT audit_id::TEXT, occurred_at, actor_provider, actor_subject, action, target, details
155
+ FROM ${s}.authz_audit WHERE action IN ('feature_flag.set', 'feature_flag.unset', 'feature_flag.user_adopt')
156
+ ORDER BY audit_id DESC LIMIT LEAST(200, GREATEST(1, COALESCE(p_limit, 50)))) a), '[]'::JSONB);
157
+ END;
158
+ $$;
159
+ CREATE OR REPLACE FUNCTION ${s}.cms_feature_users(p_provider TEXT, p_subject TEXT, p_admin BOOLEAN, p_query TEXT)
160
+ RETURNS JSONB LANGUAGE plpgsql STABLE AS $$
161
+ BEGIN
162
+ PERFORM ${s}.cms_feature_target(p_provider, p_subject, p_admin, 'cluster', NULL, true);
163
+ RETURN COALESCE((SELECT jsonb_agg(to_jsonb(u)) FROM (SELECT user_id AS "userId", provider, subject, email, display_name AS "displayName"
164
+ FROM ${s}.users WHERE COALESCE(p_query, '') = '' OR position(lower(p_query) IN lower(COALESCE(display_name, '') || ' ' || COALESCE(email, '') || ' ' || subject)) > 0
165
+ ORDER BY COALESCE(display_name, email, subject), user_id LIMIT 500) u), '[]'::JSONB);
166
+ END;
167
+ $$;
168
+
169
+ -- Frozen replacement of 0063 registration, extended for feature preferences.
170
+ CREATE OR REPLACE FUNCTION ${s}.cms_register_user(
171
+ p_provider TEXT,
172
+ p_subject TEXT,
173
+ p_email TEXT,
174
+ p_display_name TEXT
175
+ ) RETURNS BIGINT AS $$
176
+ DECLARE
177
+ v_provider TEXT := NULLIF(BTRIM(p_provider), '');
178
+ v_subject TEXT := NULLIF(BTRIM(p_subject), '');
179
+ v_email TEXT := NULLIF(BTRIM(p_email), '');
180
+ v_display TEXT := NULLIF(BTRIM(p_display_name), '');
181
+ v_user_id BIGINT;
182
+ v_ghost BIGINT;
183
+ v_feature TEXT;
184
+ v_revision BIGINT;
185
+ v_before JSONB;
186
+ v_after JSONB;
187
+ BEGIN
188
+ IF v_provider IS NULL OR v_subject IS NULL THEN
189
+ RAISE EXCEPTION 'User provider and subject are required';
190
+ END IF;
191
+
192
+ INSERT INTO ${s}.users (provider, subject, email, display_name)
193
+ VALUES (v_provider, v_subject, v_email, v_display)
194
+ ON CONFLICT (provider, subject) DO UPDATE
195
+ SET email = COALESCE(EXCLUDED.email, ${s}.users.email),
196
+ display_name = COALESCE(EXCLUDED.display_name, ${s}.users.display_name),
197
+ updated_at = now()
198
+ WHERE COALESCE(EXCLUDED.email, ${s}.users.email) IS DISTINCT FROM ${s}.users.email
199
+ OR COALESCE(EXCLUDED.display_name, ${s}.users.display_name) IS DISTINCT FROM ${s}.users.display_name;
200
+
201
+ SELECT user_id INTO v_user_id
202
+ FROM ${s}.users
203
+ WHERE provider = v_provider AND subject = v_subject;
204
+
205
+ IF v_email IS NOT NULL THEN
206
+ FOR v_ghost IN
207
+ SELECT u.user_id FROM ${s}.users u
208
+ WHERE u.provider = v_provider
209
+ AND LOWER(u.subject) = LOWER(v_email)
210
+ AND u.user_id <> v_user_id
211
+ ORDER BY u.user_id FOR UPDATE
212
+ LOOP
213
+ UPDATE ${s}.session_shares ss SET user_id = v_user_id
214
+ WHERE ss.user_id = v_ghost
215
+ AND NOT EXISTS (
216
+ SELECT 1 FROM ${s}.session_shares e
217
+ WHERE e.session_id = ss.session_id AND e.user_id = v_user_id
218
+ );
219
+ UPDATE ${s}.session_shares e SET access = 'write'
220
+ FROM ${s}.session_shares g
221
+ WHERE g.user_id = v_ghost AND g.session_id = e.session_id
222
+ AND e.user_id = v_user_id AND g.access = 'write' AND e.access <> 'write';
223
+ DELETE FROM ${s}.session_shares WHERE user_id = v_ghost;
224
+ UPDATE ${s}.session_shares SET granted_by = v_user_id WHERE granted_by = v_ghost;
225
+ -- Editor grants: move the ones the real user does not already
226
+ -- hold, drop the duplicates, re-point granted_by.
227
+ UPDATE ${s}.agent_package_editors ge SET user_id = v_user_id
228
+ WHERE ge.user_id = v_ghost
229
+ AND NOT EXISTS (
230
+ SELECT 1 FROM ${s}.agent_package_editors e
231
+ WHERE e.package_id = ge.package_id AND e.user_id = v_user_id
232
+ );
233
+ DELETE FROM ${s}.agent_package_editors WHERE user_id = v_ghost;
234
+ UPDATE ${s}.agent_package_editors SET granted_by = v_user_id WHERE granted_by = v_ghost;
235
+ UPDATE ${s}.session_owners SET user_id = v_user_id WHERE user_id = v_ghost;
236
+ UPDATE ${s}.session_group_owners SET user_id = v_user_id WHERE user_id = v_ghost;
237
+ -- Carry preferences from the email placeholder to the stable login
238
+ -- identity. A real user's explicit preference wins a collision.
239
+ -- Bump even for a collision: worker caches must discard the ghost.
240
+ FOR v_feature IN SELECT feature_key FROM ${s}.feature_flag_settings
241
+ WHERE user_id = v_ghost ORDER BY feature_key
242
+ LOOP
243
+ PERFORM 1 FROM ${s}.feature_flags WHERE feature_key = v_feature FOR UPDATE;
244
+ SELECT ${s}.cms_feature_setting_json(r) INTO v_before
245
+ FROM ${s}.feature_flag_settings r WHERE feature_key = v_feature AND user_id = v_ghost;
246
+ UPDATE ${s}.feature_flags SET revision = revision + 1 WHERE feature_key = v_feature
247
+ RETURNING revision INTO v_revision;
248
+ IF EXISTS (SELECT 1 FROM ${s}.feature_flag_settings WHERE feature_key = v_feature AND user_id = v_user_id) THEN
249
+ DELETE FROM ${s}.feature_flag_settings WHERE feature_key = v_feature AND user_id = v_ghost;
250
+ ELSE
251
+ UPDATE ${s}.feature_flag_settings SET user_id = v_user_id, revision = v_revision,
252
+ updated_by = jsonb_build_array('system', 'user-adoption')::TEXT, updated_at = now()
253
+ WHERE feature_key = v_feature AND user_id = v_ghost;
254
+ END IF;
255
+ SELECT ${s}.cms_feature_setting_json(r) INTO v_after
256
+ FROM ${s}.feature_flag_settings r WHERE feature_key = v_feature AND user_id = v_user_id;
257
+ INSERT INTO ${s}.authz_audit(actor_provider, actor_subject, action, target, decision, details)
258
+ VALUES ('system', 'user-adoption', 'feature_flag.user_adopt', v_feature, 'allow',
259
+ jsonb_build_object('scope', 'user', 'userId', v_user_id, 'previousUserId', v_ghost,
260
+ 'featureKey', v_feature, 'before', v_before, 'after', v_after, 'revision', v_revision::TEXT));
261
+ END LOOP;
262
+ DELETE FROM ${s}.users WHERE user_id = v_ghost;
263
+ END LOOP;
264
+ END IF;
265
+
266
+ RETURN v_user_id;
267
+ END;
268
+ $$ LANGUAGE plpgsql;
269
+ `;
270
+ }
271
+ //# sourceMappingURL=feature-flags-0077.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"feature-flags-0077.js","sourceRoot":"","sources":["../../src/migrations/feature-flags-0077.ts"],"names":[],"mappings":"AAAA,0EAA0E;AAC1E,MAAM,UAAU,qBAAqB,CAAC,MAAc;IAChD,MAAM,CAAC,GAAG,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,GAAG,CAAC;IAC5C,OAAO;6BACkB,CAAC;;;;;6BAKD,CAAC;;2CAEa,CAAC;;gCAEZ,CAAC;;;;;;qEAMoC,CAAC;kEACJ,CAAC;8DACL,CAAC;kEACG,CAAC;;;cAGrD,CAAC;;;;;6BAKc,CAAC,kCAAkC,CAAC;;;;;;6BAMpC,CAAC,+BAA+B,CAAC;;;;;6BAKjC,CAAC;kDACoB,CAAC;;;6BAGtB,CAAC;;oDAEsB,CAAC;mBAClC,CAAC;iDAC6B,CAAC;;mBAE/B,CAAC,sCAAsC,CAAC;;;;6BAI9B,CAAC;;;;;;;yCAOW,CAAC;;;;;;;;;;;mCAWP,CAAC;;;;6BAIP,CAAC;;;;gBAId,CAAC;;oDAEmC,CAAC,gEAAgE,CAAC;iDACrE,CAAC,sCAAsC,CAAC;;;;;6BAK5D,CAAC;;;;;;;gBAOd,CAAC;;;;yBAIQ,CAAC;;;;;;;;;;;;;;;2CAeiB,CAAC;;;;;;6CAMC,CAAC;;;aAGjC,CAAC,mDAAmD,CAAC;;aAErD,CAAC;;sBAEQ,CAAC;;iBAEN,CAAC;;;wBAGM,CAAC;;sBAEH,CAAC;;oBAEH,CAAC;;;;kBAIH,CAAC;;;;;;;;6BAQU,CAAC;;;cAGhB,CAAC;;eAEA,CAAC;;;;6BAIa,CAAC;;;cAGhB,CAAC;;eAEA,CAAC;;;;;;6BAMa,CAAC;;;;;;;;;;;;;;;;;;;;;;kBAsBZ,CAAC;;;kDAG+B,CAAC;yDACM,CAAC;;qCAErB,CAAC,kCAAkC,CAAC;4CAC7B,CAAC,yCAAyC,CAAC;;;WAG5E,CAAC;;;;;oCAKwB,CAAC;;;;;;qBAMhB,CAAC;;;kCAGY,CAAC;;;qBAGd,CAAC;mBACH,CAAC;;;0BAGM,CAAC;qBACN,CAAC;;;qBAGD,CAAC;;;kCAGY,CAAC;;;0BAGT,CAAC;qBACN,CAAC;qBACD,CAAC;qBACD,CAAC;;;;uDAIiC,CAAC;;;iCAGvB,CAAC;yBACT,CAAC;2BACC,CAAC;yBACH,CAAC;;2CAEiB,CAAC;kCACV,CAAC;;6BAEN,CAAC;;;;yBAIL,CAAC;2BACC,CAAC;8BACE,CAAC;;;;;0BAKL,CAAC;;;;;;;CAO1B,CAAC;AACF,CAAC"}
@@ -0,0 +1,3 @@
1
+ /** Publish the initial cluster policy separately from the frozen 0077 schema. */
2
+ export declare function nativeTasksDefaultPolicyMigration(schema: string): string;
3
+ //# sourceMappingURL=native-tasks-default-policy-0078.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"native-tasks-default-policy-0078.d.ts","sourceRoot":"","sources":["../../src/migrations/native-tasks-default-policy-0078.ts"],"names":[],"mappings":"AAAA,iFAAiF;AACjF,wBAAgB,iCAAiC,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAkBxE"}
@@ -0,0 +1,21 @@
1
+ /** Publish the initial cluster policy separately from the frozen 0077 schema. */
2
+ export function nativeTasksDefaultPolicyMigration(schema) {
3
+ const s = `"${schema.replace(/"/g, '""')}"`;
4
+ return `
5
+ UPDATE ${s}.feature_flags
6
+ SET default_enabled = false,
7
+ default_allow_user_override = true,
8
+ revision = revision + 1
9
+ WHERE feature_key = 'copilot.native_tasks'
10
+ AND (default_enabled IS DISTINCT FROM false
11
+ OR default_allow_user_override IS DISTINCT FROM true);
12
+
13
+ INSERT INTO ${s}.feature_flag_settings
14
+ (feature_key, scope, user_id, enabled, allow_user_override, revision, updated_by)
15
+ SELECT feature_key, 'cluster', NULL, false, true, revision, 'migration:0078'
16
+ FROM ${s}.feature_flags
17
+ WHERE feature_key = 'copilot.native_tasks'
18
+ ON CONFLICT (feature_key) WHERE scope = 'cluster' DO NOTHING;
19
+ `;
20
+ }
21
+ //# sourceMappingURL=native-tasks-default-policy-0078.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"native-tasks-default-policy-0078.js","sourceRoot":"","sources":["../../src/migrations/native-tasks-default-policy-0078.ts"],"names":[],"mappings":"AAAA,iFAAiF;AACjF,MAAM,UAAU,iCAAiC,CAAC,MAAc;IAC5D,MAAM,CAAC,GAAG,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,GAAG,CAAC;IAC5C,OAAO;SACF,CAAC;;;;;;;;cAQI,CAAC;;;OAGR,CAAC;;;CAGP,CAAC;AACF,CAAC"}
@@ -0,0 +1,25 @@
1
+ import type { CopilotSession, CustomAgentConfig, SessionHooks, Tool } from "@github/copilot-sdk";
2
+ export type NativeSubagentMode = "off" | "sync";
3
+ export declare function resolveNativeSubagents(value?: unknown): NativeSubagentMode;
4
+ export declare const NATIVE_SUBAGENT_TOOLS: string[];
5
+ export declare const NATIVE_BUILTIN_AGENTS: string[];
6
+ export declare const NATIVE_EXCLUDED_TOOLS: string[];
7
+ export declare const NATIVE_SUBAGENT_GUIDANCE = "\n## Native local delegation\nChoose delegation by role fit, expected lifetime, scale, execution location, and the user's intent.\nFirst consider the available user-creatable named agents. If one is customized for the required role,\nprefer spawn_agent(agent_name=<exact name>) over a generic durable agent or native task.\nUse the agent index already in context, or ps_list_agents when discovery is needed; do not invent names.\nMatch its capabilities and source access, not just a similar name. A specialist can perform its own\nintake: spawn the matching role rather than asking the user for details that role is designed to collect.\nGive named children their assignment through the contract and message_agent, not task/system_message overrides.\nUser words such as \"subagent\", \"sub-agent\", \"spawn\", or \"spin off\" are strong hints for durable spawn_agent:\ndefault to durable when the intended mechanism is otherwise ambiguous; short duration alone does not\noverride that hint. \"Spin off an agent to summarize the README\" therefore favors durable execution.\nThese are contextual hints, not literal keyword rules: \"spawn a native task\" still asks for native\nexecution when its lifetime and capabilities fit.\nPrefer durable spawn_agent for expected long-running sessions, broad scale-out across independently\nmanaged work, ongoing monitoring, work outliving this turn, recovery across restarts, or cross-worker work.\nNative tasks share this worker and the parent's turn time budget; they are not independent durable sessions.\nFilesystem sharing is only between a native task and its IMMEDIATE parent session.\nIf you are a durable child, a path reported by your durable parent or sibling is not\nyour local file. Before asking your native task to process it, use read_artifact(toFile)\nto materialize that session's published artifact in YOUR working directory, then pass\nyour local path to task. Native tasks have no artifact tools and cannot fetch it for you.\nThe presence of a producer path alongside an artifact reference does not establish\nshared storage, even when the request explicitly asks you to use a native task.\nUse native task for bounded, synchronously awaited local work that fits this turn and benefits from separate context:\ntask(agent_type=\"swarm-explore\", mode=\"sync\") for investigation, or task(agent_type=\"swarm-task\", mode=\"sync\")\nfor tests, builds, and verbose commands.\nSame-worker files and uncommitted changes favor native execution\nwhen the user has left the delegation mechanism open. Local files alone do not cancel a durable hint:\n\"use subagents in parallel to compare README.md and package.json\" favors durable children with source\naccess or artifact handoff, even though the files are small. An explicit requirement to execute in this\nexact checkout with uncommitted edits, however, favors native tasks when the work fits this turn.\nPreserve explicit topology: separate agents/sessions that themselves run native tasks means spawn_agent\nchildren, each using native tasks within its own turn. Do not collapse that into native tasks in the parent.\nResolve \"spawn separate subagents for this\" from the existing objective and results; do not ask the user\nto repeat an established task. Ask only when missing information materially blocks useful action.\nUse judgment rather than a fixed duration or agent-count threshold. Simple work without a delegation\nrequest is best done directly. A matching named role takes priority over native convenience.\nDurable children may run on another worker: provide task context and repository access or artifacts;\ndo not assume they can read this worker's local paths. Explain briefly if explicit native execution\ncannot satisfy a required lifetime or capability, and use a durable agent to meet that requirement.\nProvide full context and ask for findings/results. Simple lookups are best done directly.\nNative workers have local CLI tools only. They return results through task.\nPilotSwarm child contracts, facts, wake-ups, and complete_agent apply ONLY to spawn_agent children.\nNative background mode and write_agent are unavailable.\nswarm-explore and swarm-task inherit the parent model, reasoning effort, and context tier.\nOmit the model, reasoning_effort, and context_tier arguments; overrides are unavailable.\n";
8
+ export declare function nativeSubagentGuidance(): string;
9
+ export declare function nativeSubagentDefinitions(model: string): CustomAgentConfig[];
10
+ /** Native execution remains in the CLI. Compose policy around the native tool. */
11
+ export declare function nativeSubagentHooks(model: string, hooks?: SessionHooks, canAdmit?: () => boolean): SessionHooks;
12
+ export declare function isNativeChildEvent(event: any): boolean;
13
+ /** Retire reusable native agents before the worker can snapshot or release its lock.
14
+ * Do not waitForPending(): its ten-minute wait may schedule follow-up turns.
15
+ * A timeout/failure rejects the activity rather than claiming a safe boundary.
16
+ */
17
+ export declare function settleNativeSubagents(session: CopilotSession, { timeoutMs, rejectRunning }?: {
18
+ timeoutMs?: number;
19
+ rejectRunning?: boolean;
20
+ }): Promise<void>;
21
+ /** Defense in depth if a CLI tool name collides with an external tool name.
22
+ * Apply both at declaration time and when per-turn handlers are refreshed.
23
+ */
24
+ export declare function guardNativeExternalTools(tools: Tool<any>[], parentSessionId: string): Tool<any>[];
25
+ //# sourceMappingURL=native-subagents.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"native-subagents.d.ts","sourceRoot":"","sources":["../src/native-subagents.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,iBAAiB,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,qBAAqB,CAAC;AAEjG,MAAM,MAAM,kBAAkB,GAAG,KAAK,GAAG,MAAM,CAAC;AAEhD,wBAAgB,sBAAsB,CAAC,KAAK,GAAE,OAAiD,GAAG,kBAAkB,CAInH;AAID,eAAO,MAAM,qBAAqB,UAAoI,CAAC;AACvK,eAAO,MAAM,qBAAqB,UAAmH,CAAC;AACtJ,eAAO,MAAM,qBAAqB,UAAwE,CAAC;AAI3G,eAAO,MAAM,wBAAwB,wvIA+CpC,CAAC;AAEF,wBAAgB,sBAAsB,IAAI,MAAM,CAAqC;AAErF,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,MAAM,GAAG,iBAAiB,EAAE,CAO5E;AAED,kFAAkF;AAClF,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,YAAY,EAAE,QAAQ,GAAE,MAAM,OAAoB,GAAG,YAAY,CAoC3H;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,GAAG,GAAG,OAAO,CAEtD;AAED;;;GAGG;AACH,wBAAsB,qBAAqB,CAAC,OAAO,EAAE,cAAc,EAAE,EAAE,SAAiB,EAAE,aAAqB,EAAE,GAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,aAAa,CAAC,EAAE,OAAO,CAAA;CAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAoCtL;AAED;;GAEG;AACH,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,CAcjG"}
@@ -0,0 +1,186 @@
1
+ export function resolveNativeSubagents(value = process.env.PILOTSWARM_NATIVE_SUBAGENTS) {
2
+ if (value == null || value === "" || value === "off")
3
+ return "off";
4
+ if (value === "sync")
5
+ return "sync";
6
+ throw new Error("nativeSubagents / PILOTSWARM_NATIVE_SUBAGENTS must be off or sync");
7
+ }
8
+ // Scope native workers to CLI tools. In particular, do not inherit the
9
+ // parent's PilotSwarm tools or loaded durable-agent definitions.
10
+ export const NATIVE_SUBAGENT_TOOLS = ["view", "grep", "rg", "glob", "bash", "powershell", "read_bash", "read_powershell", "list_bash", "stop_bash", "stop_powershell"];
11
+ export const NATIVE_BUILTIN_AGENTS = ["explore", "task", "general-purpose", "code-review", "research", "security-review", "rubber-duck", "rem-agent"];
12
+ export const NATIVE_EXCLUDED_TOOLS = ["write_agent", "manage_schedule", "run_factory", "factories_manage"];
13
+ const names = new Set(["swarm-explore", "swarm-task"]);
14
+ const childTools = new Set(NATIVE_SUBAGENT_TOOLS);
15
+ export const NATIVE_SUBAGENT_GUIDANCE = `
16
+ ## Native local delegation
17
+ Choose delegation by role fit, expected lifetime, scale, execution location, and the user's intent.
18
+ First consider the available user-creatable named agents. If one is customized for the required role,
19
+ prefer spawn_agent(agent_name=<exact name>) over a generic durable agent or native task.
20
+ Use the agent index already in context, or ps_list_agents when discovery is needed; do not invent names.
21
+ Match its capabilities and source access, not just a similar name. A specialist can perform its own
22
+ intake: spawn the matching role rather than asking the user for details that role is designed to collect.
23
+ Give named children their assignment through the contract and message_agent, not task/system_message overrides.
24
+ User words such as "subagent", "sub-agent", "spawn", or "spin off" are strong hints for durable spawn_agent:
25
+ default to durable when the intended mechanism is otherwise ambiguous; short duration alone does not
26
+ override that hint. "Spin off an agent to summarize the README" therefore favors durable execution.
27
+ These are contextual hints, not literal keyword rules: "spawn a native task" still asks for native
28
+ execution when its lifetime and capabilities fit.
29
+ Prefer durable spawn_agent for expected long-running sessions, broad scale-out across independently
30
+ managed work, ongoing monitoring, work outliving this turn, recovery across restarts, or cross-worker work.
31
+ Native tasks share this worker and the parent's turn time budget; they are not independent durable sessions.
32
+ Filesystem sharing is only between a native task and its IMMEDIATE parent session.
33
+ If you are a durable child, a path reported by your durable parent or sibling is not
34
+ your local file. Before asking your native task to process it, use read_artifact(toFile)
35
+ to materialize that session's published artifact in YOUR working directory, then pass
36
+ your local path to task. Native tasks have no artifact tools and cannot fetch it for you.
37
+ The presence of a producer path alongside an artifact reference does not establish
38
+ shared storage, even when the request explicitly asks you to use a native task.
39
+ Use native task for bounded, synchronously awaited local work that fits this turn and benefits from separate context:
40
+ task(agent_type="swarm-explore", mode="sync") for investigation, or task(agent_type="swarm-task", mode="sync")
41
+ for tests, builds, and verbose commands.
42
+ Same-worker files and uncommitted changes favor native execution
43
+ when the user has left the delegation mechanism open. Local files alone do not cancel a durable hint:
44
+ "use subagents in parallel to compare README.md and package.json" favors durable children with source
45
+ access or artifact handoff, even though the files are small. An explicit requirement to execute in this
46
+ exact checkout with uncommitted edits, however, favors native tasks when the work fits this turn.
47
+ Preserve explicit topology: separate agents/sessions that themselves run native tasks means spawn_agent
48
+ children, each using native tasks within its own turn. Do not collapse that into native tasks in the parent.
49
+ Resolve "spawn separate subagents for this" from the existing objective and results; do not ask the user
50
+ to repeat an established task. Ask only when missing information materially blocks useful action.
51
+ Use judgment rather than a fixed duration or agent-count threshold. Simple work without a delegation
52
+ request is best done directly. A matching named role takes priority over native convenience.
53
+ Durable children may run on another worker: provide task context and repository access or artifacts;
54
+ do not assume they can read this worker's local paths. Explain briefly if explicit native execution
55
+ cannot satisfy a required lifetime or capability, and use a durable agent to meet that requirement.
56
+ Provide full context and ask for findings/results. Simple lookups are best done directly.
57
+ Native workers have local CLI tools only. They return results through task.
58
+ PilotSwarm child contracts, facts, wake-ups, and complete_agent apply ONLY to spawn_agent children.
59
+ Native background mode and write_agent are unavailable.
60
+ swarm-explore and swarm-task inherit the parent model, reasoning effort, and context tier.
61
+ Omit the model, reasoning_effort, and context_tier arguments; overrides are unavailable.
62
+ `;
63
+ export function nativeSubagentGuidance() { return NATIVE_SUBAGENT_GUIDANCE; }
64
+ export function nativeSubagentDefinitions(model) {
65
+ return [
66
+ { name: "swarm-explore", description: "Explore the local workspace and return concise source-backed findings.",
67
+ prompt: "Investigate the delegated question in the local workspace. Return concise findings with file references. Do not edit files. If you need user input or durable tools, report that to the parent. Complete the assigned investigation and return.", },
68
+ { name: "swarm-task", description: "Run local tests, builds, and commands; summarize success and include failure details.",
69
+ prompt: "Perform the delegated commands in the local workspace. Return a concise outcome; include actionable error details on failure. Await your commands; do not detach processes or schedule later work. If you need user input or durable tools, report that to the parent.", },
70
+ ].map(agent => ({ ...agent, model, tools: [...NATIVE_SUBAGENT_TOOLS], infer: true }));
71
+ }
72
+ /** Native execution remains in the CLI. Compose policy around the native tool. */
73
+ export function nativeSubagentHooks(model, hooks, canAdmit = () => true) {
74
+ return {
75
+ ...hooks,
76
+ onPreToolUse: async (input, invocation) => {
77
+ const previous = await hooks?.onPreToolUse?.(input, invocation);
78
+ if (previous?.permissionDecision === "deny")
79
+ return previous;
80
+ const deny = (reason) => ({ ...previous, permissionDecision: "deny", permissionDecisionReason: reason });
81
+ const isChild = Boolean(input.sessionId && input.sessionId !== invocation.sessionId);
82
+ if (isChild && !childTools.has(input.toolName)) {
83
+ return deny("Native workers can use only local CLI tools. Return this request to your PilotSwarm parent.");
84
+ }
85
+ if (NATIVE_EXCLUDED_TOOLS.includes(input.toolName)) {
86
+ return deny("Detached native work is unavailable. Use task with mode=sync or PilotSwarm spawn_agent.");
87
+ }
88
+ const args = previous?.modifiedArgs ?? input.toolArgs;
89
+ if (isChild && (input.toolName === "bash" || input.toolName === "powershell")) {
90
+ const shell = args;
91
+ if (shell?.detach === true || (shell?.mode !== undefined && shell.mode !== "sync")) {
92
+ return deny("Native workers must await commands; detached/background shells are unavailable.");
93
+ }
94
+ }
95
+ if (input.toolName !== "task")
96
+ return previous;
97
+ if (!canAdmit())
98
+ return deny("Native tasks are disabled by current feature policy for this turn. Use a durable spawn_agent if needed.");
99
+ if (!args || typeof args !== "object" || Array.isArray(args))
100
+ return deny("task arguments must be an object");
101
+ const task = args;
102
+ if (!names.has(String(task.agent_type)))
103
+ return deny("Use the native swarm-explore or swarm-task agent.");
104
+ if (task.mode !== undefined && task.mode !== "sync")
105
+ return deny("Use task(mode=sync). Background native tasks are unavailable on this worker.");
106
+ if (task.model !== undefined && task.model !== model)
107
+ return deny("Native workers must use the parent session model; omit the model override.");
108
+ if (task.reasoning_effort !== undefined || task.context_tier !== undefined) {
109
+ return deny("Native reasoning/context settings are managed by the worker; omit overrides.");
110
+ }
111
+ // Pin the admitted parent model rather than allowing runtime-specific
112
+ // specialist defaults or an application hook to change providers.
113
+ return { ...previous, modifiedArgs: { ...task, mode: "sync", model } };
114
+ },
115
+ };
116
+ }
117
+ export function isNativeChildEvent(event) {
118
+ return Boolean(event?.agentId || event?.data?.nativeAgentId || event?.data?.parentToolCallId);
119
+ }
120
+ /** Retire reusable native agents before the worker can snapshot or release its lock.
121
+ * Do not waitForPending(): its ten-minute wait may schedule follow-up turns.
122
+ * A timeout/failure rejects the activity rather than claiming a safe boundary.
123
+ */
124
+ export async function settleNativeSubagents(session, { timeoutMs = 5_000, rejectRunning = false } = {}) {
125
+ let timer;
126
+ let expired = false;
127
+ const timeoutError = () => new Error("Native subagent cleanup timed out; turn cannot commit");
128
+ const checked = async (operation) => {
129
+ const result = await operation;
130
+ // A timed-out RPC can resolve later. It must never continue into a
131
+ // subsequent turn and cancel that turn's newly created native agents.
132
+ if (expired)
133
+ throw timeoutError();
134
+ return result;
135
+ };
136
+ const settle = async () => {
137
+ const tasks = (await checked(session.rpc.tasks.list())).tasks.filter(task => task.type === "agent");
138
+ const hadRunning = tasks.some(task => task.status === "running");
139
+ for (const task of tasks) {
140
+ if (task.status === "running" || task.status === "idle") {
141
+ await checked(session.rpc.tasks.cancel({ id: task.id }));
142
+ }
143
+ }
144
+ const remaining = (await checked(session.rpc.tasks.list())).tasks.filter(task => task.type === "agent");
145
+ if (remaining.some(task => task.status === "running" || task.status === "idle")) {
146
+ throw new Error("Native subagent cleanup failed: a native agent is still active");
147
+ }
148
+ for (const task of remaining)
149
+ await checked(session.rpc.tasks.remove({ id: task.id }));
150
+ if (rejectRunning && hadRunning) {
151
+ throw new Error("Native execution contract violated: agent was still running after parent completion (cancelled)");
152
+ }
153
+ };
154
+ try {
155
+ await Promise.race([
156
+ settle(),
157
+ new Promise((_, reject) => {
158
+ timer = setTimeout(() => { expired = true; reject(timeoutError()); }, timeoutMs);
159
+ }),
160
+ ]);
161
+ }
162
+ finally {
163
+ if (timer)
164
+ clearTimeout(timer);
165
+ }
166
+ }
167
+ /** Defense in depth if a CLI tool name collides with an external tool name.
168
+ * Apply both at declaration time and when per-turn handlers are refreshed.
169
+ */
170
+ export function guardNativeExternalTools(tools, parentSessionId) {
171
+ return tools.map(tool => {
172
+ const handler = tool.handler;
173
+ if (!handler)
174
+ return tool;
175
+ return {
176
+ ...tool,
177
+ handler: (args, invocation) => {
178
+ if (invocation.sessionId !== parentSessionId) {
179
+ throw new Error("Native workers cannot invoke PilotSwarm external tools; return the request to the parent.");
180
+ }
181
+ return handler(args, invocation);
182
+ },
183
+ };
184
+ });
185
+ }
186
+ //# sourceMappingURL=native-subagents.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"native-subagents.js","sourceRoot":"","sources":["../src/native-subagents.ts"],"names":[],"mappings":"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"}