@pellux/goodvibes-agent 0.1.56 → 0.1.58
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/.goodvibes/GOODVIBES.md +1 -1
- package/CHANGELOG.md +18 -9
- package/README.md +3 -3
- package/docs/README.md +1 -1
- package/docs/getting-started.md +3 -3
- package/docs/release-and-publishing.md +2 -2
- package/package.json +1 -3
- package/src/agent/routine-schedule-args.ts +219 -0
- package/src/agent/routine-schedule-format.ts +173 -0
- package/src/agent/routine-schedule-promotion.ts +3 -811
- package/src/agent/routine-schedule-receipts.ts +502 -0
- package/src/cli/agent-knowledge-command.ts +6 -6
- package/src/cli/help.ts +3 -25
- package/src/cli/package-verification.ts +23 -16
- package/src/cli/redaction.ts +4 -1
- package/src/cli/routines-command.ts +10 -6
- package/src/cli/service-posture.ts +47 -280
- package/src/cli/status.ts +0 -1
- package/src/cli/tui-startup.ts +23 -0
- package/src/config/secret-config.ts +0 -2
- package/src/input/agent-workspace-categories.ts +219 -0
- package/src/input/agent-workspace-editors.ts +143 -0
- package/src/input/agent-workspace-snapshot.ts +265 -0
- package/src/input/agent-workspace-types.ts +142 -0
- package/src/input/agent-workspace.ts +22 -766
- package/src/input/commands/agent-runtime-profile-runtime.ts +1 -1
- package/src/input/commands/delegation-runtime.ts +1 -1
- package/src/input/commands/experience-runtime.ts +3 -4
- package/src/input/commands/guidance-runtime.ts +1 -2
- package/src/input/commands/health-runtime.ts +3 -65
- package/src/input/commands/knowledge.ts +7 -7
- package/src/input/commands/local-setup-review.ts +0 -61
- package/src/input/commands/local-setup-transfer.ts +0 -3
- package/src/input/commands/local-setup.ts +2 -15
- package/src/input/commands/planning-runtime.ts +4 -1
- package/src/input/commands/platform-access-runtime.ts +1 -10
- package/src/input/commands/platform-services-runtime.ts +0 -1
- package/src/input/commands/recall-query.ts +1 -1
- package/src/input/commands/routines-runtime.ts +10 -6
- package/src/input/commands/schedule-runtime.ts +10 -6
- package/src/input/commands/session-workflow.ts +1 -1
- package/src/input/commands/tasks-runtime.ts +1 -14
- package/src/input/commands.ts +0 -4
- package/src/input/handler-onboarding.ts +10 -120
- package/src/input/onboarding/onboarding-wizard-apply.ts +5 -196
- package/src/input/onboarding/onboarding-wizard-constants.ts +8 -119
- package/src/input/onboarding/onboarding-wizard-helpers.ts +2 -53
- package/src/input/onboarding/onboarding-wizard-rules.ts +2 -236
- package/src/input/onboarding/onboarding-wizard-state.ts +1 -69
- package/src/input/onboarding/onboarding-wizard-steps.ts +584 -737
- package/src/input/onboarding/onboarding-wizard-types.ts +8 -26
- package/src/input/onboarding/onboarding-wizard.ts +4 -109
- package/src/input/settings-modal-agent-policy.ts +10 -0
- package/src/input/settings-modal-types.ts +2 -4
- package/src/input/settings-modal.ts +3 -1
- package/src/input/submission-router.ts +0 -1
- package/src/main.ts +13 -12
- package/src/panels/approval-panel.ts +1 -2
- package/src/panels/builtin/operations.ts +1 -2
- package/src/panels/knowledge-panel.ts +2 -2
- package/src/panels/project-planning-panel.ts +4 -1
- package/src/panels/provider-health-domains.ts +0 -22
- package/src/panels/provider-health-panel.ts +1 -5
- package/src/panels/session-browser-panel.ts +0 -5
- package/src/panels/tasks-panel.ts +2 -64
- package/src/renderer/agent-workspace.ts +1 -1
- package/src/renderer/help-overlay.ts +1 -2
- package/src/renderer/semantic-diff.ts +1 -1
- package/src/renderer/settings-modal-helpers.ts +0 -16
- package/src/renderer/settings-modal.ts +3 -5
- package/src/runtime/bootstrap-hook-bridge.ts +0 -3
- package/src/runtime/bootstrap-shell.ts +2 -1
- package/src/runtime/bootstrap.ts +1 -1
- package/src/runtime/index.ts +0 -1
- package/src/runtime/onboarding/derivation.ts +1 -28
- package/src/runtime/onboarding/snapshot.ts +0 -1
- package/src/runtime/onboarding/types.ts +1 -4
- package/src/runtime/services.ts +4 -23
- package/src/runtime/ui-read-models.ts +4 -3
- package/src/shell/service-settings-sync.ts +15 -244
- package/src/tools/agent-context-policy.ts +1 -1
- package/src/tools/wrfc-agent-guard.ts +3 -3
- package/src/verification/live-verifier.ts +11 -5
- package/src/verification/verification-ledger.ts +3 -6
- package/src/version.ts +1 -1
- package/src/input/commands/agent-externalized-tui.ts +0 -73
- package/src/input/commands/cloudflare-runtime.ts +0 -385
- package/src/input/handler-onboarding-cloudflare.ts +0 -322
- package/src/input/onboarding/onboarding-runtime-status.ts +0 -87
- package/src/input/onboarding/onboarding-wizard-cloudflare-step.ts +0 -494
- package/src/input/onboarding/onboarding-wizard-cloudflare.ts +0 -199
- package/src/input/onboarding/onboarding-wizard-external-surface-extra-specs.ts +0 -130
- package/src/input/onboarding/onboarding-wizard-external-surfaces.ts +0 -762
- package/src/runtime/cloudflare-control-plane.ts +0 -350
- package/src/runtime/sandbox-public-gaps.ts +0 -358
|
@@ -1,31 +1,26 @@
|
|
|
1
|
-
import { isIP } from 'node:net';
|
|
2
1
|
import type { ModelPickerTarget } from '../model-picker.ts';
|
|
3
2
|
import {
|
|
4
|
-
deriveOnboardingStepState,
|
|
5
3
|
type OnboardingAcknowledgementReason,
|
|
6
|
-
type OnboardingAcknowledgementTarget,
|
|
7
4
|
type OnboardingApplyOperation,
|
|
8
5
|
type OnboardingApplyRequest,
|
|
9
6
|
type OnboardingMode,
|
|
10
7
|
type OnboardingSnapshotState,
|
|
11
|
-
type OnboardingStep1CapabilityId,
|
|
12
|
-
type OnboardingStep1CapabilityItem,
|
|
13
8
|
type OnboardingStepDerivationState,
|
|
14
9
|
} from '../../runtime/onboarding/index.ts';
|
|
15
10
|
import type { ConfigKey } from '../../config/index.ts';
|
|
16
11
|
|
|
17
12
|
export type OnboardingWizardMode = OnboardingMode;
|
|
18
13
|
|
|
19
|
-
export type OnboardingWizardExternalSurfaceStepId = `external-surface:${string}`;
|
|
20
|
-
|
|
21
14
|
export type OnboardingWizardStepId =
|
|
22
15
|
| 'loading'
|
|
23
|
-
| '
|
|
24
|
-
| '
|
|
25
|
-
| '
|
|
26
|
-
| '
|
|
27
|
-
|
|
|
28
|
-
| '
|
|
16
|
+
| 'agent-setup'
|
|
17
|
+
| 'agent-communication'
|
|
18
|
+
| 'agent-tools'
|
|
19
|
+
| 'agent-knowledge'
|
|
20
|
+
| 'agent-local-state'
|
|
21
|
+
| 'agent-automation'
|
|
22
|
+
| 'agent-voice-media'
|
|
23
|
+
| 'agent-delegation'
|
|
29
24
|
| 'provider-access'
|
|
30
25
|
| 'default-model'
|
|
31
26
|
| 'experience'
|
|
@@ -44,17 +39,6 @@ export type OnboardingWizardFieldKind =
|
|
|
44
39
|
export type OnboardingWizardAction =
|
|
45
40
|
| 'apply'
|
|
46
41
|
| 'apply-and-continue'
|
|
47
|
-
| 'select-all-capabilities'
|
|
48
|
-
| 'clear-capabilities'
|
|
49
|
-
| 'select-all-external-surfaces'
|
|
50
|
-
| 'clear-external-surfaces'
|
|
51
|
-
| 'cloudflare-token-requirements'
|
|
52
|
-
| 'cloudflare-create-operational-token'
|
|
53
|
-
| 'cloudflare-discover'
|
|
54
|
-
| 'cloudflare-validate'
|
|
55
|
-
| 'cloudflare-provision'
|
|
56
|
-
| 'cloudflare-verify'
|
|
57
|
-
| 'cloudflare-disable'
|
|
58
42
|
| 'start-openai-subscription'
|
|
59
43
|
| 'finish-openai-subscription';
|
|
60
44
|
|
|
@@ -90,7 +74,6 @@ interface OnboardingWizardFieldBase {
|
|
|
90
74
|
export interface OnboardingWizardChecklistFieldDefinition extends OnboardingWizardFieldBase {
|
|
91
75
|
readonly kind: 'checklist';
|
|
92
76
|
readonly defaultValue: boolean;
|
|
93
|
-
readonly capabilityId?: OnboardingStep1CapabilityId;
|
|
94
77
|
}
|
|
95
78
|
|
|
96
79
|
export interface OnboardingWizardRadioFieldDefinition extends OnboardingWizardFieldBase {
|
|
@@ -123,7 +106,6 @@ export interface OnboardingWizardAcknowledgementFieldDefinition extends Onboardi
|
|
|
123
106
|
readonly defaultValue: boolean;
|
|
124
107
|
readonly required: boolean;
|
|
125
108
|
readonly reason: OnboardingAcknowledgementReason;
|
|
126
|
-
readonly target?: OnboardingAcknowledgementTarget;
|
|
127
109
|
}
|
|
128
110
|
|
|
129
111
|
export interface OnboardingWizardModelPickerFieldDefinition extends OnboardingWizardFieldBase {
|
|
@@ -1,42 +1,18 @@
|
|
|
1
1
|
import type { ModelPickerTarget } from '../model-picker.ts';
|
|
2
|
-
import type { OnboardingApplyRequest, OnboardingSnapshotState,
|
|
2
|
+
import type { OnboardingApplyRequest, OnboardingSnapshotState, OnboardingStepDerivationState } from '../../runtime/onboarding/index.ts';
|
|
3
3
|
import { STEP_ORDER } from './onboarding-wizard-constants.ts';
|
|
4
4
|
import { buildOnboardingApplyRequest } from './onboarding-wizard-apply.ts';
|
|
5
5
|
import { buildOnboardingWizardSteps } from './onboarding-wizard-steps.ts';
|
|
6
6
|
import { buildDefaultDerivedState, clamp, cloneSelection, getRuntimeDerivedState, maskValue, modelSelectionLabel, normalizeText } from './onboarding-wizard-helpers.ts';
|
|
7
7
|
import {
|
|
8
|
-
clearExternalSurfaces as clearExternalSurfacesForController,
|
|
9
8
|
getBooleanFieldValue as getBooleanFieldValueForController,
|
|
10
|
-
getDefaultAdminUsername as getDefaultAdminUsernameForController,
|
|
11
|
-
getNumberFieldValue as getNumberFieldValueForController,
|
|
12
|
-
getPortFieldValue as getPortFieldValueForController,
|
|
13
9
|
getSelectedSecretMedium as getSelectedSecretMediumForController,
|
|
14
|
-
getSharedIpDefault as getSharedIpDefaultForController,
|
|
15
|
-
getSharedIpHostDefault as getSharedIpHostDefaultForController,
|
|
16
10
|
getStringFieldValue as getStringFieldValueForController,
|
|
17
|
-
hasAdminAuthUser as hasAdminAuthUserForController,
|
|
18
|
-
hasBootstrapCredentialPresent as hasBootstrapCredentialPresentForController,
|
|
19
|
-
hasLocalAuthUser as hasLocalAuthUserForController,
|
|
20
|
-
hasSelectedInboundExternalSurface as hasSelectedInboundExternalSurfaceForController,
|
|
21
|
-
hasServerCapabilitiesSelected as hasServerCapabilitiesSelectedForController,
|
|
22
|
-
isCapabilitySelected as isCapabilitySelectedForController,
|
|
23
|
-
isRequiredExternalSetupField as isRequiredExternalSetupFieldForController,
|
|
24
|
-
parseIntegerFieldValue as parseIntegerFieldValueForController,
|
|
25
|
-
requiresAuthBootstrap as requiresAuthBootstrapForController,
|
|
26
|
-
selectAllExternalSurfaces as selectAllExternalSurfacesForController,
|
|
27
|
-
selectAllServerCapabilities as selectAllServerCapabilitiesForController,
|
|
28
|
-
selectLocalTuiOnly as selectLocalTuiOnlyForController,
|
|
29
|
-
setCapabilityValue as setCapabilityValueForController,
|
|
30
|
-
shouldEnableBrowserSurface as shouldEnableBrowserSurfaceForController,
|
|
31
|
-
shouldEnableHttpListener as shouldEnableHttpListenerForController,
|
|
32
|
-
shouldExposeControlPlaneNetwork as shouldExposeControlPlaneNetworkForController,
|
|
33
|
-
shouldExposeHttpListenerNetworkFields as shouldExposeHttpListenerNetworkFieldsForController,
|
|
34
|
-
toggleCapability as toggleCapabilityForController,
|
|
35
11
|
} from './onboarding-wizard-rules.ts';
|
|
36
|
-
import { ensureSelectionVisible as ensureSelectionVisibleForController, getBlockingFieldLabels as getBlockingFieldLabelsForController,
|
|
12
|
+
import { ensureSelectionVisible as ensureSelectionVisibleForController, getBlockingFieldLabels as getBlockingFieldLabelsForController, getCompletedFieldCount as getCompletedFieldCountForController, getCompletedToggleCount as getCompletedToggleCountForController, getFieldById as getFieldByIdForController, getFieldValidationError as getFieldValidationErrorForController, getStepFieldCount as getStepFieldCountForController, getToggleFieldCount as getToggleFieldCountForController, isFieldDirty as isFieldDirtyForController, isFieldDirtyByDefinition as isFieldDirtyByDefinitionForController, isFieldSatisfied as isFieldSatisfiedForController, isStepDirty as isStepDirtyForController, recalculateDirtyState as recalculateDirtyStateForController, reconcileStateWithCurrentDefinitions as reconcileStateWithCurrentDefinitionsForController, reconcileStepCursor as reconcileStepCursorForController, resetValuesFromCurrentDefinitions as resetValuesFromCurrentDefinitionsForController } from './onboarding-wizard-state.ts';
|
|
37
13
|
import type { MutableModelSelectionMap, OnboardingWizardAction, OnboardingWizardApplyFeedback, OnboardingWizardFieldDefinition, OnboardingWizardFieldWindow, OnboardingWizardMode, OnboardingWizardModelSelection, OnboardingWizardRuntimeHydration, OnboardingWizardSnapshot, OnboardingWizardStepDefinition, OnboardingWizardStepId } from './onboarding-wizard-types.ts';
|
|
38
14
|
|
|
39
|
-
export type { OnboardingWizardAcknowledgementFieldDefinition, OnboardingWizardAction, OnboardingWizardActionFieldDefinition, OnboardingWizardApplyFeedback, OnboardingWizardApplyFeedbackSeverity, OnboardingWizardChecklistFieldDefinition,
|
|
15
|
+
export type { OnboardingWizardAcknowledgementFieldDefinition, OnboardingWizardAction, OnboardingWizardActionFieldDefinition, OnboardingWizardApplyFeedback, OnboardingWizardApplyFeedbackSeverity, OnboardingWizardChecklistFieldDefinition, OnboardingWizardFieldDefinition, OnboardingWizardFieldKind, OnboardingWizardFieldWindow, OnboardingWizardMaskedFieldDefinition, OnboardingWizardMode, OnboardingWizardModelPickerFieldDefinition, OnboardingWizardModelSelection, OnboardingWizardRadioFieldDefinition, OnboardingWizardRadioOption, OnboardingWizardRuntimeHydration, OnboardingWizardSnapshot, OnboardingWizardStatusFieldDefinition, OnboardingWizardStepDefinition, OnboardingWizardStepId, OnboardingWizardTextFieldDefinition } from './onboarding-wizard-types.ts';
|
|
40
16
|
export { getOnboardingWizardBodyRows, getOnboardingWizardVisibleFieldCount } from './onboarding-wizard-helpers.ts';
|
|
41
17
|
|
|
42
18
|
export class OnboardingWizardController {
|
|
@@ -377,15 +353,6 @@ export class OnboardingWizardController {
|
|
|
377
353
|
if (!field) return;
|
|
378
354
|
if (field.kind === 'status') return;
|
|
379
355
|
|
|
380
|
-
if (field.kind === 'checklist' && field.capabilityId) {
|
|
381
|
-
this.toggleCapability(field.capabilityId);
|
|
382
|
-
this.pendingModelPickerTarget = null;
|
|
383
|
-
this.pendingAction = null;
|
|
384
|
-
this.applyFeedback = null;
|
|
385
|
-
this.recalculateDirtyState();
|
|
386
|
-
return;
|
|
387
|
-
}
|
|
388
|
-
|
|
389
356
|
if (field.kind === 'checklist' || field.kind === 'acknowledgement') {
|
|
390
357
|
const current = this.toggleState.get(field.id) ?? field.defaultValue;
|
|
391
358
|
this.toggleState.set(field.id, !current);
|
|
@@ -417,42 +384,6 @@ export class OnboardingWizardController {
|
|
|
417
384
|
}
|
|
418
385
|
|
|
419
386
|
if (field.kind === 'action') {
|
|
420
|
-
if (field.action === 'select-all-capabilities') {
|
|
421
|
-
this.selectAllServerCapabilities();
|
|
422
|
-
this.pendingAction = null;
|
|
423
|
-
this.pendingModelPickerTarget = null;
|
|
424
|
-
this.applyFeedback = null;
|
|
425
|
-
this.recalculateDirtyState();
|
|
426
|
-
return;
|
|
427
|
-
}
|
|
428
|
-
|
|
429
|
-
if (field.action === 'clear-capabilities') {
|
|
430
|
-
this.selectLocalTuiOnly();
|
|
431
|
-
this.pendingAction = null;
|
|
432
|
-
this.pendingModelPickerTarget = null;
|
|
433
|
-
this.applyFeedback = null;
|
|
434
|
-
this.recalculateDirtyState();
|
|
435
|
-
return;
|
|
436
|
-
}
|
|
437
|
-
|
|
438
|
-
if (field.action === 'select-all-external-surfaces') {
|
|
439
|
-
this.selectAllExternalSurfaces();
|
|
440
|
-
this.pendingAction = null;
|
|
441
|
-
this.pendingModelPickerTarget = null;
|
|
442
|
-
this.applyFeedback = null;
|
|
443
|
-
this.recalculateDirtyState();
|
|
444
|
-
return;
|
|
445
|
-
}
|
|
446
|
-
|
|
447
|
-
if (field.action === 'clear-external-surfaces') {
|
|
448
|
-
this.clearExternalSurfaces();
|
|
449
|
-
this.pendingAction = null;
|
|
450
|
-
this.pendingModelPickerTarget = null;
|
|
451
|
-
this.applyFeedback = null;
|
|
452
|
-
this.recalculateDirtyState();
|
|
453
|
-
return;
|
|
454
|
-
}
|
|
455
|
-
|
|
456
387
|
this.pendingAction = field.action;
|
|
457
388
|
this.pendingModelPickerTarget = null;
|
|
458
389
|
return;
|
|
@@ -530,8 +461,7 @@ export class OnboardingWizardController {
|
|
|
530
461
|
|
|
531
462
|
if (field.kind === 'checklist' || field.kind === 'acknowledgement') {
|
|
532
463
|
if (typeof value === 'boolean') {
|
|
533
|
-
|
|
534
|
-
else this.toggleState.set(fieldId, value);
|
|
464
|
+
this.toggleState.set(fieldId, value);
|
|
535
465
|
this.applyFeedback = null;
|
|
536
466
|
this.recalculateDirtyState();
|
|
537
467
|
}
|
|
@@ -608,14 +538,12 @@ export class OnboardingWizardController {
|
|
|
608
538
|
if (field.kind === 'text') {
|
|
609
539
|
const value = normalizeText(this.getFieldValue(field) as string);
|
|
610
540
|
if (value.length === 0 && field.required === true) return 'Missing';
|
|
611
|
-
if (value.length === 0 && this.isRequiredExternalSetupField(field.id)) return 'Not set';
|
|
612
541
|
return value.length > 0 ? value : field.placeholder;
|
|
613
542
|
}
|
|
614
543
|
|
|
615
544
|
if (field.kind === 'masked') {
|
|
616
545
|
const value = normalizeText(this.getFieldValue(field) as string);
|
|
617
546
|
if (value.length === 0 && field.required === true) return 'Missing';
|
|
618
|
-
if (value.length === 0 && this.isRequiredExternalSetupField(field.id)) return 'Not set';
|
|
619
547
|
return value.length > 0 ? maskValue(value) : field.placeholder;
|
|
620
548
|
}
|
|
621
549
|
|
|
@@ -655,39 +583,9 @@ export class OnboardingWizardController {
|
|
|
655
583
|
this.applyFeedback = null;
|
|
656
584
|
}
|
|
657
585
|
|
|
658
|
-
public getSharedIpDefault(enabled: { readonly controlPlane: boolean; readonly httpListener: boolean; readonly web: boolean }): boolean {
|
|
659
|
-
return getSharedIpDefaultForController(this, enabled);
|
|
660
|
-
}
|
|
661
|
-
|
|
662
|
-
public getSharedIpHostDefault(enabled: { readonly controlPlane: boolean; readonly httpListener: boolean; readonly web: boolean }): string {
|
|
663
|
-
return getSharedIpHostDefaultForController(this, enabled);
|
|
664
|
-
}
|
|
665
|
-
|
|
666
|
-
public toggleCapability(capabilityId: OnboardingStep1CapabilityId): void { toggleCapabilityForController(this, capabilityId); }
|
|
667
|
-
public selectAllServerCapabilities(): void { selectAllServerCapabilitiesForController(this); }
|
|
668
|
-
public selectLocalTuiOnly(): void { selectLocalTuiOnlyForController(this); }
|
|
669
|
-
public selectAllExternalSurfaces(): void { selectAllExternalSurfacesForController(this); }
|
|
670
|
-
public clearExternalSurfaces(): void { clearExternalSurfacesForController(this); }
|
|
671
|
-
public setCapabilityValue(capabilityId: OnboardingStep1CapabilityId, selected: boolean): void { setCapabilityValueForController(this, capabilityId, selected); }
|
|
672
|
-
public isCapabilitySelected(capabilityId: OnboardingStep1CapabilityId): boolean { return isCapabilitySelectedForController(this, capabilityId); }
|
|
673
|
-
public hasServerCapabilitiesSelected(): boolean { return hasServerCapabilitiesSelectedForController(this); }
|
|
674
|
-
public shouldEnableBrowserSurface(): boolean { return shouldEnableBrowserSurfaceForController(this); }
|
|
675
|
-
public hasSelectedInboundExternalSurface(): boolean { return hasSelectedInboundExternalSurfaceForController(this); }
|
|
676
|
-
public isRequiredExternalSetupField(fieldId: string): boolean { return isRequiredExternalSetupFieldForController(this, fieldId); }
|
|
677
586
|
public getSelectedSecretMedium(): 'secure' | 'plaintext' { return getSelectedSecretMediumForController(this); }
|
|
678
|
-
public shouldEnableHttpListener(): boolean { return shouldEnableHttpListenerForController(this); }
|
|
679
|
-
public shouldExposeHttpListenerNetworkFields(): boolean { return shouldExposeHttpListenerNetworkFieldsForController(this); }
|
|
680
|
-
public shouldExposeControlPlaneNetwork(): boolean { return shouldExposeControlPlaneNetworkForController(this); }
|
|
681
|
-
public requiresAuthBootstrap(): boolean { return requiresAuthBootstrapForController(this); }
|
|
682
|
-
public hasAdminAuthUser(): boolean { return hasAdminAuthUserForController(this); }
|
|
683
|
-
public hasLocalAuthUser(): boolean { return hasLocalAuthUserForController(this); }
|
|
684
|
-
public hasBootstrapCredentialPresent(): boolean { return hasBootstrapCredentialPresentForController(this); }
|
|
685
|
-
public getDefaultAdminUsername(): string { return getDefaultAdminUsernameForController(this); }
|
|
686
587
|
public getBooleanFieldValue(fieldId: string, fallback: boolean): boolean { return getBooleanFieldValueForController(this, fieldId, fallback); }
|
|
687
588
|
public getStringFieldValue(fieldId: string, fallback: string): string { return getStringFieldValueForController(this, fieldId, fallback); }
|
|
688
|
-
public parseIntegerFieldValue(fieldId: string, fallback: number): number | null { return parseIntegerFieldValueForController(this, fieldId, fallback); }
|
|
689
|
-
public getPortFieldValue(fieldId: string, fallback: number): number { return getPortFieldValueForController(this, fieldId, fallback); }
|
|
690
|
-
public getNumberFieldValue(fieldId: string, fallback: number, min?: number, max?: number): number { return getNumberFieldValueForController(this, fieldId, fallback, min, max); }
|
|
691
589
|
|
|
692
590
|
public getToggleFieldCount(stepIndex: number): number { return getToggleFieldCountForController(this, stepIndex); }
|
|
693
591
|
public getCompletedToggleCount(stepIndex: number): number { return getCompletedToggleCountForController(this, stepIndex); }
|
|
@@ -705,7 +603,4 @@ export class OnboardingWizardController {
|
|
|
705
603
|
public recalculateDirtyState(): void { recalculateDirtyStateForController(this); }
|
|
706
604
|
public isFieldDirtyByDefinition(field: OnboardingWizardFieldDefinition): boolean { return isFieldDirtyByDefinitionForController(this, field); }
|
|
707
605
|
public isFieldSatisfied(field: OnboardingWizardFieldDefinition): boolean { return isFieldSatisfiedForController(this, field); }
|
|
708
|
-
public getCurrentCapabilities(): readonly OnboardingStep1CapabilityItem[] { return getCurrentCapabilitiesForController(this); }
|
|
709
|
-
public getCapabilitySelectionState(): readonly OnboardingStep1CapabilityItem[] { return getCapabilitySelectionStateForController(this); }
|
|
710
|
-
public hasExistingAccessState(): boolean { return hasExistingAccessStateForController(this); }
|
|
711
606
|
}
|
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
export const AGENT_EXTERNAL_DAEMON_SETTING_LOCK_REASON = 'GoodVibes Agent connects to an external daemon. Change this from GoodVibes TUI or the daemon host; Agent settings are read-only for daemon lifecycle and bind posture.';
|
|
2
2
|
|
|
3
|
+
const AGENT_HIDDEN_SETTING_PREFIXES = [
|
|
4
|
+
['cloud', 'flare.'].join(''),
|
|
5
|
+
['surfaces.', 'home', 'assistant.'].join(''),
|
|
6
|
+
'sandbox.',
|
|
7
|
+
] as const;
|
|
8
|
+
|
|
3
9
|
const EXTERNAL_DAEMON_SETTING_PREFIXES = [
|
|
4
10
|
'service.',
|
|
5
11
|
'controlPlane.',
|
|
@@ -16,3 +22,7 @@ export function isExternalDaemonOwnedSettingKey(key: string): boolean {
|
|
|
16
22
|
return EXTERNAL_DAEMON_SETTING_KEYS.has(key)
|
|
17
23
|
|| EXTERNAL_DAEMON_SETTING_PREFIXES.some((prefix) => key.startsWith(prefix));
|
|
18
24
|
}
|
|
25
|
+
|
|
26
|
+
export function isAgentHiddenSettingKey(key: string): boolean {
|
|
27
|
+
return AGENT_HIDDEN_SETTING_PREFIXES.some((prefix) => key.startsWith(prefix));
|
|
28
|
+
}
|
|
@@ -38,14 +38,12 @@ export type SettingsCategory =
|
|
|
38
38
|
| 'web'
|
|
39
39
|
| 'network'
|
|
40
40
|
| 'surfaces'
|
|
41
|
-
| 'cloudflare'
|
|
42
41
|
| 'batch'
|
|
43
42
|
| 'automation'
|
|
44
43
|
| 'watchers'
|
|
45
44
|
| 'runtime'
|
|
46
45
|
| 'telemetry'
|
|
47
46
|
| 'cache'
|
|
48
|
-
| 'sandbox'
|
|
49
47
|
| 'mcp'
|
|
50
48
|
| 'flags'
|
|
51
49
|
| 'release'
|
|
@@ -60,9 +58,9 @@ export const SETTINGS_CATEGORY_GROUPS: ReadonlyArray<{
|
|
|
60
58
|
{ label: 'Interface', categories: ['display', 'ui', 'behavior', 'permissions'] },
|
|
61
59
|
{ label: 'AI Routing', categories: ['provider', 'subscriptions', 'helper', 'tools', 'tts'] },
|
|
62
60
|
{ label: 'Service & Network', categories: ['service', 'network', 'controlPlane', 'httpListener', 'web'] },
|
|
63
|
-
{ label: 'Surfaces &
|
|
61
|
+
{ label: 'Surfaces & Integrations', categories: ['surfaces', 'mcp'] },
|
|
64
62
|
{ label: 'Automation', categories: ['batch', 'automation', 'watchers', 'orchestration', 'wrfc'] },
|
|
65
|
-
{ label: 'Runtime & Data', categories: ['storage', '
|
|
63
|
+
{ label: 'Runtime & Data', categories: ['storage', 'runtime', 'cache', 'telemetry'] },
|
|
66
64
|
{ label: 'Advanced', categories: ['flags', 'release', 'danger'] },
|
|
67
65
|
];
|
|
68
66
|
|
|
@@ -34,7 +34,7 @@ import {
|
|
|
34
34
|
type SettingsModalOpenOptions,
|
|
35
35
|
type SubscriptionEntry,
|
|
36
36
|
} from './settings-modal-types.ts';
|
|
37
|
-
import { AGENT_EXTERNAL_DAEMON_SETTING_LOCK_REASON, isExternalDaemonOwnedSettingKey } from './settings-modal-agent-policy.ts';
|
|
37
|
+
import { AGENT_EXTERNAL_DAEMON_SETTING_LOCK_REASON, isAgentHiddenSettingKey, isExternalDaemonOwnedSettingKey } from './settings-modal-agent-policy.ts';
|
|
38
38
|
|
|
39
39
|
export {
|
|
40
40
|
SETTINGS_CATEGORIES,
|
|
@@ -51,6 +51,7 @@ export {
|
|
|
51
51
|
type SubscriptionEntry,
|
|
52
52
|
} from './settings-modal-types.ts';
|
|
53
53
|
export { AGENT_EXTERNAL_DAEMON_SETTING_LOCK_REASON, isExternalDaemonOwnedSettingKey } from './settings-modal-agent-policy.ts';
|
|
54
|
+
export { isAgentHiddenSettingKey } from './settings-modal-agent-policy.ts';
|
|
54
55
|
|
|
55
56
|
// ---------------------------------------------------------------------------
|
|
56
57
|
// SettingsModal
|
|
@@ -621,6 +622,7 @@ export class SettingsModal {
|
|
|
621
622
|
}
|
|
622
623
|
|
|
623
624
|
for (const setting of CONFIG_SCHEMA) {
|
|
625
|
+
if (isAgentHiddenSettingKey(setting.key)) continue;
|
|
624
626
|
const rawCat = setting.key.split('.')[0] as string;
|
|
625
627
|
const cat = rawCat as SettingsCategory;
|
|
626
628
|
const currentValue = configManager.get(setting.key as ConfigKey);
|
package/src/main.ts
CHANGED
|
@@ -45,7 +45,7 @@ import { deriveComposerState } from './core/composer-state.ts';
|
|
|
45
45
|
import { buildPersistedSessionContext, formatReturnContextForDisplay, getReturnContextMode, maybeAssistReturnContextSummary } from '@/runtime/index.ts';
|
|
46
46
|
import { summarizeError } from '@pellux/goodvibes-sdk/platform/utils';
|
|
47
47
|
import { prepareShellCliRuntime } from './cli/entrypoint.ts';
|
|
48
|
-
import { applyInitialTuiCliState } from './cli/tui-startup.ts';
|
|
48
|
+
import { applyInitialTuiCliState, getInteractiveTerminalLaunchError } from './cli/tui-startup.ts';
|
|
49
49
|
import { wireSpokenTurnRuntime } from './audio/spoken-turn-wiring.ts';
|
|
50
50
|
import { attachSpokenTurnModelRouting, createSpokenTurnInputOptions } from './audio/spoken-turn-model-routing.ts';
|
|
51
51
|
import { allowTerminalWrite, installTuiTerminalOutputGuard } from './runtime/terminal-output-guard.ts';
|
|
@@ -53,17 +53,8 @@ import { ProjectPlanningCoordinator } from './planning/project-planning-coordina
|
|
|
53
53
|
import { buildCommandArgsHint } from './input/command-args-hint.ts';
|
|
54
54
|
import { GOODVIBES_AGENT_PAIRING_SURFACE } from './config/surface.ts';
|
|
55
55
|
|
|
56
|
-
const ALT_SCREEN_ENTER = '\x1b[?1049h';
|
|
57
|
-
const
|
|
58
|
-
const MOUSE_ENABLE = '\x1b[?1000h\x1b[?1002h\x1b[?1006h';
|
|
59
|
-
const MOUSE_DISABLE = '\x1b[?1006l\x1b[?1002l\x1b[?1000l';
|
|
60
|
-
const CURSOR_HIDE = '\x1b[?25l';
|
|
61
|
-
const CURSOR_SHOW = '\x1b[?25h';
|
|
62
|
-
const CLEAR_SCREEN = '\x1b[2J\x1b[3J\x1b[H';
|
|
63
|
-
const KEYBOARD_EXT_ENABLE = '\x1b[>4;2m' + '\x1b[?1u';
|
|
64
|
-
const KEYBOARD_EXT_DISABLE = '\x1b[>4;0m' + '\x1b[?1l';
|
|
65
|
-
const PASTE_ENABLE = '\x1b[?2004h';
|
|
66
|
-
const PASTE_DISABLE = '\x1b[?2004l';
|
|
56
|
+
const ALT_SCREEN_ENTER = '\x1b[?1049h', ALT_SCREEN_EXIT = '\x1b[?1049l', MOUSE_ENABLE = '\x1b[?1000h\x1b[?1002h\x1b[?1006h', MOUSE_DISABLE = '\x1b[?1006l\x1b[?1002l\x1b[?1000l', CURSOR_HIDE = '\x1b[?25l', CURSOR_SHOW = '\x1b[?25h', CLEAR_SCREEN = '\x1b[2J\x1b[3J\x1b[H';
|
|
57
|
+
const KEYBOARD_EXT_ENABLE = '\x1b[>4;2m' + '\x1b[?1u', KEYBOARD_EXT_DISABLE = '\x1b[>4;0m' + '\x1b[?1l', PASTE_ENABLE = '\x1b[?2004h', PASTE_DISABLE = '\x1b[?2004l';
|
|
67
58
|
|
|
68
59
|
async function main() {
|
|
69
60
|
const stdout = process.stdout;
|
|
@@ -73,6 +64,16 @@ async function main() {
|
|
|
73
64
|
homeDirectory: process.env['GOODVIBES_AGENT_HOME'] ?? homedir(),
|
|
74
65
|
}, 'goodvibes-agent');
|
|
75
66
|
|
|
67
|
+
const terminalLaunchError = getInteractiveTerminalLaunchError({
|
|
68
|
+
binary: cli.binary,
|
|
69
|
+
stdinIsTTY: stdin.isTTY,
|
|
70
|
+
stdoutIsTTY: stdout.isTTY,
|
|
71
|
+
});
|
|
72
|
+
if (terminalLaunchError !== null) {
|
|
73
|
+
process.stderr.write(`${terminalLaunchError}\n`);
|
|
74
|
+
process.exit(2);
|
|
75
|
+
}
|
|
76
|
+
|
|
76
77
|
const ctx: BootstrapContext = await bootstrapRuntime(stdout, {
|
|
77
78
|
configManager,
|
|
78
79
|
workingDir: bootstrapWorkingDir,
|
|
@@ -20,10 +20,9 @@ const APPROVAL_ROWS = [
|
|
|
20
20
|
['network', 'why prompted: external hosts, fetch scope, egress policy', 'review via /approval review network'],
|
|
21
21
|
['delegate', 'why prompted: recursive agents, spawn ceilings, write-set inheritance', 'review via /approval review delegate'],
|
|
22
22
|
['mcp', 'why prompted: trust escalation, host scope, path scope, coherence mismatch', 'review via /mcp trust and /security'],
|
|
23
|
-
['remote', 'why prompted: runner trust, remote write scope, artifact requirements', 'review via /remote and delegated TUI
|
|
23
|
+
['remote', 'why prompted: runner trust, remote write scope, artifact requirements', 'review via /remote and delegated TUI execution context'],
|
|
24
24
|
['hook', 'why prompted: deny/mutate authority, blocking behavior, runner provenance', 'review via /hooks and /security'],
|
|
25
25
|
['plugin', 'why prompted: install/update lifecycle, provenance, capability grants', 'review via /marketplace and /security'],
|
|
26
|
-
['sandbox', 'why prompted: WSL/VM isolation changes alter host risk posture', 'delegate sandbox changes to GoodVibes TUI'],
|
|
27
26
|
] as const;
|
|
28
27
|
|
|
29
28
|
type ApprovalRow = (typeof APPROVAL_ROWS)[number];
|
|
@@ -216,7 +216,7 @@ export function registerOperationsPanels(manager: PanelManager, deps: ResolvedBu
|
|
|
216
216
|
icon: 'J',
|
|
217
217
|
category: 'monitoring',
|
|
218
218
|
description: 'Queued, running, blocked, failed, and completed task summaries from the runtime store',
|
|
219
|
-
factory: () => new TasksPanel(ui.readModels.tasks
|
|
219
|
+
factory: () => new TasksPanel(ui.readModels.tasks),
|
|
220
220
|
});
|
|
221
221
|
|
|
222
222
|
manager.registerType({
|
|
@@ -286,7 +286,6 @@ export function registerOperationsPanels(manager: PanelManager, deps: ResolvedBu
|
|
|
286
286
|
remote: ui.readModels.remote,
|
|
287
287
|
intelligence: ui.readModels.intelligence,
|
|
288
288
|
continuity: ui.readModels.continuity,
|
|
289
|
-
worktrees: ui.readModels.worktrees,
|
|
290
289
|
},
|
|
291
290
|
deps.requestRender,
|
|
292
291
|
),
|
|
@@ -233,7 +233,7 @@ export class KnowledgePanel extends ScrollableListPanel<MemoryRecord> {
|
|
|
233
233
|
buildPanelLine(width, [
|
|
234
234
|
[' route ', C.label],
|
|
235
235
|
['/api/goodvibes-agent/knowledge/*', C.info],
|
|
236
|
-
[' isolated: no default Knowledge/Wiki or
|
|
236
|
+
[' isolated: no default Knowledge/Wiki or non-Agent fallback', C.dim],
|
|
237
237
|
]),
|
|
238
238
|
];
|
|
239
239
|
if (this.agentKnowledgeLoading && !this.agentKnowledgeStatus) {
|
|
@@ -283,7 +283,7 @@ export class KnowledgePanel extends ScrollableListPanel<MemoryRecord> {
|
|
|
283
283
|
|
|
284
284
|
if (this.records.length === 0) this.refresh();
|
|
285
285
|
|
|
286
|
-
const intro = 'Isolated Agent Knowledge plus local non-secret memory review. This surface never falls back to default Knowledge/Wiki or
|
|
286
|
+
const intro = 'Isolated Agent Knowledge plus local non-secret memory review. This surface never falls back to default Knowledge/Wiki or non-Agent knowledge segments.';
|
|
287
287
|
const records = this.registry.search({ limit: 200 });
|
|
288
288
|
const agentKnowledgeHeader = this.buildAgentKnowledgeHeader(width);
|
|
289
289
|
|
|
@@ -168,13 +168,16 @@ export class ProjectPlanningPanel extends BasePanel {
|
|
|
168
168
|
const evaluation = this.snapshot?.evaluation ?? null;
|
|
169
169
|
const language = this.snapshot?.language ?? null;
|
|
170
170
|
const decisions = this.snapshot?.decisions ?? [];
|
|
171
|
+
const planningNamespace = status
|
|
172
|
+
? String(status[['knowledge', 'SpaceId'].join('') as keyof typeof status] ?? `project:${this.projectId}`)
|
|
173
|
+
: `project:${this.projectId}`;
|
|
171
174
|
|
|
172
175
|
sections.push({
|
|
173
176
|
title: 'Workspace',
|
|
174
177
|
lines: [
|
|
175
178
|
buildKeyValueLine(width, [
|
|
176
179
|
{ label: 'project', value: this.projectId, valueColor: C.planning },
|
|
177
|
-
{ label: 'store', value:
|
|
180
|
+
{ label: 'store', value: planningNamespace, valueColor: C.value },
|
|
178
181
|
{ label: 'mode', value: 'Agent-owned workspace planning state', valueColor: C.info },
|
|
179
182
|
], C),
|
|
180
183
|
buildPanelLine(width, [
|
|
@@ -8,7 +8,6 @@ import type {
|
|
|
8
8
|
UiSecuritySnapshot,
|
|
9
9
|
UiSessionSnapshot,
|
|
10
10
|
UiSettingsSnapshot,
|
|
11
|
-
UiWorktreeSnapshot,
|
|
12
11
|
} from '../runtime/ui-read-models.ts';
|
|
13
12
|
|
|
14
13
|
export interface HealthDomainSummary {
|
|
@@ -28,7 +27,6 @@ export interface ProviderHealthDomainInputs {
|
|
|
28
27
|
readonly security: UiSecuritySnapshot;
|
|
29
28
|
readonly intelligence: UiIntelligenceSnapshot;
|
|
30
29
|
readonly continuity: UiContinuitySnapshot;
|
|
31
|
-
readonly worktrees: UiWorktreeSnapshot;
|
|
32
30
|
readonly session: UiSessionSnapshot;
|
|
33
31
|
}
|
|
34
32
|
|
|
@@ -44,7 +42,6 @@ export function buildProviderHealthDomainSummaries(
|
|
|
44
42
|
security,
|
|
45
43
|
intelligence,
|
|
46
44
|
continuity,
|
|
47
|
-
worktrees,
|
|
48
45
|
session,
|
|
49
46
|
} = input;
|
|
50
47
|
|
|
@@ -192,24 +189,5 @@ export function buildProviderHealthDomainSummaries(
|
|
|
192
189
|
: ['/session list'],
|
|
193
190
|
});
|
|
194
191
|
|
|
195
|
-
const worktreeSummary = worktrees.summary;
|
|
196
|
-
const worktreeIssues = worktreeSummary.discard + worktreeSummary.pendingCleanup + worktreeSummary.paused;
|
|
197
|
-
summaries.push({
|
|
198
|
-
name: 'worktrees',
|
|
199
|
-
level: worktreeIssues > 0 ? 'warn' : worktreeSummary.total > 0 ? 'good' : 'info',
|
|
200
|
-
summary: worktreeSummary.total === 0
|
|
201
|
-
? 'no persisted worktrees'
|
|
202
|
-
: `${worktreeSummary.total} tracked / ${worktreeIssues} need review`,
|
|
203
|
-
next: 'externalized to GoodVibes TUI',
|
|
204
|
-
details: [
|
|
205
|
-
worktreeSummary.paused > 0 ? `${worktreeSummary.paused} paused worktree(s)` : '',
|
|
206
|
-
worktreeSummary.pendingCleanup > 0 ? `${worktreeSummary.pendingCleanup} cleanup pending` : '',
|
|
207
|
-
worktreeSummary.discard > 0 ? `${worktreeSummary.discard} marked discard` : '',
|
|
208
|
-
].filter(Boolean),
|
|
209
|
-
nextSteps: worktreeIssues > 0
|
|
210
|
-
? ['Open GoodVibes TUI in the target workspace for recovery', '/delegate <task> for explicit build/fix/review recovery']
|
|
211
|
-
: ['No Agent worktree action available; use GoodVibes TUI when repository recovery is needed'],
|
|
212
|
-
});
|
|
213
|
-
|
|
214
192
|
return summaries;
|
|
215
193
|
}
|
|
@@ -22,7 +22,6 @@ import type {
|
|
|
22
22
|
UiSecuritySnapshot,
|
|
23
23
|
UiSessionSnapshot,
|
|
24
24
|
UiSettingsSnapshot,
|
|
25
|
-
UiWorktreeSnapshot,
|
|
26
25
|
} from '../runtime/ui-read-models.ts';
|
|
27
26
|
import { evaluateSessionMaintenance } from '@/runtime/index.ts';
|
|
28
27
|
import {
|
|
@@ -56,7 +55,6 @@ export interface ProviderHealthPanelDeps {
|
|
|
56
55
|
readonly remote: UiReadModel<UiRemoteSnapshot>;
|
|
57
56
|
readonly intelligence: UiReadModel<UiIntelligenceSnapshot>;
|
|
58
57
|
readonly continuity: UiReadModel<UiContinuitySnapshot>;
|
|
59
|
-
readonly worktrees: UiReadModel<UiWorktreeSnapshot>;
|
|
60
58
|
}
|
|
61
59
|
|
|
62
60
|
// Colors
|
|
@@ -434,7 +432,6 @@ export class ProviderHealthPanel extends BasePanel {
|
|
|
434
432
|
this.deps.remote,
|
|
435
433
|
this.deps.intelligence,
|
|
436
434
|
this.deps.continuity,
|
|
437
|
-
this.deps.worktrees,
|
|
438
435
|
] as const) {
|
|
439
436
|
this._unsubs.push(readModel.subscribe(() => this._markDirtyAndRender()));
|
|
440
437
|
}
|
|
@@ -524,7 +521,7 @@ export class ProviderHealthPanel extends BasePanel {
|
|
|
524
521
|
// -------------------------------------------------------------------------
|
|
525
522
|
|
|
526
523
|
override render(width: number, height: number): Line[] {
|
|
527
|
-
const intro = 'Cross-domain health workspace for providers, auth, settings, remote, MCP, continuity,
|
|
524
|
+
const intro = 'Cross-domain health workspace for providers, auth, settings, remote, MCP, continuity, and maintenance posture.';
|
|
528
525
|
|
|
529
526
|
const knownSet = new Set([
|
|
530
527
|
...this.deps.providers.getSnapshot().providerIds,
|
|
@@ -596,7 +593,6 @@ export class ProviderHealthPanel extends BasePanel {
|
|
|
596
593
|
security: this.deps.security.getSnapshot(),
|
|
597
594
|
intelligence: this.deps.intelligence.getSnapshot(),
|
|
598
595
|
continuity: this.deps.continuity.getSnapshot(),
|
|
599
|
-
worktrees: this.deps.worktrees.getSnapshot(),
|
|
600
596
|
session: this.deps.session.getSnapshot(),
|
|
601
597
|
})) {
|
|
602
598
|
domainLines.push(buildPanelLine(width, [
|
|
@@ -68,9 +68,6 @@ function formatReturnContextLines(returnContext: SessionInfo['returnContext']):
|
|
|
68
68
|
if (returnContext.remoteRunners?.length) {
|
|
69
69
|
lines.push(`remote runners: ${returnContext.remoteRunners.join(', ')}`);
|
|
70
70
|
}
|
|
71
|
-
if (returnContext.worktreePaths?.length) {
|
|
72
|
-
lines.push(`worktrees: ${returnContext.worktreePaths.join(', ')}`);
|
|
73
|
-
}
|
|
74
71
|
if (returnContext.openPanels?.length) {
|
|
75
72
|
lines.push(`open panels: ${returnContext.openPanels.join(', ')}`);
|
|
76
73
|
}
|
|
@@ -263,8 +260,6 @@ export class SessionBrowserPanel extends BasePanel {
|
|
|
263
260
|
buildPanelLine(width, [
|
|
264
261
|
[' Remote ', DEFAULT_PANEL_PALETTE.label],
|
|
265
262
|
[String(selected.returnContext?.remoteRunners?.length ?? 0), (selected.returnContext?.remoteRunners?.length ?? 0) > 0 ? DEFAULT_PANEL_PALETTE.info : DEFAULT_PANEL_PALETTE.dim],
|
|
266
|
-
[' Worktrees ', DEFAULT_PANEL_PALETTE.label],
|
|
267
|
-
[String(selected.returnContext?.worktreePaths?.length ?? 0), (selected.returnContext?.worktreePaths?.length ?? 0) > 0 ? DEFAULT_PANEL_PALETTE.info : DEFAULT_PANEL_PALETTE.dim],
|
|
268
263
|
[' Panels ', DEFAULT_PANEL_PALETTE.label],
|
|
269
264
|
[String(selected.returnContext?.openPanels?.length ?? 0), (selected.returnContext?.openPanels?.length ?? 0) > 0 ? DEFAULT_PANEL_PALETTE.good : DEFAULT_PANEL_PALETTE.dim],
|
|
270
265
|
]),
|