@flowdesk/core 0.1.12 → 0.1.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/agent-profiles.js +0 -1
- package/dist/agent-registry.d.ts +43 -0
- package/dist/agent-registry.d.ts.map +1 -0
- package/dist/agent-registry.js +309 -0
- package/dist/agent-registry.js.map +1 -0
- package/dist/audit.js +0 -1
- package/dist/authority-promotion.js +0 -1
- package/dist/bootstrap-foundation.js +0 -1
- package/dist/chat-control-authority.js +0 -1
- package/dist/chat-hook-authority-probe.js +0 -1
- package/dist/chat-routing.js +0 -1
- package/dist/command-manifest.js +0 -1
- package/dist/config-policy.js +0 -1
- package/dist/connector-gateway.js +0 -1
- package/dist/connector-profile.js +0 -1
- package/dist/controlled-conformance-doc-write.js +0 -1
- package/dist/controlled-redacted-audit-export-write.js +0 -1
- package/dist/controlled-workspace-file-write.d.ts +36 -0
- package/dist/controlled-workspace-file-write.d.ts.map +1 -0
- package/dist/controlled-workspace-file-write.js +130 -0
- package/dist/controlled-workspace-file-write.js.map +1 -0
- package/dist/core-completion-safety-contracts.js +0 -1
- package/dist/dispatch-attempt-manifest.js +0 -1
- package/dist/dispatch-idempotency.js +0 -1
- package/dist/external-auth-policy.js +0 -1
- package/dist/fake-remote-connector-adapter.js +0 -1
- package/dist/fake-runtime.js +0 -1
- package/dist/fallback-decision.js +0 -1
- package/dist/fallback-regate-plan.js +0 -1
- package/dist/fds1-schema-probe-result.js +0 -1
- package/dist/guard-boundary.js +0 -1
- package/dist/guarded-dry-run.js +0 -1
- package/dist/hook-harness.js +0 -1
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -1
- package/dist/lane-heartbeat.js +0 -1
- package/dist/lane-lifecycle-record.js +0 -1
- package/dist/lane-observability.js +0 -1
- package/dist/lane-stall-projection.d.ts +2 -1
- package/dist/lane-stall-projection.d.ts.map +1 -1
- package/dist/lane-stall-projection.js +66 -9
- package/dist/lane-stall-projection.js.map +1 -1
- package/dist/managed-dispatch-evidence-shape.js +0 -1
- package/dist/model-availability-cache.js +0 -1
- package/dist/operational-intelligence.js +0 -1
- package/dist/pending-abort.js +0 -1
- package/dist/plan.js +0 -1
- package/dist/planning-evidence-common.d.ts +18 -0
- package/dist/planning-evidence-common.d.ts.map +1 -0
- package/dist/planning-evidence-common.js +95 -0
- package/dist/planning-evidence-common.js.map +1 -0
- package/dist/pre-dispatch-audit-record.js +0 -1
- package/dist/production-approval-source.js +0 -1
- package/dist/production-enablement.js +0 -1
- package/dist/production-verification.js +0 -1
- package/dist/provider-failures.js +0 -1
- package/dist/provider-usage-collector.d.ts +1 -0
- package/dist/provider-usage-collector.d.ts.map +1 -1
- package/dist/provider-usage-collector.js +179 -29
- package/dist/provider-usage-collector.js.map +1 -1
- package/dist/redaction.js +0 -1
- package/dist/release1-contracts.js +0 -1
- package/dist/remote-write-connector-gate.js +0 -1
- package/dist/retry-plan.d.ts +20 -2
- package/dist/retry-plan.d.ts.map +1 -1
- package/dist/retry-plan.js +57 -3
- package/dist/retry-plan.js.map +1 -1
- package/dist/retry.js +0 -1
- package/dist/reviewer-lane-conformance.js +0 -1
- package/dist/runtime-lane-productization.js +0 -1
- package/dist/sanitized-auth-capture.js +0 -1
- package/dist/schema-artifacts.js +0 -1
- package/dist/schema-registry.d.ts.map +1 -1
- package/dist/schema-registry.js +5 -1
- package/dist/schema-registry.js.map +1 -1
- package/dist/session-evidence.d.ts.map +1 -1
- package/dist/session-evidence.js +44 -3
- package/dist/session-evidence.js.map +1 -1
- package/dist/state-paths.d.ts +1 -1
- package/dist/state-paths.d.ts.map +1 -1
- package/dist/state-paths.js +24 -0
- package/dist/state-paths.js.map +1 -1
- package/dist/state-store.js +0 -1
- package/dist/status.js +0 -1
- package/dist/task-agent-assignment.d.ts +30 -0
- package/dist/task-agent-assignment.d.ts.map +1 -0
- package/dist/task-agent-assignment.js +77 -0
- package/dist/task-agent-assignment.js.map +1 -0
- package/dist/task-graph.d.ts +31 -0
- package/dist/task-graph.d.ts.map +1 -0
- package/dist/task-graph.js +122 -0
- package/dist/task-graph.js.map +1 -0
- package/dist/task-model-selection.d.ts +36 -0
- package/dist/task-model-selection.d.ts.map +1 -0
- package/dist/task-model-selection.js +99 -0
- package/dist/task-model-selection.js.map +1 -0
- package/dist/task-result.d.ts +38 -1
- package/dist/task-result.d.ts.map +1 -1
- package/dist/task-result.js +148 -1
- package/dist/task-result.js.map +1 -1
- package/dist/tool-contract-fixtures.js +0 -1
- package/dist/top-tier-reviewer-lane-probe.js +0 -1
- package/dist/usage-health.js +0 -1
- package/dist/validators.d.ts.map +1 -1
- package/dist/validators.js +10 -2
- package/dist/validators.js.map +1 -1
- package/dist/workflow-authoring-result.d.ts +25 -0
- package/dist/workflow-authoring-result.d.ts.map +1 -0
- package/dist/workflow-authoring-result.js +63 -0
- package/dist/workflow-authoring-result.js.map +1 -0
- package/dist/workflow-dispatch-plan.d.ts +65 -0
- package/dist/workflow-dispatch-plan.d.ts.map +1 -0
- package/dist/workflow-dispatch-plan.js +228 -0
- package/dist/workflow-dispatch-plan.js.map +1 -0
- package/dist/workflow-synthesis.d.ts +18 -0
- package/dist/workflow-synthesis.d.ts.map +1 -0
- package/dist/workflow-synthesis.js +40 -0
- package/dist/workflow-synthesis.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"planning-evidence-common.d.ts","sourceRoot":"","sources":["../src/planning-evidence-common.ts"],"names":[],"mappings":"AAAA,OAAO,EAEN,KAAK,gBAAgB,EAKrB,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EAAE,OAAO,EAAE,KAAK,gBAAgB,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAC;AAExE,eAAO,MAAM,mCAAmC,qIAMtC,CAAC;AAiBX,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAEzF;AAED,wBAAgB,+BAA+B,CAC9C,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9B,OAAO,EAAE,WAAW,CAAC,MAAM,CAAC,EAC5B,KAAK,EAAE,MAAM,GACX,MAAM,EAAE,CAIV;AAED,wBAAgB,mBAAmB,CAClC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9B,IAAI,EAAE,SAAS,MAAM,EAAE,EACvB,KAAK,EAAE,MAAM,GACX,MAAM,EAAE,CAIV;AAED,wBAAgB,wBAAwB,CACvC,KAAK,EAAE,OAAO,EACd,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,MAAM,EACjB,OAAO,GAAE;IAAE,UAAU,CAAC,EAAE,OAAO,CAAC;IAAC,mBAAmB,CAAC,EAAE,OAAO,CAAA;CAAO,GACnE,gBAAgB,CAWlB;AAED,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,GAAG,gBAAgB,CAMzF;AAED,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,GAAG,gBAAgB,CAExF;AAED,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,GAAG,gBAAgB,CAEzF;AAED,wBAAgB,8BAA8B,CAC7C,KAAK,EAAE,OAAO,EACd,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,MAAM,GACd,gBAAgB,CAOlB;AAED,wBAAgB,8BAA8B,CAC7C,KAAK,EAAE,OAAO,EACd,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,MAAM,GACd,gBAAgB,CAOlB;AAED,wBAAgB,8BAA8B,CAC7C,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9B,KAAK,EAAE,MAAM,GACX,MAAM,EAAE,CAWV;AAED,wBAAgB,mCAAmC,CAClD,KAAK,EAAE,OAAO,EACd,KAAK,EAAE,MAAM,GACX,gBAAgB,CAElB"}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { invalid, valid, validateNoForbiddenRawPayloads, validateOpaqueId, validateOpaqueRef, } from "./validators.js";
|
|
2
|
+
export { invalid, valid } from "./validators.js";
|
|
3
|
+
export const FLOWDESK_PLANNING_AUTHORITY_KEYS_V1 = [
|
|
4
|
+
"dispatch_authority_enabled",
|
|
5
|
+
"provider_call_made",
|
|
6
|
+
"runtime_execution",
|
|
7
|
+
"actual_lane_launch",
|
|
8
|
+
"write_authority_enabled",
|
|
9
|
+
];
|
|
10
|
+
const AUTHORITY_TRUE_KEYS = new Set([
|
|
11
|
+
...FLOWDESK_PLANNING_AUTHORITY_KEYS_V1,
|
|
12
|
+
"realOpenCodeDispatch",
|
|
13
|
+
"providerCall",
|
|
14
|
+
"actualLaneLaunch",
|
|
15
|
+
"runtimeExecution",
|
|
16
|
+
"fallbackAuthority",
|
|
17
|
+
"toolAuthority",
|
|
18
|
+
"hardCancelOrNoReplyAuthority",
|
|
19
|
+
"fallback_allowed",
|
|
20
|
+
"reselection_allowed",
|
|
21
|
+
]);
|
|
22
|
+
const AUTHORITY_SMUGGLING_PATTERN = /\b(?:approve(?:d|s)?|approval|authorize(?:d|s)?|authorization|guard(?:ed)?\s+approval|dispatch(?:able|ed|es)?|dispatch\s*-?authority|real\s*-?(?:opencode\s*-?)?dispatch|provider\s*-?(?:call|payload|response)|runtime\s*-?execution|runtime[-_\s]*lane[-_\s]*launch|actual\s*-?lane\s*-?launch|lane\s*-?launch|fallback|reselection|reselect|retry\s+with\s+(?:another|different)|switch\s+(?:provider|model)|no\s*-?reply|hard\s*-?(?:cancel|stop)|opencode\s+run|hidden\s+injection)\b/i;
|
|
23
|
+
export function isPlanningEvidenceRecord(value) {
|
|
24
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
25
|
+
}
|
|
26
|
+
export function rejectUnknownPlanningProperties(value, allowed, label) {
|
|
27
|
+
return Object.keys(value)
|
|
28
|
+
.filter((key) => !allowed.has(key))
|
|
29
|
+
.map((key) => `${label} has unknown property: ${key}`);
|
|
30
|
+
}
|
|
31
|
+
export function requirePlanningKeys(value, keys, label) {
|
|
32
|
+
return keys
|
|
33
|
+
.filter((key) => !(key in value))
|
|
34
|
+
.map((key) => `${label} missing required field: ${key}`);
|
|
35
|
+
}
|
|
36
|
+
export function validatePlanningSafeText(value, label, maxLength, options = {}) {
|
|
37
|
+
if (typeof value !== "string")
|
|
38
|
+
return invalid(`${label} must be a string`);
|
|
39
|
+
if (!options.allowEmpty && value.trim().length === 0)
|
|
40
|
+
return invalid(`${label} must be a non-empty string`);
|
|
41
|
+
if (value.length > maxLength)
|
|
42
|
+
return invalid(`${label} exceeds ${maxLength} chars`);
|
|
43
|
+
const redaction = validateNoForbiddenRawPayloads(value, label);
|
|
44
|
+
if (!redaction.ok)
|
|
45
|
+
return redaction;
|
|
46
|
+
if (!options.allowAuthorityWords && AUTHORITY_SMUGGLING_PATTERN.test(value)) {
|
|
47
|
+
return invalid(`${label} contains authority-smuggling language`);
|
|
48
|
+
}
|
|
49
|
+
return valid();
|
|
50
|
+
}
|
|
51
|
+
export function validatePlanningTimestamp(value, label) {
|
|
52
|
+
if (typeof value !== "string" || value.length === 0)
|
|
53
|
+
return invalid(`${label} must be a timestamp string`);
|
|
54
|
+
return Number.isFinite(Date.parse(value))
|
|
55
|
+
? valid()
|
|
56
|
+
: invalid(`${label} must be a parseable timestamp`);
|
|
57
|
+
}
|
|
58
|
+
export function validatePlanningOpaqueId(value, label) {
|
|
59
|
+
return validateOpaqueId(value, label);
|
|
60
|
+
}
|
|
61
|
+
export function validatePlanningOpaqueRef(value, label) {
|
|
62
|
+
return validateOpaqueRef(value, label);
|
|
63
|
+
}
|
|
64
|
+
export function validatePlanningOpaqueRefArray(value, label, maxItems) {
|
|
65
|
+
if (!Array.isArray(value))
|
|
66
|
+
return invalid(`${label} must be an array`);
|
|
67
|
+
if (value.length > maxItems)
|
|
68
|
+
return invalid(`${label} exceeds ${maxItems} items`);
|
|
69
|
+
const errors = value.flatMap((item, index) => validateOpaqueRef(item, `${label}[${index}]`).errors);
|
|
70
|
+
return errors.length === 0 ? valid() : invalid(...errors);
|
|
71
|
+
}
|
|
72
|
+
export function validatePlanningSafeLabelArray(value, label, maxItems) {
|
|
73
|
+
if (!Array.isArray(value))
|
|
74
|
+
return invalid(`${label} must be an array`);
|
|
75
|
+
if (value.length > maxItems)
|
|
76
|
+
return invalid(`${label} exceeds ${maxItems} items`);
|
|
77
|
+
const errors = value.flatMap((item, index) => validatePlanningSafeText(item, `${label}[${index}]`, 120).errors);
|
|
78
|
+
return errors.length === 0 ? valid() : invalid(...errors);
|
|
79
|
+
}
|
|
80
|
+
export function validatePlanningAuthorityFalse(value, label) {
|
|
81
|
+
const errors = [];
|
|
82
|
+
for (const key of FLOWDESK_PLANNING_AUTHORITY_KEYS_V1) {
|
|
83
|
+
if (value[key] !== false)
|
|
84
|
+
errors.push(`${label}.${key} must be false`);
|
|
85
|
+
}
|
|
86
|
+
for (const [key, nested] of Object.entries(value)) {
|
|
87
|
+
if (AUTHORITY_TRUE_KEYS.has(key) && nested === true) {
|
|
88
|
+
errors.push(`${label}.${key} cannot be true`);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return errors;
|
|
92
|
+
}
|
|
93
|
+
export function validatePlanningNoForbiddenPayloads(value, label) {
|
|
94
|
+
return validateNoForbiddenRawPayloads(value, label);
|
|
95
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"planning-evidence-common.js","sourceRoot":"","sources":["../src/planning-evidence-common.ts"],"names":[],"mappings":"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"}
|
|
@@ -58,4 +58,3 @@ export function validateFlowDeskPreDispatchAuditRecordV1(value) {
|
|
|
58
58
|
errors.push(...validateNoForbiddenRawPayloads(value, "pre_dispatch_audit_record").errors);
|
|
59
59
|
return errors.length === 0 ? valid() : invalid(...errors);
|
|
60
60
|
}
|
|
61
|
-
//# sourceMappingURL=pre-dispatch-audit-record.js.map
|
|
@@ -60,6 +60,7 @@ export interface FlowDeskProviderUsageCollectorResultV1 {
|
|
|
60
60
|
providerHealthSnapshot: FlowDeskProviderHealthSnapshotV1;
|
|
61
61
|
usageAuthorityEvidence?: FlowDeskManagedDispatchBetaUsageAuthorityEvidenceV1;
|
|
62
62
|
bucketSnapshot?: FlowDeskProviderUsageCollectorBucketSnapshotV1;
|
|
63
|
+
additionalSnapshots?: readonly FlowDeskUsageSnapshotV1[];
|
|
63
64
|
redacted_reason?: string;
|
|
64
65
|
}
|
|
65
66
|
export declare function collectManagedDispatchBetaUsageEvidenceV1(target: FlowDeskProviderUsageCollectorTargetV1, acquisition: FlowDeskProviderUsageAcquisitionConfigV1 | undefined, options?: FlowDeskProviderUsageCollectorOptionsV1): Promise<FlowDeskProviderUsageCollectorResultV1>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"provider-usage-collector.d.ts","sourceRoot":"","sources":["../src/provider-usage-collector.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"provider-usage-collector.d.ts","sourceRoot":"","sources":["../src/provider-usage-collector.ts"],"names":[],"mappings":"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"}
|
|
@@ -22,8 +22,10 @@ export async function collectManagedDispatchBetaUsageEvidenceV1(target, acquisit
|
|
|
22
22
|
: refusedCollection(target.providerFamily, target.modelFamily, "provider usage acquisition is disabled");
|
|
23
23
|
const bucket = collection.bucket;
|
|
24
24
|
const resetAt = bucket?.resetAt;
|
|
25
|
-
const
|
|
26
|
-
const
|
|
25
|
+
const remaining = bucket?.remaining ?? null;
|
|
26
|
+
const usageKnown = bucket !== undefined && remaining !== null && resetAt !== undefined && bucket.uncertainty === "available";
|
|
27
|
+
const usageOk = usageKnown && remaining > 0;
|
|
28
|
+
const usageSnapshot = usageKnown
|
|
27
29
|
? {
|
|
28
30
|
schema_version: "flowdesk.usage_snapshot.v1",
|
|
29
31
|
snapshot_id: target.usageSnapshotId,
|
|
@@ -32,8 +34,8 @@ export async function collectManagedDispatchBetaUsageEvidenceV1(target, acquisit
|
|
|
32
34
|
freshness: "fresh",
|
|
33
35
|
freshness_ttl: ttlMinutes,
|
|
34
36
|
reset_time: resetAt,
|
|
35
|
-
reset_bucket: bucket.resetBucket,
|
|
36
|
-
dispatchability: "dispatchable",
|
|
37
|
+
reset_bucket: remaining === 0 ? `0% ${bucket.resetBucket}` : bucket.resetBucket,
|
|
38
|
+
dispatchability: usageOk ? "dispatchable" : "non_dispatchable",
|
|
37
39
|
uncertainty_flags: [],
|
|
38
40
|
source_ref: target.sourceRef
|
|
39
41
|
}
|
|
@@ -62,6 +64,28 @@ export async function collectManagedDispatchBetaUsageEvidenceV1(target, acquisit
|
|
|
62
64
|
uncertainty: bucket.uncertainty
|
|
63
65
|
}
|
|
64
66
|
: undefined;
|
|
67
|
+
const additionalSnapshots = [];
|
|
68
|
+
for (const addBucket of collection.additionalBuckets ?? []) {
|
|
69
|
+
const addResetAt = addBucket.resetAt;
|
|
70
|
+
const addRemaining = addBucket.remaining;
|
|
71
|
+
const addKnown = addRemaining !== null && addResetAt !== undefined && addBucket.uncertainty === "available";
|
|
72
|
+
const addOk = addKnown && addRemaining > 0;
|
|
73
|
+
additionalSnapshots.push(addKnown
|
|
74
|
+
? {
|
|
75
|
+
schema_version: "flowdesk.usage_snapshot.v1",
|
|
76
|
+
snapshot_id: `${target.usageSnapshotId}-${addBucket.resetBucket}`,
|
|
77
|
+
provider_family: target.providerFamily,
|
|
78
|
+
model_family: target.modelFamily,
|
|
79
|
+
freshness: "fresh",
|
|
80
|
+
freshness_ttl: ttlMinutes,
|
|
81
|
+
reset_time: addResetAt,
|
|
82
|
+
reset_bucket: addBucket.remaining !== null ? `${addBucket.remaining}% ${addBucket.resetBucket}` : addBucket.resetBucket,
|
|
83
|
+
dispatchability: addOk ? "dispatchable" : "non_dispatchable",
|
|
84
|
+
uncertainty_flags: [],
|
|
85
|
+
source_ref: target.sourceRef,
|
|
86
|
+
}
|
|
87
|
+
: unknownUsageSnapshot({ ...target, usageSnapshotId: `${target.usageSnapshotId}-${addBucket.resetBucket}` }, { ...collection, bucket: addBucket }, ttlMinutes));
|
|
88
|
+
}
|
|
65
89
|
if (!usageOk || collection.authProfileRef === undefined || collection.authEvidenceRef === undefined || collection.credentialScopeRef === undefined || collection.accountBoundaryRef === undefined || collection.quotaEvidenceRef === undefined) {
|
|
66
90
|
return {
|
|
67
91
|
ok: false,
|
|
@@ -69,6 +93,7 @@ export async function collectManagedDispatchBetaUsageEvidenceV1(target, acquisit
|
|
|
69
93
|
usageSnapshot,
|
|
70
94
|
providerHealthSnapshot,
|
|
71
95
|
...(bucketSnapshot !== undefined ? { bucketSnapshot } : {}),
|
|
96
|
+
...(additionalSnapshots.length > 0 ? { additionalSnapshots } : {}),
|
|
72
97
|
redacted_reason: collection.redactedReason ?? "usage evidence is unavailable"
|
|
73
98
|
};
|
|
74
99
|
}
|
|
@@ -78,6 +103,7 @@ export async function collectManagedDispatchBetaUsageEvidenceV1(target, acquisit
|
|
|
78
103
|
usageSnapshot,
|
|
79
104
|
providerHealthSnapshot,
|
|
80
105
|
...(bucketSnapshot !== undefined ? { bucketSnapshot } : {}),
|
|
106
|
+
...(additionalSnapshots.length > 0 ? { additionalSnapshots } : {}),
|
|
81
107
|
usageAuthorityEvidence: {
|
|
82
108
|
schema_version: "flowdesk.managed_dispatch_beta.usage_authority_evidence.v1",
|
|
83
109
|
authority_ref: target.authorityRef,
|
|
@@ -135,7 +161,10 @@ async function collectClaudeUsage(acquisition, options, observedAt) {
|
|
|
135
161
|
return refusedCollection("claude", "claude", "claude usage endpoint refused");
|
|
136
162
|
const payload = JSON.parse(await response.text());
|
|
137
163
|
const buckets = claudeOAuthBuckets(payload, observedAt, defaults());
|
|
138
|
-
|
|
164
|
+
const primaryBucket = firstDispatchableBucket(buckets) ?? buckets[0] ?? defaults()[0];
|
|
165
|
+
const additionalBuckets = buckets.filter((b) => b !== primaryBucket);
|
|
166
|
+
const collection = availableCollection("claude", "claude", "claude-oauth", "claude-oauth", primaryBucket);
|
|
167
|
+
return { ...collection, additionalBuckets };
|
|
139
168
|
}
|
|
140
169
|
catch {
|
|
141
170
|
return refusedCollection("claude", "claude", "claude usage collection failed");
|
|
@@ -165,8 +194,11 @@ async function collectCodexUsage(acquisition, options, observedAt) {
|
|
|
165
194
|
});
|
|
166
195
|
if (!response.ok)
|
|
167
196
|
return refusedCollection("openai", "gpt", "codex usage endpoint refused");
|
|
168
|
-
const
|
|
169
|
-
|
|
197
|
+
const buckets = codexLiveBuckets(JSON.parse(await response.text()), observedAt);
|
|
198
|
+
const primaryBucket = firstDispatchableBucket(buckets) ?? buckets[0] ?? bucket("openai-gpt-5h", "%", null, undefined, "unknown");
|
|
199
|
+
const additionalBuckets = buckets.filter((b) => b !== primaryBucket);
|
|
200
|
+
const collection = availableCollection("openai", "gpt", "codex-live", firstNonEmpty(accountId, "codex-account"), primaryBucket);
|
|
201
|
+
return { ...collection, additionalBuckets };
|
|
170
202
|
}
|
|
171
203
|
catch {
|
|
172
204
|
return refusedCollection("openai", "gpt", "codex usage collection failed");
|
|
@@ -180,20 +212,23 @@ async function collectGeminiUsage(acquisition, options, observedAt) {
|
|
|
180
212
|
return refusedCollection("gemini", "gemini", "fetch is unavailable");
|
|
181
213
|
const homeDir = normalizeHomeDir(acquisition.homeDir, options.env);
|
|
182
214
|
const filesystem = options.filesystem ?? defaultFilesystem;
|
|
215
|
+
const openCodeCreds = readOpenCodeGeminiOAuthCredentials(homeDir, options.env, filesystem);
|
|
183
216
|
const credsPath = geminiCredentialPaths(homeDir, options.env).find((candidate) => filesystem.exists(candidate));
|
|
184
|
-
if (!credsPath)
|
|
217
|
+
if (!credsPath && !openCodeCreds)
|
|
185
218
|
return refusedCollection("gemini", "gemini", "gemini auth evidence is missing");
|
|
186
219
|
try {
|
|
187
|
-
const
|
|
188
|
-
const
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
const
|
|
192
|
-
const
|
|
220
|
+
const geminiCliCreds = credsPath ? readGeminiCliOAuthCredentials(credsPath, filesystem) : null;
|
|
221
|
+
const selectedCreds = selectGeminiOAuthCredentials(openCodeCreds, geminiCliCreds, observedAt);
|
|
222
|
+
if (!selectedCreds)
|
|
223
|
+
return refusedCollection("gemini", "gemini", "gemini auth evidence is missing");
|
|
224
|
+
const refreshToken = selectedCreds.refreshToken;
|
|
225
|
+
const cachedAccessToken = selectedCreds.accessToken;
|
|
226
|
+
const cachedExpiryMs = selectedCreds.expiresAt ?? NaN;
|
|
193
227
|
const cachedTokenStillValid = cachedAccessToken !== "" && Number.isFinite(cachedExpiryMs) && cachedExpiryMs > observedAt + 5 * 60_000;
|
|
194
228
|
const env = options.env ?? {};
|
|
195
|
-
const
|
|
196
|
-
const
|
|
229
|
+
const inferredClient = readOpenCodeGeminiAuthOAuthClient(homeDir, env, filesystem);
|
|
230
|
+
const clientId = firstNonEmpty(acquisition.geminiOAuthClientId, env.FLOWDESK_GEMINI_OAUTH_CLIENT_ID, inferredClient?.clientId);
|
|
231
|
+
const clientSecret = firstNonEmpty(acquisition.geminiOAuthClientSecret, env.FLOWDESK_GEMINI_OAUTH_CLIENT_SECRET, inferredClient?.clientSecret);
|
|
197
232
|
let accessToken = "";
|
|
198
233
|
if (cachedTokenStillValid) {
|
|
199
234
|
accessToken = cachedAccessToken;
|
|
@@ -213,19 +248,101 @@ async function collectGeminiUsage(acquisition, options, observedAt) {
|
|
|
213
248
|
return refusedCollection("gemini", "gemini", "gemini oauth client evidence is missing and cached access token is expired");
|
|
214
249
|
return refusedCollection("gemini", "gemini", "gemini token refresh failed");
|
|
215
250
|
}
|
|
216
|
-
let projectId = firstNonEmpty(env.GOOGLE_CLOUD_PROJECT, env.GOOGLE_CLOUD_PROJECT_ID, acquisition.geminiProjectId);
|
|
251
|
+
let projectId = firstNonEmpty(env.GOOGLE_CLOUD_PROJECT, env.GOOGLE_CLOUD_PROJECT_ID, acquisition.geminiProjectId, selectedCreds.projectId);
|
|
217
252
|
const details = await codeAssistPost("loadCodeAssist", { cloudaicompanionProject: projectId, metadata: { ideType: "IDE_UNSPECIFIED", platform: "PLATFORM_UNSPECIFIED", pluginType: "GEMINI", duetProject: projectId } }, accessToken, fetcher);
|
|
218
253
|
projectId = firstNonEmpty(projectId, stringField(details, "cloudaicompanionProject"));
|
|
219
254
|
if (!projectId)
|
|
220
255
|
return refusedCollection("gemini", "gemini", "gemini project boundary is missing");
|
|
221
256
|
const quota = await codeAssistPost("retrieveUserQuota", { project: projectId }, accessToken, fetcher);
|
|
222
|
-
const
|
|
223
|
-
|
|
257
|
+
const buckets = geminiQuotaBuckets(quota, observedAt);
|
|
258
|
+
const primaryBucket = firstDispatchableBucket(buckets) ?? firstKnownBucket(buckets) ?? buckets[0] ?? bucket("gemini-unknown-5h", "%", null, undefined, "unknown");
|
|
259
|
+
const additionalBuckets = buckets.filter((b) => b !== primaryBucket);
|
|
260
|
+
const collection = availableCollection("gemini", "gemini", "gemini-code-assist", projectId, primaryBucket);
|
|
261
|
+
return { ...collection, additionalBuckets };
|
|
224
262
|
}
|
|
225
263
|
catch {
|
|
226
264
|
return refusedCollection("gemini", "gemini", "gemini usage collection failed");
|
|
227
265
|
}
|
|
228
266
|
}
|
|
267
|
+
function readGeminiCliOAuthCredentials(credsPath, filesystem) {
|
|
268
|
+
try {
|
|
269
|
+
const creds = JSON.parse(filesystem.readFile(credsPath));
|
|
270
|
+
const record = isRecord(creds) ? creds : {};
|
|
271
|
+
const refreshToken = stringField(record, "refresh_token");
|
|
272
|
+
const accessToken = stringField(record, "access_token");
|
|
273
|
+
const expiryRaw = record.expiry_date;
|
|
274
|
+
const expiresAt = typeof expiryRaw === "number" ? expiryRaw : typeof expiryRaw === "string" ? Number.parseInt(expiryRaw, 10) : undefined;
|
|
275
|
+
if (!refreshToken && !accessToken)
|
|
276
|
+
return null;
|
|
277
|
+
return { accessToken, refreshToken, ...(expiresAt === undefined || !Number.isFinite(expiresAt) ? {} : { expiresAt }) };
|
|
278
|
+
}
|
|
279
|
+
catch {
|
|
280
|
+
return null;
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
function readOpenCodeGeminiOAuthCredentials(homeDir, env, filesystem) {
|
|
284
|
+
const fromEnv = authRecordFromOpenCodeAuthContent(env?.OPENCODE_AUTH_CONTENT);
|
|
285
|
+
if (fromEnv)
|
|
286
|
+
return fromEnv;
|
|
287
|
+
for (const authPath of openCodeAuthPaths(homeDir, env)) {
|
|
288
|
+
if (!filesystem.exists(authPath))
|
|
289
|
+
continue;
|
|
290
|
+
try {
|
|
291
|
+
const parsed = JSON.parse(filesystem.readFile(authPath));
|
|
292
|
+
const fromFile = authRecordFromOpenCodeAuthDatabase(parsed);
|
|
293
|
+
if (fromFile)
|
|
294
|
+
return fromFile;
|
|
295
|
+
}
|
|
296
|
+
catch { }
|
|
297
|
+
}
|
|
298
|
+
return null;
|
|
299
|
+
}
|
|
300
|
+
function authRecordFromOpenCodeAuthContent(value) {
|
|
301
|
+
if (!value)
|
|
302
|
+
return null;
|
|
303
|
+
try {
|
|
304
|
+
return authRecordFromOpenCodeAuthDatabase(JSON.parse(value));
|
|
305
|
+
}
|
|
306
|
+
catch {
|
|
307
|
+
return null;
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
function authRecordFromOpenCodeAuthDatabase(value) {
|
|
311
|
+
if (!isRecord(value))
|
|
312
|
+
return null;
|
|
313
|
+
return openCodeGeminiAuthRecordToCredentials(value.google) ?? openCodeGeminiAuthRecordToCredentials(value.gemini);
|
|
314
|
+
}
|
|
315
|
+
function openCodeGeminiAuthRecordToCredentials(value) {
|
|
316
|
+
if (!isRecord(value) || value.type !== "oauth")
|
|
317
|
+
return null;
|
|
318
|
+
const accessToken = stringField(value, "access");
|
|
319
|
+
const expiresAt = numberField(value, "expires");
|
|
320
|
+
const refresh = stringField(value, "refresh");
|
|
321
|
+
const [refreshToken = "", projectId = "", managedProjectId = ""] = refresh.split("|", 3);
|
|
322
|
+
if (!refreshToken && !accessToken)
|
|
323
|
+
return null;
|
|
324
|
+
return { accessToken, refreshToken, ...(expiresAt === undefined ? {} : { expiresAt }), ...(firstNonEmpty(projectId, managedProjectId) ? { projectId: firstNonEmpty(projectId, managedProjectId) } : {}) };
|
|
325
|
+
}
|
|
326
|
+
function selectGeminiOAuthCredentials(openCodeCreds, geminiCliCreds, observedAt) {
|
|
327
|
+
const candidates = [openCodeCreds, geminiCliCreds].filter((candidate) => candidate !== null);
|
|
328
|
+
const fresh = candidates.find((candidate) => candidate.accessToken && candidate.expiresAt !== undefined && candidate.expiresAt > observedAt + 5 * 60_000);
|
|
329
|
+
return fresh ?? candidates.find((candidate) => candidate.refreshToken) ?? candidates[0] ?? null;
|
|
330
|
+
}
|
|
331
|
+
function readOpenCodeGeminiAuthOAuthClient(homeDir, env, filesystem) {
|
|
332
|
+
for (const candidate of openCodeGeminiAuthPackageEntrypoints(homeDir, env)) {
|
|
333
|
+
if (!filesystem.exists(candidate))
|
|
334
|
+
continue;
|
|
335
|
+
try {
|
|
336
|
+
const source = filesystem.readFile(candidate);
|
|
337
|
+
const clientId = source.match(/GEMINI_CLIENT_ID\s*=\s*["']([^"']+)["']/)?.[1] ?? "";
|
|
338
|
+
const clientSecret = source.match(/GEMINI_CLIENT_SECRET\s*=\s*["']([^"']+)["']/)?.[1] ?? "";
|
|
339
|
+
if (clientId && clientSecret)
|
|
340
|
+
return { clientId, clientSecret };
|
|
341
|
+
}
|
|
342
|
+
catch { }
|
|
343
|
+
}
|
|
344
|
+
return null;
|
|
345
|
+
}
|
|
229
346
|
function availableCollection(providerFamily, modelFamily, authProfile, accountBoundary, providerBucket) {
|
|
230
347
|
if (providerBucket.remaining === null || providerBucket.remaining <= 0 || providerBucket.uncertainty !== "available") {
|
|
231
348
|
return { providerFamily, modelFamily, bucket: providerBucket, failureClass: "rate_limited", availabilityState: "unavailable", redactedReason: "usage is not available" };
|
|
@@ -276,12 +393,15 @@ function claudeUsageBucket(resetBucket, defaultBucket, value, observedAt) {
|
|
|
276
393
|
const calculated = calculateRemainingUsagePercent({ utilizationPercent: numberField(rawBucket, "utilization"), resetAt: stringField(rawBucket, "resets_at"), observedAt, expiredResetBehavior: "reset_to_full" });
|
|
277
394
|
return bucket(resetBucket, "%", calculated.remaining, calculated.reset_at, calculated.uncertainty);
|
|
278
395
|
}
|
|
279
|
-
function
|
|
396
|
+
function codexLiveBuckets(payload, observedAt) {
|
|
280
397
|
const record = isRecord(payload) ? payload : {};
|
|
281
398
|
const rateLimitPayload = isRecord(record.rate_limit_status) ? record.rate_limit_status : record;
|
|
282
399
|
const details = firstRecord(rateLimitPayload.rate_limit, record.rate_limit);
|
|
283
400
|
const primary = firstRecord(details?.primary_window, details?.primary, details);
|
|
284
|
-
|
|
401
|
+
const secondary = isRecord(details?.secondary_window) ? details.secondary_window : undefined;
|
|
402
|
+
const primaryBucket = codexRateLimitBucket("openai-gpt-5h", primary, observedAt);
|
|
403
|
+
const secondaryBucket = secondary !== undefined ? codexRateLimitBucket("openai-weekly", secondary, observedAt) : undefined;
|
|
404
|
+
return secondaryBucket !== undefined ? [primaryBucket, secondaryBucket] : [primaryBucket];
|
|
285
405
|
}
|
|
286
406
|
function codexRateLimitBucket(resetBucket, rateLimit, observedAt) {
|
|
287
407
|
if (!rateLimit)
|
|
@@ -293,9 +413,9 @@ function codexRateLimitBucket(resetBucket, rateLimit, observedAt) {
|
|
|
293
413
|
const calculated = calculateRemainingUsagePercent({ remainingPercent: reportedRemainingPercent, usedPercent, resetAtUnixSeconds: resetUnix, resetAfterSeconds, observedAt, expiredResetBehavior: "stale" });
|
|
294
414
|
return bucket(resetBucket, "%", calculated.remaining, calculated.reset_at, calculated.uncertainty);
|
|
295
415
|
}
|
|
296
|
-
function
|
|
416
|
+
function geminiQuotaBuckets(quota, observedAt) {
|
|
297
417
|
const quotaBuckets = Array.isArray(quota.buckets) ? quota.buckets.filter(isRecord) : [];
|
|
298
|
-
|
|
418
|
+
const selectedByBucket = new Map();
|
|
299
419
|
for (const quotaBucket of quotaBuckets) {
|
|
300
420
|
const tokenType = stringField(quotaBucket, "tokenType");
|
|
301
421
|
if (tokenType && tokenType !== "REQUESTS")
|
|
@@ -315,20 +435,38 @@ function geminiQuotaBucket(quota, observedAt) {
|
|
|
315
435
|
resetBucket = "gemini-pro-weekly";
|
|
316
436
|
}
|
|
317
437
|
else {
|
|
318
|
-
resetBucket = "gemini-pro-
|
|
438
|
+
resetBucket = "gemini-pro-daily";
|
|
319
439
|
}
|
|
320
440
|
}
|
|
321
441
|
if (!resetBucket)
|
|
322
442
|
continue;
|
|
323
443
|
const remainingPercent = calculateRemainingUsagePercent({ remainingFraction: numberField(quotaBucket, "remainingFraction"), remainingAmount: stringField(quotaBucket, "remainingAmount"), resetAt: stringField(quotaBucket, "resetTime"), observedAt, expiredResetBehavior: "reset_to_full" });
|
|
324
444
|
const candidate = bucket(resetBucket, "%", remainingPercent.remaining, remainingPercent.reset_at, remainingPercent.uncertainty);
|
|
325
|
-
|
|
326
|
-
|
|
445
|
+
const existing = selectedByBucket.get(resetBucket);
|
|
446
|
+
if (existing === undefined || existing.remaining === null || (candidate.remaining !== null && candidate.remaining < existing.remaining))
|
|
447
|
+
selectedByBucket.set(resetBucket, candidate);
|
|
327
448
|
}
|
|
328
|
-
|
|
449
|
+
const buckets = [...selectedByBucket.values()].sort((a, b) => geminiBucketRank(a.resetBucket) - geminiBucketRank(b.resetBucket));
|
|
450
|
+
return buckets.length > 0 ? buckets : [bucket("gemini-unknown-5h", "%", null, undefined, "unknown")];
|
|
451
|
+
}
|
|
452
|
+
function geminiBucketRank(resetBucket) {
|
|
453
|
+
if (resetBucket === "gemini-pro-daily")
|
|
454
|
+
return 0;
|
|
455
|
+
if (resetBucket === "gemini-pro-weekly")
|
|
456
|
+
return 1;
|
|
457
|
+
if (resetBucket === "gemini-flash-daily")
|
|
458
|
+
return 2;
|
|
459
|
+
if (resetBucket === "gemini-flash-lite-daily")
|
|
460
|
+
return 3;
|
|
461
|
+
return 99;
|
|
329
462
|
}
|
|
330
463
|
function firstDispatchableBucket(buckets) {
|
|
331
|
-
return buckets
|
|
464
|
+
return buckets
|
|
465
|
+
.filter((candidate) => candidate.remaining !== null && candidate.remaining > 0 && candidate.resetAt !== undefined && candidate.uncertainty === "available")
|
|
466
|
+
.sort((a, b) => (a.remaining ?? Number.POSITIVE_INFINITY) - (b.remaining ?? Number.POSITIVE_INFINITY))[0];
|
|
467
|
+
}
|
|
468
|
+
function firstKnownBucket(buckets) {
|
|
469
|
+
return buckets.find((candidate) => candidate.remaining !== null && candidate.resetAt !== undefined && candidate.uncertainty === "available");
|
|
332
470
|
}
|
|
333
471
|
async function readClaudeOAuthCredentials(homeDir, filesystem, options) {
|
|
334
472
|
const keychainCreds = readClaudeKeychainCredentials(options);
|
|
@@ -466,7 +604,7 @@ function calculateRemainingUsagePercent(input) {
|
|
|
466
604
|
return { remaining: null, used: null, ...(resetAt ? { reset_at: resetAt } : {}), uncertainty: "unknown" };
|
|
467
605
|
}
|
|
468
606
|
function availableResult(remaining, used, resetAt) {
|
|
469
|
-
return { remaining, used, ...(resetAt ? { reset_at: resetAt } : {}), uncertainty:
|
|
607
|
+
return { remaining, used, ...(resetAt ? { reset_at: resetAt } : {}), uncertainty: "available" };
|
|
470
608
|
}
|
|
471
609
|
function resolveResetAt(input, observedAt) {
|
|
472
610
|
if (typeof input.resetAt === "string" && input.resetAt.trim() !== "") {
|
|
@@ -493,6 +631,18 @@ function geminiCredentialPaths(homeDir, env) {
|
|
|
493
631
|
const geminiHome = env?.GEMINI_CLI_HOME;
|
|
494
632
|
return uniqueNonEmpty([geminiHome ? path.join(geminiHome, ".gemini", "oauth_creds.json") : undefined, geminiHome ? path.join(geminiHome, "oauth_creds.json") : undefined, path.join(homeDir, ".gemini", "oauth_creds.json")]);
|
|
495
633
|
}
|
|
634
|
+
function openCodeAuthPaths(homeDir, env) {
|
|
635
|
+
const dataHome = firstNonEmpty(env?.OPENCODE_DATA_DIR, env?.XDG_DATA_HOME ? path.join(env.XDG_DATA_HOME, "opencode") : undefined, path.join(homeDir, ".local", "share", "opencode"));
|
|
636
|
+
return uniqueNonEmpty([dataHome ? path.join(dataHome, "auth.json") : undefined]);
|
|
637
|
+
}
|
|
638
|
+
function openCodeGeminiAuthPackageEntrypoints(homeDir, env) {
|
|
639
|
+
const cacheHome = firstNonEmpty(env?.OPENCODE_CACHE_DIR, env?.XDG_CACHE_HOME ? path.join(env.XDG_CACHE_HOME, "opencode") : undefined, path.join(homeDir, ".cache", "opencode"));
|
|
640
|
+
return uniqueNonEmpty([
|
|
641
|
+
cacheHome ? path.join(cacheHome, "packages", "opencode-gemini-auth@latest", "node_modules", "opencode-gemini-auth", "dist", "index.js") : undefined,
|
|
642
|
+
cacheHome ? path.join(cacheHome, "packages", "opencode-gemini-auth@latest", "dist", "index.js") : undefined,
|
|
643
|
+
cacheHome ? path.join(cacheHome, "packages", "opencode-gemini-auth", "node_modules", "opencode-gemini-auth", "dist", "index.js") : undefined,
|
|
644
|
+
]);
|
|
645
|
+
}
|
|
496
646
|
function claudeKeychainServiceName(env) {
|
|
497
647
|
const configDir = env?.CLAUDE_CONFIG_DIR;
|
|
498
648
|
const defaultService = configDir ? `Claude Code-credentials-${createHash("sha256").update(configDir).digest("hex").slice(0, 8)}` : "Claude Code-credentials";
|