@undefineds.co/linx 0.3.5 → 0.3.8
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/README.md +58 -23
- package/dist/generated/version.js +1 -1
- package/dist/generated/version.js.map +1 -1
- package/dist/index.js +336 -162
- package/dist/index.js.map +1 -1
- package/dist/lib/account-session.js +4 -8
- package/dist/lib/account-session.js.map +1 -1
- package/dist/lib/ai-command.js +228 -178
- package/dist/lib/ai-command.js.map +1 -1
- package/dist/lib/auto-mode/archive.js +38 -7
- package/dist/lib/auto-mode/archive.js.map +1 -1
- package/dist/lib/auto-mode/auth.js.map +1 -1
- package/dist/lib/auto-mode/display.js +71 -45
- package/dist/lib/auto-mode/display.js.map +1 -1
- package/dist/lib/auto-mode/format.js +9 -7
- package/dist/lib/auto-mode/format.js.map +1 -1
- package/dist/lib/auto-mode/hooks/claude.js +12 -2
- package/dist/lib/auto-mode/hooks/claude.js.map +1 -1
- package/dist/lib/auto-mode/hooks/codex.js +17 -7
- package/dist/lib/auto-mode/hooks/codex.js.map +1 -1
- package/dist/lib/auto-mode/hooks/index.js +28 -8
- package/dist/lib/auto-mode/hooks/index.js.map +1 -1
- package/dist/lib/auto-mode/pod-ai.js +20 -37
- package/dist/lib/auto-mode/pod-ai.js.map +1 -1
- package/dist/lib/auto-mode/pod-approval.js +124 -195
- package/dist/lib/auto-mode/pod-approval.js.map +1 -1
- package/dist/lib/auto-mode/pod-persistence.js +169 -90
- package/dist/lib/auto-mode/pod-persistence.js.map +1 -1
- package/dist/lib/auto-mode/runner.js +683 -81
- package/dist/lib/auto-mode/runner.js.map +1 -1
- package/dist/lib/auto-mode/secretary.js +186 -41
- package/dist/lib/auto-mode/secretary.js.map +1 -1
- package/dist/lib/auto-mode-command.js +32 -32
- package/dist/lib/auto-mode-command.js.map +1 -1
- package/dist/lib/chat-api.js +242 -50
- package/dist/lib/chat-api.js.map +1 -1
- package/dist/lib/codex-plugin/bridge.js +164 -17
- package/dist/lib/codex-plugin/bridge.js.map +1 -1
- package/dist/lib/codex-plugin/codex-native-proxy.js +370 -34
- package/dist/lib/codex-plugin/codex-native-proxy.js.map +1 -1
- package/dist/lib/credentials-store.js +33 -42
- package/dist/lib/credentials-store.js.map +1 -1
- package/dist/lib/linx-cloud-errors.js +61 -0
- package/dist/lib/linx-cloud-errors.js.map +1 -0
- package/dist/lib/linx-tui-contract.js +8 -5
- package/dist/lib/linx-tui-contract.js.map +1 -1
- package/dist/lib/login-command.js +9 -2
- package/dist/lib/login-command.js.map +1 -1
- package/dist/lib/models.js +3 -20
- package/dist/lib/models.js.map +1 -1
- package/dist/lib/oidc-auth.js +143 -17
- package/dist/lib/oidc-auth.js.map +1 -1
- package/dist/lib/oidc-session-storage.js +2 -6
- package/dist/lib/oidc-session-storage.js.map +1 -1
- package/dist/lib/pi-adapter/auto-input-controller.js +988 -0
- package/dist/lib/pi-adapter/auto-input-controller.js.map +1 -0
- package/dist/lib/pi-adapter/backend-command.js +2 -0
- package/dist/lib/pi-adapter/backend-command.js.map +1 -0
- package/dist/lib/pi-adapter/backend-credentials.js +80 -0
- package/dist/lib/pi-adapter/backend-credentials.js.map +1 -0
- package/dist/lib/pi-adapter/branding.js +246 -108
- package/dist/lib/pi-adapter/branding.js.map +1 -1
- package/dist/lib/pi-adapter/control-state.js +72 -0
- package/dist/lib/pi-adapter/control-state.js.map +1 -0
- package/dist/lib/pi-adapter/interactive.js +2634 -30
- package/dist/lib/pi-adapter/interactive.js.map +1 -1
- package/dist/lib/pi-adapter/pod-approval.js +382 -210
- package/dist/lib/pi-adapter/pod-approval.js.map +1 -1
- package/dist/lib/pi-adapter/pod-mirror-mapping.js +71 -17
- package/dist/lib/pi-adapter/pod-mirror-mapping.js.map +1 -1
- package/dist/lib/pi-adapter/pod-mirror.js +531 -64
- package/dist/lib/pi-adapter/pod-mirror.js.map +1 -1
- package/dist/lib/pi-adapter/pod-native.js +81 -85
- package/dist/lib/pi-adapter/pod-native.js.map +1 -1
- package/dist/lib/pi-adapter/pod-status-output.js +54 -0
- package/dist/lib/pi-adapter/pod-status-output.js.map +1 -0
- package/dist/lib/pi-adapter/runtime.js +458 -228
- package/dist/lib/pi-adapter/runtime.js.map +1 -1
- package/dist/lib/pi-adapter/session-control.js +509 -0
- package/dist/lib/pi-adapter/session-control.js.map +1 -0
- package/dist/lib/pi-adapter/session.js +35 -22
- package/dist/lib/pi-adapter/session.js.map +1 -1
- package/dist/lib/pi-adapter/stream.js +89 -32
- package/dist/lib/pi-adapter/stream.js.map +1 -1
- package/dist/lib/pi-adapter/sync-recovery.js +89 -0
- package/dist/lib/pi-adapter/sync-recovery.js.map +1 -0
- package/dist/lib/pi-adapter/web-fetch.js +13 -14
- package/dist/lib/pi-adapter/web-fetch.js.map +1 -1
- package/dist/lib/pod-chat-store.js +254 -78
- package/dist/lib/pod-chat-store.js.map +1 -1
- package/dist/lib/pod-data-session.js +156 -35
- package/dist/lib/pod-data-session.js.map +1 -1
- package/dist/lib/solid-auth-store.js +27 -0
- package/dist/lib/solid-auth-store.js.map +1 -0
- package/dist/lib/solid-auth.js +2 -4
- package/dist/lib/solid-auth.js.map +1 -1
- package/dist/lib/solid-client-credentials-login.js +100 -0
- package/dist/lib/solid-client-credentials-login.js.map +1 -0
- package/dist/lib/solid-local-store.js +31 -0
- package/dist/lib/solid-local-store.js.map +1 -0
- package/dist/lib/symphony/archive.js +328 -18
- package/dist/lib/symphony/archive.js.map +1 -1
- package/dist/lib/symphony/pod-projection.js +2222 -0
- package/dist/lib/symphony/pod-projection.js.map +1 -0
- package/dist/lib/symphony-command.js +602 -178
- package/dist/lib/symphony-command.js.map +1 -1
- package/dist/lib/sync-checkpoint-store.js +74 -0
- package/dist/lib/sync-checkpoint-store.js.map +1 -0
- package/dist/skills/symphony/SKILL.md +665 -0
- package/package.json +15 -9
- package/vendor/agent-runtime/dist/agent-runtime.d.ts +137 -0
- package/vendor/agent-runtime/dist/agent-runtime.js +211 -0
- package/vendor/agent-runtime/dist/auto-mode.d.ts +78 -13
- package/vendor/agent-runtime/dist/auto-mode.js +288 -31
- package/vendor/agent-runtime/dist/control-plane.d.ts +28 -0
- package/vendor/agent-runtime/dist/control-plane.js +79 -0
- package/vendor/agent-runtime/dist/file-sync.d.ts +157 -0
- package/vendor/agent-runtime/dist/file-sync.js +314 -0
- package/vendor/agent-runtime/dist/index.d.ts +7 -0
- package/vendor/agent-runtime/dist/index.js +7 -0
- package/vendor/agent-runtime/dist/reconciler.d.ts +117 -0
- package/vendor/agent-runtime/dist/reconciler.js +361 -0
- package/vendor/agent-runtime/dist/symphony.d.ts +128 -8
- package/vendor/agent-runtime/dist/symphony.js +362 -57
- package/vendor/agent-runtime/dist/sync.d.ts +271 -0
- package/vendor/agent-runtime/dist/sync.js +550 -0
- package/vendor/agent-runtime/dist/thread-reconciler-controller.d.ts +58 -0
- package/vendor/agent-runtime/dist/thread-reconciler-controller.js +137 -0
- package/vendor/agent-runtime/dist/turn-controller.js +2 -2
- package/vendor/agent-runtime/dist/wake-scheduler.d.ts +67 -0
- package/vendor/agent-runtime/dist/wake-scheduler.js +194 -0
- package/vendor/agent-runtime/package.json +8 -1
- package/vendor/pi-web-access/CHANGELOG.md +387 -0
- package/vendor/pi-web-access/LICENSE +21 -0
- package/vendor/pi-web-access/README.md +352 -0
- package/vendor/pi-web-access/activity.ts +101 -0
- package/vendor/pi-web-access/banner.png +0 -0
- package/vendor/pi-web-access/chrome-cookies.ts +322 -0
- package/vendor/pi-web-access/code-search.ts +107 -0
- package/vendor/pi-web-access/curator-page.ts +3359 -0
- package/vendor/pi-web-access/curator-server.ts +605 -0
- package/vendor/pi-web-access/exa.ts +520 -0
- package/vendor/pi-web-access/extract.ts +641 -0
- package/vendor/pi-web-access/gemini-api.ts +112 -0
- package/vendor/pi-web-access/gemini-search.ts +361 -0
- package/vendor/pi-web-access/gemini-url-context.ts +126 -0
- package/vendor/pi-web-access/gemini-web-config.ts +52 -0
- package/vendor/pi-web-access/gemini-web.ts +396 -0
- package/vendor/pi-web-access/github-api.ts +196 -0
- package/vendor/pi-web-access/github-extract.ts +634 -0
- package/vendor/pi-web-access/index.ts +2346 -0
- package/vendor/pi-web-access/package.json +45 -0
- package/vendor/pi-web-access/pdf-extract.ts +192 -0
- package/vendor/pi-web-access/perplexity.ts +195 -0
- package/vendor/pi-web-access/pi-web-fetch-demo.mp4 +0 -0
- package/vendor/pi-web-access/rsc-extract.ts +338 -0
- package/vendor/pi-web-access/skills/librarian/SKILL.md +195 -0
- package/vendor/pi-web-access/storage.ts +72 -0
- package/vendor/pi-web-access/summary-review.ts +276 -0
- package/vendor/pi-web-access/test/gemini-web-cookie-opt-in.test.mjs +41 -0
- package/vendor/pi-web-access/test/pdf-extract.test.mjs +95 -0
- package/vendor/pi-web-access/utils.ts +44 -0
- package/vendor/pi-web-access/video-extract.ts +378 -0
- package/vendor/pi-web-access/youtube-extract.ts +310 -0
- package/dist/lib/pi-adapter/auth.js +0 -68
- package/dist/lib/pi-adapter/auth.js.map +0 -1
- package/dist/lib/pi-adapter/pod-tools.js +0 -140
- package/dist/lib/pi-adapter/pod-tools.js.map +0 -1
- package/dist/skills/drizzle-solid/SKILL.md +0 -340
- package/dist/skills/pod-storage/SKILL.md +0 -100
- package/dist/skills/solid-modeling/SKILL.md +0 -274
- package/dist/skills/xpod-componentsjs/SKILL.md +0 -284
|
@@ -40,6 +40,87 @@ export function autoModeApprovalRequestMessage(request) {
|
|
|
40
40
|
export const DEFAULT_AUTO_MODE_SECRETARY_REACTION_WINDOW_MS = 5_000;
|
|
41
41
|
export const MIN_AUTO_MODE_SECRETARY_REACTION_WINDOW_MS = 5_000;
|
|
42
42
|
export const MAX_AUTO_MODE_SECRETARY_REACTION_WINDOW_MS = 60_000;
|
|
43
|
+
export function resolveAutoModeCommandRoute(input) {
|
|
44
|
+
const text = normalizeAutoModeCommandText(input);
|
|
45
|
+
if (!text) {
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
const autoRoute = resolveAutoModeAutoControlCommand(text);
|
|
49
|
+
if (autoRoute) {
|
|
50
|
+
return autoRoute;
|
|
51
|
+
}
|
|
52
|
+
return resolveAutoModePeerCommand(text);
|
|
53
|
+
}
|
|
54
|
+
export function resolveAutoModePeerCommand(input) {
|
|
55
|
+
const text = normalizeAutoModeCommandText(input);
|
|
56
|
+
if (text !== '/goal' && !text.startsWith('/goal ')) {
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
const argument = text.slice('/goal'.length).trim();
|
|
60
|
+
const goalMode = inferSecretaryGoalModeFromGoalPeerCommand(argument);
|
|
61
|
+
return {
|
|
62
|
+
kind: 'peer-command',
|
|
63
|
+
targetRole: 'peer-command',
|
|
64
|
+
command: 'goal',
|
|
65
|
+
text,
|
|
66
|
+
...(goalMode === undefined ? {} : { secretaryBehavior: { goalMode } }),
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
function resolveAutoModeAutoControlCommand(text) {
|
|
70
|
+
if (text === '/auto' || text === '/auto status') {
|
|
71
|
+
return {
|
|
72
|
+
kind: 'control-command',
|
|
73
|
+
targetRole: 'control-command',
|
|
74
|
+
command: 'auto',
|
|
75
|
+
text,
|
|
76
|
+
auto: { action: 'status' },
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
if (text === '/auto on') {
|
|
80
|
+
return {
|
|
81
|
+
kind: 'control-command',
|
|
82
|
+
targetRole: 'control-command',
|
|
83
|
+
command: 'auto',
|
|
84
|
+
text,
|
|
85
|
+
auto: { action: 'set', enabled: true },
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
if (text === '/auto off') {
|
|
89
|
+
return {
|
|
90
|
+
kind: 'control-command',
|
|
91
|
+
targetRole: 'control-command',
|
|
92
|
+
command: 'auto',
|
|
93
|
+
text,
|
|
94
|
+
auto: { action: 'set', enabled: false },
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
if (text.startsWith('/auto ')) {
|
|
98
|
+
const initialInput = text.slice('/auto'.length).trim();
|
|
99
|
+
if (initialInput && initialInput !== 'on' && initialInput !== 'off' && initialInput !== 'status') {
|
|
100
|
+
return {
|
|
101
|
+
kind: 'control-command',
|
|
102
|
+
targetRole: 'control-command',
|
|
103
|
+
command: 'auto',
|
|
104
|
+
text,
|
|
105
|
+
auto: { action: 'set', enabled: true, initialInput },
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
return null;
|
|
110
|
+
}
|
|
111
|
+
function normalizeAutoModeCommandText(input) {
|
|
112
|
+
return typeof input === 'string' ? input.trim() : '';
|
|
113
|
+
}
|
|
114
|
+
function inferSecretaryGoalModeFromGoalPeerCommand(argument) {
|
|
115
|
+
if (!argument || argument === 'status') {
|
|
116
|
+
return undefined;
|
|
117
|
+
}
|
|
118
|
+
const firstToken = argument.split(/\s+/, 1)[0]?.toLowerCase();
|
|
119
|
+
if (firstToken === 'pause' || firstToken === 'close' || firstToken === 'cancel') {
|
|
120
|
+
return false;
|
|
121
|
+
}
|
|
122
|
+
return true;
|
|
123
|
+
}
|
|
43
124
|
export const AUTO_MODE_HOME_DIRNAME = 'auto-mode';
|
|
44
125
|
export const AUTO_MODE_SESSIONS_DIRNAME = 'sessions';
|
|
45
126
|
export const AUTO_MODE_SESSION_FILE_NAME = 'session.json';
|
|
@@ -208,6 +289,119 @@ export function normalizeAutoModeApprovalOptions(value) {
|
|
|
208
289
|
})
|
|
209
290
|
.filter((option) => option !== null);
|
|
210
291
|
}
|
|
292
|
+
export function parseAutoModeApprovalOptions(value) {
|
|
293
|
+
if (Array.isArray(value)) {
|
|
294
|
+
return normalizeAutoModeApprovalOptions(value);
|
|
295
|
+
}
|
|
296
|
+
if (typeof value !== 'string' || !value.trim()) {
|
|
297
|
+
return [];
|
|
298
|
+
}
|
|
299
|
+
try {
|
|
300
|
+
const parsed = JSON.parse(value);
|
|
301
|
+
return normalizeAutoModeApprovalOptions(parsed);
|
|
302
|
+
}
|
|
303
|
+
catch {
|
|
304
|
+
return [];
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
export function encodeAutoModeApprovalOptions(options) {
|
|
308
|
+
return options && options.length > 0 ? JSON.stringify(options) : undefined;
|
|
309
|
+
}
|
|
310
|
+
export function buildAutoModeApprovalDecisionReason(options, note) {
|
|
311
|
+
const input = typeof options === 'string' ? { decision: options, note } : options;
|
|
312
|
+
const selectedOptionId = input.selectedOption?.optionId ?? input.selectedOptionId;
|
|
313
|
+
const selectedLabel = input.selectedOption?.label ?? input.selectedLabel;
|
|
314
|
+
return JSON.stringify({
|
|
315
|
+
...(input.source?.trim() ? { source: input.source.trim() } : {}),
|
|
316
|
+
...(input.decision ? { decision: input.decision } : {}),
|
|
317
|
+
...(input.note?.trim() ? { note: input.note.trim() } : {}),
|
|
318
|
+
...(selectedOptionId?.trim() ? { selectedOptionId: selectedOptionId.trim() } : {}),
|
|
319
|
+
...(selectedLabel?.trim() ? { selectedLabel: selectedLabel.trim() } : {}),
|
|
320
|
+
});
|
|
321
|
+
}
|
|
322
|
+
export function parseAutoModeApprovalDecisionReason(value) {
|
|
323
|
+
if (typeof value !== 'string' || !value.trim()) {
|
|
324
|
+
return null;
|
|
325
|
+
}
|
|
326
|
+
try {
|
|
327
|
+
const parsed = JSON.parse(value);
|
|
328
|
+
const record = recordFromUnknown(parsed);
|
|
329
|
+
if (!record) {
|
|
330
|
+
return null;
|
|
331
|
+
}
|
|
332
|
+
const decision = normalizeAutoModeApprovalDecision(record.decision);
|
|
333
|
+
const nested = parseAutoModeApprovalDecisionReason(record.note);
|
|
334
|
+
const source = stringFromUnknown(record.source);
|
|
335
|
+
const note = stringFromUnknown(record.note);
|
|
336
|
+
const selectedOptionId = stringFromUnknown(record.selectedOptionId) ?? nested?.selectedOptionId;
|
|
337
|
+
const selectedLabel = stringFromUnknown(record.selectedLabel) ?? nested?.selectedLabel;
|
|
338
|
+
if (!source && !decision && !note && !selectedOptionId && !selectedLabel) {
|
|
339
|
+
return null;
|
|
340
|
+
}
|
|
341
|
+
return {
|
|
342
|
+
...(source ? { source } : {}),
|
|
343
|
+
...(decision ? { decision } : {}),
|
|
344
|
+
...(note ? { note } : {}),
|
|
345
|
+
...(selectedOptionId ? { selectedOptionId } : {}),
|
|
346
|
+
...(selectedLabel ? { selectedLabel } : {}),
|
|
347
|
+
};
|
|
348
|
+
}
|
|
349
|
+
catch {
|
|
350
|
+
return null;
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
export function autoModeApprovalDecisionForOption(option) {
|
|
354
|
+
if (option.kind === 'allow_for_session') {
|
|
355
|
+
return 'accept_for_session';
|
|
356
|
+
}
|
|
357
|
+
if (option.kind === 'allow_always') {
|
|
358
|
+
return 'accept_always';
|
|
359
|
+
}
|
|
360
|
+
if (option.kind === 'reject_once' || option.kind === 'reject_always') {
|
|
361
|
+
return 'decline';
|
|
362
|
+
}
|
|
363
|
+
if (option.kind === 'cancel') {
|
|
364
|
+
return 'cancel';
|
|
365
|
+
}
|
|
366
|
+
return 'accept';
|
|
367
|
+
}
|
|
368
|
+
export function autoModeApprovalDecisionForStoredApproval(input) {
|
|
369
|
+
if (input.status === 'pending') {
|
|
370
|
+
return null;
|
|
371
|
+
}
|
|
372
|
+
const parsed = parseAutoModeApprovalDecisionReason(input.reason);
|
|
373
|
+
if (input.status === 'rejected') {
|
|
374
|
+
return parsed?.decision === 'cancel' ? 'cancel' : 'decline';
|
|
375
|
+
}
|
|
376
|
+
const option = parsed?.selectedOptionId
|
|
377
|
+
? parseAutoModeApprovalOptions(input.approvalOptions).find((entry) => entry.optionId === parsed.selectedOptionId)
|
|
378
|
+
: null;
|
|
379
|
+
if (option) {
|
|
380
|
+
return autoModeApprovalDecisionForOption(option);
|
|
381
|
+
}
|
|
382
|
+
if (parsed?.decision === 'accept_for_session') {
|
|
383
|
+
return 'accept_for_session';
|
|
384
|
+
}
|
|
385
|
+
if (parsed?.decision === 'accept_always') {
|
|
386
|
+
return 'accept_always';
|
|
387
|
+
}
|
|
388
|
+
if (parsed?.decision === 'decline' || parsed?.decision === 'cancel') {
|
|
389
|
+
return parsed.decision;
|
|
390
|
+
}
|
|
391
|
+
return input.status === 'approved' ? 'accept' : null;
|
|
392
|
+
}
|
|
393
|
+
export function shouldMaterializeAutoModeGrant(decision) {
|
|
394
|
+
return decision === 'accept_for_session' || decision === 'accept_always';
|
|
395
|
+
}
|
|
396
|
+
export function autoModeGrantScopeForDecision(decision) {
|
|
397
|
+
if (decision === 'accept_for_session') {
|
|
398
|
+
return 'session';
|
|
399
|
+
}
|
|
400
|
+
if (decision === 'accept_always') {
|
|
401
|
+
return 'durable';
|
|
402
|
+
}
|
|
403
|
+
return null;
|
|
404
|
+
}
|
|
211
405
|
function normalizeDurationMs(value, unit) {
|
|
212
406
|
const numeric = typeof value === 'number'
|
|
213
407
|
? value
|
|
@@ -274,10 +468,12 @@ function selectAcpPermissionOption(options, decision) {
|
|
|
274
468
|
return undefined;
|
|
275
469
|
}
|
|
276
470
|
const preferredKinds = decision === 'accept'
|
|
277
|
-
? ['allow_once', 'allow_always']
|
|
471
|
+
? ['allow_once', 'allow_for_session', 'allow_always']
|
|
278
472
|
: decision === 'accept_for_session'
|
|
279
|
-
? ['allow_always', 'allow_once']
|
|
280
|
-
:
|
|
473
|
+
? ['allow_for_session', 'allow_always', 'allow_once']
|
|
474
|
+
: decision === 'accept_always'
|
|
475
|
+
? ['allow_always', 'allow_for_session', 'allow_once']
|
|
476
|
+
: ['reject_once', 'reject_always'];
|
|
281
477
|
for (const kind of preferredKinds) {
|
|
282
478
|
const match = options.find((option) => option.kind === kind && typeof option.optionId === 'string');
|
|
283
479
|
if (match && typeof match.optionId === 'string') {
|
|
@@ -307,11 +503,11 @@ export function createAutoModeSessionId(options = {}) {
|
|
|
307
503
|
const stamp = now.toISOString().replace(/[:.]/g, '-');
|
|
308
504
|
return `auto_${stamp}_${randomId}`;
|
|
309
505
|
}
|
|
310
|
-
export function normalizeAutoModeCredentialSource(
|
|
311
|
-
return 'cloud';
|
|
506
|
+
export function normalizeAutoModeCredentialSource(source) {
|
|
507
|
+
return source === 'local' ? 'local' : 'cloud';
|
|
312
508
|
}
|
|
313
|
-
export function shouldAttemptCloudCredentialProbe(
|
|
314
|
-
return
|
|
509
|
+
export function shouldAttemptCloudCredentialProbe(requestedSource, _localAuthStatus) {
|
|
510
|
+
return normalizeAutoModeCredentialSource(requestedSource) === 'cloud';
|
|
315
511
|
}
|
|
316
512
|
export function formatAutoModeAutoFallbackMessage(localMessage, detail) {
|
|
317
513
|
return `${localMessage} Cloud credential fallback unavailable: ${detail}`;
|
|
@@ -319,6 +515,20 @@ export function formatAutoModeAutoFallbackMessage(localMessage, detail) {
|
|
|
319
515
|
export function resolveAutoModeCredentialSourceResolution(input) {
|
|
320
516
|
const requestedSource = normalizeAutoModeCredentialSource(input.requestedSource);
|
|
321
517
|
const cloudCredentialProbe = input.cloudCredentialProbe;
|
|
518
|
+
if (requestedSource === 'local') {
|
|
519
|
+
if (input.localAuthStatus.state === 'unauthenticated') {
|
|
520
|
+
return {
|
|
521
|
+
requestedSource,
|
|
522
|
+
authStatus: input.localAuthStatus,
|
|
523
|
+
error: input.localAuthStatus.message ?? input.defaultLocalMessage ?? 'Local backend authentication unavailable.',
|
|
524
|
+
};
|
|
525
|
+
}
|
|
526
|
+
return {
|
|
527
|
+
requestedSource,
|
|
528
|
+
resolvedSource: 'local',
|
|
529
|
+
authStatus: input.localAuthStatus,
|
|
530
|
+
};
|
|
531
|
+
}
|
|
322
532
|
if (cloudCredentialProbe?.status === 'available') {
|
|
323
533
|
return {
|
|
324
534
|
requestedSource,
|
|
@@ -333,27 +543,22 @@ export function resolveAutoModeCredentialSourceResolution(input) {
|
|
|
333
543
|
};
|
|
334
544
|
}
|
|
335
545
|
export function resolveAutoModeAutoApprovalDecision(input) {
|
|
336
|
-
const {
|
|
546
|
+
const { request } = input;
|
|
547
|
+
const autoEnabled = isAutoModeSecretaryControlEnabled(input);
|
|
337
548
|
if (request.kind === 'command-approval') {
|
|
338
|
-
if (
|
|
549
|
+
if (autoEnabled) {
|
|
339
550
|
return 'accept_for_session';
|
|
340
551
|
}
|
|
341
|
-
if (mode === 'smart' && isTrustedAutoModeCommand(request.command)) {
|
|
342
|
-
return 'accept';
|
|
343
|
-
}
|
|
344
552
|
return null;
|
|
345
553
|
}
|
|
346
554
|
if (request.kind === 'file-change-approval') {
|
|
347
|
-
if (
|
|
555
|
+
if (autoEnabled) {
|
|
348
556
|
return 'accept_for_session';
|
|
349
557
|
}
|
|
350
|
-
if (mode === 'smart') {
|
|
351
|
-
return 'accept';
|
|
352
|
-
}
|
|
353
558
|
return null;
|
|
354
559
|
}
|
|
355
560
|
if (request.kind === 'permissions-approval') {
|
|
356
|
-
if (
|
|
561
|
+
if (autoEnabled) {
|
|
357
562
|
return 'accept_for_session';
|
|
358
563
|
}
|
|
359
564
|
return null;
|
|
@@ -361,14 +566,15 @@ export function resolveAutoModeAutoApprovalDecision(input) {
|
|
|
361
566
|
return null;
|
|
362
567
|
}
|
|
363
568
|
export function createFallbackAutoModeSecretaryRecommendation(input) {
|
|
364
|
-
if (input
|
|
569
|
+
if (!isAutoModeSecretaryControlEnabled(input) || input.request.kind === 'user-input') {
|
|
365
570
|
return null;
|
|
366
571
|
}
|
|
367
572
|
const decision = resolveAutoModeAutoApprovalDecision({
|
|
368
573
|
mode: input.mode,
|
|
574
|
+
autoEnabled: input.autoEnabled,
|
|
369
575
|
request: input.request,
|
|
370
576
|
});
|
|
371
|
-
const secretaryDecision = decision
|
|
577
|
+
const secretaryDecision = normalizeAutoModeDecisionForSecretary(decision);
|
|
372
578
|
if (!secretaryDecision) {
|
|
373
579
|
return null;
|
|
374
580
|
}
|
|
@@ -376,7 +582,7 @@ export function createFallbackAutoModeSecretaryRecommendation(input) {
|
|
|
376
582
|
kind: input.request.kind,
|
|
377
583
|
canAutoDecide: true,
|
|
378
584
|
decision: secretaryDecision,
|
|
379
|
-
confidence:
|
|
585
|
+
confidence: 0.7,
|
|
380
586
|
reason: 'Matched local fallback policy while AI secretary was unavailable.',
|
|
381
587
|
reactionWindowMs: 0,
|
|
382
588
|
source: 'fallback',
|
|
@@ -444,6 +650,9 @@ export function autoModeApprovalDecisionLabel(decision) {
|
|
|
444
650
|
if (decision === 'accept_for_session') {
|
|
445
651
|
return 'Grant';
|
|
446
652
|
}
|
|
653
|
+
if (decision === 'accept_always') {
|
|
654
|
+
return 'Always allow';
|
|
655
|
+
}
|
|
447
656
|
if (decision === 'decline') {
|
|
448
657
|
return 'Deny';
|
|
449
658
|
}
|
|
@@ -527,7 +736,7 @@ function normalizeSecretaryApprovalDecision(value) {
|
|
|
527
736
|
return undefined;
|
|
528
737
|
}
|
|
529
738
|
const normalized = value.trim().toLowerCase().replace(/-/g, '_');
|
|
530
|
-
if (['accept', 'allow', 'allow_once', 'approve', 'yes', 'accept_for_session', 'allow_always', 'grant', 'session', 'approve_for_session'].includes(normalized)) {
|
|
739
|
+
if (['accept', 'allow', 'allow_once', 'approve', 'yes', 'accept_for_session', 'accept_always', 'allow_for_session', 'allow_always', 'grant', 'session', 'approve_for_session'].includes(normalized)) {
|
|
531
740
|
return 'accept';
|
|
532
741
|
}
|
|
533
742
|
if (['decline', 'deny', 'reject', 'reject_once', 'reject_always', 'no'].includes(normalized)) {
|
|
@@ -538,6 +747,37 @@ function normalizeSecretaryApprovalDecision(value) {
|
|
|
538
747
|
}
|
|
539
748
|
return undefined;
|
|
540
749
|
}
|
|
750
|
+
function normalizeAutoModeDecisionForSecretary(decision) {
|
|
751
|
+
if (decision === 'accept' || decision === 'accept_for_session' || decision === 'accept_always') {
|
|
752
|
+
return 'accept';
|
|
753
|
+
}
|
|
754
|
+
if (decision === 'decline' || decision === 'cancel') {
|
|
755
|
+
return decision;
|
|
756
|
+
}
|
|
757
|
+
return undefined;
|
|
758
|
+
}
|
|
759
|
+
function normalizeAutoModeApprovalDecision(value) {
|
|
760
|
+
if (typeof value !== 'string') {
|
|
761
|
+
return undefined;
|
|
762
|
+
}
|
|
763
|
+
const normalized = value.trim().toLowerCase().replace(/-/g, '_');
|
|
764
|
+
if (['accept', 'allow', 'allow_once', 'approve', 'yes'].includes(normalized)) {
|
|
765
|
+
return 'accept';
|
|
766
|
+
}
|
|
767
|
+
if (['accept_for_session', 'allow_for_session', 'session', 'approve_for_session'].includes(normalized)) {
|
|
768
|
+
return 'accept_for_session';
|
|
769
|
+
}
|
|
770
|
+
if (['accept_always', 'allow_always', 'grant', 'always', 'approve_always'].includes(normalized)) {
|
|
771
|
+
return 'accept_always';
|
|
772
|
+
}
|
|
773
|
+
if (['decline', 'deny', 'reject', 'reject_once', 'reject_always', 'no'].includes(normalized)) {
|
|
774
|
+
return 'decline';
|
|
775
|
+
}
|
|
776
|
+
if (['cancel', 'abort'].includes(normalized)) {
|
|
777
|
+
return 'cancel';
|
|
778
|
+
}
|
|
779
|
+
return undefined;
|
|
780
|
+
}
|
|
541
781
|
function parseJsonObjectFromText(text) {
|
|
542
782
|
const trimmed = text.trim();
|
|
543
783
|
if (!trimmed) {
|
|
@@ -630,6 +870,9 @@ function normalizeAutoModeAuthText(value, depth = 0) {
|
|
|
630
870
|
]);
|
|
631
871
|
}
|
|
632
872
|
export function getAutoModeAuthLoginCommand(backend) {
|
|
873
|
+
if (backend === 'linx') {
|
|
874
|
+
return null;
|
|
875
|
+
}
|
|
633
876
|
if (backend === 'claude') {
|
|
634
877
|
return 'claude auth login';
|
|
635
878
|
}
|
|
@@ -640,11 +883,18 @@ export function getAutoModeAuthLoginCommand(backend) {
|
|
|
640
883
|
}
|
|
641
884
|
export function formatAutoModeBackendAuthMessage(backend, detail) {
|
|
642
885
|
const command = getAutoModeAuthLoginCommand(backend);
|
|
643
|
-
const label = backend === '
|
|
644
|
-
? '
|
|
645
|
-
: backend === '
|
|
646
|
-
? '
|
|
647
|
-
: '
|
|
886
|
+
const label = backend === 'linx'
|
|
887
|
+
? 'LinX'
|
|
888
|
+
: backend === 'claude'
|
|
889
|
+
? 'Claude Code'
|
|
890
|
+
: backend === 'codebuddy'
|
|
891
|
+
? 'CodeBuddy Code'
|
|
892
|
+
: 'Codex';
|
|
893
|
+
if (backend === 'linx') {
|
|
894
|
+
return detail
|
|
895
|
+
? `${label} backend is unavailable. Native message: ${detail}`
|
|
896
|
+
: `${label} backend is unavailable.`;
|
|
897
|
+
}
|
|
648
898
|
if (backend === 'codebuddy') {
|
|
649
899
|
return detail
|
|
650
900
|
? `${label} is not authenticated. Open \`codebuddy\` and complete login first. Native message: ${detail}`
|
|
@@ -821,12 +1071,13 @@ export function normalizeCodexAppServerInteractionRequest(message) {
|
|
|
821
1071
|
return null;
|
|
822
1072
|
}
|
|
823
1073
|
export function resolveAutoModeInteractionAutoResponse(input) {
|
|
824
|
-
const {
|
|
1074
|
+
const { request } = input;
|
|
825
1075
|
if (request.kind === 'user-input' || request.kind === 'codex-approval') {
|
|
826
1076
|
return null;
|
|
827
1077
|
}
|
|
828
1078
|
const decision = resolveAutoModeAutoApprovalDecision({
|
|
829
|
-
mode,
|
|
1079
|
+
mode: input.mode,
|
|
1080
|
+
autoEnabled: input.autoEnabled,
|
|
830
1081
|
request,
|
|
831
1082
|
});
|
|
832
1083
|
if (!decision) {
|
|
@@ -834,12 +1085,17 @@ export function resolveAutoModeInteractionAutoResponse(input) {
|
|
|
834
1085
|
}
|
|
835
1086
|
return buildCodexApprovalResponse(request, decision);
|
|
836
1087
|
}
|
|
1088
|
+
function isAutoModeSecretaryControlEnabled(input) {
|
|
1089
|
+
return typeof input.autoEnabled === 'boolean'
|
|
1090
|
+
? input.autoEnabled
|
|
1091
|
+
: input.mode === 'auto';
|
|
1092
|
+
}
|
|
837
1093
|
export function buildCodexApprovalResponse(request, decision) {
|
|
838
1094
|
if (request.kind === 'permissions-approval') {
|
|
839
1095
|
if (decision === 'accept') {
|
|
840
1096
|
return { permissions: request.permissions, scope: 'turn' };
|
|
841
1097
|
}
|
|
842
|
-
if (decision === 'accept_for_session') {
|
|
1098
|
+
if (decision === 'accept_for_session' || decision === 'accept_always') {
|
|
843
1099
|
return { permissions: request.permissions, scope: 'session' };
|
|
844
1100
|
}
|
|
845
1101
|
return { permissions: {}, scope: 'turn' };
|
|
@@ -848,7 +1104,7 @@ export function buildCodexApprovalResponse(request, decision) {
|
|
|
848
1104
|
if (decision === 'accept') {
|
|
849
1105
|
return { decision: 'approved' };
|
|
850
1106
|
}
|
|
851
|
-
if (decision === 'accept_for_session') {
|
|
1107
|
+
if (decision === 'accept_for_session' || decision === 'accept_always') {
|
|
852
1108
|
return { decision: 'approved_for_session' };
|
|
853
1109
|
}
|
|
854
1110
|
if (decision === 'cancel') {
|
|
@@ -859,7 +1115,7 @@ export function buildCodexApprovalResponse(request, decision) {
|
|
|
859
1115
|
if (decision === 'accept') {
|
|
860
1116
|
return { decision: 'accept' };
|
|
861
1117
|
}
|
|
862
|
-
if (decision === 'accept_for_session') {
|
|
1118
|
+
if (decision === 'accept_for_session' || decision === 'accept_always') {
|
|
863
1119
|
return { decision: 'acceptForSession' };
|
|
864
1120
|
}
|
|
865
1121
|
if (decision === 'cancel') {
|
|
@@ -1380,6 +1636,7 @@ export function buildAutoModeThreadMetadata(record) {
|
|
|
1380
1636
|
runtime: record.runtime,
|
|
1381
1637
|
transport: record.transport,
|
|
1382
1638
|
mode: record.mode,
|
|
1639
|
+
...(record.autoEnabled !== undefined ? { autoEnabled: record.autoEnabled } : {}),
|
|
1383
1640
|
...(record.goalMode !== undefined ? { goalMode: record.goalMode } : {}),
|
|
1384
1641
|
cwd: record.cwd,
|
|
1385
1642
|
model: record.model,
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export type LinxSessionControlSurface = 'cli' | 'app' | 'desktop' | 'runtime';
|
|
2
|
+
export interface LinxSessionControlState {
|
|
3
|
+
autoEnabled?: boolean;
|
|
4
|
+
symphonyEnabled?: boolean;
|
|
5
|
+
updatedAt: string;
|
|
6
|
+
updatedBy?: LinxSessionControlSurface | string;
|
|
7
|
+
}
|
|
8
|
+
export interface LinxSessionControlMetadata {
|
|
9
|
+
controlPlane: {
|
|
10
|
+
linxSession: LinxSessionControlState;
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
export declare function buildLinxSessionControlState(input: {
|
|
14
|
+
autoEnabled?: boolean;
|
|
15
|
+
symphonyEnabled?: boolean;
|
|
16
|
+
updatedAt?: Date | string;
|
|
17
|
+
updatedBy?: LinxSessionControlSurface | string;
|
|
18
|
+
}): LinxSessionControlState;
|
|
19
|
+
export declare function buildLinxSessionControlMetadata(input: {
|
|
20
|
+
autoEnabled?: boolean;
|
|
21
|
+
symphonyEnabled?: boolean;
|
|
22
|
+
updatedAt?: Date | string;
|
|
23
|
+
updatedBy?: LinxSessionControlSurface | string;
|
|
24
|
+
}): LinxSessionControlMetadata;
|
|
25
|
+
export declare function mergeLinxSessionControlMetadata(metadata: Record<string, unknown> | null | undefined, state: LinxSessionControlState): Record<string, unknown>;
|
|
26
|
+
export declare function readLinxSessionControlMetadata(metadata: Record<string, unknown> | null | undefined): LinxSessionControlState | null;
|
|
27
|
+
export declare function resolveLinxSessionAutoEnabled(metadata: Record<string, unknown> | null | undefined): boolean | null;
|
|
28
|
+
export declare function resolveLinxSessionSymphonyEnabled(metadata: Record<string, unknown> | null | undefined): boolean | null;
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
export function buildLinxSessionControlState(input) {
|
|
2
|
+
return {
|
|
3
|
+
...(input.autoEnabled !== undefined ? { autoEnabled: input.autoEnabled } : {}),
|
|
4
|
+
...(input.symphonyEnabled !== undefined ? { symphonyEnabled: input.symphonyEnabled } : {}),
|
|
5
|
+
updatedAt: toControlStateIsoString(input.updatedAt ?? new Date()),
|
|
6
|
+
...(input.updatedBy ? { updatedBy: input.updatedBy } : {}),
|
|
7
|
+
};
|
|
8
|
+
}
|
|
9
|
+
export function buildLinxSessionControlMetadata(input) {
|
|
10
|
+
return {
|
|
11
|
+
controlPlane: {
|
|
12
|
+
linxSession: buildLinxSessionControlState(input),
|
|
13
|
+
},
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
export function mergeLinxSessionControlMetadata(metadata, state) {
|
|
17
|
+
const existing = isRecord(metadata) ? metadata : {};
|
|
18
|
+
const existingControlPlane = isRecord(existing.controlPlane) ? existing.controlPlane : {};
|
|
19
|
+
const existingSession = isRecord(existingControlPlane.linxSession) ? existingControlPlane.linxSession : {};
|
|
20
|
+
return {
|
|
21
|
+
...existing,
|
|
22
|
+
controlPlane: {
|
|
23
|
+
...existingControlPlane,
|
|
24
|
+
linxSession: {
|
|
25
|
+
...existingSession,
|
|
26
|
+
...state,
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
export function readLinxSessionControlMetadata(metadata) {
|
|
32
|
+
if (!isRecord(metadata)) {
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
const controlPlane = isRecord(metadata.controlPlane) ? metadata.controlPlane : null;
|
|
36
|
+
const session = controlPlane && isRecord(controlPlane.linxSession) ? controlPlane.linxSession : null;
|
|
37
|
+
if (!session) {
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
const updatedAt = typeof session.updatedAt === 'string'
|
|
41
|
+
? session.updatedAt
|
|
42
|
+
: undefined;
|
|
43
|
+
const autoEnabled = typeof session.autoEnabled === 'boolean'
|
|
44
|
+
? session.autoEnabled
|
|
45
|
+
: undefined;
|
|
46
|
+
const symphonyEnabled = typeof session.symphonyEnabled === 'boolean'
|
|
47
|
+
? session.symphonyEnabled
|
|
48
|
+
: undefined;
|
|
49
|
+
const updatedBy = typeof session.updatedBy === 'string'
|
|
50
|
+
? session.updatedBy
|
|
51
|
+
: undefined;
|
|
52
|
+
if (autoEnabled === undefined && symphonyEnabled === undefined && !updatedAt && !updatedBy) {
|
|
53
|
+
return null;
|
|
54
|
+
}
|
|
55
|
+
return {
|
|
56
|
+
...(autoEnabled !== undefined ? { autoEnabled } : {}),
|
|
57
|
+
...(symphonyEnabled !== undefined ? { symphonyEnabled } : {}),
|
|
58
|
+
updatedAt: updatedAt ? toControlStateIsoString(updatedAt) : new Date(0).toISOString(),
|
|
59
|
+
...(updatedBy ? { updatedBy } : {}),
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
export function resolveLinxSessionAutoEnabled(metadata) {
|
|
63
|
+
const state = readLinxSessionControlMetadata(metadata);
|
|
64
|
+
return typeof state?.autoEnabled === 'boolean' ? state.autoEnabled : null;
|
|
65
|
+
}
|
|
66
|
+
export function resolveLinxSessionSymphonyEnabled(metadata) {
|
|
67
|
+
const state = readLinxSessionControlMetadata(metadata);
|
|
68
|
+
return typeof state?.symphonyEnabled === 'boolean' ? state.symphonyEnabled : null;
|
|
69
|
+
}
|
|
70
|
+
function toControlStateIsoString(value) {
|
|
71
|
+
if (value instanceof Date) {
|
|
72
|
+
return value.toISOString();
|
|
73
|
+
}
|
|
74
|
+
const date = new Date(value);
|
|
75
|
+
return Number.isNaN(date.getTime()) ? new Date().toISOString() : date.toISOString();
|
|
76
|
+
}
|
|
77
|
+
function isRecord(value) {
|
|
78
|
+
return typeof value === 'object' && value !== null;
|
|
79
|
+
}
|