@codyswann/lisa 2.338.5 → 2.339.0
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/dist/core/upstream-evidence-manifest.d.ts.map +1 -1
- package/dist/core/upstream-evidence-manifest.js +2 -1
- package/dist/core/upstream-evidence-manifest.js.map +1 -1
- package/package.json +1 -1
- package/plugins/lisa/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa/.codex-plugin/skills/lisa-secrets-access/scripts/surfaces.mjs +61 -3
- package/plugins/lisa/skills/lisa-secrets-access/scripts/surfaces.mjs +61 -3
- package/plugins/lisa-agy/plugin.json +1 -1
- package/plugins/lisa-agy/skills/lisa-secrets-access/scripts/surfaces.mjs +61 -3
- package/plugins/lisa-cdk/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cdk/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-cdk-agy/plugin.json +1 -1
- package/plugins/lisa-cdk-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cdk-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-copilot/skills/lisa-secrets-access/scripts/surfaces.mjs +61 -3
- package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cursor/skills/lisa-secrets-access/scripts/surfaces.mjs +61 -3
- package/plugins/lisa-expo/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-expo/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-expo-agy/plugin.json +1 -1
- package/plugins/lisa-expo-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-expo-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric-agy/plugin.json +1 -1
- package/plugins/lisa-harper-fabric-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs-agy/plugin.json +1 -1
- package/plugins/lisa-nestjs-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw-agy/plugin.json +1 -1
- package/plugins/lisa-openclaw-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser-agy/plugin.json +1 -1
- package/plugins/lisa-phaser-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-rails/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-rails/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-rails-agy/plugin.json +1 -1
- package/plugins/lisa-rails-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-rails-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript-agy/plugin.json +1 -1
- package/plugins/lisa-typescript-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki-agy/plugin.json +1 -1
- package/plugins/lisa-wiki-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/src/base/skills/lisa-secrets-access/scripts/surfaces.mjs +61 -3
package/package.json
CHANGED
|
@@ -118,7 +118,7 @@
|
|
|
118
118
|
}
|
|
119
119
|
},
|
|
120
120
|
"name": "@codyswann/lisa",
|
|
121
|
-
"version": "2.
|
|
121
|
+
"version": "2.339.0",
|
|
122
122
|
"description": "Claude Code governance framework that applies guardrails, guidance, and automated enforcement to projects",
|
|
123
123
|
"main": "dist/index.js",
|
|
124
124
|
"exports": {
|
|
@@ -81,6 +81,28 @@ export const SURFACES = {
|
|
|
81
81
|
// recoverable; an absent one means the environment does not work.
|
|
82
82
|
materializeAt: "both",
|
|
83
83
|
},
|
|
84
|
+
// A container an operator builds and runs themselves — locally, or anywhere
|
|
85
|
+
// Lisa is not the one provisioning the host.
|
|
86
|
+
//
|
|
87
|
+
// It exists because `local` was standing in for it, and `local` is
|
|
88
|
+
// `materialized: false`. That default is right for a human at a keyboard: the
|
|
89
|
+
// provider CLI is authenticated, secrets resolve live, and writing them to
|
|
90
|
+
// disk would be a second copy to keep honest. A container has no keychain and
|
|
91
|
+
// dies with its filesystem, so the same default leaves it with the CLIs
|
|
92
|
+
// installed and nothing to authenticate them.
|
|
93
|
+
//
|
|
94
|
+
// The workaround was to claim `claude-web`, which materializes correctly and
|
|
95
|
+
// is a lie — it made a local container indistinguishable from a cloud session
|
|
96
|
+
// in every diagnostic and log.
|
|
97
|
+
//
|
|
98
|
+
// `setup` rather than `both`: a container has no session-start hook to run,
|
|
99
|
+
// and it is started fresh rather than resumed from a vendor's cache, so the
|
|
100
|
+
// start of the container IS the refresh.
|
|
101
|
+
container: {
|
|
102
|
+
materialized: true,
|
|
103
|
+
mayWriteValues: true,
|
|
104
|
+
materializeAt: "setup",
|
|
105
|
+
},
|
|
84
106
|
};
|
|
85
107
|
|
|
86
108
|
/** Config defaults when `.lisa.config.json` carries no `secrets` block. */
|
|
@@ -187,17 +209,49 @@ export function readConfig(cwd = process.cwd(), env = process.env) {
|
|
|
187
209
|
throw new Error(`.lisa.config.json is not readable: ${err.message}`);
|
|
188
210
|
}
|
|
189
211
|
if (!cfg) return withSurface(DEFAULTS);
|
|
212
|
+
const provider = cfg.provider ?? DEFAULTS.provider;
|
|
213
|
+
const namespace = assertNamespace(cfg.namespace ?? DEFAULTS.namespace);
|
|
190
214
|
return withSurface({
|
|
191
|
-
provider
|
|
192
|
-
bootstrap:
|
|
215
|
+
provider,
|
|
216
|
+
bootstrap: resolveBootstrap(cfg.bootstrap, provider, namespace),
|
|
193
217
|
require: cfg.require ?? null,
|
|
194
218
|
rotating: cfg.rotating ?? [],
|
|
195
|
-
namespace
|
|
219
|
+
namespace,
|
|
196
220
|
narrow: { ...DEFAULTS.narrow, ...(cfg.narrow ?? {}) },
|
|
197
221
|
surface: cfg.surface ?? null,
|
|
198
222
|
});
|
|
199
223
|
}
|
|
200
224
|
|
|
225
|
+
/**
|
|
226
|
+
* Fill in the bootstrap block a project did not spell out.
|
|
227
|
+
*
|
|
228
|
+
* Both defaults exist because a token stored on the machine was going unread.
|
|
229
|
+
*
|
|
230
|
+
* **The key** follows the same convention the repo-less path uses,
|
|
231
|
+
* `<PROVIDER_VAR>_<namespace>`, so a machine provisioned once serves every
|
|
232
|
+
* project of that tenant without each restating the name. A project that sets
|
|
233
|
+
* one keeps it: a name that is not derivable is a legitimate choice, and
|
|
234
|
+
* overriding it would point sessions at a variable nobody set.
|
|
235
|
+
*
|
|
236
|
+
* **The sources** gain `keychain` because `["env"]` alone meant a token in the
|
|
237
|
+
* OS keychain was never consulted — so the machine setup appeared to work and
|
|
238
|
+
* every project still failed until someone hand-edited its config. Env stays
|
|
239
|
+
* first, so a CI runner injecting the bootstrap never reaches for a local store.
|
|
240
|
+
* On a platform with no keychain the extra source reads as empty and costs
|
|
241
|
+
* nothing.
|
|
242
|
+
* @param {object|undefined} bootstrap The project's own block, if any.
|
|
243
|
+
* @param {string} provider Resolved provider name.
|
|
244
|
+
* @param {string} namespace Resolved namespace.
|
|
245
|
+
* @returns {{sources: string[], key: string|null}} The resolved block.
|
|
246
|
+
*/
|
|
247
|
+
function resolveBootstrap(bootstrap, provider, namespace) {
|
|
248
|
+
const given = bootstrap ?? {};
|
|
249
|
+
return {
|
|
250
|
+
sources: given.sources ?? ["env", "keychain"],
|
|
251
|
+
key: given.key ?? bootstrapKeyFor(provider, namespace),
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
|
|
201
255
|
/**
|
|
202
256
|
* Build a configuration from the environment, for sessions with no checkout.
|
|
203
257
|
*
|
|
@@ -243,6 +297,10 @@ function fromEnvironment(env) {
|
|
|
243
297
|
// name. Hardcoding it told a Doppler tenant to set BWS_ACCESS_TOKEN_<ns>,
|
|
244
298
|
// which its CLI has never heard of — on the one surface that has no
|
|
245
299
|
// config file to override the guess.
|
|
300
|
+
// Same two defaults as a project config gets, for the same reasons —
|
|
301
|
+
// see `resolveBootstrap`. Stated here too because this path never reads
|
|
302
|
+
// a file, so it cannot inherit them.
|
|
303
|
+
sources: ["env", "keychain"],
|
|
246
304
|
key:
|
|
247
305
|
env.LISA_BOOTSTRAP_KEY ??
|
|
248
306
|
env.LISA_SECRETS_BOOTSTRAP_KEY ??
|
|
@@ -81,6 +81,28 @@ export const SURFACES = {
|
|
|
81
81
|
// recoverable; an absent one means the environment does not work.
|
|
82
82
|
materializeAt: "both",
|
|
83
83
|
},
|
|
84
|
+
// A container an operator builds and runs themselves — locally, or anywhere
|
|
85
|
+
// Lisa is not the one provisioning the host.
|
|
86
|
+
//
|
|
87
|
+
// It exists because `local` was standing in for it, and `local` is
|
|
88
|
+
// `materialized: false`. That default is right for a human at a keyboard: the
|
|
89
|
+
// provider CLI is authenticated, secrets resolve live, and writing them to
|
|
90
|
+
// disk would be a second copy to keep honest. A container has no keychain and
|
|
91
|
+
// dies with its filesystem, so the same default leaves it with the CLIs
|
|
92
|
+
// installed and nothing to authenticate them.
|
|
93
|
+
//
|
|
94
|
+
// The workaround was to claim `claude-web`, which materializes correctly and
|
|
95
|
+
// is a lie — it made a local container indistinguishable from a cloud session
|
|
96
|
+
// in every diagnostic and log.
|
|
97
|
+
//
|
|
98
|
+
// `setup` rather than `both`: a container has no session-start hook to run,
|
|
99
|
+
// and it is started fresh rather than resumed from a vendor's cache, so the
|
|
100
|
+
// start of the container IS the refresh.
|
|
101
|
+
container: {
|
|
102
|
+
materialized: true,
|
|
103
|
+
mayWriteValues: true,
|
|
104
|
+
materializeAt: "setup",
|
|
105
|
+
},
|
|
84
106
|
};
|
|
85
107
|
|
|
86
108
|
/** Config defaults when `.lisa.config.json` carries no `secrets` block. */
|
|
@@ -187,17 +209,49 @@ export function readConfig(cwd = process.cwd(), env = process.env) {
|
|
|
187
209
|
throw new Error(`.lisa.config.json is not readable: ${err.message}`);
|
|
188
210
|
}
|
|
189
211
|
if (!cfg) return withSurface(DEFAULTS);
|
|
212
|
+
const provider = cfg.provider ?? DEFAULTS.provider;
|
|
213
|
+
const namespace = assertNamespace(cfg.namespace ?? DEFAULTS.namespace);
|
|
190
214
|
return withSurface({
|
|
191
|
-
provider
|
|
192
|
-
bootstrap:
|
|
215
|
+
provider,
|
|
216
|
+
bootstrap: resolveBootstrap(cfg.bootstrap, provider, namespace),
|
|
193
217
|
require: cfg.require ?? null,
|
|
194
218
|
rotating: cfg.rotating ?? [],
|
|
195
|
-
namespace
|
|
219
|
+
namespace,
|
|
196
220
|
narrow: { ...DEFAULTS.narrow, ...(cfg.narrow ?? {}) },
|
|
197
221
|
surface: cfg.surface ?? null,
|
|
198
222
|
});
|
|
199
223
|
}
|
|
200
224
|
|
|
225
|
+
/**
|
|
226
|
+
* Fill in the bootstrap block a project did not spell out.
|
|
227
|
+
*
|
|
228
|
+
* Both defaults exist because a token stored on the machine was going unread.
|
|
229
|
+
*
|
|
230
|
+
* **The key** follows the same convention the repo-less path uses,
|
|
231
|
+
* `<PROVIDER_VAR>_<namespace>`, so a machine provisioned once serves every
|
|
232
|
+
* project of that tenant without each restating the name. A project that sets
|
|
233
|
+
* one keeps it: a name that is not derivable is a legitimate choice, and
|
|
234
|
+
* overriding it would point sessions at a variable nobody set.
|
|
235
|
+
*
|
|
236
|
+
* **The sources** gain `keychain` because `["env"]` alone meant a token in the
|
|
237
|
+
* OS keychain was never consulted — so the machine setup appeared to work and
|
|
238
|
+
* every project still failed until someone hand-edited its config. Env stays
|
|
239
|
+
* first, so a CI runner injecting the bootstrap never reaches for a local store.
|
|
240
|
+
* On a platform with no keychain the extra source reads as empty and costs
|
|
241
|
+
* nothing.
|
|
242
|
+
* @param {object|undefined} bootstrap The project's own block, if any.
|
|
243
|
+
* @param {string} provider Resolved provider name.
|
|
244
|
+
* @param {string} namespace Resolved namespace.
|
|
245
|
+
* @returns {{sources: string[], key: string|null}} The resolved block.
|
|
246
|
+
*/
|
|
247
|
+
function resolveBootstrap(bootstrap, provider, namespace) {
|
|
248
|
+
const given = bootstrap ?? {};
|
|
249
|
+
return {
|
|
250
|
+
sources: given.sources ?? ["env", "keychain"],
|
|
251
|
+
key: given.key ?? bootstrapKeyFor(provider, namespace),
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
|
|
201
255
|
/**
|
|
202
256
|
* Build a configuration from the environment, for sessions with no checkout.
|
|
203
257
|
*
|
|
@@ -243,6 +297,10 @@ function fromEnvironment(env) {
|
|
|
243
297
|
// name. Hardcoding it told a Doppler tenant to set BWS_ACCESS_TOKEN_<ns>,
|
|
244
298
|
// which its CLI has never heard of — on the one surface that has no
|
|
245
299
|
// config file to override the guess.
|
|
300
|
+
// Same two defaults as a project config gets, for the same reasons —
|
|
301
|
+
// see `resolveBootstrap`. Stated here too because this path never reads
|
|
302
|
+
// a file, so it cannot inherit them.
|
|
303
|
+
sources: ["env", "keychain"],
|
|
246
304
|
key:
|
|
247
305
|
env.LISA_BOOTSTRAP_KEY ??
|
|
248
306
|
env.LISA_SECRETS_BOOTSTRAP_KEY ??
|
|
@@ -81,6 +81,28 @@ export const SURFACES = {
|
|
|
81
81
|
// recoverable; an absent one means the environment does not work.
|
|
82
82
|
materializeAt: "both",
|
|
83
83
|
},
|
|
84
|
+
// A container an operator builds and runs themselves — locally, or anywhere
|
|
85
|
+
// Lisa is not the one provisioning the host.
|
|
86
|
+
//
|
|
87
|
+
// It exists because `local` was standing in for it, and `local` is
|
|
88
|
+
// `materialized: false`. That default is right for a human at a keyboard: the
|
|
89
|
+
// provider CLI is authenticated, secrets resolve live, and writing them to
|
|
90
|
+
// disk would be a second copy to keep honest. A container has no keychain and
|
|
91
|
+
// dies with its filesystem, so the same default leaves it with the CLIs
|
|
92
|
+
// installed and nothing to authenticate them.
|
|
93
|
+
//
|
|
94
|
+
// The workaround was to claim `claude-web`, which materializes correctly and
|
|
95
|
+
// is a lie — it made a local container indistinguishable from a cloud session
|
|
96
|
+
// in every diagnostic and log.
|
|
97
|
+
//
|
|
98
|
+
// `setup` rather than `both`: a container has no session-start hook to run,
|
|
99
|
+
// and it is started fresh rather than resumed from a vendor's cache, so the
|
|
100
|
+
// start of the container IS the refresh.
|
|
101
|
+
container: {
|
|
102
|
+
materialized: true,
|
|
103
|
+
mayWriteValues: true,
|
|
104
|
+
materializeAt: "setup",
|
|
105
|
+
},
|
|
84
106
|
};
|
|
85
107
|
|
|
86
108
|
/** Config defaults when `.lisa.config.json` carries no `secrets` block. */
|
|
@@ -187,17 +209,49 @@ export function readConfig(cwd = process.cwd(), env = process.env) {
|
|
|
187
209
|
throw new Error(`.lisa.config.json is not readable: ${err.message}`);
|
|
188
210
|
}
|
|
189
211
|
if (!cfg) return withSurface(DEFAULTS);
|
|
212
|
+
const provider = cfg.provider ?? DEFAULTS.provider;
|
|
213
|
+
const namespace = assertNamespace(cfg.namespace ?? DEFAULTS.namespace);
|
|
190
214
|
return withSurface({
|
|
191
|
-
provider
|
|
192
|
-
bootstrap:
|
|
215
|
+
provider,
|
|
216
|
+
bootstrap: resolveBootstrap(cfg.bootstrap, provider, namespace),
|
|
193
217
|
require: cfg.require ?? null,
|
|
194
218
|
rotating: cfg.rotating ?? [],
|
|
195
|
-
namespace
|
|
219
|
+
namespace,
|
|
196
220
|
narrow: { ...DEFAULTS.narrow, ...(cfg.narrow ?? {}) },
|
|
197
221
|
surface: cfg.surface ?? null,
|
|
198
222
|
});
|
|
199
223
|
}
|
|
200
224
|
|
|
225
|
+
/**
|
|
226
|
+
* Fill in the bootstrap block a project did not spell out.
|
|
227
|
+
*
|
|
228
|
+
* Both defaults exist because a token stored on the machine was going unread.
|
|
229
|
+
*
|
|
230
|
+
* **The key** follows the same convention the repo-less path uses,
|
|
231
|
+
* `<PROVIDER_VAR>_<namespace>`, so a machine provisioned once serves every
|
|
232
|
+
* project of that tenant without each restating the name. A project that sets
|
|
233
|
+
* one keeps it: a name that is not derivable is a legitimate choice, and
|
|
234
|
+
* overriding it would point sessions at a variable nobody set.
|
|
235
|
+
*
|
|
236
|
+
* **The sources** gain `keychain` because `["env"]` alone meant a token in the
|
|
237
|
+
* OS keychain was never consulted — so the machine setup appeared to work and
|
|
238
|
+
* every project still failed until someone hand-edited its config. Env stays
|
|
239
|
+
* first, so a CI runner injecting the bootstrap never reaches for a local store.
|
|
240
|
+
* On a platform with no keychain the extra source reads as empty and costs
|
|
241
|
+
* nothing.
|
|
242
|
+
* @param {object|undefined} bootstrap The project's own block, if any.
|
|
243
|
+
* @param {string} provider Resolved provider name.
|
|
244
|
+
* @param {string} namespace Resolved namespace.
|
|
245
|
+
* @returns {{sources: string[], key: string|null}} The resolved block.
|
|
246
|
+
*/
|
|
247
|
+
function resolveBootstrap(bootstrap, provider, namespace) {
|
|
248
|
+
const given = bootstrap ?? {};
|
|
249
|
+
return {
|
|
250
|
+
sources: given.sources ?? ["env", "keychain"],
|
|
251
|
+
key: given.key ?? bootstrapKeyFor(provider, namespace),
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
|
|
201
255
|
/**
|
|
202
256
|
* Build a configuration from the environment, for sessions with no checkout.
|
|
203
257
|
*
|
|
@@ -243,6 +297,10 @@ function fromEnvironment(env) {
|
|
|
243
297
|
// name. Hardcoding it told a Doppler tenant to set BWS_ACCESS_TOKEN_<ns>,
|
|
244
298
|
// which its CLI has never heard of — on the one surface that has no
|
|
245
299
|
// config file to override the guess.
|
|
300
|
+
// Same two defaults as a project config gets, for the same reasons —
|
|
301
|
+
// see `resolveBootstrap`. Stated here too because this path never reads
|
|
302
|
+
// a file, so it cannot inherit them.
|
|
303
|
+
sources: ["env", "keychain"],
|
|
246
304
|
key:
|
|
247
305
|
env.LISA_BOOTSTRAP_KEY ??
|
|
248
306
|
env.LISA_SECRETS_BOOTSTRAP_KEY ??
|
|
@@ -81,6 +81,28 @@ export const SURFACES = {
|
|
|
81
81
|
// recoverable; an absent one means the environment does not work.
|
|
82
82
|
materializeAt: "both",
|
|
83
83
|
},
|
|
84
|
+
// A container an operator builds and runs themselves — locally, or anywhere
|
|
85
|
+
// Lisa is not the one provisioning the host.
|
|
86
|
+
//
|
|
87
|
+
// It exists because `local` was standing in for it, and `local` is
|
|
88
|
+
// `materialized: false`. That default is right for a human at a keyboard: the
|
|
89
|
+
// provider CLI is authenticated, secrets resolve live, and writing them to
|
|
90
|
+
// disk would be a second copy to keep honest. A container has no keychain and
|
|
91
|
+
// dies with its filesystem, so the same default leaves it with the CLIs
|
|
92
|
+
// installed and nothing to authenticate them.
|
|
93
|
+
//
|
|
94
|
+
// The workaround was to claim `claude-web`, which materializes correctly and
|
|
95
|
+
// is a lie — it made a local container indistinguishable from a cloud session
|
|
96
|
+
// in every diagnostic and log.
|
|
97
|
+
//
|
|
98
|
+
// `setup` rather than `both`: a container has no session-start hook to run,
|
|
99
|
+
// and it is started fresh rather than resumed from a vendor's cache, so the
|
|
100
|
+
// start of the container IS the refresh.
|
|
101
|
+
container: {
|
|
102
|
+
materialized: true,
|
|
103
|
+
mayWriteValues: true,
|
|
104
|
+
materializeAt: "setup",
|
|
105
|
+
},
|
|
84
106
|
};
|
|
85
107
|
|
|
86
108
|
/** Config defaults when `.lisa.config.json` carries no `secrets` block. */
|
|
@@ -187,17 +209,49 @@ export function readConfig(cwd = process.cwd(), env = process.env) {
|
|
|
187
209
|
throw new Error(`.lisa.config.json is not readable: ${err.message}`);
|
|
188
210
|
}
|
|
189
211
|
if (!cfg) return withSurface(DEFAULTS);
|
|
212
|
+
const provider = cfg.provider ?? DEFAULTS.provider;
|
|
213
|
+
const namespace = assertNamespace(cfg.namespace ?? DEFAULTS.namespace);
|
|
190
214
|
return withSurface({
|
|
191
|
-
provider
|
|
192
|
-
bootstrap:
|
|
215
|
+
provider,
|
|
216
|
+
bootstrap: resolveBootstrap(cfg.bootstrap, provider, namespace),
|
|
193
217
|
require: cfg.require ?? null,
|
|
194
218
|
rotating: cfg.rotating ?? [],
|
|
195
|
-
namespace
|
|
219
|
+
namespace,
|
|
196
220
|
narrow: { ...DEFAULTS.narrow, ...(cfg.narrow ?? {}) },
|
|
197
221
|
surface: cfg.surface ?? null,
|
|
198
222
|
});
|
|
199
223
|
}
|
|
200
224
|
|
|
225
|
+
/**
|
|
226
|
+
* Fill in the bootstrap block a project did not spell out.
|
|
227
|
+
*
|
|
228
|
+
* Both defaults exist because a token stored on the machine was going unread.
|
|
229
|
+
*
|
|
230
|
+
* **The key** follows the same convention the repo-less path uses,
|
|
231
|
+
* `<PROVIDER_VAR>_<namespace>`, so a machine provisioned once serves every
|
|
232
|
+
* project of that tenant without each restating the name. A project that sets
|
|
233
|
+
* one keeps it: a name that is not derivable is a legitimate choice, and
|
|
234
|
+
* overriding it would point sessions at a variable nobody set.
|
|
235
|
+
*
|
|
236
|
+
* **The sources** gain `keychain` because `["env"]` alone meant a token in the
|
|
237
|
+
* OS keychain was never consulted — so the machine setup appeared to work and
|
|
238
|
+
* every project still failed until someone hand-edited its config. Env stays
|
|
239
|
+
* first, so a CI runner injecting the bootstrap never reaches for a local store.
|
|
240
|
+
* On a platform with no keychain the extra source reads as empty and costs
|
|
241
|
+
* nothing.
|
|
242
|
+
* @param {object|undefined} bootstrap The project's own block, if any.
|
|
243
|
+
* @param {string} provider Resolved provider name.
|
|
244
|
+
* @param {string} namespace Resolved namespace.
|
|
245
|
+
* @returns {{sources: string[], key: string|null}} The resolved block.
|
|
246
|
+
*/
|
|
247
|
+
function resolveBootstrap(bootstrap, provider, namespace) {
|
|
248
|
+
const given = bootstrap ?? {};
|
|
249
|
+
return {
|
|
250
|
+
sources: given.sources ?? ["env", "keychain"],
|
|
251
|
+
key: given.key ?? bootstrapKeyFor(provider, namespace),
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
|
|
201
255
|
/**
|
|
202
256
|
* Build a configuration from the environment, for sessions with no checkout.
|
|
203
257
|
*
|
|
@@ -243,6 +297,10 @@ function fromEnvironment(env) {
|
|
|
243
297
|
// name. Hardcoding it told a Doppler tenant to set BWS_ACCESS_TOKEN_<ns>,
|
|
244
298
|
// which its CLI has never heard of — on the one surface that has no
|
|
245
299
|
// config file to override the guess.
|
|
300
|
+
// Same two defaults as a project config gets, for the same reasons —
|
|
301
|
+
// see `resolveBootstrap`. Stated here too because this path never reads
|
|
302
|
+
// a file, so it cannot inherit them.
|
|
303
|
+
sources: ["env", "keychain"],
|
|
246
304
|
key:
|
|
247
305
|
env.LISA_BOOTSTRAP_KEY ??
|
|
248
306
|
env.LISA_SECRETS_BOOTSTRAP_KEY ??
|
|
@@ -81,6 +81,28 @@ export const SURFACES = {
|
|
|
81
81
|
// recoverable; an absent one means the environment does not work.
|
|
82
82
|
materializeAt: "both",
|
|
83
83
|
},
|
|
84
|
+
// A container an operator builds and runs themselves — locally, or anywhere
|
|
85
|
+
// Lisa is not the one provisioning the host.
|
|
86
|
+
//
|
|
87
|
+
// It exists because `local` was standing in for it, and `local` is
|
|
88
|
+
// `materialized: false`. That default is right for a human at a keyboard: the
|
|
89
|
+
// provider CLI is authenticated, secrets resolve live, and writing them to
|
|
90
|
+
// disk would be a second copy to keep honest. A container has no keychain and
|
|
91
|
+
// dies with its filesystem, so the same default leaves it with the CLIs
|
|
92
|
+
// installed and nothing to authenticate them.
|
|
93
|
+
//
|
|
94
|
+
// The workaround was to claim `claude-web`, which materializes correctly and
|
|
95
|
+
// is a lie — it made a local container indistinguishable from a cloud session
|
|
96
|
+
// in every diagnostic and log.
|
|
97
|
+
//
|
|
98
|
+
// `setup` rather than `both`: a container has no session-start hook to run,
|
|
99
|
+
// and it is started fresh rather than resumed from a vendor's cache, so the
|
|
100
|
+
// start of the container IS the refresh.
|
|
101
|
+
container: {
|
|
102
|
+
materialized: true,
|
|
103
|
+
mayWriteValues: true,
|
|
104
|
+
materializeAt: "setup",
|
|
105
|
+
},
|
|
84
106
|
};
|
|
85
107
|
|
|
86
108
|
/** Config defaults when `.lisa.config.json` carries no `secrets` block. */
|
|
@@ -187,17 +209,49 @@ export function readConfig(cwd = process.cwd(), env = process.env) {
|
|
|
187
209
|
throw new Error(`.lisa.config.json is not readable: ${err.message}`);
|
|
188
210
|
}
|
|
189
211
|
if (!cfg) return withSurface(DEFAULTS);
|
|
212
|
+
const provider = cfg.provider ?? DEFAULTS.provider;
|
|
213
|
+
const namespace = assertNamespace(cfg.namespace ?? DEFAULTS.namespace);
|
|
190
214
|
return withSurface({
|
|
191
|
-
provider
|
|
192
|
-
bootstrap:
|
|
215
|
+
provider,
|
|
216
|
+
bootstrap: resolveBootstrap(cfg.bootstrap, provider, namespace),
|
|
193
217
|
require: cfg.require ?? null,
|
|
194
218
|
rotating: cfg.rotating ?? [],
|
|
195
|
-
namespace
|
|
219
|
+
namespace,
|
|
196
220
|
narrow: { ...DEFAULTS.narrow, ...(cfg.narrow ?? {}) },
|
|
197
221
|
surface: cfg.surface ?? null,
|
|
198
222
|
});
|
|
199
223
|
}
|
|
200
224
|
|
|
225
|
+
/**
|
|
226
|
+
* Fill in the bootstrap block a project did not spell out.
|
|
227
|
+
*
|
|
228
|
+
* Both defaults exist because a token stored on the machine was going unread.
|
|
229
|
+
*
|
|
230
|
+
* **The key** follows the same convention the repo-less path uses,
|
|
231
|
+
* `<PROVIDER_VAR>_<namespace>`, so a machine provisioned once serves every
|
|
232
|
+
* project of that tenant without each restating the name. A project that sets
|
|
233
|
+
* one keeps it: a name that is not derivable is a legitimate choice, and
|
|
234
|
+
* overriding it would point sessions at a variable nobody set.
|
|
235
|
+
*
|
|
236
|
+
* **The sources** gain `keychain` because `["env"]` alone meant a token in the
|
|
237
|
+
* OS keychain was never consulted — so the machine setup appeared to work and
|
|
238
|
+
* every project still failed until someone hand-edited its config. Env stays
|
|
239
|
+
* first, so a CI runner injecting the bootstrap never reaches for a local store.
|
|
240
|
+
* On a platform with no keychain the extra source reads as empty and costs
|
|
241
|
+
* nothing.
|
|
242
|
+
* @param {object|undefined} bootstrap The project's own block, if any.
|
|
243
|
+
* @param {string} provider Resolved provider name.
|
|
244
|
+
* @param {string} namespace Resolved namespace.
|
|
245
|
+
* @returns {{sources: string[], key: string|null}} The resolved block.
|
|
246
|
+
*/
|
|
247
|
+
function resolveBootstrap(bootstrap, provider, namespace) {
|
|
248
|
+
const given = bootstrap ?? {};
|
|
249
|
+
return {
|
|
250
|
+
sources: given.sources ?? ["env", "keychain"],
|
|
251
|
+
key: given.key ?? bootstrapKeyFor(provider, namespace),
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
|
|
201
255
|
/**
|
|
202
256
|
* Build a configuration from the environment, for sessions with no checkout.
|
|
203
257
|
*
|
|
@@ -243,6 +297,10 @@ function fromEnvironment(env) {
|
|
|
243
297
|
// name. Hardcoding it told a Doppler tenant to set BWS_ACCESS_TOKEN_<ns>,
|
|
244
298
|
// which its CLI has never heard of — on the one surface that has no
|
|
245
299
|
// config file to override the guess.
|
|
300
|
+
// Same two defaults as a project config gets, for the same reasons —
|
|
301
|
+
// see `resolveBootstrap`. Stated here too because this path never reads
|
|
302
|
+
// a file, so it cannot inherit them.
|
|
303
|
+
sources: ["env", "keychain"],
|
|
246
304
|
key:
|
|
247
305
|
env.LISA_BOOTSTRAP_KEY ??
|
|
248
306
|
env.LISA_SECRETS_BOOTSTRAP_KEY ??
|