@hraness/ghostget 0.17.5 → 0.18.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.
Files changed (56) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/README.md +16 -9
  3. package/dist/apple-photos-client.js +1 -1
  4. package/dist/beeper-client.js +1 -1
  5. package/dist/{index-pf74yjs2.js → index-9wca02er.js} +1 -1
  6. package/docs/control-panel.md +147 -0
  7. package/package.json +47 -7
  8. package/skills/ghostget/SKILL.md +3 -1
  9. package/skills/ghostget/references/control-panel.md +43 -0
  10. package/skills/ghostget/references/install.md +5 -5
  11. package/skills/ghostget/references/linkedin-adapter.md +17 -3
  12. package/skills/ghostget/references/platform-patterns.md +1 -1
  13. package/src/assets/adapters/linkedin/wrench-web-adapter.json +1 -1
  14. package/src/auth.ts +35 -1
  15. package/src/beeper-client-types.ts +1 -1
  16. package/src/cli.ts +18 -0
  17. package/src/confirmed-write-platform.ts +16 -1
  18. package/src/control/account-revision.ts +16 -0
  19. package/src/control/activity.ts +104 -0
  20. package/src/control/approval-broker.ts +59 -0
  21. package/src/control/approval-client.ts +49 -0
  22. package/src/control/bundled-interfaces.ts +20 -0
  23. package/src/control/cli.ts +20 -0
  24. package/src/control/connections.ts +87 -0
  25. package/src/control/credential-helper.ts +152 -0
  26. package/src/control/helper.ts +79 -0
  27. package/src/control/interface-cli.ts +22 -0
  28. package/src/control/interface-json.ts +94 -0
  29. package/src/control/interface-schema.ts +120 -0
  30. package/src/control/interfaces.ts +438 -0
  31. package/src/control/protocol.ts +182 -0
  32. package/src/control/service.ts +104 -0
  33. package/src/control/validation.ts +103 -0
  34. package/src/control/vault.ts +105 -0
  35. package/src/control/web-gateway.ts +62 -0
  36. package/src/control/web-policy.ts +56 -0
  37. package/src/ghostget.ts +2 -0
  38. package/src/messaging-runtime.ts +3 -0
  39. package/src/oauth-google.ts +11 -5
  40. package/src/omni-runtime.ts +18 -3
  41. package/src/operation-permission-store.ts +92 -0
  42. package/src/operation-permission.ts +308 -0
  43. package/src/pinned-https.ts +5 -0
  44. package/src/provider-http.ts +11 -3
  45. package/src/provider-plugin-contract-identity.ts +2 -2
  46. package/src/provider-plugin-import-analysis.ts +52 -0
  47. package/src/provider-plugin-module-analysis.ts +21 -1
  48. package/src/provider-plugin-registry.ts +4 -8
  49. package/src/provider-plugin.ts +4 -8
  50. package/src/providers/linkedin-web-contact.ts +237 -21
  51. package/src/read-client.ts +12 -2
  52. package/src/runtime.ts +81 -9
  53. package/src/state-helper.ts +2 -0
  54. package/src/storage.ts +71 -1
  55. package/src/usage.ts +6 -0
  56. package/src/version.ts +1 -1
package/src/storage.ts CHANGED
@@ -101,11 +101,13 @@ const stateDirectoryNames = [
101
101
  "auth",
102
102
  "browser-snapshots",
103
103
  "captures",
104
+ "control",
104
105
  "derivations",
105
106
  "idempotency",
106
107
  "linked-device-stores",
107
108
  "messaging",
108
109
  "omni-read-projections",
110
+ "operation-permissions",
109
111
  "plan-assets",
110
112
  "plans",
111
113
  "provider-plugin-state",
@@ -1158,7 +1160,7 @@ function validateStateRoot(root: string): StateRootRecord {
1158
1160
  return { claimed, creationAnchor: null, identity: { device: stats.dev.toString(), inode: stats.ino.toString() } };
1159
1161
  }
1160
1162
 
1161
- export function ghostgetStateHome(environment: Readonly<Record<string, string | undefined>> = process.env): string {
1163
+ function selectStateHome(environment: Readonly<Record<string, string | undefined>>): string {
1162
1164
  const configuredRoots = [
1163
1165
  ["GHOSTGET_STATE_HOME", environment.GHOSTGET_STATE_HOME],
1164
1166
  ["WRENCH_STATE_HOME", environment.WRENCH_STATE_HOME],
@@ -1215,6 +1217,74 @@ export function ghostgetStateHome(environment: Readonly<Record<string, string |
1215
1217
  if (forbiddenRoots.has(root) || isWithinPath(ghostgetSourcePackageRoot, root)) {
1216
1218
  throw new Error(`GHOSTGET_STATE_HOME must be a dedicated child directory, not a filesystem, home, temporary, repository, or shared data root: ${root}`);
1217
1219
  }
1220
+ return root;
1221
+ }
1222
+
1223
+ /**
1224
+ * Inspect only whether an optional policy may exist, without adopting a state
1225
+ * root. CLI validation and local file inputs must not claim or register state.
1226
+ * A present file still requires the ordinary inode-bound private state reader.
1227
+ */
1228
+ export function privateStateFilesMayExist(
1229
+ collection: typeof stateDirectoryNames[number],
1230
+ fileNames: readonly string[],
1231
+ environment: Readonly<Record<string, string | undefined>> = process.env,
1232
+ ): boolean {
1233
+ if (!stateDirectoryNames.includes(collection) || fileNames.length < 1 || fileNames.length > 8
1234
+ || fileNames.some(name => !/^[a-zA-Z0-9][a-zA-Z0-9._-]{0,127}$/u.test(name))) {
1235
+ throw new Error("optional private state file selection is invalid");
1236
+ }
1237
+ const root = selectStateHome(environment);
1238
+ const inspect = (path: string): BigIntStats | null => {
1239
+ try { return lstatSync(path, { bigint: true }); }
1240
+ catch (error) { if (hasCode(error, "ENOENT")) return null; throw error; }
1241
+ };
1242
+ const inspectDirectory = (path: string): BigIntStats | null => {
1243
+ const stats = inspect(path);
1244
+ if (stats !== null && (!stats.isDirectory() || stats.isSymbolicLink()
1245
+ || !ownedByCurrentUser(stats) || (stats.mode & 0o777n) !== 0o700n)) {
1246
+ throw new Error("optional private state directory is unsafe");
1247
+ }
1248
+ return stats;
1249
+ };
1250
+ const assertUnchanged = (path: string, before: BigIntStats | null): void => {
1251
+ const after = inspect(path);
1252
+ if (before === null ? after !== null : after === null
1253
+ || before.dev !== after.dev || before.ino !== after.ino
1254
+ || before.mode !== after.mode || before.uid !== after.uid
1255
+ || before.ctimeNs !== after.ctimeNs || before.mtimeNs !== after.mtimeNs) {
1256
+ throw new Error("optional private state changed during inspection");
1257
+ }
1258
+ };
1259
+ if (knownStateRoots.has(root)) assertStateRootIdentity(root);
1260
+ const rootBefore = inspectDirectory(root);
1261
+ // A missing root is observed from its existing, owned creation anchor; no
1262
+ // directory, mode, marker, or process-local state registration is changed.
1263
+ const anchor = rootBefore === null ? findCreationAnchor(root).path : null;
1264
+ const anchorBefore = anchor === null ? null : inspect(anchor);
1265
+ const markerPath = join(root, stateMarkerName);
1266
+ const markerBefore = inspect(markerPath);
1267
+ if (markerBefore !== null) readStateMarker(markerPath);
1268
+ else if (rootBefore !== null && !hasGhostgetPathIdentity(root)) {
1269
+ throw new Error("optional private state root does not identify dedicated Ghostget state");
1270
+ }
1271
+ const directory = join(root, collection);
1272
+ const directoryBefore = inspectDirectory(directory);
1273
+ let present = false;
1274
+ for (const name of fileNames) {
1275
+ if (inspect(join(directory, name)) !== null) present = true;
1276
+ }
1277
+ if (selectStateHome(environment) !== root) throw new Error("optional private state root selection changed");
1278
+ assertUnchanged(directory, directoryBefore);
1279
+ assertUnchanged(markerPath, markerBefore);
1280
+ assertUnchanged(root, rootBefore);
1281
+ if (anchor !== null) assertUnchanged(anchor, anchorBefore);
1282
+ if (knownStateRoots.has(root)) assertStateRootIdentity(root);
1283
+ return present;
1284
+ }
1285
+
1286
+ export function ghostgetStateHome(environment: Readonly<Record<string, string | undefined>> = process.env): string {
1287
+ const root = selectStateHome(environment);
1218
1288
  const inspected = validateStateRoot(root);
1219
1289
  const remembered = knownStateRoots.get(root);
1220
1290
  if (remembered !== undefined) {
package/src/usage.ts CHANGED
@@ -30,6 +30,12 @@ export const ghostgetUsage = `Usage:
30
30
  ghostget transcriber setup --engine whisper-cpp --model <file> [media-options]
31
31
  ghostget doctor [--json] Check capture, media, auth, and action dependencies
32
32
  ghostget capabilities [adapter] [--json] List installed semantic capabilities
33
+ ghostget web request <https-url> [--method GET|HEAD]
34
+ Retrieve public text through native web rules and approvals
35
+ ghostget interface list List user and imported OpenAPI drafts
36
+ ghostget interface export [adapter] Export installed semantic interfaces as OpenAPI
37
+ ghostget interface import <openapi.json> [--expected-digest <sha256>]
38
+ Save an inert draft; review and activate it in the native app
33
39
  ghostget imessage transport install --binary <absolute-reviewed-imsg-file> [--json]
34
40
  Install only the current reviewed iMessage transport bytes
35
41
  ghostget plugin list [--json] List trusted source and installed portable plugins
package/src/version.ts CHANGED
@@ -1,2 +1,2 @@
1
1
  /** Canonical immutable Ghostget package release identity. */
2
- export const GHOSTGET_VERSION = "0.17.5" as const;
2
+ export const GHOSTGET_VERSION = "0.18.0" as const;