@code-yeongyu/senpi 2026.11.6-1 → 2026.11.6-2
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/CHANGELOG.md +35 -0
- package/dist/bundle/chunks/{chunk-5MWHZH2O.js → chunk-2FDW2LQL.js} +1 -1
- package/dist/bundle/chunks/{chunk-GG2JO3CL.js → chunk-4E7GDG4H.js} +1 -1
- package/dist/bundle/chunks/{chunk-K5JLYACP.js → chunk-4GKU755E.js} +1 -1
- package/dist/bundle/chunks/{chunk-437VLZQZ.js → chunk-7III44PV.js} +1 -1
- package/dist/bundle/chunks/chunk-7PSBD5KS.js +9 -0
- package/dist/bundle/chunks/{chunk-KFWHLVVH.js → chunk-C7OKUC7L.js} +1 -1
- package/dist/bundle/chunks/{chunk-CX32K5KD.js → chunk-CF5OGBC4.js} +7 -7
- package/dist/bundle/chunks/{chunk-7TGZJH6Z.js → chunk-D5MRJWUK.js} +40 -39
- package/dist/bundle/chunks/{chunk-E6L5VZSM.js → chunk-DSWDJ7HT.js} +1 -1
- package/dist/bundle/chunks/{chunk-6NMTFURP.js → chunk-ECW7VBMB.js} +1 -1
- package/dist/bundle/chunks/{chunk-2CSLJLM6.js → chunk-GKAYPJ4E.js} +2 -2
- package/dist/bundle/chunks/{chunk-KCGUUIUS.js → chunk-GNSMNSL7.js} +1 -1
- package/dist/bundle/chunks/{chunk-V3JSQ3PG.js → chunk-GSKCWXXG.js} +1 -1
- package/dist/bundle/chunks/{chunk-USKWGPA6.js → chunk-GTJJ73DE.js} +1 -1
- package/dist/bundle/chunks/{chunk-HHSYTDKO.js → chunk-HLM46XEB.js} +2 -2
- package/dist/bundle/chunks/{chunk-A4F4J2KH.js → chunk-I3PHVJAS.js} +2 -2
- package/dist/bundle/chunks/{chunk-LAMRXFHZ.js → chunk-LNPAT22L.js} +1 -1
- package/dist/bundle/chunks/chunk-NH7SYIGN.js +2 -0
- package/dist/bundle/chunks/{chunk-ZIIDIVTG.js → chunk-R2Z7CX77.js} +1 -1
- package/dist/bundle/chunks/{chunk-32I42CEY.js → chunk-RQ6CHXQ2.js} +1 -1
- package/dist/bundle/chunks/chunk-SJI6UB23.js +2 -0
- package/dist/bundle/chunks/{chunk-KUIEHAPR.js → chunk-T2SMQPRE.js} +1 -1
- package/dist/bundle/chunks/{chunk-IPG434JT.js → chunk-TIPKAMSS.js} +1 -1
- package/dist/bundle/chunks/{chunk-RI5ABX7A.js → chunk-TMXRR3N7.js} +2 -2
- package/dist/bundle/chunks/chunk-VD7AKTGP.js +3 -0
- package/dist/bundle/chunks/{chunk-22JICYKS.js → chunk-WAOGBBZR.js} +1 -1
- package/dist/bundle/chunks/{chunk-6MHCFJDB.js → chunk-WGRKM3N6.js} +2 -2
- package/dist/bundle/chunks/{chunk-WF5R2VSP.js → chunk-X5ZVYNOL.js} +1 -1
- package/dist/bundle/chunks/{chunk-H2FBGZNP.js → chunk-XCMII2VQ.js} +2 -2
- package/dist/bundle/chunks/{chunk-5JUCTKYS.js → chunk-YK3ZZCHI.js} +1 -1
- package/dist/bundle/chunks/{cli-main-ZQBSX5H5.js → cli-main-T74YJGIF.js} +1 -1
- package/dist/bundle/chunks/{hand-entry-7U7354GG.js → hand-entry-AYRUGE2A.js} +2 -2
- package/dist/bundle/chunks/{headless-host-7LKTG76U.js → headless-host-ES74ZB6M.js} +1 -1
- package/dist/bundle/chunks/{help-fast-path-NLSWH2CA.js → help-fast-path-TMTGLOBG.js} +1 -1
- package/dist/bundle/chunks/{host-command-3YRFN35E.js → host-command-YRXZE4TV.js} +1 -1
- package/dist/bundle/chunks/{host-lifecycle-6XLVIECJ.js → host-lifecycle-6VCXMPDW.js} +1 -1
- package/dist/bundle/chunks/host-lifecycle.js +1 -1
- package/dist/bundle/chunks/{host-session-command-F7USXUZV.js → host-session-command-N7IN7ZDV.js} +1 -1
- package/dist/bundle/chunks/{interactive-mode-4RF3PUQ2.js → interactive-mode-B5SQDLH7.js} +1 -1
- package/dist/bundle/chunks/{list-tips-H6VGDFTS.js → list-tips-DU57HHKA.js} +1 -1
- package/dist/bundle/chunks/{main-G2SRZYQN.js → main-UQFVFCNY.js} +1 -1
- package/dist/bundle/chunks/{multi-session-host-RPN54GUC.js → multi-session-host-XSUJDHFZ.js} +5 -5
- package/dist/bundle/chunks/{openai-codex-responses-MJZKUS6I.js → openai-codex-responses-7V6LTDRU.js} +2 -2
- package/dist/bundle/chunks/{package-manager-cli-D2VFD463.js → package-manager-cli-GLUNPQJU.js} +1 -1
- package/dist/bundle/chunks/{role-37WVG42T.js → role-RRFFHZF5.js} +1 -1
- package/dist/bundle/chunks/{rotation-stream-QELPMM4N.js → rotation-stream-BN2YK2MC.js} +1 -1
- package/dist/bundle/chunks/{rpc-mode-P4D3DVYD.js → rpc-mode-JYN3E7P7.js} +1 -1
- package/dist/bundle/chunks/rpc-monitor-source-C6VQ3BC4.js +3 -0
- package/dist/bundle/chunks/{run-attached-tui-CGA6O5FR.js → run-attached-tui-W236SEOR.js} +1 -1
- package/dist/bundle/chunks/{schedule-command-XWSNOAGG.js → schedule-command-B2EJTBOE.js} +1 -1
- package/dist/bundle/chunks/session-control-endpoint-YIMLHGLG.js +3 -0
- package/dist/bundle/chunks/{session-picker-OA2AUVZG.js → session-picker-E6ZONUJB.js} +1 -1
- package/dist/bundle/chunks/session-worker.js +294 -292
- package/dist/bundle/cli.js +2 -2
- package/dist/bundle/host-supervisor.js +1 -1
- package/dist/bundle/index.js +1 -1
- package/dist/bundle/rpc-entry.js +1 -1
- package/dist/bundle/runtime-manifest.json +1 -1
- package/dist/cli/project-trust-headless.d.ts +13 -0
- package/dist/cli/project-trust-headless.js +35 -0
- package/dist/cli/project-trust.js +13 -50
- package/dist/cli/schedule-delivery.d.ts +4 -0
- package/dist/cli/schedule-delivery.js +6 -0
- package/dist/cli/schedule-runner.js +8 -0
- package/dist/cli/session-opening.d.ts +19 -0
- package/dist/cli/session-opening.js +47 -1
- package/dist/core/agent-session-runtime.d.ts +12 -0
- package/dist/core/agent-session-runtime.js +41 -0
- package/dist/core/agent-session.js +13 -22
- package/dist/core/egress/api-table.d.ts +121 -0
- package/dist/core/egress/api-table.js +41 -0
- package/dist/core/egress/classify.d.ts +19 -0
- package/dist/core/egress/classify.js +197 -0
- package/dist/core/egress/credential-fields.d.ts +18 -0
- package/dist/core/egress/credential-fields.js +83 -0
- package/dist/core/egress/custody-sidecar.d.ts +44 -0
- package/dist/core/egress/custody-sidecar.js +91 -0
- package/dist/core/egress/device-custody.d.ts +12 -0
- package/dist/core/egress/device-custody.js +82 -0
- package/dist/core/egress/endpoint.d.ts +33 -0
- package/dist/core/egress/endpoint.js +115 -0
- package/dist/core/execute-tool-on-host.d.ts +26 -0
- package/dist/core/execute-tool-on-host.js +96 -0
- package/dist/core/extensions/builtin/compaction/retained-message-safety.js +15 -0
- package/dist/core/extensions/builtin/goal/index.js +15 -3
- package/dist/core/extensions/builtin/goal/stop-pause.d.ts +2 -0
- package/dist/core/extensions/builtin/goal/stop-pause.js +5 -0
- package/dist/core/extensions/builtin/herdr/herdr-state.d.ts +10 -0
- package/dist/core/extensions/builtin/herdr/herdr-state.js +34 -6
- package/dist/core/extensions/builtin/herdr/index.js +6 -2
- package/dist/core/extensions/builtin/mcp/service.d.ts +9 -1
- package/dist/core/extensions/builtin/mcp/service.js +32 -1
- package/dist/core/extensions/builtin/terminal/rpc-monitor-remote.d.ts +43 -0
- package/dist/core/extensions/builtin/terminal/rpc-monitor-remote.js +158 -0
- package/dist/core/extensions/builtin/terminal/rpc-monitor-render.d.ts +2 -0
- package/dist/core/extensions/builtin/terminal/rpc-monitor-render.js +4 -0
- package/dist/core/extensions/builtin/terminal/rpc-monitor-source.d.ts +5 -2
- package/dist/core/extensions/builtin/terminal/rpc-monitor-source.js +19 -4
- package/dist/core/extensions/builtin/terminal/rpc-monitor-targets.d.ts +4 -0
- package/dist/core/extensions/builtin/terminal/rpc-monitor-targets.js +15 -0
- package/dist/core/extensions/builtin/terminal/rpc-monitor-watch.d.ts +10 -0
- package/dist/core/extensions/builtin/terminal/rpc-monitor-watch.js +28 -2
- package/dist/core/extensions/builtin/terminal/rpc-remote-source.d.ts +59 -0
- package/dist/core/extensions/builtin/terminal/rpc-remote-source.js +15 -0
- package/dist/core/extensions/builtin/terminal/terminal-manifest-model.d.ts +5 -0
- package/dist/core/extensions/builtin/terminal/terminal-manifest-parse.js +14 -1
- package/dist/core/extensions/builtin/terminal/tools/monitor-rpc.js +8 -1
- package/dist/core/extensions/loader.js +8 -0
- package/dist/core/extensions/types.d.ts +6 -0
- package/dist/core/foreign-session-holders.d.ts +1 -1
- package/dist/core/foreign-session-holders.js +3 -3
- package/dist/core/session-import/jsonl-import.d.ts +8 -12
- package/dist/core/session-import/jsonl-import.js +99 -40
- package/dist/core/session-manager.d.ts +2 -0
- package/dist/core/session-manager.js +7 -2
- package/dist/core/session-store/durable-binding.d.ts +2 -0
- package/dist/core/session-store/durable-binding.js +26 -4
- package/dist/core/settings-manager.d.ts +20 -0
- package/dist/core/settings-manager.js +51 -0
- package/dist/core/trust-manager.d.ts +1 -18
- package/dist/core/trust-manager.js +3 -124
- package/dist/core/trust-requiring-resources.d.ts +21 -0
- package/dist/core/trust-requiring-resources.js +189 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/main.js +42 -12
- package/dist/modes/interactive/interactive-mode.js +2 -2
- package/dist/modes/interactive/session-control-commands.js +2 -0
- package/dist/modes/rpc/connection-handler.js +17 -0
- package/dist/modes/rpc/connection-question-bridge.js +7 -4
- package/dist/modes/rpc/effect-commands.d.ts +24 -0
- package/dist/modes/rpc/host-boot-extensions.d.ts +4 -0
- package/dist/modes/rpc/host-boot-extensions.js +17 -0
- package/dist/modes/rpc/host-lifecycle-shutdown.js +11 -2
- package/dist/modes/rpc/loopless-runtime-settings.js +5 -1
- package/dist/modes/rpc/method-classes-schema-session.d.ts +33 -0
- package/dist/modes/rpc/method-classes-schema-session.js +4 -0
- package/dist/modes/rpc/method-classes-schema.d.ts +33 -0
- package/dist/modes/rpc/method-classes.d.ts +4 -0
- package/dist/modes/rpc/method-classes.js +7 -0
- package/dist/modes/rpc/multi-session-host.d.ts +2 -0
- package/dist/modes/rpc/multi-session-host.js +7 -2
- package/dist/modes/rpc/project-workspace-commands.d.ts +60 -0
- package/dist/modes/rpc/project-workspace-commands.js +145 -0
- package/dist/modes/rpc/rpc-error-types.d.ts +11 -1
- package/dist/modes/rpc/rpc-error-types.js +10 -0
- package/dist/modes/rpc/rpc-input-validation.js +4 -0
- package/dist/modes/rpc/rpc-mutation-response-types.d.ts +13 -0
- package/dist/modes/rpc/rpc-read-response-types.d.ts +13 -0
- package/dist/modes/rpc/rpc-session-command-types.d.ts +15 -0
- package/dist/modes/rpc/session-attachment-gate.js +2 -0
- package/dist/modes/rpc/session-command-activity.js +2 -0
- package/docs/engine-socket/fixtures/admission-routes/h-legacy.json +1 -1
- package/docs/engine-socket/fixtures/rpc-inbound-samples.json +41 -2
- package/docs/extensions.md +17 -1
- package/docs/rpc.md +121 -4
- package/docs/terminal-tools.md +8 -0
- package/native/socket-secret/prebuilds/win32-arm64/senpi_socket_secret.win32-arm64.node +0 -0
- package/native/socket-secret/prebuilds/win32-x64/senpi_socket_secret.win32-x64.node +0 -0
- package/package.json +6 -6
- package/dist/bundle/chunks/chunk-FUQJK2TU.js +0 -2
- package/dist/bundle/chunks/chunk-POZMRM6V.js +0 -2
- package/dist/bundle/chunks/chunk-XBG63MJZ.js +0 -8
- package/dist/bundle/chunks/chunk-YP47G4YP.js +0 -3
- package/dist/bundle/chunks/rpc-monitor-source-KKN2UP4T.js +0 -3
- package/dist/bundle/chunks/session-control-endpoint-OST7WAKP.js +0 -3
|
@@ -78,6 +78,12 @@ export class DurableSessionBinding {
|
|
|
78
78
|
this.stale = false;
|
|
79
79
|
// Bumped by every store commit: a deferred whole-image ledger record is skipped once a later write superseded it.
|
|
80
80
|
this.generation = 0;
|
|
81
|
+
// Projected appends not yet in the ledger, in file order. A later append's record carries them, so a burst of appends
|
|
82
|
+
// keeps the ledger's prefix chain even though only the last one's record runs.
|
|
83
|
+
this.unrecordedTails = [];
|
|
84
|
+
// A whole-file write whose ledger record a later append superseded: the chain has no start until a record covers the
|
|
85
|
+
// whole file, so the next record writes today's whole image instead of the tails.
|
|
86
|
+
this.wholeUnrecorded = false;
|
|
81
87
|
this.binding = binding;
|
|
82
88
|
this.handle = handle;
|
|
83
89
|
this.importer = importer;
|
|
@@ -134,10 +140,20 @@ export class DurableSessionBinding {
|
|
|
134
140
|
const offset = this.projectedSize;
|
|
135
141
|
this.projectedSize += Buffer.byteLength(entry.line) + 1;
|
|
136
142
|
const sessionId = String(this.handle.header().id);
|
|
143
|
+
this.unrecordedTails.push({ key: entry.key, line: entry.line, offset });
|
|
137
144
|
this.record(path, async () => {
|
|
145
|
+
const tails = [...this.unrecordedTails];
|
|
146
|
+
const whole = this.wholeUnrecorded ? projectionImage(this.handle.header(), this.handle.entries()) : undefined;
|
|
138
147
|
const written = await stampOf(path);
|
|
139
|
-
if (written
|
|
140
|
-
|
|
148
|
+
if (written === undefined)
|
|
149
|
+
return;
|
|
150
|
+
if (whole === undefined)
|
|
151
|
+
await this.importer.recordProjectedTail(path, sessionId, tails, written);
|
|
152
|
+
else
|
|
153
|
+
await this.importer.recordProjection(path, whole, written);
|
|
154
|
+
this.unrecordedTails.splice(0, tails.length);
|
|
155
|
+
if (whole !== undefined)
|
|
156
|
+
this.wholeUnrecorded = false;
|
|
141
157
|
});
|
|
142
158
|
}
|
|
143
159
|
/** The caller wrote the whole file from today's serializer: record that image, unless a later write supersedes it. */
|
|
@@ -145,10 +161,14 @@ export class DurableSessionBinding {
|
|
|
145
161
|
const path = resolve(sessionFile);
|
|
146
162
|
const contents = projectionImage(this.handle.header(), this.handle.entries());
|
|
147
163
|
this.projectedSize = Buffer.byteLength(contents);
|
|
164
|
+
this.unrecordedTails = [];
|
|
165
|
+
this.wholeUnrecorded = true;
|
|
148
166
|
this.record(path, async () => {
|
|
149
167
|
const written = await stampOf(path);
|
|
150
|
-
if (written
|
|
151
|
-
|
|
168
|
+
if (written === undefined)
|
|
169
|
+
return;
|
|
170
|
+
await this.importer.recordProjection(path, contents, written);
|
|
171
|
+
this.wholeUnrecorded = false;
|
|
152
172
|
});
|
|
153
173
|
}
|
|
154
174
|
/** Marks the projection stale in the store (durable, so a crash before the repair still reprojects on open). */
|
|
@@ -198,6 +218,8 @@ export class DurableSessionBinding {
|
|
|
198
218
|
this.binding.store.commitSync(this.binding.epoch, [{ op: "delete", key: staleKey(path) }], () => { });
|
|
199
219
|
this.stale = false;
|
|
200
220
|
this.projectedSize = Buffer.byteLength(contents);
|
|
221
|
+
this.unrecordedTails = [];
|
|
222
|
+
this.wholeUnrecorded = false;
|
|
201
223
|
const written = await stampOf(path);
|
|
202
224
|
if (written !== undefined && generation === this.generation) {
|
|
203
225
|
await this.importer.recordProjection(path, contents, written);
|
|
@@ -199,6 +199,15 @@ export interface SettingsManagerCreateOptions {
|
|
|
199
199
|
projectTrusted?: boolean;
|
|
200
200
|
/** The project trust exists only because the session runs Full access (senpi#3414): leaving it withdraws the trust. */
|
|
201
201
|
trustFromFullAccess?: boolean;
|
|
202
|
+
/** The launch named the project trust explicitly (`--approve`/`--no-approve`): nothing in the session may change it. */
|
|
203
|
+
projectTrustLocked?: boolean;
|
|
204
|
+
}
|
|
205
|
+
/** The project settings file as stored, read whether or not the project is trusted (reading runs nothing). */
|
|
206
|
+
export interface ProjectSettingsFile {
|
|
207
|
+
path: string;
|
|
208
|
+
exists: boolean;
|
|
209
|
+
settings: Settings | null;
|
|
210
|
+
error: string | null;
|
|
202
211
|
}
|
|
203
212
|
export interface SettingsStorage {
|
|
204
213
|
withLock(scope: SettingsScope, fn: (current: string | undefined) => string | undefined): void;
|
|
@@ -293,6 +302,14 @@ export declare class SettingsManager {
|
|
|
293
302
|
getSettings(): Settings;
|
|
294
303
|
getGlobalSettings(): Settings;
|
|
295
304
|
getProjectSettings(): Settings;
|
|
305
|
+
/** The project settings file at `path` as stored: parsed and migrated like a load, but never gated by trust. */
|
|
306
|
+
readProjectSettingsFile(path: string): ProjectSettingsFile;
|
|
307
|
+
/**
|
|
308
|
+
* Writes one top-level key of the project settings file (`null` removes it) through the same trusted-only,
|
|
309
|
+
* locked, merge-on-write path every project setter uses. Refuses a file that failed to load: that path skips
|
|
310
|
+
* the write silently, which an explicit caller must not mistake for success.
|
|
311
|
+
*/
|
|
312
|
+
setProjectSetting(key: string, value: unknown): Promise<void>;
|
|
296
313
|
getProviderSettings(): Record<string, ProviderConcurrencySettings>;
|
|
297
314
|
getProviderConcurrencyLimit(providerId: string): number;
|
|
298
315
|
subscribeToProviderSettings(listener: () => void): () => void;
|
|
@@ -322,6 +339,9 @@ export declare class SettingsManager {
|
|
|
322
339
|
getTodoFirstTurnPlan(): TodoFirstTurnPlan;
|
|
323
340
|
getTodoTurnEndBackstop(): boolean;
|
|
324
341
|
isProjectTrusted(): boolean;
|
|
342
|
+
private projectTrustLocked;
|
|
343
|
+
/** True when the launch named the project trust explicitly; a trust decision saved in the session cannot apply. */
|
|
344
|
+
isProjectTrustLocked(): boolean;
|
|
325
345
|
/**
|
|
326
346
|
* True when this session's project trust came only from its Full access preset (never asked, never
|
|
327
347
|
* saved): leaving Full access withdraws it, and going back restores it (senpi#3414, #3420).
|
|
@@ -484,6 +484,7 @@ export class SettingsManager {
|
|
|
484
484
|
this.selectedSources = new Map();
|
|
485
485
|
this.sourceListeners = [];
|
|
486
486
|
this.providerSettingsListeners = new Set();
|
|
487
|
+
this.projectTrustLocked = false;
|
|
487
488
|
/**
|
|
488
489
|
* True when this session's project trust came only from its Full access preset (never asked, never
|
|
489
490
|
* saved): leaving Full access withdraws it, and going back restores it (senpi#3414, #3420).
|
|
@@ -534,6 +535,7 @@ export class SettingsManager {
|
|
|
534
535
|
}
|
|
535
536
|
const manager = new SettingsManager(storage, globalLoad.settings, projectLoad.settings, globalLoad.error, projectLoad.error, initialErrors, projectTrusted, initialSources, settingsPaths);
|
|
536
537
|
manager.trustFromFullAccess = options.trustFromFullAccess === true;
|
|
538
|
+
manager.projectTrustLocked = options.projectTrustLocked === true;
|
|
537
539
|
return manager;
|
|
538
540
|
}
|
|
539
541
|
/** Create an in-memory SettingsManager (no file I/O) */
|
|
@@ -695,6 +697,51 @@ export class SettingsManager {
|
|
|
695
697
|
getProjectSettings() {
|
|
696
698
|
return structuredClone(this.projectSettings);
|
|
697
699
|
}
|
|
700
|
+
/** The project settings file at `path` as stored: parsed and migrated like a load, but never gated by trust. */
|
|
701
|
+
readProjectSettingsFile(path) {
|
|
702
|
+
let content;
|
|
703
|
+
try {
|
|
704
|
+
this.storage.withLock("project", (current) => {
|
|
705
|
+
content = current;
|
|
706
|
+
return undefined;
|
|
707
|
+
});
|
|
708
|
+
if (content === undefined)
|
|
709
|
+
return { path, exists: false, settings: null, error: null };
|
|
710
|
+
return {
|
|
711
|
+
path,
|
|
712
|
+
exists: true,
|
|
713
|
+
settings: SettingsManager.migrateSettings(parseSettingsJson(content)),
|
|
714
|
+
error: null,
|
|
715
|
+
};
|
|
716
|
+
}
|
|
717
|
+
catch (error) {
|
|
718
|
+
return { path, exists: content !== undefined, settings: null, error: String(error) };
|
|
719
|
+
}
|
|
720
|
+
}
|
|
721
|
+
/**
|
|
722
|
+
* Writes one top-level key of the project settings file (`null` removes it) through the same trusted-only,
|
|
723
|
+
* locked, merge-on-write path every project setter uses. Refuses a file that failed to load: that path skips
|
|
724
|
+
* the write silently, which an explicit caller must not mistake for success.
|
|
725
|
+
*/
|
|
726
|
+
async setProjectSetting(key, value) {
|
|
727
|
+
this.assertProjectTrustedForWrite();
|
|
728
|
+
if (this.projectSettingsLoadError) {
|
|
729
|
+
throw new Error(`Project settings file could not be read; refusing to write: ${this.projectSettingsLoadError.message}`);
|
|
730
|
+
}
|
|
731
|
+
const field = key;
|
|
732
|
+
const recordedBefore = new Set(this.errors);
|
|
733
|
+
this.updateProjectSettings(field, (settings) => {
|
|
734
|
+
if (value === null)
|
|
735
|
+
delete settings[field];
|
|
736
|
+
else
|
|
737
|
+
settings[key] = value;
|
|
738
|
+
});
|
|
739
|
+
await this.flush();
|
|
740
|
+
// The queued write records its failure instead of throwing; an explicit caller is told.
|
|
741
|
+
const failure = this.errors.find((entry) => entry.scope === "project" && !recordedBefore.has(entry));
|
|
742
|
+
if (failure)
|
|
743
|
+
throw failure.error;
|
|
744
|
+
}
|
|
698
745
|
getProviderSettings() {
|
|
699
746
|
return structuredClone(this.settings.providers ?? {});
|
|
700
747
|
}
|
|
@@ -785,6 +832,10 @@ export class SettingsManager {
|
|
|
785
832
|
isProjectTrusted() {
|
|
786
833
|
return this.projectTrusted;
|
|
787
834
|
}
|
|
835
|
+
/** True when the launch named the project trust explicitly; a trust decision saved in the session cannot apply. */
|
|
836
|
+
isProjectTrustLocked() {
|
|
837
|
+
return this.projectTrustLocked;
|
|
838
|
+
}
|
|
788
839
|
isTrustFromFullAccess() {
|
|
789
840
|
return this.trustFromFullAccess && this.projectTrusted;
|
|
790
841
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
export { hasTrustRequiringProjectResources, projectAgentsSkillDirs } from "./trust-requiring-resources.ts";
|
|
1
2
|
export type ProjectTrustDecision = boolean | null;
|
|
2
3
|
export interface ProjectTrustStoreEntry {
|
|
3
4
|
path: string;
|
|
@@ -17,24 +18,6 @@ export declare function getProjectTrustParentPath(cwd: string): string | undefin
|
|
|
17
18
|
export declare function getProjectTrustOptions(cwd: string, options?: {
|
|
18
19
|
includeSessionOnly?: boolean;
|
|
19
20
|
}): ProjectTrustOption[];
|
|
20
|
-
/**
|
|
21
|
-
* The project `.agents/skills` directories for `cwd`, nearest first: one per folder from cwd up to
|
|
22
|
-
* the git root (or the filesystem root), stopping below the user's home. Home and every folder
|
|
23
|
-
* above it are never a project; `~/.agents/skills` is the user's own global skills. The ONE walk
|
|
24
|
-
* both the trust check and the loader use, over the same spelling and the same git root (#3420
|
|
25
|
-
* review): paths stay as spelled (resources are compared as strings), and each folder's real path
|
|
26
|
-
* decides whether it is home or above, so a symlink can't carry the walk past home either way.
|
|
27
|
-
*/
|
|
28
|
-
export declare function projectAgentsSkillDirs(cwd: string): string[];
|
|
29
|
-
/**
|
|
30
|
-
* Returns true when cwd has project-local resources that must be gated by
|
|
31
|
-
* project trust: trust-requiring entries under the project config dir or the
|
|
32
|
-
* legacy cwd/.pi dir (whose resources are also discovered), or a project
|
|
33
|
-
* `.agents/skills` (`projectAgentsSkillDirs`, the same walk the loader uses).
|
|
34
|
-
* The user's home and every folder above it are never a project: their config
|
|
35
|
-
* dirs and .agents/skills are the user's own global resources (#2465).
|
|
36
|
-
*/
|
|
37
|
-
export declare function hasTrustRequiringProjectResources(cwd: string): boolean;
|
|
38
21
|
export declare class ProjectTrustStore {
|
|
39
22
|
private trustPath;
|
|
40
23
|
constructor(agentDir: string);
|
|
@@ -1,70 +1,10 @@
|
|
|
1
1
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
2
2
|
import { readFile, realpath, stat } from "node:fs/promises";
|
|
3
|
-
import {
|
|
4
|
-
import { basename, dirname, join, relative, resolve, sep } from "node:path";
|
|
3
|
+
import { basename, dirname, join, relative, resolve } from "node:path";
|
|
5
4
|
import lockfile from "proper-lockfile";
|
|
6
|
-
import {
|
|
7
|
-
import { canonicalizePath, canonicalizePathStrict, resolvePath } from "../utils/paths.js";
|
|
5
|
+
import { canonicalizePathStrict, resolvePath } from "../utils/paths.js";
|
|
8
6
|
import { stripBom } from "../utils/text.js";
|
|
9
|
-
|
|
10
|
-
const TRUST_REQUIRING_PROJECT_CONFIG_RESOURCES = [
|
|
11
|
-
"settings.json",
|
|
12
|
-
"mcp.json",
|
|
13
|
-
"extensions",
|
|
14
|
-
"skills",
|
|
15
|
-
"prompts",
|
|
16
|
-
"themes",
|
|
17
|
-
"SYSTEM.md",
|
|
18
|
-
"APPEND_SYSTEM.md",
|
|
19
|
-
];
|
|
20
|
-
const LEGACY_PROJECT_CONFIG_DIR_NAME = ".pi";
|
|
21
|
-
/**
|
|
22
|
-
* A project codemode file that sets any setting naming an executable (the codemode package's
|
|
23
|
-
* `executable-settings.json` list, today `languages.pyInterpreter`) makes the session run that executable at start,
|
|
24
|
-
* so it asks for a trust decision. A file the check cannot read is treated like a project `mcp.json`, whose mere
|
|
25
|
-
* presence asks; so is any file when the list itself cannot be read.
|
|
26
|
-
*/
|
|
27
|
-
function projectCodemodeNamesExecutable(configDir) {
|
|
28
|
-
const path = join(configDir, "codemode.json");
|
|
29
|
-
if (!existsSync(path))
|
|
30
|
-
return false;
|
|
31
|
-
const executableSettings = codemodeExecutableSettings();
|
|
32
|
-
if (executableSettings === undefined)
|
|
33
|
-
return true;
|
|
34
|
-
let parsed;
|
|
35
|
-
try {
|
|
36
|
-
parsed = JSON.parse(stripBom(readFileSync(path, "utf8")));
|
|
37
|
-
}
|
|
38
|
-
catch {
|
|
39
|
-
return true;
|
|
40
|
-
}
|
|
41
|
-
return executableSettings.some((settingPath) => valueAtPath(parsed, settingPath) !== undefined);
|
|
42
|
-
}
|
|
43
|
-
function codemodeExecutableSettings() {
|
|
44
|
-
const codemode = bundledBuiltinExtensions.find((extension) => extension.id === "codemode");
|
|
45
|
-
try {
|
|
46
|
-
const packageJson = codemode?.resolvePackage();
|
|
47
|
-
if (packageJson === undefined)
|
|
48
|
-
return undefined;
|
|
49
|
-
const list = JSON.parse(readFileSync(join(dirname(packageJson), "src", "config", "executable-settings.json"), "utf8"));
|
|
50
|
-
if (typeof list !== "object" || list === null)
|
|
51
|
-
return undefined;
|
|
52
|
-
const paths = Reflect.get(list, "projectExecutableSettings");
|
|
53
|
-
return Array.isArray(paths) && paths.every((entry) => typeof entry === "string") ? paths : undefined;
|
|
54
|
-
}
|
|
55
|
-
catch {
|
|
56
|
-
return undefined;
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
function valueAtPath(value, path) {
|
|
60
|
-
let current = value;
|
|
61
|
-
for (const key of path.split(".")) {
|
|
62
|
-
if (typeof current !== "object" || current === null)
|
|
63
|
-
return undefined;
|
|
64
|
-
current = Reflect.get(current, key);
|
|
65
|
-
}
|
|
66
|
-
return current;
|
|
67
|
-
}
|
|
7
|
+
export { hasTrustRequiringProjectResources, projectAgentsSkillDirs } from "./trust-requiring-resources.js";
|
|
68
8
|
function normalizeCwd(cwd) {
|
|
69
9
|
const resolved = resolvePath(cwd);
|
|
70
10
|
try {
|
|
@@ -202,67 +142,6 @@ function withTrustFileLock(path, fn) {
|
|
|
202
142
|
release();
|
|
203
143
|
}
|
|
204
144
|
}
|
|
205
|
-
/** True when `dir` is the user's home or a folder above it: never a project (#2465). */
|
|
206
|
-
function isHomeOrAboveDir(dir, homeDir) {
|
|
207
|
-
return dir === homeDir || homeDir.startsWith(dir.endsWith(sep) ? dir : `${dir}${sep}`);
|
|
208
|
-
}
|
|
209
|
-
/** The nearest folder at or above `dir` that holds `.git`, as spelled; undefined outside a repository. */
|
|
210
|
-
function findGitRepoRoot(dir) {
|
|
211
|
-
let currentDir = dir;
|
|
212
|
-
while (!existsSync(join(currentDir, ".git"))) {
|
|
213
|
-
const parentDir = dirname(currentDir);
|
|
214
|
-
if (parentDir === currentDir)
|
|
215
|
-
return undefined;
|
|
216
|
-
currentDir = parentDir;
|
|
217
|
-
}
|
|
218
|
-
return currentDir;
|
|
219
|
-
}
|
|
220
|
-
/**
|
|
221
|
-
* The project `.agents/skills` directories for `cwd`, nearest first: one per folder from cwd up to
|
|
222
|
-
* the git root (or the filesystem root), stopping below the user's home. Home and every folder
|
|
223
|
-
* above it are never a project; `~/.agents/skills` is the user's own global skills. The ONE walk
|
|
224
|
-
* both the trust check and the loader use, over the same spelling and the same git root (#3420
|
|
225
|
-
* review): paths stay as spelled (resources are compared as strings), and each folder's real path
|
|
226
|
-
* decides whether it is home or above, so a symlink can't carry the walk past home either way.
|
|
227
|
-
*/
|
|
228
|
-
export function projectAgentsSkillDirs(cwd) {
|
|
229
|
-
const homeDir = canonicalizePath(resolvePath(process.env.HOME || homedir()));
|
|
230
|
-
const startDir = resolvePath(cwd);
|
|
231
|
-
const gitRepoRoot = findGitRepoRoot(startDir);
|
|
232
|
-
const dirs = [];
|
|
233
|
-
let currentDir = startDir;
|
|
234
|
-
while (!isHomeOrAboveDir(canonicalizePath(currentDir), homeDir)) {
|
|
235
|
-
dirs.push(join(currentDir, ".agents", "skills"));
|
|
236
|
-
if (currentDir === gitRepoRoot)
|
|
237
|
-
break;
|
|
238
|
-
const parentDir = dirname(currentDir);
|
|
239
|
-
if (parentDir === currentDir)
|
|
240
|
-
break;
|
|
241
|
-
currentDir = parentDir;
|
|
242
|
-
}
|
|
243
|
-
return dirs;
|
|
244
|
-
}
|
|
245
|
-
/**
|
|
246
|
-
* Returns true when cwd has project-local resources that must be gated by
|
|
247
|
-
* project trust: trust-requiring entries under the project config dir or the
|
|
248
|
-
* legacy cwd/.pi dir (whose resources are also discovered), or a project
|
|
249
|
-
* `.agents/skills` (`projectAgentsSkillDirs`, the same walk the loader uses).
|
|
250
|
-
* The user's home and every folder above it are never a project: their config
|
|
251
|
-
* dirs and .agents/skills are the user's own global resources (#2465).
|
|
252
|
-
*/
|
|
253
|
-
export function hasTrustRequiringProjectResources(cwd) {
|
|
254
|
-
const homeDir = canonicalizePath(resolvePath(process.env.HOME || homedir()));
|
|
255
|
-
const currentDir = canonicalizePath(resolvePath(cwd));
|
|
256
|
-
if (!isHomeOrAboveDir(currentDir, homeDir)) {
|
|
257
|
-
const configDirs = [join(currentDir, CONFIG_DIR_NAME), join(currentDir, LEGACY_PROJECT_CONFIG_DIR_NAME)];
|
|
258
|
-
if (configDirs.some((configDir) => TRUST_REQUIRING_PROJECT_CONFIG_RESOURCES.some((entry) => existsSync(join(configDir, entry))))) {
|
|
259
|
-
return true;
|
|
260
|
-
}
|
|
261
|
-
if (projectCodemodeNamesExecutable(join(currentDir, CONFIG_DIR_NAME)))
|
|
262
|
-
return true;
|
|
263
|
-
}
|
|
264
|
-
return projectAgentsSkillDirs(cwd).some((dir) => existsSync(dir));
|
|
265
|
-
}
|
|
266
145
|
export class ProjectTrustStore {
|
|
267
146
|
constructor(agentDir) {
|
|
268
147
|
this.trustPath = join(resolvePath(agentDir), "trust.json");
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The project `.agents/skills` directories for `cwd`, nearest first: one per folder from cwd up to
|
|
3
|
+
* the git root (or the filesystem root), stopping below the user's home. Home and every folder
|
|
4
|
+
* above it are never a project; `~/.agents/skills` is the user's own global skills. The ONE walk
|
|
5
|
+
* both the trust check and the loader use, over the same spelling and the same git root (#3420
|
|
6
|
+
* review): paths stay as spelled (resources are compared as strings), and each folder's real path
|
|
7
|
+
* decides whether it is home or above, so a symlink can't carry the walk past home either way.
|
|
8
|
+
*/
|
|
9
|
+
export declare function projectAgentsSkillDirs(cwd: string): string[];
|
|
10
|
+
/**
|
|
11
|
+
* Returns true when cwd has project-local resources that must be gated by
|
|
12
|
+
* project trust: trust-requiring entries under the project config dir or the
|
|
13
|
+
* legacy cwd/.pi dir (whose resources are also discovered), or a project
|
|
14
|
+
* `.agents/skills` (`projectAgentsSkillDirs`, the same walk the loader uses).
|
|
15
|
+
* The user's home and every folder above it are never a project: their config
|
|
16
|
+
* dirs and .agents/skills are the user's own global resources (#2465).
|
|
17
|
+
*/
|
|
18
|
+
export declare function hasTrustRequiringProjectResources(cwd: string): boolean;
|
|
19
|
+
/** `hasTrustRequiringProjectResources` without blocking: the same walk, answered through `node:fs/promises`. */
|
|
20
|
+
export declare function hasTrustRequiringProjectResourcesAsync(cwd: string): Promise<boolean>;
|
|
21
|
+
//# sourceMappingURL=trust-requiring-resources.d.ts.map
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
2
|
+
import { access, readFile } from "node:fs/promises";
|
|
3
|
+
import { homedir } from "node:os";
|
|
4
|
+
import { dirname, join, sep } from "node:path";
|
|
5
|
+
import { CONFIG_DIR_NAME } from "../config.js";
|
|
6
|
+
import { canonicalizePath, resolvePath } from "../utils/paths.js";
|
|
7
|
+
import { stripBom } from "../utils/text.js";
|
|
8
|
+
import { bundledBuiltinExtensions } from "./bundled-resources.js";
|
|
9
|
+
const TRUST_REQUIRING_PROJECT_CONFIG_RESOURCES = [
|
|
10
|
+
"settings.json",
|
|
11
|
+
"mcp.json",
|
|
12
|
+
"extensions",
|
|
13
|
+
"skills",
|
|
14
|
+
"prompts",
|
|
15
|
+
"themes",
|
|
16
|
+
"SYSTEM.md",
|
|
17
|
+
"APPEND_SYSTEM.md",
|
|
18
|
+
];
|
|
19
|
+
const LEGACY_PROJECT_CONFIG_DIR_NAME = ".pi";
|
|
20
|
+
function* exists(path) {
|
|
21
|
+
return (yield { kind: "exists", path }) === true;
|
|
22
|
+
}
|
|
23
|
+
function* readText(path) {
|
|
24
|
+
const text = yield { kind: "read", path };
|
|
25
|
+
return typeof text === "string" ? text : undefined;
|
|
26
|
+
}
|
|
27
|
+
function parseJson(text) {
|
|
28
|
+
try {
|
|
29
|
+
return { ok: true, value: JSON.parse(stripBom(text)) };
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
return { ok: false };
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
function valueAtPath(value, path) {
|
|
36
|
+
let current = value;
|
|
37
|
+
for (const key of path.split(".")) {
|
|
38
|
+
if (typeof current !== "object" || current === null)
|
|
39
|
+
return undefined;
|
|
40
|
+
current = Reflect.get(current, key);
|
|
41
|
+
}
|
|
42
|
+
return current;
|
|
43
|
+
}
|
|
44
|
+
function* codemodeExecutableSettings() {
|
|
45
|
+
const codemode = bundledBuiltinExtensions.find((extension) => extension.id === "codemode");
|
|
46
|
+
let packageJson;
|
|
47
|
+
try {
|
|
48
|
+
packageJson = codemode?.resolvePackage();
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
return undefined;
|
|
52
|
+
}
|
|
53
|
+
if (packageJson === undefined)
|
|
54
|
+
return undefined;
|
|
55
|
+
const text = yield* readText(join(dirname(packageJson), "src", "config", "executable-settings.json"));
|
|
56
|
+
const list = text === undefined ? { ok: false } : parseJson(text);
|
|
57
|
+
if (!list.ok || typeof list.value !== "object" || list.value === null)
|
|
58
|
+
return undefined;
|
|
59
|
+
const paths = Reflect.get(list.value, "projectExecutableSettings");
|
|
60
|
+
return Array.isArray(paths) && paths.every((entry) => typeof entry === "string") ? paths : undefined;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* A project codemode file that sets any setting naming an executable (the codemode package's
|
|
64
|
+
* `executable-settings.json` list, today `languages.pyInterpreter`) makes the session run that executable at start,
|
|
65
|
+
* so it asks for a trust decision. A file the check cannot read is treated like a project `mcp.json`, whose mere
|
|
66
|
+
* presence asks; so is any file when the list itself cannot be read.
|
|
67
|
+
*/
|
|
68
|
+
function* projectCodemodeNamesExecutable(configDir) {
|
|
69
|
+
const path = join(configDir, "codemode.json");
|
|
70
|
+
if (!(yield* exists(path)))
|
|
71
|
+
return false;
|
|
72
|
+
const executableSettings = yield* codemodeExecutableSettings();
|
|
73
|
+
if (executableSettings === undefined)
|
|
74
|
+
return true;
|
|
75
|
+
const text = yield* readText(path);
|
|
76
|
+
const parsed = text === undefined ? { ok: false } : parseJson(text);
|
|
77
|
+
if (!parsed.ok)
|
|
78
|
+
return true;
|
|
79
|
+
return executableSettings.some((settingPath) => valueAtPath(parsed.value, settingPath) !== undefined);
|
|
80
|
+
}
|
|
81
|
+
/** True when `dir` is the user's home or a folder above it: never a project (#2465). */
|
|
82
|
+
function isHomeOrAboveDir(dir, homeDir) {
|
|
83
|
+
return dir === homeDir || homeDir.startsWith(dir.endsWith(sep) ? dir : `${dir}${sep}`);
|
|
84
|
+
}
|
|
85
|
+
/** The nearest folder at or above `dir` that holds `.git`, as spelled; undefined outside a repository. */
|
|
86
|
+
function* findGitRepoRoot(dir) {
|
|
87
|
+
let currentDir = dir;
|
|
88
|
+
while (!(yield* exists(join(currentDir, ".git")))) {
|
|
89
|
+
const parentDir = dirname(currentDir);
|
|
90
|
+
if (parentDir === currentDir)
|
|
91
|
+
return undefined;
|
|
92
|
+
currentDir = parentDir;
|
|
93
|
+
}
|
|
94
|
+
return currentDir;
|
|
95
|
+
}
|
|
96
|
+
function homeDirectory() {
|
|
97
|
+
return canonicalizePath(resolvePath(process.env.HOME || homedir()));
|
|
98
|
+
}
|
|
99
|
+
function* agentsSkillDirs(cwd) {
|
|
100
|
+
const homeDir = homeDirectory();
|
|
101
|
+
const startDir = resolvePath(cwd);
|
|
102
|
+
const gitRepoRoot = yield* findGitRepoRoot(startDir);
|
|
103
|
+
const dirs = [];
|
|
104
|
+
let currentDir = startDir;
|
|
105
|
+
while (!isHomeOrAboveDir(canonicalizePath(currentDir), homeDir)) {
|
|
106
|
+
dirs.push(join(currentDir, ".agents", "skills"));
|
|
107
|
+
if (currentDir === gitRepoRoot)
|
|
108
|
+
break;
|
|
109
|
+
const parentDir = dirname(currentDir);
|
|
110
|
+
if (parentDir === currentDir)
|
|
111
|
+
break;
|
|
112
|
+
currentDir = parentDir;
|
|
113
|
+
}
|
|
114
|
+
return dirs;
|
|
115
|
+
}
|
|
116
|
+
function* trustRequiringResources(cwd) {
|
|
117
|
+
const homeDir = homeDirectory();
|
|
118
|
+
const currentDir = canonicalizePath(resolvePath(cwd));
|
|
119
|
+
if (!isHomeOrAboveDir(currentDir, homeDir)) {
|
|
120
|
+
for (const configDir of [join(currentDir, CONFIG_DIR_NAME), join(currentDir, LEGACY_PROJECT_CONFIG_DIR_NAME)]) {
|
|
121
|
+
for (const entry of TRUST_REQUIRING_PROJECT_CONFIG_RESOURCES) {
|
|
122
|
+
if (yield* exists(join(configDir, entry)))
|
|
123
|
+
return true;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
if (yield* projectCodemodeNamesExecutable(join(currentDir, CONFIG_DIR_NAME)))
|
|
127
|
+
return true;
|
|
128
|
+
}
|
|
129
|
+
for (const dir of yield* agentsSkillDirs(cwd)) {
|
|
130
|
+
if (yield* exists(dir))
|
|
131
|
+
return true;
|
|
132
|
+
}
|
|
133
|
+
return false;
|
|
134
|
+
}
|
|
135
|
+
function answerSync(probe) {
|
|
136
|
+
if (probe.kind === "exists")
|
|
137
|
+
return existsSync(probe.path);
|
|
138
|
+
try {
|
|
139
|
+
return readFileSync(probe.path, "utf8");
|
|
140
|
+
}
|
|
141
|
+
catch {
|
|
142
|
+
return undefined;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
async function answerAsync(probe) {
|
|
146
|
+
if (probe.kind === "exists") {
|
|
147
|
+
return access(probe.path).then(() => true, () => false);
|
|
148
|
+
}
|
|
149
|
+
return readFile(probe.path, "utf8").catch(() => undefined);
|
|
150
|
+
}
|
|
151
|
+
function runSync(walk) {
|
|
152
|
+
let step = walk.next();
|
|
153
|
+
while (!step.done)
|
|
154
|
+
step = walk.next(answerSync(step.value));
|
|
155
|
+
return step.value;
|
|
156
|
+
}
|
|
157
|
+
async function runAsync(walk) {
|
|
158
|
+
let step = walk.next();
|
|
159
|
+
while (!step.done)
|
|
160
|
+
step = walk.next(await answerAsync(step.value));
|
|
161
|
+
return step.value;
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* The project `.agents/skills` directories for `cwd`, nearest first: one per folder from cwd up to
|
|
165
|
+
* the git root (or the filesystem root), stopping below the user's home. Home and every folder
|
|
166
|
+
* above it are never a project; `~/.agents/skills` is the user's own global skills. The ONE walk
|
|
167
|
+
* both the trust check and the loader use, over the same spelling and the same git root (#3420
|
|
168
|
+
* review): paths stay as spelled (resources are compared as strings), and each folder's real path
|
|
169
|
+
* decides whether it is home or above, so a symlink can't carry the walk past home either way.
|
|
170
|
+
*/
|
|
171
|
+
export function projectAgentsSkillDirs(cwd) {
|
|
172
|
+
return runSync(agentsSkillDirs(cwd));
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Returns true when cwd has project-local resources that must be gated by
|
|
176
|
+
* project trust: trust-requiring entries under the project config dir or the
|
|
177
|
+
* legacy cwd/.pi dir (whose resources are also discovered), or a project
|
|
178
|
+
* `.agents/skills` (`projectAgentsSkillDirs`, the same walk the loader uses).
|
|
179
|
+
* The user's home and every folder above it are never a project: their config
|
|
180
|
+
* dirs and .agents/skills are the user's own global resources (#2465).
|
|
181
|
+
*/
|
|
182
|
+
export function hasTrustRequiringProjectResources(cwd) {
|
|
183
|
+
return runSync(trustRequiringResources(cwd));
|
|
184
|
+
}
|
|
185
|
+
/** `hasTrustRequiringProjectResources` without blocking: the same walk, answered through `node:fs/promises`. */
|
|
186
|
+
export function hasTrustRequiringProjectResourcesAsync(cwd) {
|
|
187
|
+
return runAsync(trustRequiringResources(cwd));
|
|
188
|
+
}
|
|
189
|
+
//# sourceMappingURL=trust-requiring-resources.js.map
|
package/dist/index.d.ts
CHANGED
|
@@ -42,6 +42,7 @@ export { createSyntheticSourceInfo } from "./core/source-info.ts";
|
|
|
42
42
|
export { type EditDiffResult, generateDiffString, generateUnifiedPatch } from "./core/tools/edit-diff.ts";
|
|
43
43
|
export { type BashOperations, type BashSpawnContext, type BashSpawnHook, type BashToolDetails, type BashToolInput, type BashToolOptions, createBashToolDefinition, createEditToolDefinition, createFindToolDefinition, createGrepToolDefinition, createLocalBashOperations, createLsToolDefinition, createReadToolDefinition, createWriteToolDefinition, DEFAULT_MAX_BYTES, DEFAULT_MAX_LINES, type EditOperations, type EditToolDetails, type EditToolInput, type EditToolOptions, type FindOperations, type FindToolDetails, type FindToolInput, type FindToolOptions, formatSize, type GrepOperations, type GrepToolDetails, type GrepToolInput, type GrepToolOptions, type LsOperations, type LsToolDetails, type LsToolInput, type LsToolOptions, type ReadOperations, type ReadToolDetails, type ReadToolInput, type ReadToolOptions, type ToolsOptions, type TruncationOptions, type TruncationResult, truncateHead, truncateLine, truncateTail, type WriteOperations, type WriteToolInput, type WriteToolOptions, withFileMutationQueue, } from "./core/tools/index.ts";
|
|
44
44
|
export { type CompactReadClassification, classifyRead, type ReadClassifier, registerReadClassifier, } from "./core/tools/read-classifiers.ts";
|
|
45
|
+
export { registerRpcRemoteSource, type RpcRemoteHandlers, type RpcRemoteOpenOptions, type RpcRemoteSettledTurn, type RpcRemoteSource, type RpcRemoteState, type RpcRemoteSubscription, type RpcRemoteTarget, } from "./core/extensions/builtin/terminal/rpc-remote-source.ts";
|
|
45
46
|
export { hasTrustRequiringProjectResources, type ProjectTrustDecision, ProjectTrustStore, type ProjectTrustStoreEntry, type ProjectTrustUpdate, } from "./core/trust-manager.ts";
|
|
46
47
|
export { UnknownCommandError, type UnknownCommandReason } from "./core/unknown-command.ts";
|
|
47
48
|
export { type ModelRoute, type ModelRouteReason, type ModelRouteRequest, VIRTUAL_MODEL_STATE_ENTRY, type VirtualModelDefinition, type VirtualModelStateData, } from "./core/virtual-models.ts";
|
package/dist/index.js
CHANGED
|
@@ -50,6 +50,7 @@ export { generateDiffString, generateUnifiedPatch } from "./core/tools/edit-diff
|
|
|
50
50
|
// Tools
|
|
51
51
|
export { createBashToolDefinition, createEditToolDefinition, createFindToolDefinition, createGrepToolDefinition, createLocalBashOperations, createLsToolDefinition, createReadToolDefinition, createWriteToolDefinition, DEFAULT_MAX_BYTES, DEFAULT_MAX_LINES, formatSize, truncateHead, truncateLine, truncateTail, withFileMutationQueue, } from "./core/tools/index.js";
|
|
52
52
|
export { classifyRead, registerReadClassifier, } from "./core/tools/read-classifiers.js";
|
|
53
|
+
export { registerRpcRemoteSource, } from "./core/extensions/builtin/terminal/rpc-remote-source.js";
|
|
53
54
|
export { hasTrustRequiringProjectResources, ProjectTrustStore, } from "./core/trust-manager.js";
|
|
54
55
|
export { UnknownCommandError } from "./core/unknown-command.js";
|
|
55
56
|
export { VIRTUAL_MODEL_STATE_ENTRY, } from "./core/virtual-models.js";
|